Skip to content

Commit

Permalink
Simplify DVD startup to improve playback reliability
Browse files Browse the repository at this point in the history
The startup code for DVD playback jumps around somewhat trying to find
a playable title, which is then used to create audio/video decoders
before playback is restarted at firstplay.

This doesn't always work as it can leave the DVDs VM in an
inconsistent state and, depending on the DVD, looks ugly as playback
starts and then restarts or appears to jump somewhere else after a
couple of seconds. Because the VM can be left in an inconsistent
state, menu navigation/selection issues can arise, which can make it
difficult to start playback.

The attached patch attempts to clean up the startup code. The
DVDRingBuffer no longer tries to find a playable title in OpenFile?,
but rather just lets the VM get on with playback. AVFormatDecoder no
longer processes the initial frames more than is required to create
decoders. Once this has been achieved, any cached data is flushed
before jumping back to 'firstplay' (and cleanly resetting the VM). By
not displaying the initial frames used to determine the decoders and
flushing the cached data, the ugly jump at the start of some DVDs is
no longer visible.

Fixes #11288

Signed-off-by: Stuart Morgan <smorgan@mythtv.org>
  • Loading branch information
Richard authored and stuartm committed Dec 29, 2012
1 parent c5a4229 commit 414de88
Show file tree
Hide file tree
Showing 5 changed files with 38 additions and 59 deletions.
6 changes: 6 additions & 0 deletions mythtv/libs/libmythtv/DVD/avformatdecoderdvd.cpp
Expand Up @@ -26,6 +26,12 @@ void AvFormatDecoderDVD::UpdateFramesPlayed(void)
m_parent->SetFramesPlayed(currentpos + 1);
}

bool AvFormatDecoderDVD::GetFrame(DecodeType decodetype)
{
// Always try to decode audio and video for DVDs
return AvFormatDecoder::GetFrame( kDecodeAV );
}

void AvFormatDecoderDVD::PostProcessTracks(void)
{
if (!ringBuffer)
Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/DVD/avformatdecoderdvd.h
Expand Up @@ -10,6 +10,7 @@ class AvFormatDecoderDVD : public AvFormatDecoder
PlayerFlags flags);
virtual void Reset(bool reset_video_data, bool seek_reset, bool reset_file);
virtual void UpdateFramesPlayed(void);
virtual bool GetFrame(DecodeType decodetype); // DecoderBase

private:
virtual bool DoRewindSeek(long long desiredFrame);
Expand Down
50 changes: 1 addition & 49 deletions mythtv/libs/libmythtv/DVD/dvdringbuffer.cpp
Expand Up @@ -342,55 +342,6 @@ bool DVDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms)
dvdnav_set_readahead_flag(m_dvdnav, 0);
dvdnav_set_PGC_positioning_flag(m_dvdnav, 1);

int32_t num_titles = 0;
res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles);
if (num_titles == 0 || res == DVDNAV_STATUS_ERR)
{
char buf[DVD_BLOCK_SIZE * 5];
LOG(VB_GENERAL, LOG_INFO,
LOC + QString("Reading %1 bytes from the drive")
.arg(DVD_BLOCK_SIZE * 5));
safe_read(buf, DVD_BLOCK_SIZE * 5);
res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles);
}

if (res == DVDNAV_STATUS_ERR)
{
LOG(VB_GENERAL, LOG_ERR,
LOC + QString("Failed to get the number of titles on the DVD" ));
}
else
{
LOG(VB_GENERAL, LOG_INFO,
LOC + QString("There are %1 titles on the disk")
.arg(num_titles));
}

int startTitle = 1;
dvdnav_status_t result = DVDNAV_STATUS_ERR;
while (startTitle <= num_titles)
{
result = dvdnav_title_play(m_dvdnav, startTitle);
if (result == DVDNAV_STATUS_OK)
break;
else if (startTitle < num_titles)
LOG(VB_GENERAL, LOG_WARNING, QString("Unable to play DVD title %1, "
"trying next title")
.arg(startTitle));
startTitle++;
}

