From 6f24a61d842c8ae495bbf5d38d6d87fea01d726a Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 11 Feb 2015 15:46:12 +0100 Subject: af_rubberband: attempt to fix audio position calculation The problem here is that librubberband can buffer an arbitrary amount of data, but at the same time doesn't provide a way to query how much data is buffered. So we keep track of this manually, assuming that librubberband tries to reach the requested time ratio for input and output (which is probably true). The disadvantage is that rounding errors could accumulate over time. (Maybe it should try to round towards keeping the time ratio.) --- audio/filter/af_rubberband.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'audio/filter') diff --git a/audio/filter/af_rubberband.c b/audio/filter/af_rubberband.c index 27e26c1039..4863c2282d 100644 --- a/audio/filter/af_rubberband.c +++ b/audio/filter/af_rubberband.c @@ -28,6 +28,9 @@ struct priv { double speed; struct mp_audio *pending; bool needs_reset; + // Estimate how much librubberband has buffered internally. + // I could not find a way to do this with the librubberband API. + double rubber_delay; }; static void update_speed(struct af_instance *af, double new_speed) @@ -66,6 +69,7 @@ static int control(struct af_instance *af, int cmd, void *arg) } update_speed(af, p->speed); + control(af, AF_CONTROL_RESET, NULL); return mp_audio_config_equals(in, &orig_in) ? AF_OK : AF_FALSE; } @@ -78,6 +82,7 @@ static int control(struct af_instance *af, int cmd, void *arg) rubberband_reset(p->rubber); talloc_free(p->pending); p->pending = NULL; + p->rubber_delay = 0; return AF_OK; } return AF_UNKNOWN; @@ -106,8 +111,10 @@ static int filter_out(struct af_instance *af) break; // recover from previous EOF - if (p->needs_reset) + if (p->needs_reset) { rubberband_reset(p->rubber); + p->rubber_delay = 0; + } p->needs_reset = false; size_t needs = rubberband_get_samples_required(p->rubber); @@ -120,6 +127,8 @@ static int filter_out(struct af_instance *af) p->needs_reset = !p->pending; // EOF rubberband_process(p->rubber, in_data, in_samples, p->needs_reset); + p->rubber_delay += in_samples; + if (!p->pending) break; mp_audio_skip_samples(p->pending, in_samples); @@ -133,14 +142,18 @@ static int filter_out(struct af_instance *af) return -1; if (p->pending) mp_audio_copy_config(out, p->pending); + float **out_data = (void *)&out->planes; out->samples = rubberband_retrieve(p->rubber, out_data, out->samples); + p->rubber_delay -= out->samples * p->speed; + af_add_output_frame(af, out); } - int delay = rubberband_get_latency(p->rubber); - delay += p->pending ? p->pending->samples : 0; - af->delay = delay / (double)af->data->rate; + int delay_samples = p->rubber_delay; + if (p->pending) + delay_samples += p->pending->samples; + af->delay = delay_samples / (af->data->rate * p->speed); return 0; } -- cgit v1.2.3