summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTaylor Ralph <tralph@mythtv.org>2010-11-23 21:19:26 (GMT)
committer Taylor Ralph <tralph@mythtv.org>2010-11-23 21:19:26 (GMT)
commitee9af286f44cedacb718c91cc6093cc671eca8bf (patch)
tree96cb2dcf3238744f77e0e81bc55fc22fbef0f534
parentba1f912e85cedf465a5ef4a13b8119e2fc16ed81 (diff)
Several changes to fix the current position and duration of the playback 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
-rw-r--r--mythtv/libs/libmythtv/avformatdecoder.cpp75
-rw-r--r--mythtv/libs/libmythtv/avformatdecoder.h1
-rw-r--r--mythtv/libs/libmythtv/frame.h1
-rw-r--r--mythtv/libs/libmythtv/mythplayer.cpp18
-rw-r--r--mythtv/libs/libmythtv/mythplayer.h3
5 files changed, 69 insertions, 29 deletions
diff --git a/mythtv/libs/libmythtv/avformatdecoder.cpp b/mythtv/libs/libmythtv/avformatdecoder.cpp
index 51b2424..b31ad0e 100644
--- a/mythtv/libs/libmythtv/avformatdecoder.cpp
+++ b/mythtv/libs/libmythtv/avformatdecoder.cpp
@@ -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++)
{
@@ -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()
@@ -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)
{
@@ -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);
@@ -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
@@ -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 &&
@@ -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);
diff --git a/mythtv/libs/libmythtv/avformatdecoder.h b/mythtv/libs/libmythtv/avformatdecoder.h
index d3947e5..487ab2b 100644
--- a/mythtv/libs/libmythtv/avformatdecoder.h
+++ b/mythtv/libs/libmythtv/avformatdecoder.h
@@ -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*);
diff --git a/mythtv/libs/libmythtv/frame.h b/mythtv/libs/libmythtv/frame.h
index 90e4dd2..0db21a4 100644
--- a/mythtv/libs/libmythtv/frame.h
+++ b/mythtv/libs/libmythtv/frame.h
@@ -40,6 +40,7 @@ typedef struct VideoFrame_
long long frameNumber;
long long timecode;
+ int64_t disp_timecode;
unsigned char *priv[4]; // random empty storage
diff --git a/mythtv/libs/libmythtv/mythplayer.cpp b/mythtv/libs/libmythtv/mythplayer.cpp
index 681d041..2e991bd 100644
--- a/mythtv/libs/libmythtv/mythplayer.cpp
+++ b/mythtv/libs/libmythtv/mythplayer.cpp
@@ -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),
@@ -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
@@ -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;
@@ -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;
@@ -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();
@@ -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);
}
diff --git a/mythtv/libs/libmythtv/mythplayer.h b/mythtv/libs/libmythtv/mythplayer.h
index 99663bf..325efee 100644
--- a/mythtv/libs/libmythtv/mythplayer.h
+++ b/mythtv/libs/libmythtv/mythplayer.h
@@ -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);
@@ -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 --
@@ -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