From ea5e75df4e52efc5e03cc2bf2ce4893097c7375b Mon Sep 17 00:00:00 2001
From: Lawrence Rust <lvr@softsystem.co.uk>
Date: Thu, 2 Jun 2011 12:55:13 +0200
Subject: [PATCH 40/42] MythPlayer: Improvements to DVB-S radio playback
This fixes a number of issues to do with changing program to DVB-S radio and
the lack of video stream causing garbage video display.
Signed-off-by: Lawrence Rust <lvr@softsystem.co.uk>
---
mythtv/libs/libmythtv/RingBuffer.cpp | 3 +-
mythtv/libs/libmythtv/avformatdecoder.cpp | 13 +++
mythtv/libs/libmythtv/mythplayer.cpp | 123 +++++++++++++++++++----------
mythtv/libs/libmythtv/mythplayer.h | 2 +-
mythtv/libs/libmythtv/tv_play.cpp | 4 +-
5 files changed, 99 insertions(+), 46 deletions(-)
diff --git a/mythtv/libs/libmythtv/RingBuffer.cpp b/mythtv/libs/libmythtv/RingBuffer.cpp
index 1e40c43..95fb96b 100644
|
a
|
b
|
int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)
|
| 761 | 761 | void RingBuffer::UpdateRawBitrate(uint raw_bitrate) |
| 762 | 762 | { |
| 763 | 763 | VERBOSE(VB_FILE, LOC + QString("UpdateRawBitrate(%1Kb)").arg(raw_bitrate)); |
| 764 | | if (raw_bitrate < 2500) |
| | 764 | // NB DVB-S radio can be 64kbps |
| | 765 | if (raw_bitrate < 64) |
| 765 | 766 | { |
| 766 | 767 | VERBOSE(VB_FILE, LOC + |
| 767 | 768 | QString("UpdateRawBitrate(%1Kb) - ignoring bitrate,") |
diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
index 548de7b..fed322a 100644
|
a
|
b
|
bool AvFormatDecoder::GetFrame(DecodeType decodetype)
|
| 4272 | 4272 | av_init_packet(pkt); |
| 4273 | 4273 | } |
| 4274 | 4274 | |
| | 4275 | // NB av_read_frame will block until |
| | 4276 | // either a frame is read or an error occurs |
| | 4277 | // so MythPlayer::DecoderLoop will be unable to pause or stop |
| 4275 | 4278 | int retval; |
| 4276 | 4279 | if (!ic || ((retval = av_read_frame(ic, pkt)) < 0)) |
| 4277 | 4280 | { |
| … |
… |
bool AvFormatDecoder::GetFrame(DecodeType decodetype)
|
| 4421 | 4424 | case CODEC_TYPE_AUDIO: |
| 4422 | 4425 | { |
| 4423 | 4426 | if (!ProcessAudioPacket(curstream, pkt, decodetype)) |
| | 4427 | { |
| 4424 | 4428 | have_err = true; |
| | 4429 | if (!has_video) |
| | 4430 | { |
| | 4431 | VERBOSE(VB_PLAYBACK, LOC + |
| | 4432 | "GetFrame: exiting due to audio decode error"); |
| | 4433 | av_free_packet(pkt); |
| | 4434 | delete pkt; |
| | 4435 | return false; |
| | 4436 | } |
| | 4437 | } |
| 4425 | 4438 | break; |
| 4426 | 4439 | } |
| 4427 | 4440 | |
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 3233b96..1155a7b 100644
|
a
|
b
|
bool MythPlayer::Pause(void)
|
| 353 | 353 | |
| 354 | 354 | bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio) |
| 355 | 355 | { |
| 356 | | pauseLock.lock(); |
| | 356 | QMutexLocker locker(&pauseLock); |
| 357 | 357 | VERBOSE(VB_PLAYBACK, LOC + |
| 358 | 358 | QString("Play(%1, normal %2, unpause audio %3)") |
| 359 | 359 | .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio)); |
| … |
… |
bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
|
| 361 | 361 | if (deleteMap.IsEditing()) |
| 362 | 362 | { |
| 363 | 363 | VERBOSE(VB_IMPORTANT, LOC + "Ignoring Play(), in edit mode."); |
| 364 | | pauseLock.unlock(); |
| 365 | 364 | return false; |
| 366 | 365 | } |
| 367 | 366 | |
| … |
… |
bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
|
| 373 | 372 | allpaused = false; |
| 374 | 373 | next_play_speed = speed; |
| 375 | 374 | next_normal_speed = normal; |
| 376 | | pauseLock.unlock(); |
| 377 | 375 | return true; |
| 378 | 376 | } |
| 379 | 377 | |
| … |
… |
void MythPlayer::ReinitOSD(void)
|
| 548 | 546 | if (videoOutput && !using_null_videoout) |
| 549 | 547 | { |
| 550 | 548 | osdLock.lock(); |
| 551 | | if (QThread::currentThread() != (QThread*)playerThread) |
| | 549 | if (QThread::currentThread() != playerThread) |
| 552 | 550 | { |
| 553 | 551 | reinit_osd = true; |
| 554 | 552 | osdLock.unlock(); |
| … |
… |
void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
|
| 1932 | 1930 | // clear the buffering state |
| 1933 | 1931 | SetBuffering(false); |
| 1934 | 1932 | |
| 1935 | | videoOutput->StartDisplayingFrame(); |
| | 1933 | bool const bDisplayFrame = videoOutput->ValidVideoFrames() > 0; |
| | 1934 | if (bDisplayFrame) |
| | 1935 | videoOutput->StartDisplayingFrame(); |
| | 1936 | |
| 1936 | 1937 | VideoFrame *frame = videoOutput->GetLastShownFrame(); |
| 1937 | 1938 | PreProcessNormalFrame(); |
| 1938 | 1939 | |
| 1939 | | // handle scan type changes |
| 1940 | | AutoDeint(frame); |
| 1941 | | detect_letter_box->SwitchTo(frame); |
| | 1940 | if (!noVideoTracks) |
| | 1941 | { |
| | 1942 | // handle scan type changes |
| | 1943 | AutoDeint(frame); |
| | 1944 | detect_letter_box->SwitchTo(frame); |
| | 1945 | } |
| 1942 | 1946 | |
| 1943 | 1947 | FrameScanType ps = m_scan; |
| 1944 | 1948 | if (kScan_Detect == m_scan || kScan_Ignore == m_scan) |
| … |
… |
void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
|
| 1951 | 1955 | osdLock.unlock(); |
| 1952 | 1956 | |
| 1953 | 1957 | AVSync(frame, 0); |
| 1954 | | videoOutput->DoneDisplayingFrame(frame); |
| | 1958 | if (bDisplayFrame) |
| | 1959 | videoOutput->DoneDisplayingFrame(frame); |
| 1955 | 1960 | } |
| 1956 | 1961 | |
| 1957 | 1962 | void MythPlayer::PreProcessNormalFrame(void) |
| … |
… |
void MythPlayer::PreProcessNormalFrame(void)
|
| 1960 | 1965 | // handle Interactive TV |
| 1961 | 1966 | if (GetInteractiveTV()) |
| 1962 | 1967 | { |
| 1963 | | osdLock.lock(); |
| 1964 | | itvLock.lock(); |
| | 1968 | QMutexLocker lk1(&osdLock); |
| | 1969 | |
| 1965 | 1970 | if (osd && videoOutput->GetOSDPainter()) |
| 1966 | 1971 | { |
| | 1972 | QMutexLocker lk2(&itvLock); |
| | 1973 | |
| 1967 | 1974 | InteractiveScreen *window = |
| 1968 | 1975 | (InteractiveScreen*)osd->GetWindow(OSD_WIN_INTERACT); |
| 1969 | 1976 | if ((interactiveTV->ImageHasChanged() || !itvVisible) && window) |
| … |
… |
void MythPlayer::PreProcessNormalFrame(void)
|
| 1971 | 1978 | interactiveTV->UpdateOSD(window, videoOutput->GetOSDPainter()); |
| 1972 | 1979 | itvVisible = true; |
| 1973 | 1980 | } |
| | 1981 | // Hide the iTV window if OSD is active otherwise OSD messages |
| | 1982 | // can be hidden |
| | 1983 | if (window && itvVisible && noVideoTracks) |
| | 1984 | window->SetVisible(!osd->IsVisible()); |
| 1974 | 1985 | } |
| 1975 | | itvLock.unlock(); |
| 1976 | | osdLock.unlock(); |
| 1977 | 1986 | } |
| 1978 | 1987 | #endif // USING_MHEG |
| 1979 | 1988 | } |
| … |
… |
bool MythPlayer::VideoLoop(void)
|
| 2088 | 2097 | DisplayPauseFrame(); |
| 2089 | 2098 | } |
| 2090 | 2099 | else |
| 2091 | | DisplayNormalFrame(); |
| | 2100 | DisplayNormalFrame(!noVideoTracks); |
| 2092 | 2101 | |
| 2093 | 2102 | if (using_null_videoout && decoder) |
| 2094 | 2103 | decoder->UpdateFramesPlayed(); |
| … |
… |
void MythPlayer::SwitchToProgram(void)
|
| 2189 | 2198 | QSharedPointer<ProgramInfo> pginfo(player_ctx->tvchain->GetSwitchProgram( |
| 2190 | 2199 | discontinuity, newtype, newid)); |
| 2191 | 2200 | if (!pginfo) |
| | 2201 | { |
| | 2202 | VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram - No ProgramInfo"); |
| 2192 | 2203 | return; |
| | 2204 | } |
| 2193 | 2205 | |
| 2194 | 2206 | bool newIsDummy = player_ctx->tvchain->GetCardType(newid) == "DUMMY"; |
| 2195 | 2207 | |
| … |
… |
void MythPlayer::JumpToProgram(void)
|
| 2304 | 2316 | QSharedPointer<ProgramInfo> pginfo(player_ctx->tvchain->GetSwitchProgram( |
| 2305 | 2317 | discontinuity, newtype, newid)); |
| 2306 | 2318 | if (!pginfo) |
| | 2319 | { |
| | 2320 | VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram - No ProgramInfo"); |
| 2307 | 2321 | return; |
| | 2322 | } |
| 2308 | 2323 | newtype = true; // force reloading of context and stream properties |
| 2309 | 2324 | |
| 2310 | 2325 | bool newIsDummy = player_ctx->tvchain->GetCardType(newid) == "DUMMY"; |
| 2311 | 2326 | SetPlayingInfo(*pginfo); |
| 2312 | 2327 | |
| 2313 | 2328 | Pause(); |
| 2314 | | ChangeSpeed(); |
| 2315 | 2329 | ResetCaptions(); |
| 2316 | 2330 | player_ctx->tvchain->SetProgram(*pginfo); |
| 2317 | 2331 | player_ctx->buffer->Reset(true); |
| … |
… |
void MythPlayer::EventLoop(void)
|
| 2500 | 2514 | player_ctx->tvchain->JumpToNext(true, 1); |
| 2501 | 2515 | JumpToProgram(); |
| 2502 | 2516 | } |
| 2503 | | else if ((!allpaused || GetEof()) && player_ctx->tvchain && |
| 2504 | | (decoder && !decoder->GetWaitForChange())) |
| | 2517 | else if ((!allpaused || GetEof()) && |
| | 2518 | decoder && !decoder->GetWaitForChange() && |
| | 2519 | player_ctx->tvchain && player_ctx->tvchain->NeedsToSwitch()) |
| 2505 | 2520 | { |
| 2506 | 2521 | // Switch to the next program in livetv |
| 2507 | | if (player_ctx->tvchain->NeedsToSwitch()) |
| 2508 | | SwitchToProgram(); |
| | 2522 | SwitchToProgram(); |
| 2509 | 2523 | } |
| 2510 | 2524 | |
| 2511 | 2525 | // Jump to the next program in livetv |
| … |
… |
void MythPlayer::AudioEnd(void)
|
| 2663 | 2677 | |
| 2664 | 2678 | bool MythPlayer::PauseDecoder(void) |
| 2665 | 2679 | { |
| 2666 | | decoderPauseLock.lock(); |
| 2667 | | if (QThread::currentThread() == (QThread*)decoderThread) |
| | 2680 | VERBOSE(VB_PLAYBACK+VB_EXTRA, LOC + "Pause decoder."); |
| | 2681 | |
| | 2682 | QMutexLocker locker(&decoderPauseLock); |
| | 2683 | |
| | 2684 | if (QThread::currentThread() == static_cast<QThread*>(decoderThread)) |
| 2668 | 2685 | { |
| | 2686 | pauseDecoder = false; |
| 2669 | 2687 | decoderPaused = true; |
| 2670 | 2688 | decoderThreadPause.wakeAll(); |
| 2671 | | decoderPauseLock.unlock(); |
| 2672 | | return decoderPaused; |
| | 2689 | return true; |
| 2673 | 2690 | } |
| 2674 | 2691 | |
| 2675 | | int tries = 0; |
| 2676 | 2692 | pauseDecoder = true; |
| 2677 | | while (decoderThread && !killdecoder && (tries++ < 100) && |
| 2678 | | !decoderThreadPause.wait(&decoderPauseLock, 100)) |
| | 2693 | int tries = 0; |
| | 2694 | while (!decoderPaused && decoderThread && !killdecoder && (tries++ < 1) && |
| | 2695 | !decoderThreadPause.wait(locker.mutex(), 100)) |
| 2679 | 2696 | { |
| 2680 | 2697 | VERBOSE(VB_IMPORTANT, LOC_WARN + "Waited 100ms for decoder to pause"); |
| 2681 | 2698 | } |
| 2682 | 2699 | pauseDecoder = false; |
| 2683 | | decoderPauseLock.unlock(); |
| 2684 | 2700 | return decoderPaused; |
| 2685 | | } |
| | 2701 | } |
| 2686 | 2702 | |
| 2687 | 2703 | void MythPlayer::UnpauseDecoder(void) |
| 2688 | 2704 | { |
| 2689 | | decoderPauseLock.lock(); |
| | 2705 | VERBOSE(VB_PLAYBACK+VB_EXTRA, LOC + "Unpause decoder."); |
| | 2706 | |
| | 2707 | QMutexLocker locker(&decoderPauseLock); |
| 2690 | 2708 | |
| 2691 | | if (QThread::currentThread() == (QThread*)decoderThread) |
| | 2709 | if (QThread::currentThread() == static_cast<QThread*>(decoderThread)) |
| 2692 | 2710 | { |
| | 2711 | unpauseDecoder = false; |
| 2693 | 2712 | decoderPaused = false; |
| 2694 | 2713 | decoderThreadUnpause.wakeAll(); |
| 2695 | | decoderPauseLock.unlock(); |
| 2696 | 2714 | return; |
| 2697 | 2715 | } |
| 2698 | 2716 | |
| 2699 | | int tries = 0; |
| 2700 | 2717 | unpauseDecoder = true; |
| 2701 | | while (decoderThread && !killdecoder && (tries++ < 100) && |
| 2702 | | !decoderThreadUnpause.wait(&decoderPauseLock, 100)) |
| | 2718 | int tries = 0; |
| | 2719 | while (decoderPaused && decoderThread && !killdecoder && (tries++ < 1) && |
| | 2720 | !decoderThreadUnpause.wait(locker.mutex(), 100)) |
| 2703 | 2721 | { |
| 2704 | 2722 | VERBOSE(VB_IMPORTANT, LOC_WARN + "Waited 100ms for decoder to unpause"); |
| 2705 | 2723 | } |
| 2706 | 2724 | unpauseDecoder = false; |
| 2707 | | decoderPauseLock.unlock(); |
| 2708 | 2725 | } |
| 2709 | 2726 | |
| 2710 | 2727 | void MythPlayer::DecoderStart(bool start_paused) |
| … |
… |
void MythPlayer::DecoderEnd(void)
|
| 2730 | 2747 | SetPlaying(false); |
| 2731 | 2748 | killdecoder = true; |
| 2732 | 2749 | int tries = 0; |
| 2733 | | while (decoderThread && !decoderThread->wait(100) && (tries++ < 50)) |
| | 2750 | while (decoderThread && !decoderThread->wait(100) && (tries++ < 2)) |
| 2734 | 2751 | VERBOSE(VB_PLAYBACK, LOC + "Waited 100ms for decoder loop to stop"); |
| 2735 | 2752 | |
| 2736 | 2753 | if (decoderThread && decoderThread->isRunning()) |
| … |
… |
void MythPlayer::DecoderEnd(void)
|
| 2741 | 2758 | |
| 2742 | 2759 | void MythPlayer::DecoderPauseCheck(void) |
| 2743 | 2760 | { |
| 2744 | | if (QThread::currentThread() != (QThread*)decoderThread) |
| | 2761 | if (QThread::currentThread() != static_cast<QThread*>(decoderThread)) |
| 2745 | 2762 | return; |
| | 2763 | |
| | 2764 | QMutexLocker locker(&decoderPauseLock); |
| | 2765 | |
| 2746 | 2766 | if (pauseDecoder) |
| 2747 | | PauseDecoder(); |
| | 2767 | { |
| | 2768 | pauseDecoder = false; |
| | 2769 | decoderPaused = true; |
| | 2770 | VERBOSE(VB_PLAYBACK+VB_EXTRA, LOC + "Decoder paused."); |
| | 2771 | decoderThreadPause.wakeAll(); |
| | 2772 | } |
| | 2773 | |
| 2748 | 2774 | if (unpauseDecoder) |
| 2749 | | UnpauseDecoder(); |
| | 2775 | { |
| | 2776 | unpauseDecoder = false; |
| | 2777 | decoderPaused = false; |
| | 2778 | VERBOSE(VB_PLAYBACK+VB_EXTRA, LOC + "Decoder unpaused."); |
| | 2779 | decoderThreadUnpause.wakeAll(); |
| | 2780 | } |
| 2750 | 2781 | } |
| 2751 | 2782 | |
| 2752 | 2783 | //// FIXME - move the eof ownership back into MythPlayer |
| 2753 | 2784 | bool MythPlayer::GetEof(void) |
| 2754 | 2785 | { |
| 2755 | | if (QThread::currentThread() == (QThread*)playerThread) |
| | 2786 | if (QThread::currentThread() == playerThread) |
| 2756 | 2787 | return decoder ? decoder->GetEof() : true; |
| 2757 | 2788 | |
| 2758 | | decoder_change_lock.lock(); |
| | 2789 | // This must be a tryLock for the case of an audio only stream |
| | 2790 | // when the decoder thread never exits decoder->GetFrame |
| | 2791 | if (!decoder_change_lock.tryLock(10)) |
| | 2792 | return false; |
| 2759 | 2793 | bool eof = decoder ? decoder->GetEof() : true; |
| 2760 | 2794 | decoder_change_lock.unlock(); |
| 2761 | 2795 | return eof; |
| … |
… |
bool MythPlayer::GetEof(void)
|
| 2763 | 2797 | |
| 2764 | 2798 | void MythPlayer::SetEof(bool eof) |
| 2765 | 2799 | { |
| 2766 | | if (QThread::currentThread() == (QThread*)playerThread) |
| | 2800 | if (QThread::currentThread() == playerThread) |
| 2767 | 2801 | { |
| 2768 | 2802 | if (decoder) |
| 2769 | 2803 | decoder->SetEof(eof); |
| 2770 | 2804 | return; |
| 2771 | 2805 | } |
| 2772 | 2806 | |
| 2773 | | decoder_change_lock.lock(); |
| | 2807 | // This must be a tryLock for the case of an audio only stream |
| | 2808 | // when the decoder thread never exits decoder->GetFrame |
| | 2809 | if (!decoder_change_lock.tryLock(10)) |
| | 2810 | return; |
| 2774 | 2811 | if (decoder) |
| 2775 | 2812 | decoder->SetEof(eof); |
| 2776 | 2813 | decoder_change_lock.unlock(); |
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index 5aba7de..57213c8 100644
|
a
|
b
|
class MPUBLIC MythPlayer
|
| 537 | 537 | bool decoderPaused; |
| 538 | 538 | bool pauseDecoder; |
| 539 | 539 | bool unpauseDecoder; |
| 540 | | bool killdecoder; |
| | 540 | bool volatile killdecoder; |
| 541 | 541 | int64_t decoderSeek; |
| 542 | 542 | bool decodeOneFrame; |
| 543 | 543 | bool needNewPauseFrame; |
diff --git a/mythtv/libs/libmythtv/tv_play.cpp b/mythtv/libs/libmythtv/tv_play.cpp
index e8d0c2d..004db3e 100644
|
a
|
b
|
void TV::ChangeChannel(PlayerContext *ctx, uint chanid, const QString &chan)
|
| 6894 | 6894 | if (ctx->prevChan.empty()) |
| 6895 | 6895 | ctx->PushPreviousChannel(); |
| 6896 | 6896 | |
| 6897 | | PauseAudioUntilBuffered(ctx); |
| | 6897 | if (ctx->player) |
| | 6898 | ctx->player->GetAudio()->Pause(true); |
| 6898 | 6899 | PauseLiveTV(ctx); |
| 6899 | 6900 | |
| 6900 | 6901 | ctx->LockDeletePlayer(__FILE__, __LINE__); |
| … |
… |
void TV::ChangeChannel(PlayerContext *ctx, uint chanid, const QString &chan)
|
| 6911 | 6912 | ctx->player->GetAudio()->Reset(); |
| 6912 | 6913 | |
| 6913 | 6914 | UnpauseLiveTV(ctx); |
| | 6915 | PauseAudioUntilBuffered(ctx); |
| 6914 | 6916 | |
| 6915 | 6917 | if (oldinputname != ctx->recorder->GetInput()) |
| 6916 | 6918 | UpdateOSDInput(ctx); |