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); |