play media to end when eof detected
From: Mark Spieth <mspieth@digivation.com.au>
---
mythtv/libs/libmythtv/decoderbase.cpp | 4 +-
mythtv/libs/libmythtv/decoderbase.h | 15 +++++--
mythtv/libs/libmythtv/mythplayer.cpp | 61 ++++++++++++++++-----------
mythtv/libs/libmythtv/mythplayer.h | 4 +-
mythtv/programs/mythtranscode/transcode.cpp | 1
5 files changed, 53 insertions(+), 32 deletions(-)
diff --git a/mythtv/libs/libmythtv/decoderbase.cpp b/mythtv/libs/libmythtv/decoderbase.cpp
index 3286be9..caa1216 100644
a
|
b
|
DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo) |
30 | 30 | framesPlayed(0), framesRead(0), totalDuration(0), |
31 | 31 | lastKey(0), keyframedist(-1), indexOffset(0), |
32 | 32 | |
33 | | ateof(false), exitafterdecoded(false), transcoding(false), |
| 33 | ateof(kEofStateNone), exitafterdecoded(false), transcoding(false), |
34 | 34 | |
35 | 35 | hasFullPositionMap(false), recordingHasPositionMap(false), |
36 | 36 | posmapStarted(false), positionMapType(MARK_UNSET), |
… |
… |
void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file) |
90 | 90 | if (reset_file) |
91 | 91 | { |
92 | 92 | waitingForChange = false; |
93 | | SetEof(false); |
| 93 | SetEof(kEofStateNone); |
94 | 94 | } |
95 | 95 | } |
96 | 96 | |
diff --git a/mythtv/libs/libmythtv/decoderbase.h b/mythtv/libs/libmythtv/decoderbase.h
index a9925d4..678094e 100644
a
|
b
|
typedef enum DecodeTypes |
47 | 47 | kDecodeAV = 0x03, |
48 | 48 | } DecodeType; |
49 | 49 | |
| 50 | // Eof States |
| 51 | typedef enum |
| 52 | { |
| 53 | kEofStateNone, |
| 54 | kEofStateDelayed, |
| 55 | kEofStateImmediate |
| 56 | } EofState; |
| 57 | |
50 | 58 | class StreamInfo |
51 | 59 | { |
52 | 60 | public: |
… |
… |
class DecoderBase |
97 | 105 | char testbuf[kDecoderProbeBufferSize], |
98 | 106 | int testbufsize = kDecoderProbeBufferSize) = 0; |
99 | 107 | |
100 | | virtual void SetEof(bool eof) { ateof = eof; } |
101 | | bool GetEof(void) const { return ateof; } |
| 108 | virtual void SetEof(EofState eof) { ateof = eof; } |
| 109 | virtual void SetEof(bool eof) { ateof = eof?kEofStateDelayed:kEofStateNone; } |
| 110 | EofState GetEof(void) { return ateof; } |
102 | 111 | |
103 | 112 | void setExactSeeks(bool exact) { exactseeks = exact; } |
104 | 113 | bool getExactSeeks(void) const { return exactseeks; } |
… |
… |
class DecoderBase |
244 | 253 | int keyframedist; |
245 | 254 | long long indexOffset; |
246 | 255 | |
247 | | bool ateof; |
| 256 | EofState ateof; |
248 | 257 | bool exitafterdecoded; |
249 | 258 | bool transcoding; |
250 | 259 | |
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index bffc141..167694e 100644
a
|
b
|
bool MythPlayer::PrebufferEnoughFrames(int min_buffers) |
2033 | 2033 | return false; |
2034 | 2034 | |
2035 | 2035 | if (!(min_buffers ? (videoOutput->ValidVideoFrames() >= min_buffers) : |
| 2036 | (GetEof() != kEofStateNone) || |
2036 | 2037 | (videoOutput->hasHWAcceleration() ? |
2037 | 2038 | videoOutput->EnoughPrebufferedFrames() : |
2038 | 2039 | videoOutput->EnoughDecodedFrames()))) |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2413 | 2414 | { |
2414 | 2415 | OpenDummy(); |
2415 | 2416 | ResetPlaying(); |
2416 | | SetEof(false); |
| 2417 | SetEof(kEofStateNone); |
2417 | 2418 | delete pginfo; |
2418 | 2419 | return; |
2419 | 2420 | } |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2427 | 2428 | QString("(card type: %1).") |
2428 | 2429 | .arg(player_ctx->tvchain->GetCardType(newid))); |
2429 | 2430 | LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString()); |
2430 | | SetEof(true); |
| 2431 | SetEof(kEofStateImmediate); |
2431 | 2432 | SetErrored(QObject::tr("Error opening switch program buffer")); |
2432 | 2433 | delete pginfo; |
2433 | 2434 | return; |
2434 | 2435 | } |
2435 | 2436 | |
2436 | | if (GetEof()) |
| 2437 | if (GetEof() != kEofStateNone) |
2437 | 2438 | ResetCaptions(); |
2438 | 2439 | |
2439 | 2440 | LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("newid: %1 decoderEof: %2") |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2452 | 2453 | if (IsErrored()) |
2453 | 2454 | { |
2454 | 2455 | LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram failed."); |
2455 | | SetEof(true); |
| 2456 | SetEof(kEofStateDelayed); |
2456 | 2457 | return; |
2457 | 2458 | } |
2458 | 2459 | |
2459 | | SetEof(false); |
| 2460 | SetEof(kEofStateNone); |
2460 | 2461 | |
2461 | 2462 | // the bitrate is reset by player_ctx->buffer->OpenFile()... |
2462 | 2463 | if (decoder) |
… |
… |
void MythPlayer::FileChangedCallback(void) |
2480 | 2481 | player_ctx->buffer->Reset(false, true); |
2481 | 2482 | else |
2482 | 2483 | player_ctx->buffer->Reset(false, true, true); |
2483 | | SetEof(false); |
| 2484 | SetEof(kEofStateNone); |
2484 | 2485 | Play(); |
2485 | 2486 | |
2486 | 2487 | player_ctx->SetPlayerChangingBuffers(false); |
… |
… |
void MythPlayer::JumpToProgram(void) |
2518 | 2519 | { |
2519 | 2520 | OpenDummy(); |
2520 | 2521 | ResetPlaying(); |
2521 | | SetEof(false); |
| 2522 | SetEof(kEofStateNone); |
2522 | 2523 | delete pginfo; |
2523 | 2524 | return; |
2524 | 2525 | } |
… |
… |
void MythPlayer::JumpToProgram(void) |
2534 | 2535 | QString("(card type: %1).") |
2535 | 2536 | .arg(player_ctx->tvchain->GetCardType(newid))); |
2536 | 2537 | LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString()); |
2537 | | SetEof(true); |
| 2538 | SetEof(kEofStateImmediate); |
2538 | 2539 | SetErrored(QObject::tr("Error opening jump program file buffer")); |
2539 | 2540 | delete pginfo; |
2540 | 2541 | return; |
… |
… |
void MythPlayer::JumpToProgram(void) |
2552 | 2553 | return; |
2553 | 2554 | } |
2554 | 2555 | |
2555 | | SetEof(false); |
| 2556 | SetEof(kEofStateNone); |
2556 | 2557 | |
2557 | 2558 | // the bitrate is reset by player_ctx->buffer->OpenFile()... |
2558 | 2559 | player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate()); |
… |
… |
void MythPlayer::EventLoop(void) |
2703 | 2704 | player_ctx->tvchain->JumpToNext(true, 1); |
2704 | 2705 | JumpToProgram(); |
2705 | 2706 | } |
2706 | | else if ((!allpaused || GetEof()) && player_ctx->tvchain && |
| 2707 | else if ((!allpaused || (GetEof() != kEofStateNone)) && player_ctx->tvchain && |
2707 | 2708 | (decoder && !decoder->GetWaitForChange())) |
2708 | 2709 | { |
2709 | 2710 | // Switch to the next program in livetv |
… |
… |
void MythPlayer::EventLoop(void) |
2753 | 2754 | } |
2754 | 2755 | |
2755 | 2756 | // Handle end of file |
2756 | | if (GetEof()) |
| 2757 | EofState _eof = GetEof(); |
| 2758 | if (_eof != kEofStateNone) |
2757 | 2759 | { |
2758 | 2760 | if (player_ctx->tvchain) |
2759 | 2761 | { |
… |
… |
void MythPlayer::EventLoop(void) |
2766 | 2768 | } |
2767 | 2769 | else if (!allpaused) |
2768 | 2770 | { |
2769 | | SetPlaying(false); |
2770 | | return; |
| 2771 | if (_eof == kEofStateImmediate) |
| 2772 | { |
| 2773 | SetPlaying(false); |
| 2774 | return; |
| 2775 | } |
| 2776 | LOG(VB_PLAYBACK, LOG_INFO, QString("waiting for no video frames %1").arg(videoOutput->ValidVideoFrames())); |
| 2777 | if (videoOutput && videoOutput->ValidVideoFrames() < 3) |
| 2778 | { |
| 2779 | SetPlaying(false); |
| 2780 | return; |
| 2781 | } |
2771 | 2782 | } |
2772 | 2783 | } |
2773 | 2784 | |
… |
… |
void MythPlayer::EventLoop(void) |
2786 | 2797 | if (fftime > 0) |
2787 | 2798 | { |
2788 | 2799 | DoFastForward(fftime); |
2789 | | if (GetEof()) |
| 2800 | if (GetEof() != kEofStateNone) |
2790 | 2801 | return; |
2791 | 2802 | } |
2792 | 2803 | } |
… |
… |
void MythPlayer::EventLoop(void) |
2847 | 2858 | if (!(endExitPrompt == 1 && !player_ctx->IsPIP() && |
2848 | 2859 | player_ctx->GetState() == kState_WatchingPreRecorded)) |
2849 | 2860 | { |
2850 | | SetEof(true); |
| 2861 | SetEof(kEofStateDelayed); |
2851 | 2862 | } |
2852 | 2863 | } |
2853 | 2864 | else |
… |
… |
void MythPlayer::DecoderPauseCheck(void) |
2954 | 2965 | } |
2955 | 2966 | |
2956 | 2967 | //// FIXME - move the eof ownership back into MythPlayer |
2957 | | bool MythPlayer::GetEof(void) |
| 2968 | EofState MythPlayer::GetEof(void) |
2958 | 2969 | { |
2959 | 2970 | if (is_current_thread(playerThread)) |
2960 | | return decoder ? decoder->GetEof() : true; |
| 2971 | return decoder ? decoder->GetEof() : kEofStateImmediate; |
2961 | 2972 | |
2962 | 2973 | if (!decoder_change_lock.tryLock(50)) |
2963 | | return false; |
2964 | | |
2965 | | bool eof = decoder ? decoder->GetEof() : true; |
| 2974 | return kEofStateNone; |
| 2975 | |
| 2976 | EofState eof = decoder ? decoder->GetEof() : kEofStateImmediate; |
2966 | 2977 | decoder_change_lock.unlock(); |
2967 | 2978 | return eof; |
2968 | 2979 | } |
2969 | 2980 | |
2970 | | void MythPlayer::SetEof(bool eof) |
| 2981 | void MythPlayer::SetEof(EofState eof) |
2971 | 2982 | { |
2972 | 2983 | if (is_current_thread(playerThread)) |
2973 | 2984 | { |
… |
… |
void MythPlayer::DecoderLoop(bool pause) |
3029 | 3040 | decoder_change_lock.unlock(); |
3030 | 3041 | } |
3031 | 3042 | |
3032 | | bool obey_eof = GetEof() && |
3033 | | !(GetEof() && player_ctx->tvchain && !allpaused); |
| 3043 | bool obey_eof = (GetEof() != kEofStateNone) && |
| 3044 | !((GetEof() != kEofStateNone) && player_ctx->tvchain && !allpaused); |
3034 | 3045 | if (isDummy || ((decoderPaused || ffrew_skip == 0 || obey_eof) && |
3035 | 3046 | !decodeOneFrame)) |
3036 | 3047 | { |
… |
… |
bool MythPlayer::TranscodeGetNextFrame( |
4374 | 4385 | if (!decoder->GetFrame(kDecodeAV)) |
4375 | 4386 | return false; |
4376 | 4387 | |
4377 | | if (GetEof()) |
| 4388 | if (GetEof() != kEofStateNone) |
4378 | 4389 | return false; |
4379 | 4390 | |
4380 | 4391 | if (honorCutList && !deleteMap.IsEmpty()) |
… |
… |
bool MythPlayer::TranscodeGetNextFrame( |
4400 | 4411 | did_ff = 1; |
4401 | 4412 | } |
4402 | 4413 | } |
4403 | | if (GetEof()) |
| 4414 | if (GetEof() != kEofStateNone) |
4404 | 4415 | return false; |
4405 | 4416 | is_key = decoder->IsLastFrameKey(); |
4406 | 4417 | |
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index a1aec32..42cfe52 100644
a
|
b
|
class MTV_PUBLIC MythPlayer |
144 | 144 | void SetLength(int len) { totalLength = len; } |
145 | 145 | void SetFramesPlayed(uint64_t played); |
146 | 146 | void SetVideoFilters(const QString &override); |
147 | | void SetEof(bool eof); |
| 147 | void SetEof(EofState eof); |
148 | 148 | void SetPIPActive(bool is_active) { pip_active = is_active; } |
149 | 149 | void SetPIPVisible(bool is_visible) { pip_visible = is_visible; } |
150 | 150 | |
… |
… |
class MTV_PUBLIC MythPlayer |
200 | 200 | bool IsPaused(void) const { return allpaused; } |
201 | 201 | bool GetRawAudioState(void) const; |
202 | 202 | bool GetLimitKeyRepeat(void) const { return limitKeyRepeat; } |
203 | | bool GetEof(void); |
| 203 | EofState GetEof(void); |
204 | 204 | bool IsErrored(void) const; |
205 | 205 | bool IsPlaying(uint wait_ms = 0, bool wait_for = true) const; |
206 | 206 | bool AtNormalSpeed(void) const { return next_normal_speed; } |
diff --git a/mythtv/programs/mythtranscode/transcode.cpp b/mythtv/programs/mythtranscode/transcode.cpp
index 7d8bb9d..70d6f75 100644
a
|
b
|
class AudioReencodeBuffer : public AudioOutput |
84 | 84 | eff_audiorate = (dsprate / 100); |
85 | 85 | } |
86 | 86 | |
| 87 | virtual void SetTimedBlocking(bool block) { (void)block; } |
87 | 88 | virtual void Reset(void) |
88 | 89 | { |
89 | 90 | audiobuffer_len = 0; |