Permalink
Browse files

Refactor 'eof' handling in the decoder and player classes.

This moves all eof 'ownership' into the decoder which is then queried by
the player as needed. AvFormatDecoder is extended to reset the picture
buffer eof flag to zero if we are clearing the eof state.

This fixes livetv program transitions where the decoder has already
decided it has hit the end of the file before we switch to the next
program and as a result stops returning frames.

My only concern here is the extra locking now required inside the GetEof
method in MythPlayer. The current plan of action is however to ensure
the decoder locking is 'industrial strength' (Hint: it currently isn't)
before looking at how to minimise the locking required in the main
playback loop.
(cherry picked from commit 679b668)
  • Loading branch information...
1 parent b2c0afc commit ad1543aefe287de8706c2e8365208b973427f5dd Mark Kendall committed Jan 29, 2011
@@ -743,6 +743,18 @@ void AvFormatDecoder::SeekReset(long long newKey, uint skipFrames,
}
}
+void AvFormatDecoder::SetEof(bool eof)
+{
+ if (!eof && ic && ic->pb)
+ {
+ VERBOSE(VB_IMPORTANT, LOC +
+ QString("Resetting byte context eof (livetv %1 was eof %2)")
+ .arg(livetv).arg(ic->pb->eof_reached));
+ ic->pb->eof_reached = 0;
+ }
+ DecoderBase::SetEof(eof);
+}
+
void AvFormatDecoder::Reset(bool reset_video_data, bool seek_reset)
{
VERBOSE(VB_PLAYBACK, LOC + QString("Reset(%1, %2)")
@@ -4259,8 +4271,7 @@ bool AvFormatDecoder::GetFrame(DecodeType decodetype)
if (retval == -EAGAIN)
continue;
- ateof = true;
- m_parent->SetEof();
+ SetEof(true);
delete pkt;
return false;
}
@@ -95,9 +95,11 @@ class AvFormatDecoder : public DecoderBase
AVSpecialDecode av_special_decode = kAVSpecialDecode_None);
~AvFormatDecoder();
+ virtual void SetEof(bool eof);
+
void CloseCodecs();
void CloseContext();
- void Reset(void);
+ virtual void Reset(void);
void Reset(bool reset_video_data = true, bool seek_reset = true);
/// Perform an av_probe_input_format on the passed data to see if we
@@ -77,7 +77,7 @@ void DecoderBase::Reset(void)
dontSyncPositionMap = false;
waitingForChange = false;
- ateof = false;
+ SetEof(false);
}
void DecoderBase::SeekReset(long long, uint, bool, bool)
@@ -94,6 +94,9 @@ class DecoderBase
char testbuf[kDecoderProbeBufferSize],
int testbufsize = kDecoderProbeBufferSize) = 0;
+ virtual void SetEof(bool eof) { ateof = eof; }
+ bool GetEof(void) { return ateof; }
+
void setExactSeeks(bool exact) { exactseeks = exact; }
bool getExactSeeks(void) const { return exactseeks; }
void setLiveTVMode(bool live) { livetv = live; }
@@ -108,7 +108,7 @@ bool MythCommFlagPlayer::RebuildSeekTable(
fflush( stdout );
}
- while (!decoderEof)
+ while (!GetEof())
{
if (inuse_timer.elapsed() > 2534)
{
@@ -130,7 +130,6 @@ MythPlayer::MythPlayer(bool muted)
parentWidget(NULL), embedid(0),
embx(-1), emby(-1), embw(-1), embh(-1),
// State
- decoderEof(false),
decoderPaused(false), pauseDecoder(false), unpauseDecoder(false),
killdecoder(false), decoderSeek(-1), decodeOneFrame(false),
needNewPauseFrame(false),
@@ -968,9 +967,6 @@ int MythPlayer::OpenFile(uint retries, bool allow_libmpeg2)
CheckExtraAudioDecode();
noVideoTracks = !decoder->GetTrackCount(kTrackTypeVideo);
-
- decoderEof = false;
-
// Set 'no_video_decode' to true for audio only decodeing
bool no_video_decode = false;
@@ -2193,7 +2189,7 @@ void MythPlayer::SwitchToProgram(void)
{
OpenDummy();
ResetPlaying();
- decoderEof = false;
+ SetEof(false);
delete pginfo;
return;
}
@@ -2207,21 +2203,21 @@ void MythPlayer::SwitchToProgram(void)
QString("(card type: %1).")
.arg(player_ctx->tvchain->GetCardType(newid)));
VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
- decoderEof = true;
+ SetEof(true);
SetErrored(QObject::tr("Error opening switch program buffer"));
delete pginfo;
return;
}
- if (decoderEof)
+ if (GetEof())
{
discontinuity = true;
ResetCaptions();
}
VERBOSE(VB_PLAYBACK, LOC + QString("SwitchToProgram(void) "
"discont: %1 newtype: %2 newid: %3 decoderEof: %4")
- .arg(discontinuity).arg(newtype).arg(newid).arg(decoderEof));
+ .arg(discontinuity).arg(newtype).arg(newid).arg(GetEof()));
if (discontinuity || newtype)
{
@@ -2251,10 +2247,12 @@ void MythPlayer::SwitchToProgram(void)
if (IsErrored())
{
VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram failed.");
- decoderEof = true;
+ SetEof(true);
return;
}
+ SetEof(false);
+
// the bitrate is reset by player_ctx->buffer->OpenFile()...
if (decoder)
player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate());
@@ -2266,7 +2264,6 @@ void MythPlayer::SwitchToProgram(void)
forcePositionMapSync = true;
}
- decoderEof = false;
Play();
VERBOSE(VB_PLAYBACK, LOC + "SwitchToProgram - end");
}
@@ -2281,10 +2278,9 @@ void MythPlayer::FileChangedCallback(void)
player_ctx->buffer->Reset(false, true);
else
player_ctx->buffer->Reset(false, true, true);
+ SetEof(false);
Play();
- decoderEof = false;
-
player_ctx->SetPlayerChangingBuffers(false);
player_ctx->LockPlayingInfo(__FILE__, __LINE__);
@@ -2322,7 +2318,7 @@ void MythPlayer::JumpToProgram(void)
{
OpenDummy();
ResetPlaying();
- decoderEof = false;
+ SetEof(false);
delete pginfo;
return;
}
@@ -2338,8 +2334,7 @@ void MythPlayer::JumpToProgram(void)
QString("(card type: %1).")
.arg(player_ctx->tvchain->GetCardType(newid)));
VERBOSE(VB_IMPORTANT, QString("\n") + player_ctx->tvchain->toString());
-
- decoderEof = true;
+ SetEof(true);
SetErrored(QObject::tr("Error opening jump program file buffer"));
delete pginfo;
return;
@@ -2363,6 +2358,8 @@ void MythPlayer::JumpToProgram(void)
return;
}
+ SetEof(false);
+
// the bitrate is reset by player_ctx->buffer->OpenFile()...
player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate());
player_ctx->buffer->IgnoreLiveEOF(false);
@@ -2383,7 +2380,6 @@ void MythPlayer::JumpToProgram(void)
if (nextpos > 10)
DoFastForward(nextpos, true, false);
- decoderEof = false;
player_ctx->SetPlayerChangingBuffers(false);
VERBOSE(VB_PLAYBACK, LOC + "JumpToProgram - end");
}
@@ -2506,7 +2502,7 @@ void MythPlayer::EventLoop(void)
player_ctx->tvchain->JumpToNext(true, 1);
JumpToProgram();
}
- else if ((!allpaused || decoderEof) && player_ctx->tvchain &&
+ else if ((!allpaused || GetEof()) && player_ctx->tvchain &&
(decoder && !decoder->GetWaitForChange()))
{
// Switch to the next program in livetv
@@ -2557,7 +2553,7 @@ void MythPlayer::EventLoop(void)
}
// Handle end of file
- if (decoderEof)
+ if (GetEof())
{
if (player_ctx->tvchain)
{
@@ -2590,7 +2586,7 @@ void MythPlayer::EventLoop(void)
if (fftime > 0)
{
DoFastForward(fftime);
- if (decoderEof)
+ if (GetEof())
return;
}
}
@@ -2652,7 +2648,7 @@ void MythPlayer::EventLoop(void)
&& !player_ctx->IsPIP() &&
player_ctx->GetState() == kState_WatchingPreRecorded))
{
- decoderEof = true;
+ SetEof(true);
}
}
else
@@ -2755,6 +2751,22 @@ void MythPlayer::DecoderPauseCheck(void)
UnpauseDecoder();
}
+bool MythPlayer::GetEof(void)
+{
+ decoder_change_lock.lock();
+ bool eof = decoder ? decoder->GetEof() : true;
+ decoder_change_lock.unlock();
+ return eof;
+}
+
+void MythPlayer::SetEof(bool eof)
+{
+ decoder_change_lock.lock();
+ if (decoder)
+ decoder->SetEof(eof);
+ decoder_change_lock.unlock();
+}
+
void MythPlayer::DecoderLoop(bool pause)
{
if (pause)
@@ -2796,8 +2808,8 @@ void MythPlayer::DecoderLoop(bool pause)
decoder_change_lock.unlock();
}
- bool obey_eof = decoderEof &&
- !(decoderEof && player_ctx->tvchain && !allpaused);
+ bool obey_eof = GetEof() &&
+ !(GetEof() && player_ctx->tvchain && !allpaused);
if (isDummy || ((decoderPaused || ffrew_skip == 0 || obey_eof) &&
!decodeOneFrame))
{
@@ -4135,7 +4147,7 @@ bool MythPlayer::TranscodeGetNextFrame(
if (!decoder->GetFrame(kDecodeAV))
return false;
- if (decoderEof)
+ if (GetEof())
return false;
if (honorCutList && !deleteMap.IsEmpty())
@@ -4160,7 +4172,7 @@ bool MythPlayer::TranscodeGetNextFrame(
did_ff = 1;
}
}
- if (decoderEof)
+ if (GetEof())
return false;
is_key = decoder->isLastFrameKey();
return true;
@@ -124,7 +124,7 @@ class MPUBLIC MythPlayer
void SetLength(int len) { totalLength = len; }
void SetFramesPlayed(uint64_t played) { framesPlayed = played; }
void SetVideoFilters(const QString &override);
- void SetEof(void) { decoderEof = true; }
+ void SetEof(bool eof);
void SetPIPActive(bool is_active) { pip_active = is_active; }
void SetPIPVisible(bool is_visible) { pip_visible = is_visible; }
@@ -175,7 +175,7 @@ class MPUBLIC MythPlayer
// Bool Gets
bool GetRawAudioState(void) const;
bool GetLimitKeyRepeat(void) const { return limitKeyRepeat; }
- bool GetEof(void) const { return decoderEof; }
+ bool GetEof(void);
bool IsErrored(void) const;
bool IsPlaying(uint wait_ms = 0, bool wait_for = true) const;
bool AtNormalSpeed(void) const { return next_normal_speed; }
@@ -531,7 +531,6 @@ class MPUBLIC MythPlayer
QWaitCondition decoderThreadUnpause;
mutable QMutex decoderPauseLock;
mutable QMutex decoderSeekLock;
- bool decoderEof;
bool decoderPaused;
bool pauseDecoder;
bool unpauseDecoder;
@@ -1056,17 +1056,15 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype)
if (!ReadFrameheader(&frameheader))
{
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
if (!ringBuffer->LiveMode() &&
((frameheader.frametype == 'Q') || (frameheader.frametype == 'K')))
{
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
@@ -1083,8 +1081,7 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype)
if (!ReadFrameheader(&frameheader))
{
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
seeklen = 1;
@@ -1098,8 +1095,7 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype)
if (ringBuffer->Read(dummy, sizetoskip) != sizetoskip)
{
delete [] dummy;
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
@@ -1157,15 +1153,13 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype)
VERBOSE(VB_IMPORTANT, QString("Broken packet: %1 %2")
.arg(frameheader.frametype)
.arg(frameheader.packetlength));
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
if (ringBuffer->Read(strm, frameheader.packetlength) !=
frameheader.packetlength)
{
- ateof = true;
- GetPlayer()->SetEof();
+ SetEof(true);
return false;
}
}

0 comments on commit ad1543a

Please sign in to comment.