From e0f8d797720ed00a731d8fb8d41995501609c34b Mon Sep 17 00:00:00 2001 From: wm4 Date: Wed, 14 Oct 2015 18:51:12 +0200 Subject: af_lavrresample: fix unintended audio drift when setting playback speed Small adjustments to the playback speed use swr_set_compensation() to stretch the audio as it is required. But since large adjustments are now handled by actually reinitializing libswresample, the small adjustments get rounded off completely with typical frame sizes. Compensate for this by accounting for the rounding error and keeping track of fractional samples that should have been output to achieve the correct ratio. This fixes display sync mode behavior, which requires these adjustments to be relatively accurate. --- audio/filter/af_lavrresample.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'audio/filter') diff --git a/audio/filter/af_lavrresample.c b/audio/filter/af_lavrresample.c index b73f0d8d0e..11af645910 100644 --- a/audio/filter/af_lavrresample.c +++ b/audio/filter/af_lavrresample.c @@ -91,6 +91,8 @@ struct af_resample { int out_rate; int out_format; struct mp_chmap out_channels; + + double missing_samples; // fractional samples not yet output }; #if HAVE_LIBAVRESAMPLE @@ -224,6 +226,8 @@ static int configure_lavrr(struct af_instance *af, struct mp_audio *in, s->out_channels= out->channels; s->in_channels = in->channels; + s->missing_samples = 0; + av_opt_set_int(s->avrctx, "filter_size", s->opts.filter_size, 0); av_opt_set_int(s->avrctx, "phase_shift", s->opts.phase_shift, 0); av_opt_set_int(s->avrctx, "linear_interp", s->opts.linear, 0); @@ -519,10 +523,12 @@ static int filter(struct af_instance *af, struct mp_audio *in) if (!need_reinit && s->avrctx) { double speed_factor = s->playback_speed * s->in_rate_af / s->in_rate; int in_samples = in ? in->samples : 0; - int wanted_samples = lrint(in_samples / speed_factor); + double wanted_samples = in_samples / speed_factor + s->missing_samples; + int wanted_samples_i = lrint(wanted_samples); + s->missing_samples = wanted_samples - wanted_samples_i; if (avresample_set_compensation(s->avrctx, - (wanted_samples - in_samples) * s->out_rate / s->in_rate, - wanted_samples * s->out_rate / s->in_rate) < 0) + (wanted_samples_i - in_samples) * s->out_rate / s->in_rate, + wanted_samples_i * s->out_rate / s->in_rate) < 0) need_reinit = true; } -- cgit v1.2.3