Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
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
stichnot committed Jan 3, 2013
1 parent 8c4434a commit c13683f
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 17 deletions.
2 changes: 1 addition & 1 deletion mythtv/libs/libmythbase/mythversion.h
Expand Up @@ -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.
*
Expand Down
23 changes: 21 additions & 2 deletions mythtv/libs/libmythtv/decoderbase.cpp
Expand Up @@ -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;
}

Expand Down Expand Up @@ -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);
}
Expand All @@ -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
Expand Down
5 changes: 3 additions & 2 deletions mythtv/libs/libmythtv/decoderbase.h
Expand Up @@ -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; }

Expand Down Expand Up @@ -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;
Expand Down
20 changes: 19 additions & 1 deletion mythtv/libs/libmythtv/mythplayer.cpp
Expand Up @@ -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
Expand Down Expand Up @@ -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)
Expand Down
6 changes: 1 addition & 5 deletions mythtv/libs/libmythtv/mythplayer.h
Expand Up @@ -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,
Expand Down
8 changes: 2 additions & 6 deletions mythtv/libs/libmythtv/recorders/recorderbase.h
Expand Up @@ -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
*/
Expand Down

0 comments on commit c13683f

Please sign in to comment.