From 9be52e5dd8d5b4ae56dfd68430191c818f646beb Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Thu, 16 Jun 2022 03:12:44 +0200 Subject: ad_lavc: strip non-normalized floats `opus` codec likes returning denormalized floats in some cases, causing wacky issues. Fixes #10290 --- audio/aframe.c | 31 +++++++++++++++++++++++++++++++ audio/aframe.h | 1 + audio/decode/ad_lavc.c | 3 +++ 3 files changed, 35 insertions(+) diff --git a/audio/aframe.c b/audio/aframe.c index 6781bb7b55..9b0827f64c 100644 --- a/audio/aframe.c +++ b/audio/aframe.c @@ -466,6 +466,37 @@ void mp_aframe_skip_samples(struct mp_aframe *f, int samples) f->pts += samples / mp_aframe_get_effective_rate(f); } +// sanitize a floating point sample value +#define sanitizef(f) do { \ + if (!isnormal(f)) \ + (f) = 0; \ +} while (0) + +void mp_aframe_sanitize_float(struct mp_aframe *mpa) +{ + int format = af_fmt_from_planar(mp_aframe_get_format(mpa)); + if (format != AF_FORMAT_FLOAT && format != AF_FORMAT_DOUBLE) + return; + int num_planes = mp_aframe_get_planes(mpa); + uint8_t **planes = mp_aframe_get_data_rw(mpa); + if (!planes) + return; + for (int p = 0; p < num_planes; p++) { + void *ptr = planes[p]; + int total = mp_aframe_get_total_plane_samples(mpa); + switch (format) { + case AF_FORMAT_FLOAT: + for (int s = 0; s < total; s++) + sanitizef(((float *)ptr)[s]); + break; + case AF_FORMAT_DOUBLE: + for (int s = 0; s < total; s++) + sanitizef(((double *)ptr)[s]); + break; + } + } +} + // Return the timestamp of the sample just after the end of this frame. double mp_aframe_end_pts(struct mp_aframe *f) { diff --git a/audio/aframe.h b/audio/aframe.h index be456a3dd1..d19c7e8bcb 100644 --- a/audio/aframe.h +++ b/audio/aframe.h @@ -60,6 +60,7 @@ char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt #define mp_aframe_format_str(fmt) mp_aframe_format_str_buf((char[32]){0}, 32, (fmt)) void mp_aframe_skip_samples(struct mp_aframe *f, int samples); +void mp_aframe_sanitize_float(struct mp_aframe *f); double mp_aframe_end_pts(struct mp_aframe *f); double mp_aframe_duration(struct mp_aframe *f); void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end); diff --git a/audio/decode/ad_lavc.c b/audio/decode/ad_lavc.c index 34c3a183eb..6ae7d80bf5 100644 --- a/audio/decode/ad_lavc.c +++ b/audio/decode/ad_lavc.c @@ -260,6 +260,9 @@ static int receive_frame(struct mp_filter *da, struct mp_frame *out) priv->trim_samples -= trim; } + // Strip possibly bogus float values like Infinity, NaN, denormalized + mp_aframe_sanitize_float(mpframe); + if (mp_aframe_get_size(mpframe) > 0) { *out = MAKE_FRAME(MP_FRAME_AUDIO, mpframe); } else { -- cgit v1.2.3