diff options
author | wm4 <wm4@nowhere> | 2020-05-23 04:04:46 +0200 |
---|---|---|
committer | wm4 <wm4@nowhere> | 2020-05-23 04:04:46 +0200 |
commit | ab4e0c42fbb11f2e7459fe9fe98265e0323b1ef4 (patch) | |
tree | 8d202d9a8d7aecf3f305c0311d5115b46ba009d9 /audio/filter | |
parent | 43a67970b6c17f8d0525f90fac25923cd4a989bf (diff) | |
download | mpv-ab4e0c42fbb11f2e7459fe9fe98265e0323b1ef4.tar.bz2 mpv-ab4e0c42fbb11f2e7459fe9fe98265e0323b1ef4.tar.xz |
audio: redo video-sync=display-adrop
This mode drops or repeats audio data to adapt to video speed, instead
of resampling it or such. It was added to deal with SPDIF. The
implementation was part of fill_audio_out_buffers() - the entire
function is something whose complexity exploded in my face, and which I
want to clean up, and this is hopefully a first step.
Put it in a filter, and mess with the shitty glue code. It's all sort of
roundabout and illogical, but that can be rectified later. The important
part is that it works much like the resample or scaletempo filters.
For PCM audio, this does not work on samples anymore. This makes it much
worse. But for PCM you can use saner mechanisms that sound better. Also,
something about PTS tracking is wrong. But not wasting more time on
this.
Diffstat (limited to 'audio/filter')
-rw-r--r-- | audio/filter/af_drop.c | 114 |
1 files changed, 114 insertions, 0 deletions
diff --git a/audio/filter/af_drop.c b/audio/filter/af_drop.c new file mode 100644 index 0000000000..724c482720 --- /dev/null +++ b/audio/filter/af_drop.c @@ -0,0 +1,114 @@ +#include "audio/aframe.h" +#include "audio/format.h" +#include "common/common.h" +#include "filters/f_autoconvert.h" +#include "filters/filter_internal.h" +#include "filters/user_filters.h" + +struct priv { + double speed; + double diff; // amount of too many additional samples in normal speed + struct mp_aframe *last; // for repeating +}; + +static void process(struct mp_filter *f) +{ + struct priv *p = f->priv; + + if (!mp_pin_in_needs_data(f->ppins[1])) + return; + + struct mp_frame frame = {0}; + + double last_dur = p->last ? mp_aframe_duration(p->last) : 0; + if (p->last && p->diff < 0 && -p->diff > last_dur / 2) { + MP_VERBOSE(f, "repeat\n"); + frame = MAKE_FRAME(MP_FRAME_AUDIO, p->last); + p->last = NULL; + } else { + frame = mp_pin_out_read(f->ppins[0]); + + if (frame.type == MP_FRAME_AUDIO) { + last_dur = mp_aframe_duration(frame.data); + p->diff -= last_dur; + if (p->diff > last_dur / 2) { + MP_VERBOSE(f, "drop\n"); + mp_frame_unref(&frame); + mp_filter_internal_mark_progress(f); + } + } + } + + if (frame.type == MP_FRAME_AUDIO) { + struct mp_aframe *fr = frame.data; + talloc_free(p->last); + p->last = mp_aframe_new_ref(fr); + mp_aframe_mul_speed(fr, p->speed); + p->diff += mp_aframe_duration(fr); + mp_aframe_set_pts(p->last, mp_aframe_end_pts(fr)); + } else if (frame.type == MP_FRAME_EOF) { + TA_FREEP(&p->last); + } + mp_pin_in_write(f->ppins[1], frame); +} + +static bool command(struct mp_filter *f, struct mp_filter_command *cmd) +{ + struct priv *p = f->priv; + + switch (cmd->type) { + case MP_FILTER_COMMAND_SET_SPEED: + p->speed = cmd->speed; + return true; + } + + return false; +} + +static void reset(struct mp_filter *f) +{ + struct priv *p = f->priv; + + TA_FREEP(&p->last); + p->diff = 0; +} + +static void destroy(struct mp_filter *f) +{ + reset(f); +} + +static const struct mp_filter_info af_drop_filter = { + .name = "drop", + .priv_size = sizeof(struct priv), + .process = process, + .command = command, + .reset = reset, + .destroy = destroy, +}; + +static struct mp_filter *af_drop_create(struct mp_filter *parent, void *options) +{ + struct mp_filter *f = mp_filter_create(parent, &af_drop_filter); + if (!f) { + talloc_free(options); + return NULL; + } + + mp_filter_add_pin(f, MP_PIN_IN, "in"); + mp_filter_add_pin(f, MP_PIN_OUT, "out"); + + struct priv *p = f->priv; + p->speed = 1.0; + + return f; +} + +const struct mp_user_filter_entry af_drop = { + .desc = { + .description = "Change audio speed by dropping/repeating frames", + .name = "drop", + .priv_size = sizeof(struct priv), + }, + .create = af_drop_create, +}; |