summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-02-03 12:41:56 +0100
committerKevin Mitchell <kevmitch@gmail.com>2018-02-03 05:01:33 -0800
commit87d8f292f51621a5ad76bd7acebd232b5e6aefce (patch)
tree7744bd258fe51bd5c2470acfb929b358a27c2acb
parent07c54d8c5ca0388cd9466438c09d380e32c13183 (diff)
downloadmpv-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.c18
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);