summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--DOCS/man/options.rst7
-rw-r--r--player/audio.c29
2 files changed, 32 insertions, 4 deletions
diff --git a/DOCS/man/options.rst b/DOCS/man/options.rst
index a5d146690a..2776bf7b10 100644
--- a/DOCS/man/options.rst
+++ b/DOCS/man/options.rst
@@ -1541,9 +1541,10 @@ Audio
changes, the audio device is closed and reopened. This means that
you will normally get gapless audio with files that were encoded
using the same settings, but might not be gapless in other cases.
- (Unlike with ``yes``, you don't have to worry about corner cases
- like the first file setting a very low quality output format, and
- ruining the playback of higher quality files that follow.)
+ The exact conditions under which the audio device is kept open is
+ an implementation detail, and can change from version to version.
+ Currently, the device is kept even if the sample format changes,
+ but the sample formats are convertible.
.. note::
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);