Skip to content

Commit

Permalink
Several changes to fix the current position and duration of the playb…
Browse files Browse the repository at this point in the history
…ack OSD

 * Start using the currently displayed video timecode for the OSD position instead of frame number and total frames which is inaccurate.
 * Use FFmpeg duration for pre-recorded and video playback length. LiveTV is already correct since it uses the actual recording times but in-progress recordings still uses frames written and fps which is obviously wrong for variable framerate and repeat frame material. The problem with in-progress duration should be able to be fixed by using recording times like livetv does. An update to mythplayer and the recorder class will be necessary.
 * Refactor and clean-up some timestamp/timecode handling.

Refs #8631.

Fixes #9109.


git-svn-id: http://svn.mythtv.org/svn/trunk@27326 7dbf422c-18fa-0310-86e9-fd20926502f2
  • Loading branch information
tralph committed Nov 23, 2010
1 parent ba1f912 commit ee9af28
Show file tree
Hide file tree
Showing 5 changed files with 69 additions and 29 deletions.
75 changes: 51 additions & 24 deletions mythtv/libs/libmythtv/avformatdecoder.cpp
Expand Up @@ -403,6 +403,8 @@ static int64_t lsb3full(int64_t lsb, int64_t base_ts, int lsb_bits)

int64_t AvFormatDecoder::NormalizeVideoTimecode(int64_t timecode)
{
int64_t start_pts = 0, pts;

AVStream *st = NULL;
for (uint i = 0; i < ic->nb_streams; i++)
{
Expand All @@ -416,19 +418,39 @@ int64_t AvFormatDecoder::NormalizeVideoTimecode(int64_t timecode)
if (!st)
return false;

// convert timecode and start_time to AV_TIME_BASE units
int64_t start_ts = av_rescale(ic->start_time,
st->time_base.den,
AV_TIME_BASE * (int64_t)st->time_base.num);
if (ic->start_time != AV_NOPTS_VALUE)
start_pts = av_rescale(ic->start_time,
st->time_base.den,
AV_TIME_BASE * (int64_t)st->time_base.num);

pts = av_rescale(timecode / 1000.0,
st->time_base.den,
st->time_base.num);

// adjust for start time and wrap
pts = lsb3full(pts, start_pts, st->pts_wrap_bits);

return (int64_t)(av_q2d(st->time_base) * pts * 1000);
}

int64_t AvFormatDecoder::NormalizeVideoTimecode(AVStream *st,
int64_t timecode)
{
int64_t start_pts = 0, pts;

if (ic->start_time != AV_NOPTS_VALUE)
start_pts = av_rescale(ic->start_time,
st->time_base.den,
AV_TIME_BASE * (int64_t)st->time_base.num);

int64_t ts = av_rescale(timecode / 1000.0 * AV_TIME_BASE,
st->time_base.den,
AV_TIME_BASE * (int64_t)st->time_base.num);
pts = av_rescale(timecode / 1000.0,
st->time_base.den,
st->time_base.num);

// adjust for start time and wrap
ts = lsb3full(ts, start_ts, st->pts_wrap_bits);
// adjust for start time and wrap
pts = lsb3full(pts, start_pts, st->pts_wrap_bits);

return (int64_t)(av_q2d(st->time_base) * ts * 1000);
return (int64_t)(av_q2d(st->time_base) * pts * 1000);
}

int AvFormatDecoder::GetNumChapters()
Expand Down Expand Up @@ -957,12 +979,18 @@ int AvFormatDecoder::OpenFile(RingBuffer *rbuffer, bool novideo,
}
}

// If watching pre-recorded television or video use ffmpeg duration
int64_t dur = ic->duration / (int64_t)AV_TIME_BASE;
if (dur > 0 && !livetv && !watchingrecording)
{
m_parent->SetDuration((int)dur);
}

