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.
This commit is contained in:
wm4 2015-10-14 18:51:12 +02:00
parent da496ae2fe
commit e0f8d79772
1 changed files with 9 additions and 3 deletions

View File

@ -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;
}