From 7bfb240309225fa6fb4e51a0deda8fd8e34953e0 Mon Sep 17 00:00:00 2001 From: wm4 Date: Thu, 12 Apr 2018 22:08:56 +0200 Subject: 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. --- DOCS/interface-changes.rst | 2 +- DOCS/man/af.rst | 13 +++++++++++++ filters/f_lavfi.c | 31 +++++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/DOCS/interface-changes.rst b/DOCS/interface-changes.rst index e3d50021ed..576a472cd0 100644 --- a/DOCS/interface-changes.rst +++ b/DOCS/interface-changes.rst @@ -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 diff --git a/DOCS/man/af.rst b/DOCS/man/af.rst index 93a25cd4bb..4e806d482e 100644 --- a/DOCS/man/af.rst +++ b/DOCS/man/af.rst @@ -245,3 +245,16 @@ Available filters are: ``o=`` AVOptions. + + ``fix-pts=`` + 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. diff --git a/filters/f_lavfi.c b/filters/f_lavfi.c index 3716dd1f85..1b41c93aac 100644 --- a/filters/f_lavfi.c +++ b/filters/f_lavfi.c @@ -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} }, -- cgit v1.2.3