summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-04-12 22:08:56 +0200
committerJan Ekström <jeebjp@gmail.com>2018-04-15 23:11:33 +0300
commit7bfb240309225fa6fb4e51a0deda8fd8e34953e0 (patch)
tree7c912d645a3e786e8713d93cbbaf3b9b73a65885
parent3ca0a7fd4d6615e438fdc80192dca951fff74ff1 (diff)
downloadmpv-7bfb240309225fa6fb4e51a0deda8fd8e34953e0.tar.bz2
mpv-7bfb240309225fa6fb4e51a0deda8fd8e34953e0.tar.xz
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.
-rw-r--r--DOCS/interface-changes.rst2
-rw-r--r--DOCS/man/af.rst13
-rw-r--r--filters/f_lavfi.c31
3 files changed, 45 insertions, 1 deletions
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=<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.
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}
},