command: add property that estimates current video FPS

This is done after filters, so things like framerate-doubling
deinterlacing is accounted for.

Unfortunately, framedropping can cause inaccuracies (especially after
precise seeks), and we can't really know when that happens. Even though
we know that the decoder might drop a frame if we request it to do so,
we don't know when the dropped frame will start or stop affecting the
video filter chain. Video filters can have frames buffered, and we
can't tell at which point the dropped frame would have been output.
It's not even possible to mark a discontinuity after seek, because
again we don't know if the filter chain still has the discontinuity
within its buffers.

So we have to live with the fact that the output of this property can
be completely broken after seek, unless --no-hr-seek-framedrop is used.
This commit is contained in:
wm4 2014-05-08 00:49:21 +02:00
parent c57660fbf7
commit 996ab61a6a
2 changed files with 35 additions and 0 deletions

View File

@ -978,6 +978,14 @@ Property list
Container FPS. This can easily contain bogus values. For videos that use
modern container formats or video codecs, this will often be incorrect.
``estimated-vf-fps``
Estimated/measured FPS of the video filter chain output. (If no filters
are used, this corresponds to decoder output.) This uses the average of
the 10 past frame durations to calculate the FPS. It will be inaccurate
if framedropping is involved (such as when framedrop is explicitly
enabled, or after precise seeking). Files with imprecise timestamps (such
as Matroska) might lead to unstable results.
``window-scale`` (RW)
Window size multiplier. Setting this will resize the video window to the
values contained in ``dwidth`` and ``dheight`` multiplied with the value

View File

@ -1986,6 +1986,32 @@ static int mp_property_fps(m_option_t *prop, int action, void *arg,
return m_property_float_ro(prop, action, arg, mpctx->d_video->fps);
}
static int mp_property_vf_fps(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
{
if (!mpctx->d_video)
return M_PROPERTY_UNAVAILABLE;
double next_pts = mpctx->vo_pts_history_pts[0];
if (mpctx->vo_pts_history_seek[0] != mpctx->vo_pts_history_seek_ts)
return M_PROPERTY_UNAVAILABLE;
if (next_pts == MP_NOPTS_VALUE)
return M_PROPERTY_UNAVAILABLE;
int num_samples = 10;
assert(num_samples + 1 <= MAX_NUM_VO_PTS);
double duration = 0;
for (int n = 1; n < 1 + num_samples; n++) {
double frame_pts = mpctx->vo_pts_history_pts[n];
// Discontinuity -> refuse to return a value.
if (mpctx->vo_pts_history_seek[n] != mpctx->vo_pts_history_seek_ts)
return M_PROPERTY_UNAVAILABLE;
if (frame_pts == MP_NOPTS_VALUE)
return M_PROPERTY_UNAVAILABLE;
duration += next_pts - frame_pts;
next_pts = frame_pts;
}
return m_property_double_ro(prop, action, arg, num_samples / duration);
}
/// Video aspect (RO)
static int mp_property_aspect(m_option_t *prop, int action, void *arg,
MPContext *mpctx)
@ -2432,6 +2458,7 @@ static const m_option_t mp_properties[] = {
CONF_RANGE, 0.125, 8 },
{ "fps", mp_property_fps, CONF_TYPE_FLOAT,
0, 0, 0, NULL },
{ "estimated-vf-fps", mp_property_vf_fps, CONF_TYPE_DOUBLE },
{ "video-aspect", mp_property_aspect, CONF_TYPE_FLOAT,
CONF_RANGE, -1, 10, NULL },
M_OPTION_PROPERTY_CUSTOM("vid", mp_property_video),