diff options
Diffstat (limited to 'audio/filter/af_lavrresample.c')
-rw-r--r-- | audio/filter/af_lavrresample.c | 90 |
1 files changed, 73 insertions, 17 deletions
diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index dc2f0628b7..48f69b72e8 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -24,6 +24,7 @@ #include <stdlib.h> #include <string.h> #include <inttypes.h> +#include <math.h> #include <assert.h> #include <libavutil/opt.h> @@ -32,7 +33,7 @@ #include <libavutil/samplefmt.h> #include <libavutil/mathematics.h> -#include "talloc.h" +#include "common/common.h" #include "config.h" #if HAVE_LIBAVRESAMPLE @@ -64,7 +65,8 @@ struct af_resample_opts { int linear; double cutoff; - int in_rate; + int in_rate_af; // filter input sample rate + int in_rate; // actual rate (used by lavr), adjusted for playback speed int in_format; struct mp_chmap in_channels; int out_rate; @@ -75,6 +77,9 @@ struct af_resample_opts { struct af_resample { int allow_detach; char **avopts; + double playback_speed; + struct mp_audio *pending; + bool avrctx_ok; struct AVAudioResampleContext *avrctx; struct AVAudioResampleContext *avrctx_out; // for output channel reordering struct af_resample_opts ctx; // opts in the context @@ -94,6 +99,10 @@ static void drop_all_output(struct af_resample *s) { while (avresample_read(s->avrctx, NULL, 1000) > 0) {} } +static int get_drain_samples(struct af_resample *s) +{ + return avresample_get_out_samples(s->avrctx, 0); +} #else static int get_delay(struct af_resample *s) { @@ -103,18 +112,39 @@ static void drop_all_output(struct af_resample *s) { while (swr_drop_output(s->avrctx, 1000) > 0) {} } +static int get_drain_samples(struct af_resample *s) +{ + return 4096; // libswscale does not have this +} #endif +static int resample_frame(struct AVAudioResampleContext *r, + struct mp_audio *out, struct mp_audio *in) +{ + return avresample_convert(r, + out ? (uint8_t **)out->planes : NULL, + out ? mp_audio_get_allocated_size(out) : 0, + out ? out->samples : 0, + in ? (uint8_t **)in->planes : NULL, + in ? mp_audio_get_allocated_size(in) : 0, + in ? in->samples : 0); +} + static double af_resample_default_cutoff(int filter_size) { return FFMAX(1.0 - 6.5 / (filter_size + 8), 0.80); } +static int rate_from_speed(int rate, double speed) +{ + return lrint(rate * speed); +} + static bool needs_lavrctx_reconfigure(struct af_resample *s, struct mp_audio *in, struct mp_audio *out) { - return s->ctx.in_rate != in->rate || + return s->ctx.in_rate_af != in->rate || s->ctx.in_format != in->format || !mp_chmap_equals(&s->ctx.in_channels, &in->channels) || s->ctx.out_rate != out->rate || @@ -138,6 +168,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in, { struct af_resample *s = af->priv; + s->avrctx_ok = false; + enum AVSampleFormat in_samplefmt = af_to_avformat(in->format); enum AVSampleFormat out_samplefmt = af_to_avformat(out->format); @@ -147,8 +179,12 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in, avresample_close(s->avrctx); avresample_close(s->avrctx_out); + talloc_free(s->pending); + s->pending = NULL; + s->ctx.out_rate = out->rate; - s->ctx.in_rate = in->rate; + s->ctx.in_rate_af = in->rate; + s->ctx.in_rate = rate_from_speed(in->rate, s->playback_speed); s->ctx.out_format = out->format; s->ctx.in_format = in->format; s->ctx.out_channels= out->channels; @@ -217,6 +253,7 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in, MP_ERR(af, "Cannot open Libavresample Context. \n"); return AF_ERROR; } + s->avrctx_ok = true; return AF_OK; } @@ -234,7 +271,7 @@ static int control(struct af_instance *af, int cmd, void *arg) if (((out->rate == in->rate) || (out->rate == 0)) && (out->format == in->format) && (mp_chmap_equals(&out->channels, &in->channels) || out->nch == 0) && - s->allow_detach) + s->allow_detach && s->playback_speed == 1.0) return AF_DETACH; if (out->rate == 0) @@ -270,6 +307,26 @@ static int control(struct af_instance *af, int cmd, void *arg) case AF_CONTROL_SET_RESAMPLE_RATE: out->rate = *(int *)arg; return AF_OK; + case AF_CONTROL_SET_PLAYBACK_SPEED_RESAMPLE: { + s->playback_speed = *(double *)arg; + int new_rate = rate_from_speed(s->ctx.in_rate_af, s->playback_speed); + if (new_rate != s->ctx.in_rate && s->avrctx_ok && af->fmt_out.format) { + // Before reconfiguring, drain the audio that is still buffered + // in the resampler. + talloc_free(s->pending); + s->pending = talloc_zero(NULL, struct mp_audio); + mp_audio_copy_config(s->pending, &af->fmt_out); + s->pending->samples = get_drain_samples(s); + if (s->pending->samples > 0) { + mp_audio_realloc_min(s->pending, s->pending->samples); + int r = resample_frame(s->avrctx, s->pending, NULL); + s->pending->samples = MPMAX(r, 0); + } + // Reinitialize resampler. + configure_lavrr(af, &af->fmt_in, &af->fmt_out); + } + return AF_OK; + } case AF_CONTROL_RESET: drop_all_output(s); return AF_OK; @@ -289,6 +346,7 @@ static void uninit(struct af_instance *af) if (s->avrctx_out) avresample_close(s->avrctx_out); avresample_free(&s->avrctx_out); + talloc_free(s->pending); } static bool needs_reorder(int *reorder, int num_ch) @@ -309,22 +367,19 @@ static void reorder_planes(struct mp_audio *mpa, int *reorder) } } -static int resample_frame(struct AVAudioResampleContext *r, - struct mp_audio *out, struct mp_audio *in) -{ - return avresample_convert(r, - out ? (uint8_t **)out->planes : NULL, - out ? mp_audio_get_allocated_size(out) : 0, - out ? out->samples : 0, - in ? (uint8_t **)in->planes : NULL, - in ? mp_audio_get_allocated_size(in) : 0, - in ? in->samples : 0); -} - static int filter(struct af_instance *af, struct mp_audio *in) { struct af_resample *s = af->priv; + if (s->pending) { + if (s->pending->samples) { + af_add_output_frame(af, s->pending); + } else { + talloc_free(s->pending); + } + s->pending = NULL; + } + int samples = avresample_available(s->avrctx) + av_rescale_rnd(get_delay(s) + (in ? in->samples : 0), s->ctx.out_rate, s->ctx.in_rate, AV_ROUND_UP); @@ -412,6 +467,7 @@ const struct af_info af_info_lavrresample = { .cutoff = 0.0, .phase_shift = 10, }, + .playback_speed = 1.0, .allow_detach = 1, }, .options = (const struct m_option[]) { |