From 87d8f292f51621a5ad76bd7acebd232b5e6aefce Mon Sep 17 00:00:00 2001 From: wm4 Date: Sat, 3 Feb 2018 12:41:56 +0100 Subject: swresample: actually reinit resampler on large speed changes If the speed is changed by a large amount, we need to effectively change the output rate by a large amount, and swr_set_compensation() is apparently not designed to handle such large changes well. So it's better to reinitialize the resampler on all large changes. Also, strictly reinitialize the resampler if the rate changes, otherwise it could happen that libavresample (which does not automatically initialize resampling if avresample_set_compensation() is used) would never apply speed changes properly. Also document some conditions better that handle corner cases (remove the inline condition from the if gating the compensation code). It also appears that we crashed with very large compensation ratios (when raising audio speed quickly by keeping the "[" key down), and this commit accidentally mitigates it by not allowing large compensation. --- filters/f_swresample.c | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/filters/f_swresample.c b/filters/f_swresample.c index 593a052a76..39efe173bf 100644 --- a/filters/f_swresample.c +++ b/filters/f_swresample.c @@ -624,7 +624,14 @@ static void process(struct mp_filter *f) } int new_rate = rate_from_speed(p->in_rate_user, p->speed); - if (p->avrctx && !(!p->is_resampling && new_rate == p->in_rate)) { + bool exact_rate = new_rate == p->in_rate; + bool use_comp = fabs(new_rate / (double)p->in_rate - 1) <= 0.01; + // If we've never used compensation, avoid setting it - even if it's in + // theory a NOP, libswresample will enable resampling. _If_ we're + // resampling, we might have to disable previously enabled compensation. + if (exact_rate && !p->is_resampling) + use_comp = false; + if (p->avrctx && use_comp) { AVRational r = av_d2q(p->speed * p->in_rate_user / p->in_rate, INT_MAX / 2); // Essentially, swr/avresample_set_compensation() does 2 things: @@ -635,14 +642,15 @@ static void process(struct mp_filter *f) // feeding it, until the next filter() call. int mult = INT_MAX / 2 / MPMAX(MPMAX(abs(r.num), abs(r.den)), 1); r = (AVRational){ r.num * mult, r.den * mult }; + if (r.den == r.num) + r = (AVRational){0}; // fully disable if (avresample_set_compensation(p->avrctx, r.den - r.num, r.den) >= 0) { - new_rate = p->in_rate; - p->is_resampling = true; + exact_rate = true; + p->is_resampling = true; // libswresample can auto-enable it } } - bool need_reinit = fabs(new_rate / (double)p->in_rate - 1) > 0.01; - if (need_reinit && new_rate != p->in_rate) { + if (!exact_rate) { // Before reconfiguring, drain the audio that is still buffered // in the resampler. struct mp_frame out = filter_resample_output(p, NULL); -- cgit v1.2.3