if (result == DVDNAV_STATUS_ERR)
{
LOG(VB_GENERAL, LOG_ERR, QString("Unable to play any title on this "
"DVD. Disc may be damaged or "
"corrupted as a means of copy "
"protection."));

rwlock.unlock();
return false;
}

// Check we aren't starting in a still frame (which will probably fail as
// ffmpeg will be unable to create a decoder)
if (dvdnav_get_next_still_flag(m_dvdnav))
Expand Down Expand Up @@ -446,6 +397,7 @@ bool DVDRingBuffer::StartFromBeginning(void)
if (m_dvdnav)
{
QMutexLocker lock(&m_seekLock);
dvdnav_reset(m_dvdnav);
dvdnav_first_play(m_dvdnav);
m_audioStreamsChanged = true;
}
Expand Down
39 changes: 29 additions & 10 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -334,7 +334,8 @@ AvFormatDecoder::AvFormatDecoder(MythPlayer *parent,
// Audio
disable_passthru(false),
m_fps(0.0f),
codec_is_mpeg(false)
codec_is_mpeg(false),
m_processFrames(true)
{
memset(&readcontext, 0, sizeof(readcontext));
memset(ccX08_in_pmt, 0, sizeof(ccX08_in_pmt));
Expand Down Expand Up @@ -684,9 +685,6 @@ void AvFormatDecoder::SeekReset(long long newKey, uint skipFrames,
if (!ringBuffer)
return; // nothing to reset...

if (ringBuffer->IsInDiscMenuOrStillFrame() || newKey == 0)
return;

LOG(VB_PLAYBACK, LOG_INFO, LOC +
QString("SeekReset(%1, %2, %3 flush, %4 discard)")
.arg(newKey).arg(skipFrames)
Expand Down Expand Up @@ -935,6 +933,11 @@ int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,

ringBuffer = rbuffer;

// Process frames immediately unless we're decoding
// a DVD, in which case don't so that we don't show
// anything whilst probing the data streams.
m_processFrames = !ringBuffer->IsDVD();

if (avfRingBuffer)
delete avfRingBuffer;
avfRingBuffer = new AVFRingBuffer(rbuffer);
Expand Down Expand Up @@ -982,12 +985,6 @@ int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,
}

int ret = FindStreamInfo();

// Reset DVD/bluray ringbuffers
if (!ringBuffer->StartFromBeginning())
return -1;
ringBuffer->IgnoreWaitStates(false);

if (ret < 0)
{
LOG(VB_GENERAL, LOG_ERR, LOC + "Could not find codec parameters. " +
Expand Down Expand Up @@ -1143,6 +1140,23 @@ int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,
if (getenv("FORCE_DTS_TIMESTAMPS"))
force_dts_timestamps = true;

if (ringBuffer->IsDVD())
{
// Reset DVD playback and clear any of
// our buffers so that none of the data
// parsed so far to determine decoders
// gets shown.
if (!ringBuffer->StartFromBeginning())
return -1;
ringBuffer->IgnoreWaitStates(false);

Reset(true, true, true);

// Now we're ready to process and show frames
m_processFrames = true;
}


// Return true if recording has position map
return recordingHasPositionMap;
}
Expand Down Expand Up @@ -4484,6 +4498,11 @@ bool AvFormatDecoder::GetFrame(DecodeType decodetype)

skipaudio = (lastvpts == 0);

if( !m_processFrames )
{
return false;
}

hasVideo = HasVideo(ic);
needDummyVideoFrames = false;

Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -360,6 +360,7 @@ class AvFormatDecoder : public DecoderBase

float m_fps;
bool codec_is_mpeg;
bool m_processFrames;
};

#endif
Expand Down

0 comments on commit 414de88

Please sign in to comment.