diff --git a/mythtv/libs/libmythtv/decoderbase.cpp b/mythtv/libs/libmythtv/decoderbase.cpp
index 77947a4..5398d64 100644
a
|
b
|
DecoderBase::DecoderBase(MythPlayer *parent, const ProgramInfo &pginfo) |
31 | 31 | lastKey(0), keyframedist(-1), indexOffset(0), |
32 | 32 | trackTotalDuration(false), |
33 | 33 | |
34 | | ateof(false), exitafterdecoded(false), transcoding(false), |
| 34 | ateof(kEofStateNone), exitafterdecoded(false), transcoding(false), |
35 | 35 | |
36 | 36 | hasFullPositionMap(false), recordingHasPositionMap(false), |
37 | 37 | posmapStarted(false), positionMapType(MARK_UNSET), |
… |
… |
void DecoderBase::Reset(bool reset_video_data, bool seek_reset, bool reset_file) |
92 | 92 | if (reset_file) |
93 | 93 | { |
94 | 94 | waitingForChange = false; |
95 | | SetEof(false); |
| 95 | SetEof(kEofStateNone); |
96 | 96 | } |
97 | 97 | } |
98 | 98 | |
diff --git a/mythtv/libs/libmythtv/decoderbase.h b/mythtv/libs/libmythtv/decoderbase.h
index 2620c0c..7b7a568 100644
a
|
b
|
typedef enum AudioTrackType |
59 | 59 | } AudioTrackType; |
60 | 60 | QString toString(AudioTrackType type); |
61 | 61 | |
| 62 | // Eof States |
| 63 | typedef enum |
| 64 | { |
| 65 | kEofStateNone, |
| 66 | kEofStateDelayed, |
| 67 | kEofStateImmediate |
| 68 | } EofState; |
| 69 | |
62 | 70 | class StreamInfo |
63 | 71 | { |
64 | 72 | public: |
… |
… |
class DecoderBase |
115 | 123 | char testbuf[kDecoderProbeBufferSize], |
116 | 124 | int testbufsize = kDecoderProbeBufferSize) = 0; |
117 | 125 | |
118 | | virtual void SetEof(bool eof) { ateof = eof; } |
119 | | bool GetEof(void) const { return ateof; } |
| 126 | virtual void SetEof(EofState eof) { ateof = eof; } |
| 127 | virtual void SetEof(bool eof) { ateof = eof?kEofStateDelayed:kEofStateNone; } |
| 128 | EofState GetEof(void) { return ateof; } |
120 | 129 | |
121 | 130 | void SetSeekSnap(uint64_t snap) { seeksnap = snap; } |
122 | 131 | uint64_t GetSeekSnap(void) const { return seeksnap; } |
… |
… |
class DecoderBase |
289 | 298 | // indicates whether this is the case. |
290 | 299 | bool trackTotalDuration; |
291 | 300 | |
292 | | bool ateof; |
| 301 | EofState ateof; |
293 | 302 | bool exitafterdecoded; |
294 | 303 | bool transcoding; |
295 | 304 | |
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 56eeb53..d43fc67 100644
a
|
b
|
bool MythPlayer::PrebufferEnoughFrames(int min_buffers) |
2078 | 2078 | return false; |
2079 | 2079 | |
2080 | 2080 | if (!(min_buffers ? (videoOutput->ValidVideoFrames() >= min_buffers) : |
| 2081 | (GetEof() != kEofStateNone) || |
2081 | 2082 | (videoOutput->hasHWAcceleration() ? |
2082 | 2083 | videoOutput->EnoughPrebufferedFrames() : |
2083 | 2084 | videoOutput->EnoughDecodedFrames()))) |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2490 | 2491 | { |
2491 | 2492 | OpenDummy(); |
2492 | 2493 | ResetPlaying(); |
2493 | | SetEof(false); |
| 2494 | SetEof(kEofStateNone); |
2494 | 2495 | delete pginfo; |
2495 | 2496 | return; |
2496 | 2497 | } |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2512 | 2513 | QString("(card type: %1).") |
2513 | 2514 | .arg(player_ctx->tvchain->GetCardType(newid))); |
2514 | 2515 | LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString()); |
2515 | | SetEof(true); |
| 2516 | SetEof(kEofStateImmediate); |
2516 | 2517 | SetErrored(tr("Error opening switch program buffer")); |
2517 | 2518 | delete pginfo; |
2518 | 2519 | return; |
2519 | 2520 | } |
2520 | 2521 | |
2521 | | if (GetEof()) |
| 2522 | if (GetEof() != kEofStateNone) |
2522 | 2523 | { |
2523 | 2524 | discontinuity = true; |
2524 | 2525 | ResetCaptions(); |
… |
… |
void MythPlayer::SwitchToProgram(void) |
2557 | 2558 | if (IsErrored()) |
2558 | 2559 | { |
2559 | 2560 | LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram failed."); |
2560 | | SetEof(true); |
| 2561 | SetEof(kEofStateDelayed); |
2561 | 2562 | return; |
2562 | 2563 | } |
2563 | 2564 | |
2564 | | SetEof(false); |
| 2565 | SetEof(kEofStateNone); |
2565 | 2566 | |
2566 | 2567 | // the bitrate is reset by player_ctx->buffer->OpenFile()... |
2567 | 2568 | if (decoder) |
… |
… |
void MythPlayer::FileChangedCallback(void) |
2588 | 2589 | player_ctx->buffer->Reset(false, true); |
2589 | 2590 | else |
2590 | 2591 | player_ctx->buffer->Reset(false, true, true); |
2591 | | SetEof(false); |
| 2592 | SetEof(kEofStateNone); |
2592 | 2593 | Play(); |
2593 | 2594 | |
2594 | 2595 | player_ctx->SetPlayerChangingBuffers(false); |
… |
… |
void MythPlayer::JumpToProgram(void) |
2629 | 2630 | { |
2630 | 2631 | OpenDummy(); |
2631 | 2632 | ResetPlaying(); |
2632 | | SetEof(false); |
| 2633 | SetEof(kEofStateNone); |
2633 | 2634 | delete pginfo; |
2634 | 2635 | inJumpToProgramPause = false; |
2635 | 2636 | return; |
… |
… |
void MythPlayer::JumpToProgram(void) |
2654 | 2655 | QString("(card type: %1).") |
2655 | 2656 | .arg(player_ctx->tvchain->GetCardType(newid))); |
2656 | 2657 | LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString()); |
2657 | | SetEof(true); |
| 2658 | SetEof(kEofStateImmediate); |
2658 | 2659 | SetErrored(tr("Error opening jump program file buffer")); |
2659 | 2660 | delete pginfo; |
2660 | 2661 | inJumpToProgramPause = false; |
… |
… |
void MythPlayer::JumpToProgram(void) |
2680 | 2681 | return; |
2681 | 2682 | } |
2682 | 2683 | |
2683 | | SetEof(false); |
| 2684 | SetEof(kEofStateNone); |
2684 | 2685 | |
2685 | 2686 | // the bitrate is reset by player_ctx->buffer->OpenFile()... |
2686 | 2687 | player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate()); |
… |
… |
void MythPlayer::EventLoop(void) |
2831 | 2832 | player_ctx->tvchain->JumpToNext(true, 1); |
2832 | 2833 | JumpToProgram(); |
2833 | 2834 | } |
2834 | | else if ((!allpaused || GetEof()) && player_ctx->tvchain && |
| 2835 | else if ((!allpaused || (GetEof() != kEofStateNone)) && player_ctx->tvchain && |
2835 | 2836 | (decoder && !decoder->GetWaitForChange())) |
2836 | 2837 | { |
2837 | 2838 | // Switch to the next program in livetv |
… |
… |
void MythPlayer::EventLoop(void) |
2891 | 2892 | } |
2892 | 2893 | |
2893 | 2894 | // Handle end of file |
2894 | | if ((GetEof() && !allpaused) || |
| 2895 | EofState _eof = GetEof(); |
| 2896 | if (((_eof != kEofStateNone) && !allpaused) || |
2895 | 2897 | (!GetEditMode() && framesPlayed >= deleteMap.GetLastFrame())) |
2896 | 2898 | { |
2897 | 2899 | #ifdef USING_MHEG |
… |
… |
void MythPlayer::EventLoop(void) |
2908 | 2910 | return; |
2909 | 2911 | } |
2910 | 2912 | |
2911 | | Pause(); |
2912 | | SetPlaying(false); |
2913 | | return; |
| 2913 | if (_eof != kEofStateDelayed) |
| 2914 | { |
| 2915 | Pause(); |
| 2916 | SetPlaying(false); |
| 2917 | return; |
| 2918 | } |
| 2919 | LOG(VB_PLAYBACK, LOG_INFO, QString("waiting for no video frames %1").arg(videoOutput->ValidVideoFrames())); |
| 2920 | if (videoOutput && videoOutput->ValidVideoFrames() < 3) |
| 2921 | { |
| 2922 | Pause(); |
| 2923 | SetPlaying(false); |
| 2924 | return; |
| 2925 | } |
2914 | 2926 | } |
2915 | 2927 | |
2916 | 2928 | // Handle rewind |
… |
… |
void MythPlayer::EventLoop(void) |
2928 | 2940 | if (fftime > 0) |
2929 | 2941 | { |
2930 | 2942 | DoFastForward(fftime, kInaccuracyDefault); |
2931 | | if (GetEof()) |
| 2943 | if (GetEof() != kEofStateNone) |
2932 | 2944 | return; |
2933 | 2945 | } |
2934 | 2946 | } |
… |
… |
void MythPlayer::EventLoop(void) |
2993 | 3005 | if (!(endExitPrompt == 1 && !player_ctx->IsPIP() && |
2994 | 3006 | player_ctx->GetState() == kState_WatchingPreRecorded)) |
2995 | 3007 | { |
2996 | | SetEof(true); |
| 3008 | SetEof(kEofStateDelayed); |
2997 | 3009 | } |
2998 | 3010 | } |
2999 | 3011 | else |
… |
… |
void MythPlayer::DecoderPauseCheck(void) |
3100 | 3112 | } |
3101 | 3113 | |
3102 | 3114 | //// FIXME - move the eof ownership back into MythPlayer |
3103 | | bool MythPlayer::GetEof(void) |
| 3115 | EofState MythPlayer::GetEof(void) |
3104 | 3116 | { |
3105 | 3117 | if (is_current_thread(playerThread)) |
3106 | | return decoder ? decoder->GetEof() : true; |
| 3118 | return decoder ? decoder->GetEof() : kEofStateImmediate; |
3107 | 3119 | |
3108 | 3120 | if (!decoder_change_lock.tryLock(50)) |
3109 | | return false; |
| 3121 | return kEofStateNone; |
3110 | 3122 | |
3111 | | bool eof = decoder ? decoder->GetEof() : true; |
| 3123 | EofState eof = decoder ? decoder->GetEof() : kEofStateImmediate; |
3112 | 3124 | decoder_change_lock.unlock(); |
3113 | 3125 | return eof; |
3114 | 3126 | } |
3115 | 3127 | |
3116 | | void MythPlayer::SetEof(bool eof) |
| 3128 | void MythPlayer::SetEof(EofState eof) |
3117 | 3129 | { |
3118 | 3130 | if (is_current_thread(playerThread)) |
3119 | 3131 | { |
… |
… |
void MythPlayer::DecoderLoop(bool pause) |
3175 | 3187 | decoder_change_lock.unlock(); |
3176 | 3188 | } |
3177 | 3189 | |
3178 | | bool obey_eof = GetEof() && |
3179 | | !(GetEof() && player_ctx->tvchain && !allpaused); |
| 3190 | bool obey_eof = (GetEof() != kEofStateNone) && |
| 3191 | !((GetEof() != kEofStateNone) && player_ctx->tvchain && !allpaused); |
3180 | 3192 | if (isDummy || ((decoderPaused || ffrew_skip == 0 || obey_eof) && |
3181 | 3193 | !decodeOneFrame)) |
3182 | 3194 | { |
… |
… |
bool MythPlayer::TranscodeGetNextFrame( |
4510 | 4522 | if (!decoder->GetFrame(kDecodeAV)) |
4511 | 4523 | return false; |
4512 | 4524 | |
4513 | | if (GetEof()) |
| 4525 | if (GetEof() != kEofStateNone) |
4514 | 4526 | return false; |
4515 | 4527 | |
4516 | 4528 | if (honorCutList && !deleteMap.IsEmpty()) |
… |
… |
bool MythPlayer::TranscodeGetNextFrame( |
4535 | 4547 | did_ff = 1; |
4536 | 4548 | } |
4537 | 4549 | } |
4538 | | if (GetEof()) |
| 4550 | if (GetEof() != kEofStateNone) |
4539 | 4551 | return false; |
4540 | 4552 | is_key = decoder->IsLastFrameKey(); |
4541 | 4553 | |
… |
… |
bool MythPlayer::SetStream(const QString &stream) |
4998 | 5010 | player_ctx->buffer->GetType() == ICRingBuffer::kRingBufferType) |
4999 | 5011 | { |
5000 | 5012 | // Restore livetv |
5001 | | SetEof(true); |
| 5013 | SetEof(kEofStateDelayed); |
5002 | 5014 | player_ctx->tvchain->JumpToNext(false, 1); |
5003 | 5015 | player_ctx->tvchain->JumpToNext(true, 1); |
5004 | 5016 | } |
… |
… |
void MythPlayer::JumpToStream(const QString &stream) |
5028 | 5040 | if (!player_ctx->buffer->IsOpen()) |
5029 | 5041 | { |
5030 | 5042 | LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToStream buffer OpenFile failed"); |
5031 | | SetEof(true); |
| 5043 | SetEof(kEofStateImmediate); |
5032 | 5044 | SetErrored(QObject::tr("Error opening remote stream buffer")); |
5033 | 5045 | return; |
5034 | 5046 | } |
… |
… |
void MythPlayer::JumpToStream(const QString &stream) |
5041 | 5053 | if (OpenFile(120) < 0) // 120 retries ~= 60 seconds |
5042 | 5054 | { |
5043 | 5055 | LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToStream OpenFile failed."); |
5044 | | SetEof(true); |
| 5056 | SetEof(kEofStateImmediate); |
5045 | 5057 | SetErrored(QObject::tr("Error opening remote stream")); |
5046 | 5058 | return; |
5047 | 5059 | } |
… |
… |
void MythPlayer::JumpToStream(const QString &stream) |
5057 | 5069 | .arg(player_ctx->buffer->GetRealFileSize()).arg(decoder->GetRawBitrate()) |
5058 | 5070 | .arg(totalLength).arg(totalFrames).arg(decoder->GetFPS()) ); |
5059 | 5071 | |
5060 | | SetEof(false); |
| 5072 | SetEof(kEofStateNone); |
5061 | 5073 | |
5062 | 5074 | // the bitrate is reset by player_ctx->buffer->OpenFile()... |
5063 | 5075 | player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate()); |
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index bf27f48..4037c71 100644
a
|
b
|
class MTV_PUBLIC MythPlayer |
142 | 142 | void SetLength(int len) { totalLength = len; } |
143 | 143 | void SetFramesPlayed(uint64_t played); |
144 | 144 | void SetVideoFilters(const QString &override); |
145 | | void SetEof(bool eof); |
| 145 | void SetEof(EofState eof); |
146 | 146 | void SetPIPActive(bool is_active) { pip_active = is_active; } |
147 | 147 | void SetPIPVisible(bool is_visible) { pip_visible = is_visible; } |
148 | 148 | |
… |
… |
class MTV_PUBLIC MythPlayer |
198 | 198 | bool IsPaused(void) const { return allpaused; } |
199 | 199 | bool GetRawAudioState(void) const; |
200 | 200 | bool GetLimitKeyRepeat(void) const { return limitKeyRepeat; } |
201 | | bool GetEof(void); |
| 201 | EofState GetEof(void); |
202 | 202 | bool IsErrored(void) const; |
203 | 203 | bool IsPlaying(uint wait_ms = 0, bool wait_for = true) const; |
204 | 204 | bool AtNormalSpeed(void) const { return next_normal_speed; } |