summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2015-02-11 15:46:12 +0100
committerwm4 <wm4@nowhere>2015-02-11 16:32:40 +0100
commit6f24a61d842c8ae495bbf5d38d6d87fea01d726a (patch)
tree128553b7c16f4206317a6bb82447325e68e0d73b
parent76501f4f57d6d00a914a2e7242ab393fb751a190 (diff)
downloadmpv-6f24a61d842c8ae495bbf5d38d6d87fea01d726a.tar.bz2
mpv-6f24a61d842c8ae495bbf5d38d6d87fea01d726a.tar.xz
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.)
-rw-r--r--audio/filter/af_rubberband.c21
1 files changed, 17 insertions, 4 deletions
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;
}