// If we don't have a position map, set up ffmpeg for seeking
if (!recordingHasPositionMap && !livetv)
{
VERBOSE(VB_PLAYBACK, LOC +
"Recording has no position -- using libavformat seeking.");
int64_t dur = ic->duration / (int64_t)AV_TIME_BASE;

if (dur > 0)
{
Expand Down Expand Up @@ -2946,7 +2974,7 @@ bool AvFormatDecoder::PreProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
{
int ret = 0, gotpicture = 0;
long long pts = 0;
int64_t pts = 0;
AVCodecContext *context = curstream->codec;
AVFrame mpa_pic;
avcodec_get_frame_defaults(&mpa_pic);
Expand Down Expand Up @@ -3069,27 +3097,25 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
if (ringBuffer->isDVD())
{
if (pkt->dts != (int64_t)AV_NOPTS_VALUE)
pts = (long long)pkt->dts;
pts = pkt->dts;
}
else if (private_dec && private_dec->NeedsReorderedPTS() &&
mpa_pic.reordered_opaque != (int64_t)AV_NOPTS_VALUE)
{
pts = (long long)mpa_pic.reordered_opaque;
pts = mpa_pic.reordered_opaque;
}
else if ((force_reordered_opaque || faulty_pts <= faulty_dts ||
pkt->dts == (int64_t)AV_NOPTS_VALUE) &&
mpa_pic.reordered_opaque != (int64_t)AV_NOPTS_VALUE)
{
pts = (long long)mpa_pic.reordered_opaque;
pts = mpa_pic.reordered_opaque;
}
else if ((faulty_dts < faulty_pts || !reordered_pts_detected) &&
pkt->dts != (int64_t)AV_NOPTS_VALUE)
{
pts = (long long)pkt->dts;
pts = pkt->dts;
}
pts = (long long)(av_q2d(curstream->time_base) * pts * 1000);

long long temppts = pts;
long long temppts = (long long)(av_q2d(curstream->time_base) * pts * 1000);

// Validate the video pts against the last pts. If it's
// a little bit smaller, equal or missing, compute
Expand All @@ -3105,8 +3131,8 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
}

VERBOSE(VB_PLAYBACK+VB_TIMESTAMP, LOC +
QString("video timecode %1 %2 %3 %4 %5").arg(mpa_pic.reordered_opaque).arg(pkt->pts).arg(pkt->dts)
.arg(temppts).arg(lastvpts));
QString("video timecode %1 %2 %3 %4 %5").arg(mpa_pic.reordered_opaque)
.arg(pkt->pts).arg(pkt->dts).arg(temppts).arg(lastvpts));

/* XXX: Broken.
if (mpa_pic.qscale_table != NULL && mpa_pic.qstride > 0 &&
Expand All @@ -3130,10 +3156,11 @@ bool AvFormatDecoder::ProcessVideoPacket(AVStream *curstream, AVPacket *pkt)
*/

picframe->interlaced_frame = mpa_pic.interlaced_frame;
picframe->top_field_first = mpa_pic.top_field_first;
picframe->repeat_pict = mpa_pic.repeat_pict;
picframe->top_field_first = mpa_pic.top_field_first;
picframe->repeat_pict = mpa_pic.repeat_pict;
picframe->disp_timecode = NormalizeVideoTimecode(curstream, temppts);
picframe->frameNumber = framesPlayed;

picframe->frameNumber = framesPlayed;
m_parent->ReleaseNextVideoFrame(picframe, temppts);
if (private_dec && mpa_pic.data[3])
context->release_buffer(context, &mpa_pic);
Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/avformatdecoder.h
Expand Up @@ -155,6 +155,7 @@ class AvFormatDecoder : public DecoderBase
virtual bool DoFastForward(long long desiredFrame, bool doflush = true);

virtual int64_t NormalizeVideoTimecode(int64_t timecode);
virtual int64_t NormalizeVideoTimecode(AVStream *st, int64_t timecode);

virtual int GetTeletextDecoderType(void) const;
virtual void SetTeletextDecoderViewer(TeletextViewer*);
Expand Down
1 change: 1 addition & 0 deletions mythtv/libs/libmythtv/frame.h
Expand Up @@ -40,6 +40,7 @@ typedef struct VideoFrame_

long long frameNumber;
long long timecode;
int64_t disp_timecode;

unsigned char *priv[4]; // random empty storage

Expand Down
18 changes: 13 additions & 5 deletions mythtv/libs/libmythtv/mythplayer.cpp
Expand Up @@ -191,6 +191,7 @@ MythPlayer::MythPlayer(bool muted)
// Playback misc.
videobuf_retries(0), framesPlayed(0),
totalFrames(0), totalLength(0),
totalDuration(0),
rewindtime(0),
// Input Video Attributes
video_disp_dim(0,0), video_dim(0,0),
Expand Down Expand Up @@ -240,6 +241,7 @@ MythPlayer::MythPlayer(bool muted)
avsync_adjustment(0), avsync_avg(0),
refreshrate(0),
lastsync(false), repeat_delay(0),
disp_timecode(0),
// Time Code stuff
prevtc(0), prevrp(0),
// LiveTVChain stuff
Expand Down Expand Up @@ -897,6 +899,11 @@ void MythPlayer::SetFileLength(int total, int frames)
totalFrames = frames;
}

void MythPlayer::SetDuration(int duration)
{
totalDuration = duration;
}

void MythPlayer::OpenDummy(void)
{
isDummy = true;
Expand Down Expand Up @@ -1674,8 +1681,9 @@ void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)

if (buffer)
{
repeat_pict = buffer->repeat_pict;
timecode = buffer->timecode;
repeat_pict = buffer->repeat_pict;
timecode = buffer->timecode;
disp_timecode = buffer->disp_timecode;
}

float diverge = 0.0f;
Expand Down Expand Up @@ -4267,8 +4275,8 @@ void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
info.values.insert("progbefore", 0);
info.values.insert("progafter", 0);

int playbackLen = totalLength;

int playbackLen = (totalDuration > 0) ? totalDuration : totalLength;
if (livetv && player_ctx->tvchain)
{
info.values["progbefore"] = (int)player_ctx->tvchain->HasPrev();
Expand All @@ -4285,7 +4293,7 @@ void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
islive = true;
}

float secsplayed = ((float)framesPlayed / video_frame_rate);
float secsplayed = (float)(disp_timecode / 1000.f);
calcSliderPosPriv(info, paddedFields, playbackLen, secsplayed, islive);
}

Expand Down
3 changes: 3 additions & 0 deletions mythtv/libs/libmythtv/mythplayer.h
Expand Up @@ -150,6 +150,7 @@ class MPUBLIC MythPlayer
float a = 1.33333, FrameScanType scan = kScan_Ignore,
bool video_codec_changed = false);
void SetFileLength(int total, int frames);
void SetDuration(int duration);
void SetForcedAspectRatio(int mpeg2_aspect_value, int letterbox_permission);
void SetVideoResize(const QRect &videoRect);

Expand Down Expand Up @@ -595,6 +596,7 @@ class MPUBLIC MythPlayer
uint64_t framesPlayed;
uint64_t totalFrames;
long long totalLength;
int64_t totalDuration;
long long rewindtime;

// -- end state stuff --
Expand Down Expand Up @@ -704,6 +706,7 @@ class MPUBLIC MythPlayer
bool lastsync;
bool decode_extra_audio;
int repeat_delay;
int64_t disp_timecode;

// Time Code stuff
int prevtc; ///< 32 bit timecode if last VideoFrame shown
Expand Down

0 comments on commit ee9af28

Please sign in to comment.