Skip to content

Commit

Permalink
Refactor 'eof' handling in the decoder and player classes.
Browse files Browse the repository at this point in the history
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
Mark Kendall committed Feb 15, 2011
1 parent b2c0afc commit ad1543a
Show file tree
Hide file tree
Showing 8 changed files with 65 additions and 44 deletions.
15 changes: 13 additions & 2 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -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)")
Expand Down Expand Up @@ -4259,8 +4271,7 @@ bool AvFormatDecoder::GetFrame(DecodeType decodetype)
if (retval == -EAGAIN)
continue;

ateof = true;
m_parent->SetEof();
SetEof(true);
delete pkt;
return false;
}
Expand Down
4 changes: 3 additions & 1 deletion mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/decoderbase.cpp
Expand Up @@ -77,7 +77,7 @@ void DecoderBase::Reset(void)
dontSyncPositionMap = false;

waitingForChange = false;
ateof = false;
SetEof(false);
}

void DecoderBase::SeekReset(long long, uint, bool, bool)
Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythtv/decoderbase.h
Expand Up @@ -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; }
Expand Down
2 changes: 1 addition & 1 deletion mythtv/libs/libmythtv/mythcommflagplayer.cpp
Expand Up @@ -108,7 +108,7 @@ bool MythCommFlagPlayer::RebuildSeekTable(
fflush( stdout );
}

while (!decoderEof)
while (!GetEof())
{
if (inuse_timer.elapsed() > 2534)
{
Expand Down
60 changes: 36 additions & 24 deletions mythtv/libs/libmythtv/mythplayer.cpp
Expand Up @@ -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),
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -2193,7 +2189,7 @@ void MythPlayer::SwitchToProgram(void)
{
OpenDummy();
ResetPlaying();
decoderEof = false;
SetEof(false);
delete pginfo;
return;
}
Expand All @@ -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)
{
Expand Down Expand Up @@ -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());
Expand All @@ -2266,7 +2264,6 @@ void MythPlayer::SwitchToProgram(void)
forcePositionMapSync = true;
}

decoderEof = false;
Play();
VERBOSE(VB_PLAYBACK, LOC + "SwitchToProgram - end");
}
Expand All @@ -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__);
Expand Down Expand Up @@ -2322,7 +2318,7 @@ void MythPlayer::JumpToProgram(void)
{
OpenDummy();
ResetPlaying();
decoderEof = false;
SetEof(false);
delete pginfo;
return;
}
Expand All @@ -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;
Expand All @@ -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);
Expand All @@ -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");
}
Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -2557,7 +2553,7 @@ void MythPlayer::EventLoop(void)
}

// Handle end of file
if (decoderEof)
if (GetEof())
{
if (player_ctx->tvchain)
{
Expand Down Expand Up @@ -2590,7 +2586,7 @@ void MythPlayer::EventLoop(void)
if (fftime > 0)
{
DoFastForward(fftime);
if (decoderEof)
if (GetEof())
return;
}
}
Expand Down Expand Up @@ -2652,7 +2648,7 @@ void MythPlayer::EventLoop(void)
&& !player_ctx->IsPIP() &&
player_ctx->GetState() == kState_WatchingPreRecorded))
{
decoderEof = true;
SetEof(true);
}
}
else
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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))
{
Expand Down Expand Up @@ -4135,7 +4147,7 @@ bool MythPlayer::TranscodeGetNextFrame(
if (!decoder->GetFrame(kDecodeAV))
return false;

if (decoderEof)
if (GetEof())
return false;

if (honorCutList && !deleteMap.IsEmpty())
Expand All @@ -4160,7 +4172,7 @@ bool MythPlayer::TranscodeGetNextFrame(
did_ff = 1;
}
}
if (decoderEof)
if (GetEof())
return false;
is_key = decoder->isLastFrameKey();
return true;
Expand Down
5 changes: 2 additions & 3 deletions mythtv/libs/libmythtv/mythplayer.h
Expand Up @@ -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; }

Expand Down Expand Up @@ -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; }
Expand Down Expand Up @@ -531,7 +531,6 @@ class MPUBLIC MythPlayer
QWaitCondition decoderThreadUnpause;
mutable QMutex decoderPauseLock;
mutable QMutex decoderSeekLock;
bool decoderEof;
bool decoderPaused;
bool pauseDecoder;
bool unpauseDecoder;
Expand Down
18 changes: 6 additions & 12 deletions mythtv/libs/libmythtv/nuppeldecoder.cpp
Expand Up @@ -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;
}

Expand All @@ -1083,8 +1081,7 @@ bool NuppelDecoder::GetFrame(DecodeType decodetype)

if (!ReadFrameheader(&frameheader))
{
ateof = true;
GetPlayer()->SetEof();
SetEof(true);
return false;
}
seeklen = 1;
Expand All @@ -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;
}

Expand Down Expand Up @@ -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;
}
}
Expand Down

0 comments on commit ad1543a

Please sign in to comment.