Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Several changes to fix the current position and duration of the playb…

…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
(cherry picked from commit ee9af28)
  • Loading branch information...
commit 1a69c92db869ebb47b638404ac4fd1bb4078c584 1 parent 08a8a65
tralph tralph authored
75 mythtv/libs/libmythtv/avformatdecoder.cpp
View
@@ -406,6 +406,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++)
{
@@ -419,19 +421,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()
@@ -965,12 +987,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)
{
@@ -2953,7 +2981,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);
@@ -3076,27 +3104,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
@@ -3112,8 +3138,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 &&
@@ -3137,10 +3163,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);
1  mythtv/libs/libmythtv/avformatdecoder.h
View
@@ -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;
1  mythtv/libs/libmythtv/frame.h
View
@@ -40,6 +40,7 @@ typedef struct VideoFrame_
long long frameNumber;
long long timecode;
+ int64_t disp_timecode;
unsigned char *priv[4]; // random empty storage
18 mythtv/libs/libmythtv/mythplayer.cpp
View
@@ -152,6 +152,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),
@@ -200,6 +201,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),
savedAudioTimecodeOffset(0),
@@ -848,6 +850,11 @@ void MythPlayer::SetFileLength(int total, int frames)
totalFrames = frames;
}
+void MythPlayer::SetDuration(int duration)
+{
+ totalDuration = duration;
+}
+
void MythPlayer::OpenDummy(void)
{
isDummy = true;
@@ -1608,8 +1615,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;
@@ -4230,8 +4238,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();
@@ -4248,7 +4256,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);
}
3  mythtv/libs/libmythtv/mythplayer.h
View
@@ -136,6 +136,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);
@@ -583,6 +584,7 @@ class MPUBLIC MythPlayer
uint64_t framesPlayed;
uint64_t totalFrames;
long long totalLength;
+ int64_t totalDuration;
long long rewindtime;
// -- end state stuff --
@@ -692,6 +694,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
Please sign in to comment.
Something went wrong with that request. Please try again.