summaryrefslogtreecommitdiffstats
path: root/audio/filter/af_lavrresample.c
diff options
context:
space:
mode:
Diffstat (limited to 'audio/filter/af_lavrresample.c')
-rw-r--r--audio/filter/af_lavrresample.c90
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[]) {