Skip to content
Browse files

Fix duration display for in-progress variable-framerate recordings.

The last frame is used for calculating total duration, and since the
last frame is almost always beyond the end of the duration map,
requiring extrapolation based on the frame rate.  The problem was that
the frame rate for the current playback position was used, rather than
the frame rate for the current end of the recording, leading to
noticeable errors in duration calculation.  Instead, we can request
the latest frame rate from the recorder.

Thanks to David Engel for testing on a variable-framerate source.
  • Loading branch information...
1 parent 8c4434a commit c13683f20bb9e1f55b240499a01ea13aa821b47a @stichnot stichnot committed
View
2 mythtv/libs/libmythbase/mythversion.h
@@ -12,7 +12,7 @@
/// Update this whenever the plug-in API changes.
/// Including changes in the libmythbase, libmyth, libmythtv, libmythav* and
/// libmythui class methods used by plug-ins.
-#define MYTH_BINARY_VERSION "0.27.20121231-1"
+#define MYTH_BINARY_VERSION "0.27.20130102-1"
/** \brief Increment this whenever the MythTV network protocol changes.
*
View
23 mythtv/libs/libmythtv/decoderbase.cpp
@@ -425,6 +425,10 @@ bool DecoderBase::SyncPositionMap(void)
.arg(totframes).arg(length).arg(new_posmap_size));
}
recordingHasPositionMap |= (0 != new_posmap_size);
+ {
+ QMutexLocker locker(&m_positionMapLock);
+ m_lastPositionMapUpdate = QDateTime::currentDateTime();
+ }
return ret_val;
}
@@ -1265,9 +1269,25 @@ uint64_t DecoderBase::TranslatePosition(const frm_pos_map_t &map,
uint64_t DecoderBase::TranslatePositionFrameToMs(uint64_t position,
float fallback_framerate,
const frm_dir_map_t &cutlist)
- const
{
QMutexLocker locker(&m_positionMapLock);
+ // Accurate calculation of duration requires an up-to-date
+ // duration map. However, the last frame (total duration) will
+ // almost always appear to be past the end of the duration map, so
+ // we limit duration map syncing to once every 3 seconds (a
+ // somewhat arbitrary value).
+ if (!m_frameToDurMap.empty())
+ {
+ frm_pos_map_t::const_iterator it = m_frameToDurMap.end();
+ --it;
+ if (position > it.key())
+ {
+ if (!m_lastPositionMapUpdate.isValid() ||
+ (QDateTime::currentDateTime() >
+ m_lastPositionMapUpdate.addSecs(3)))
+ SyncPositionMap();
+ }
+ }
return TranslatePositionAbsToRel(cutlist, position, m_frameToDurMap,
1000 / fallback_framerate);
}
@@ -1277,7 +1297,6 @@ uint64_t DecoderBase::TranslatePositionFrameToMs(uint64_t position,
uint64_t DecoderBase::TranslatePositionMsToFrame(uint64_t dur_ms,
float fallback_framerate,
const frm_dir_map_t &cutlist)
- const
{
QMutexLocker locker(&m_positionMapLock);
// Convert relative position in milliseconds (cutlist-adjusted) to
View
5 mythtv/libs/libmythtv/decoderbase.h
@@ -156,10 +156,10 @@ class DecoderBase
float fallback_ratio);
uint64_t TranslatePositionFrameToMs(uint64_t position,
float fallback_framerate,
- const frm_dir_map_t &cutlist) const;
+ const frm_dir_map_t &cutlist);
uint64_t TranslatePositionMsToFrame(uint64_t dur_ms,
float fallback_framerate,
- const frm_dir_map_t &cutlist) const;
+ const frm_dir_map_t &cutlist);
float GetVideoAspect(void) const { return current_aspect; }
@@ -297,6 +297,7 @@ class DecoderBase
frm_pos_map_t m_frameToDurMap; // guarded by m_positionMapLock
frm_pos_map_t m_durToFrameMap; // guarded by m_positionMapLock
bool dontSyncPositionMap;
+ mutable QDateTime m_lastPositionMapUpdate; // guarded by m_positionMapLock
uint64_t seeksnap;
bool livetv;
View
20 mythtv/libs/libmythtv/mythplayer.cpp
@@ -4711,7 +4711,7 @@ void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
}
else if (IsWatchingInprogress())
{
- total_frames = player_ctx->recorder->GetFramesWritten();
+ total_frames = -1;
islive = true;
}
else
@@ -4814,6 +4814,24 @@ void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
}
}
+// If position == -1, it signifies that we are computing the current
+// duration of an in-progress recording. In this case, we fetch the
+// current frame rate and frame count from the recorder.
+uint64_t MythPlayer::TranslatePositionFrameToMs(uint64_t position,
+ bool use_cutlist) const
+{
+ float frameRate = GetFrameRate();
+ if (position == -1)
+ {
+ float recorderFrameRate = player_ctx->recorder->GetFrameRate();
+ if (recorderFrameRate > 0)
+ frameRate = recorderFrameRate;
+ position = player_ctx->recorder->GetFramesWritten();
+ }
+ return deleteMap.TranslatePositionFrameToMs(position, frameRate,
+ use_cutlist);
+}
+
int MythPlayer::GetNumChapters()
{
if (decoder)
View
6 mythtv/libs/libmythtv/mythplayer.h
@@ -393,11 +393,7 @@ class MTV_PUBLIC MythPlayer
long long CalcRWTime(long long rw) const;
virtual void calcSliderPos(osdInfo &info, bool paddedFields = false);
uint64_t TranslatePositionFrameToMs(uint64_t position,
- bool use_cutlist) const {
- return deleteMap.TranslatePositionFrameToMs(position,
- GetFrameRate(),
- use_cutlist);
- }
+ bool use_cutlist) const;
uint64_t TranslatePositionMsToFrame(uint64_t position,
bool use_cutlist) const {
return deleteMap.TranslatePositionMsToFrame(position,
View
8 mythtv/libs/libmythtv/recorders/recorderbase.h
@@ -189,13 +189,9 @@ class MTV_PUBLIC RecorderBase : public QRunnable
virtual bool IsPaused(bool holding_lock = false) const;
virtual bool WaitForPause(int timeout = 1000);
- /** \brief Returns an approximation of the frame rate.
- *
- * \bug This can be off by at least half, our non-frame grabber based
- * recorders do not not try to approximate the frame rate. So
- * a 720p recording at 60fps will report a frame-rate of 25fps.
+ /** \brief Returns the latest frame rate.
*/
- double GetFrameRate(void) { return video_frame_rate; }
+ double GetFrameRate(void) { return m_frameRate / 1000; }
/** \brief If requested, switch to new RingBuffer/ProgramInfo objects
*/

0 comments on commit c13683f

Please sign in to comment.
Something went wrong with that request. Please try again.