f_lavfi: add an option to use old audio PTS handling for af_lavfi

The fix-pts option basically uses the old af_lavfi's (before filter
rewrite) timestamp logic. The rest is explained in the manpage.
This commit is contained in:
wm4 2018-04-12 22:08:56 +02:00 committed by Jan Ekström
parent 3ca0a7fd4d
commit 7bfb240309
3 changed files with 45 additions and 1 deletions

View File

@ -68,7 +68,7 @@ Interface changes
- if filters do not pass through PTS values correctly, A/V sync can
result over time. Some libavfilter filters are known to be affected by
this, such as af_loudnorm, which can desync over time, depending on
how the audio track was muxed.
how the audio track was muxed (af_lavfi's fix-pts suboption can help).
- remove out-format sub-parameter from "format" audio filter (no replacement)
- --lavfi-complex now requires uniquely named filter pads. In addition,
unconnected filter pads are not allowed anymore (that means every filter

View File

@ -245,3 +245,16 @@ Available filters are:
``o=<string>``
AVOptions.
``fix-pts=<yes|no>``
Determine PTS based on sample count (default: no). If this is enabled,
the player won't rely on libavfilter passing through PTS accurately.
Instead, it pass a sample count as PTS to libavfilter, and compute the
PTS used by mpv based on that and the input PTS. This helps with filters
which output a recomputed PTS instead of the original PTS (including
filters which require the PTS to start at 0). mpv normally expects
filters to not touch the PTS (or only to the extent of changing frame
boundaries), so this is not the default, but it will be needed to use
broken filters. In practice, these broken filters will either cause slow
A/V desync over time (with some files), or break playback completely if
you seek or start playback from the middle of a file.

View File

@ -93,6 +93,12 @@ struct lavfi {
AVFrame *tmp_frame;
// Audio timestamp emulation.
bool emulate_audio_pts;
double in_pts; // last input timestamps
int64_t in_samples; // samples ever sent to the filter
double delay; // seconds of audio apparently buffered by filter
struct mp_lavfi public;
};
@ -137,6 +143,9 @@ static void free_graph(struct lavfi *c)
}
c->initialized = false;
c->draining_recover = false;
c->in_pts = MP_NOPTS_VALUE;
c->in_samples = 0;
c->delay = 0;
}
static void add_pad(struct lavfi *c, int dir, int index, AVFilterContext *filter,
@ -611,6 +620,13 @@ static bool feed_input_pads(struct lavfi *c)
AVFrame *frame = mp_frame_to_av(pad->pending, &pad->timebase);
bool eof = pad->pending.type == MP_FRAME_EOF;
if (c->emulate_audio_pts && pad->pending.type == MP_FRAME_AUDIO) {
struct mp_aframe *aframe = pad->pending.data;
c->in_pts = mp_aframe_end_pts(aframe);
frame->pts = c->in_samples; // timebase is 1/sample_rate
c->in_samples += frame->nb_samples;
}
mp_frame_unref(&pad->pending);
if (!frame && !eof) {
@ -656,6 +672,14 @@ static bool read_output_pads(struct lavfi *c)
#endif
struct mp_frame frame =
mp_frame_from_av(pad->type, c->tmp_frame, &pad->timebase);
if (c->emulate_audio_pts && frame.type == MP_FRAME_AUDIO) {
AVFrame *avframe = c->tmp_frame;
struct mp_aframe *aframe = frame.data;
double in_time = c->in_samples * av_q2d(c->in_pads[0]->timebase);
double out_time = avframe->pts * av_q2d(pad->timebase);
mp_aframe_set_pts(aframe, c->in_pts +
(c->in_pts != MP_NOPTS_VALUE ? (out_time - in_time) : 0));
}
av_frame_unref(c->tmp_frame);
if (frame.type) {
mp_pin_in_write(pad->pin, frame);
@ -871,6 +895,8 @@ struct lavfi_user_opts {
char *filter_name;
char **filter_opts;
int fix_pts;
};
static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options)
@ -884,6 +910,10 @@ static struct mp_filter *lavfi_create(struct mp_filter *parent, void *options)
l = mp_lavfi_create_graph(parent, opts->type, true,
opts->avopts, opts->graph);
}
if (l) {
struct lavfi *c = l->f->priv;
c->emulate_audio_pts = opts->fix_pts;
}
talloc_free(opts);
return l ? l->f : NULL;
}
@ -1030,6 +1060,7 @@ const struct mp_user_filter_entry af_lavfi = {
.priv_size = sizeof(OPT_BASE_STRUCT),
.options = (const m_option_t[]){
OPT_STRING("graph", graph, M_OPT_MIN, .min = 1),
OPT_FLAG("fix-pts", fix_pts, 0),
OPT_KEYVALUELIST("o", avopts, 0),
{0}
},