PR #23160 opened by chris-hld URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23160 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/23160.patch
>From 7d29d2777c92c2c6f55c7af234a90754d8b3a50d Mon Sep 17 00:00:00 2001 From: chrishold <[email protected]> Date: Tue, 19 May 2026 19:07:58 +0100 Subject: [PATCH] Handle CMF2, CMF3, and CMF255 with libopus decoder --- libavcodec/libopusdec.c | 37 ++++++++++++++++++++++++++++++------- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c index fc2119baff..6a992c2d70 100644 --- a/libavcodec/libopusdec.c +++ b/libavcodec/libopusdec.c @@ -65,19 +65,39 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) avc->sample_rate = 48000; avc->sample_fmt = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ? AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16; + if (avc->extradata_size >= OPUS_HEAD_SIZE) { + opus->pre_skip = AV_RL16(avc->extradata + 10); + gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16); + channel_map = AV_RL8 (avc->extradata + 18); + } + av_channel_layout_uninit(&avc->ch_layout); - if (channels > 8) { + if (channel_map == 2 || channel_map == 3) { + /* RFC 7845: channel mapping families 2 and 3 are SN3D Ambisonics in + * ACN order. Family 3 appends a stereo non-diegetic pair (FL+FR) + * after the (order+1)^2 ambisonic channels. */ + int nondiegetic_channels = (channel_map == 3) ? 2 : 0; + int ambi_channels = channels - nondiegetic_channels; + int order = 0; + while ((order + 1) * (order + 1) < ambi_channels) + order++; + if (ambi_channels < 1 || (order + 1) * (order + 1) != ambi_channels) { + avc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; + avc->ch_layout.nb_channels = channels; + } else { + avc->ch_layout.order = AV_CHANNEL_ORDER_AMBISONIC; + avc->ch_layout.nb_channels = channels; + avc->ch_layout.u.mask = nondiegetic_channels ? AV_CH_LAYOUT_STEREO : 0; + } + } else if (channels > 8 || channel_map > 1) { + /* Channel mapping family != 1 (e.g. family 255) has discrete or + * undefined channel order. Do not impose a native (Vorbis) layout. */ avc->ch_layout.order = AV_CHANNEL_ORDER_UNSPEC; avc->ch_layout.nb_channels = channels; } else { av_channel_layout_copy(&avc->ch_layout, &ff_vorbis_ch_layouts[channels - 1]); } - if (avc->extradata_size >= OPUS_HEAD_SIZE) { - opus->pre_skip = AV_RL16(avc->extradata + 10); - gain_db = sign_extend(AV_RL16(avc->extradata + 16), 16); - channel_map = AV_RL8 (avc->extradata + 18); - } if (avc->extradata_size >= OPUS_HEAD_SIZE + 2 + channels) { nb_streams = avc->extradata[OPUS_HEAD_SIZE + 0]; nb_coupled = avc->extradata[OPUS_HEAD_SIZE + 1]; @@ -95,7 +115,10 @@ static av_cold int libopus_decode_init(AVCodecContext *avc) mapping = mapping_arr; } - if (channels > 2 && channels <= 8) { + /* Only mapping family 1 uses Vorbis channel ordering. For families + * 0/2/3/255 the mapping array is in identity/discrete order and must + * be passed through unchanged. */ + if (channel_map == 1 && channels > 2 && channels <= 8) { const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[channels - 1]; int ch; -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
