summaryrefslogtreecommitdiffstats
path: root/player/audio.c
diff options
context:
space:
mode:
authorwm4 <wm4@nowhere>2018-04-12 18:47:25 +0200
committerJan Ekström <jeebjp@gmail.com>2018-04-15 23:11:33 +0300
commit4e7cbb760603074ee5d7b81500b7d52883bd9e24 (patch)
tree80719bad99f56710d15bdaa00fd73f9e2be37fef /player/audio.c
parent9ee9313465ca49f2cfdd407797febed7692e1144 (diff)
downloadmpv-4e7cbb760603074ee5d7b81500b7d52883bd9e24.tar.bz2
mpv-4e7cbb760603074ee5d7b81500b7d52883bd9e24.tar.xz
audio: don't recreate AO if a filter changes the output format
Until recently, the AO was reinitialized strictly only on decoder format changes. But the commit for simplifying audio format negotiation removed this. Now the AO is recreated for any format change. This is sort of annoying if you change playback speed. The insertion/removal of af_scaletempo can change the sample format. For example, the acompressor filter will convert output to double, so toggling scaletempo will force the format back to float. This recreates the AO under the --gapless-audio=weak default. This likely affects a lot of other filters too. Work this around by allowing sample format changes, and keeping the current AO format in these cases. This is probably not a big problem. Most audio APIs force the output format to float anyway. This means you actually have to worry about what the default gapless mode does to your audio. If you start with a file that uses 8 bit per sample, and then continue playing a 24 bit FLAC, it will be converted down to 8 bit per sample. (Assuming they are played in a way that uses the gapless logic.)
Diffstat (limited to 'player/audio.c')
-rw-r--r--player/audio.c29
1 files changed, 28 insertions, 1 deletions
diff --git a/player/audio.c b/player/audio.c
index a6b7601df2..842d965d49 100644
--- a/player/audio.c
+++ b/player/audio.c
@@ -255,6 +255,33 @@ static char *audio_config_to_str_buf(char *buf, size_t buf_sz, int rate,
return buf;
}
+// Decide whether on a format change, we should reinit the AO.
+static bool keep_weak_gapless_format(struct mp_aframe *old, struct mp_aframe* new)
+{
+ bool res = false;
+ struct mp_aframe *new_mod = mp_aframe_new_ref(new);
+ if (!new_mod)
+ abort();
+
+ // If the sample formats are compatible (== libswresample generally can
+ // convert them), keep the AO. On other changes, recreate it.
+
+ int old_fmt = mp_aframe_get_format(old);
+ int new_fmt = mp_aframe_get_format(new);
+
+ if (af_format_conversion_score(old_fmt, new_fmt) == INT_MIN)
+ goto done; // completely incompatible formats
+
+ if (!mp_aframe_set_format(new_mod, old_fmt))
+ goto done;
+
+ res = mp_aframe_config_equals(old, new_mod);
+
+done:
+ talloc_free(new_mod);
+ return res;
+}
+
static void reinit_audio_filters_and_output(struct MPContext *mpctx)
{
struct MPOpts *opts = mpctx->opts;
@@ -290,7 +317,7 @@ static void reinit_audio_filters_and_output(struct MPContext *mpctx)
// previous one, keep the AO and don't reinit anything.
// Strong gapless: always keep the AO
if ((mpctx->ao_filter_fmt && mpctx->ao && opts->gapless_audio < 0 &&
- mp_aframe_config_equals(mpctx->ao_filter_fmt, out_fmt)) ||
+ keep_weak_gapless_format(mpctx->ao_filter_fmt, out_fmt)) ||
(mpctx->ao && opts->gapless_audio > 0))
{
mp_output_chain_set_ao(ao_c->filter, mpctx->ao);