mirror of https://github.com/mpv-player/mpv
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:
parent
3ca0a7fd4d
commit
7bfb240309
|
@ -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
|
||||
|
|
|
@ -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.
|
||||
|
|
|
@ -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}
|
||||
},
|
||||
|
|
Loading…
Reference in New Issue