af_lavrresample: work around libswresample misbehavior

The touched code is for seek resets and such - we simply want to reset
the entire resample state. But I noticed after a seek a tiny bit of
audio is missing (mpv's audio sync code inserted silence to compensate).

It turns out swr_drop_output() either does not reset some internal state
as we expect, or it's designed to drop not only buffered samples, but
also future samples.

On the other hand, libavresample's avresample_read(), does not have this
problem. (It is also pretty explicit in what it does - return/skip
buffered data, nothing else.)

Is the libswresample behavior a bug? Or a feature? Does nobody even
know? Who cares - use the hammer to unfuck the situation. Destroy and
deallocate the libswresample context and recreate it. On every seek.
This commit is contained in:
wm4 2016-08-16 00:03:02 +02:00
parent 86fa1e6129
commit 814dacdd7d
1 changed files with 10 additions and 10 deletions

View File

@ -99,10 +99,6 @@ static double get_delay(struct af_resample *s)
return avresample_get_delay(s->avrctx) / (double)s->in_rate +
avresample_available(s->avrctx) / (double)s->out_rate;
}
static void drop_all_output(struct af_resample *s)
{
while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
}
static int get_out_samples(struct af_resample *s, int in_samples)
{
return avresample_get_out_samples(s->avrctx, in_samples);
@ -113,10 +109,6 @@ static double get_delay(struct af_resample *s)
int64_t base = s->in_rate * (int64_t)s->out_rate;
return swr_get_delay(s->avrctx, base) / (double)base;
}
static void drop_all_output(struct af_resample *s)
{
while (swr_drop_output(s->avrctx, 1000) > 0) {}
}
static int get_out_samples(struct af_resample *s, int in_samples)
{
#if LIBSWRESAMPLE_VERSION_MAJOR > 1 || LIBSWRESAMPLE_VERSION_MINOR >= 2
@ -406,8 +398,16 @@ static int control(struct af_instance *af, int cmd, void *arg)
return AF_OK;
}
case AF_CONTROL_RESET:
if (s->avrctx)
drop_all_output(s);
if (s->avrctx) {
#if HAVE_LIBSWRESAMPLE
// This POS either can't drop state correctly, or doesn't want to.
// It will swallow some minor audio e.g. after a seek.
// Deallocate and recreate the resample state for a full reset.
configure_lavrr(af, &af->fmt_in, &af->fmt_out, false);
#else
while (avresample_read(s->avrctx, NULL, 1000) > 0) {}
#endif
}
return AF_OK;
}
return AF_UNKNOWN;