Skip to content

Commit

Permalink
Provide better seeking and position display for some videos.
Browse files Browse the repository at this point in the history
Specifically, there are examples of poorly-encoded avi files that
report a video frame rate of 30fps but the video stream is actually
24fps.  Because frame intervals are actually encoded as 30fps, every
4th frame has to be repeated.  Without an adjustment to framesPlayed,
translations between MythPlayer's frame-based seeking/display and
ffmpeg's timecode-based seeking drift out of sync.

Note: Similar adjustments may be necessary if frames have to be
dropped due to a frame rate mismatch.

Refs #11415.
  • Loading branch information
stichnot committed Sep 28, 2013
1 parent fd94407 commit e7a8dfc
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 3 deletions.
17 changes: 14 additions & 3 deletions mythtv/libs/libmythtv/mythplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ MythPlayer::MythPlayer(PlayerFlags flags)
fftime(0),
// Playback misc.
videobuf_retries(0), framesPlayed(0),
framesPlayedExtra(0),
totalFrames(0), totalLength(0),
totalDuration(0),
rewindtime(0),
Expand Down Expand Up @@ -376,7 +377,7 @@ bool MythPlayer::Pause(void)
if (FlagIsSet(kVideoIsNull) && decoder)
decoder->UpdateFramesPlayed();
else if (videoOutput && !FlagIsSet(kVideoIsNull))
framesPlayed = videoOutput->GetFramesPlayed();
framesPlayed = videoOutput->GetFramesPlayed() + framesPlayedExtra;
}
pauseLock.unlock();
return already_paused;
Expand Down Expand Up @@ -1025,6 +1026,7 @@ int MythPlayer::OpenFile(uint retries)
void MythPlayer::SetFramesPlayed(uint64_t played)
{
framesPlayed = played;
framesPlayedExtra = 0;
if (videoOutput)
videoOutput->SetFramesPlayed(played);
}
Expand Down Expand Up @@ -1995,6 +1997,13 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
QString("A/V delay %1").arg(delta));
avsync_adjustment += frame_interval;
// If we're duplicating a frame, it may be because
// the container frame rate doesn't match the
// stream frame rate. In this case, we increment
// the fake frame counter so that avformat
// timestamp-based seeking will work.
if (!decoder->HasPositionMap())
++framesPlayedExtra;
}
}
prevtc = timecode;
Expand Down Expand Up @@ -2402,7 +2411,7 @@ bool MythPlayer::VideoLoop(void)
else if (decoder && decoder->GetEof() != kEofStateNone)
++framesPlayed;
else
framesPlayed = videoOutput->GetFramesPlayed();
framesPlayed = videoOutput->GetFramesPlayed() + framesPlayedExtra;
return !IsErrored();
}

Expand Down Expand Up @@ -2488,7 +2497,7 @@ void MythPlayer::ResetPlaying(bool resetframes)
ClearAfterSeek();
ffrew_skip = 1;
if (resetframes)
framesPlayed = 0;
framesPlayed = framesPlayedExtra = 0;
if (decoder)
{
decoder->Reset(true, true, true);
Expand Down Expand Up @@ -2761,6 +2770,7 @@ bool MythPlayer::StartPlaying(void)
}

framesPlayed = 0;
framesPlayedExtra = 0;
rewindtime = fftime = 0;
next_play_speed = audio.GetStretchFactor();
jumpchapter = 0;
Expand Down Expand Up @@ -4541,6 +4551,7 @@ void MythPlayer::InitForTranscode(bool copyaudio, bool copyvideo)
}

framesPlayed = 0;
framesPlayedExtra = 0;
ClearAfterSeek();

if (copyvideo && decoder)
Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythtv/mythplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,9 @@ class MTV_PUBLIC MythPlayer
/// How often we have tried to wait for a video output buffer and failed
int videobuf_retries;
uint64_t framesPlayed;
// "Fake" frame counter for when the container frame rate doesn't
// match the stream frame rate.
uint64_t framesPlayedExtra;
uint64_t totalFrames;
long long totalLength;
int64_t totalDuration;
Expand Down

0 comments on commit e7a8dfc

Please sign in to comment.