diff options
author | wm4 <wm4@nowhere> | 2018-02-03 12:41:56 +0100 |
---|---|---|
committer | Kevin Mitchell <kevmitch@gmail.com> | 2018-02-03 05:01:33 -0800 |
commit | 87d8f292f51621a5ad76bd7acebd232b5e6aefce (patch) | |
tree | 7744bd258fe51bd5c2470acfb929b358a27c2acb | |
parent | 07c54d8c5ca0388cd9466438c09d380e32c13183 (diff) | |
download | mpv-87d8f292f51621a5ad76bd7acebd232b5e6aefce.tar.bz2 mpv-87d8f292f51621a5ad76bd7acebd232b5e6aefce.tar.xz |
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.
-rw-r--r-- | filters/f_swresample.c | 18 |
1 files 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); |