[FFmpeg-devel] [PATCH 229/281] libopus: convert to new channel layout API

James Almer jamrial at gmail.com
Thu Jan 13 04:05:08 EET 2022


From: Anton Khirnov <anton at khirnov.net>

Signed-off-by: James Almer <jamrial at gmail.com>
---
 libavcodec/libopusdec.c  | 39 +++++++++++++-----------
 libavcodec/libopusenc.c  | 65 ++++++++++++++++++++++------------------
 libavcodec/vorbis.h      |  3 ++
 libavcodec/vorbis_data.c | 18 +++++++++++
 4 files changed, 79 insertions(+), 46 deletions(-)

diff --git a/libavcodec/libopusdec.c b/libavcodec/libopusdec.c
index 86ef715205..abffd5f463 100644
--- a/libavcodec/libopusdec.c
+++ b/libavcodec/libopusdec.c
@@ -50,55 +50,60 @@ struct libopus_context {
 static av_cold int libopus_decode_init(AVCodecContext *avc)
 {
     struct libopus_context *opus = avc->priv_data;
-    int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled;
+    int ret, channel_map = 0, gain_db = 0, nb_streams, nb_coupled, channels;
     uint8_t mapping_arr[8] = { 0, 1 }, *mapping;
 
-    avc->channels = avc->extradata_size >= 10 ? avc->extradata[9] : (avc->channels == 1) ? 1 : 2;
-    if (avc->channels <= 0) {
+    channels = avc->extradata_size >= 10 ? avc->extradata[9] : (channels == 1) ? 1 : 2;
+    if (channels <= 0) {
         av_log(avc, AV_LOG_WARNING,
-               "Invalid number of channels %d, defaulting to stereo\n", avc->channels);
-        avc->channels = 2;
+               "Invalid number of channels %d, defaulting to stereo\n", channels);
+        channels = 2;
     }
 
     avc->sample_rate    = 48000;
     avc->sample_fmt     = avc->request_sample_fmt == AV_SAMPLE_FMT_FLT ?
                           AV_SAMPLE_FMT_FLT : AV_SAMPLE_FMT_S16;
-    avc->channel_layout = avc->channels > 8 ? 0 :
-                          ff_vorbis_channel_layouts[avc->channels - 1];
+    av_channel_layout_uninit(&avc->ch_layout);
+    if (channels > 8) {
+        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 + avc->channels) {
+    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];
-        if (nb_streams + nb_coupled != avc->channels)
+        if (nb_streams + nb_coupled != channels)
             av_log(avc, AV_LOG_WARNING, "Inconsistent channel mapping.\n");
         mapping = avc->extradata + OPUS_HEAD_SIZE + 2;
     } else {
-        if (avc->channels > 2 || channel_map) {
+        if (channels > 2 || channel_map) {
             av_log(avc, AV_LOG_ERROR,
-                   "No channel mapping for %d channels.\n", avc->channels);
+                   "No channel mapping for %d channels.\n", channels);
             return AVERROR(EINVAL);
         }
         nb_streams = 1;
-        nb_coupled = avc->channels > 1;
+        nb_coupled = channels > 1;
         mapping    = mapping_arr;
     }
 
-    if (avc->channels > 2 && avc->channels <= 8) {
-        const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[avc->channels - 1];
+    if (channels > 2 && channels <= 8) {
+        const uint8_t *vorbis_offset = ff_vorbis_channel_layout_offsets[channels - 1];
         int ch;
 
         /* Remap channels from Vorbis order to ffmpeg order */
-        for (ch = 0; ch < avc->channels; ch++)
+        for (ch = 0; ch < channels; ch++)
             mapping_arr[ch] = mapping[vorbis_offset[ch]];
         mapping = mapping_arr;
     }
 
-    opus->dec = opus_multistream_decoder_create(avc->sample_rate, avc->channels,
+    opus->dec = opus_multistream_decoder_create(avc->sample_rate, channels,
                                                 nb_streams, nb_coupled,
                                                 mapping, &ret);
     if (!opus->dec) {
@@ -178,7 +183,7 @@ static int libopus_decode(AVCodecContext *avc, void *data,
 
 #ifndef OPUS_SET_GAIN
     {
-        int i = avc->channels * nb_samples;
+        int i = avc->ch_layout.nb_channels * nb_samples;
         if (avc->sample_fmt == AV_SAMPLE_FMT_FLT) {
             float *pcm = (float *)frame->data[0];
             for (; i > 0; i--, pcm++)
diff --git a/libavcodec/libopusenc.c b/libavcodec/libopusenc.c
index 45b23fcbb5..401a2c17c8 100644
--- a/libavcodec/libopusenc.c
+++ b/libavcodec/libopusenc.c
@@ -91,7 +91,7 @@ static void libopus_write_header(AVCodecContext *avctx, int stream_count,
                                  const uint8_t *channel_mapping)
 {
     uint8_t *p   = avctx->extradata;
-    int channels = avctx->channels;
+    int channels = avctx->ch_layout.nb_channels;
 
     bytestream_put_buffer(&p, "OpusHead", 8);
     bytestream_put_byte(&p, 1); /* Version */
@@ -180,9 +180,9 @@ static int libopus_configure_encoder(AVCodecContext *avctx, OpusMSEncoder *enc,
 
 static int libopus_check_max_channels(AVCodecContext *avctx,
                                       int max_channels) {
-    if (avctx->channels > max_channels) {
+    if (avctx->ch_layout.nb_channels > max_channels) {
         av_log(avctx, AV_LOG_ERROR, "Opus mapping family undefined for %d channels.\n",
-               avctx->channels);
+               avctx->ch_layout.nb_channels);
         return AVERROR(EINVAL);
     }
 
@@ -190,21 +190,26 @@ static int libopus_check_max_channels(AVCodecContext *avctx,
 }
 
 static int libopus_check_vorbis_layout(AVCodecContext *avctx, int mapping_family) {
-    av_assert2(avctx->channels < FF_ARRAY_ELEMS(ff_vorbis_channel_layouts));
+    av_assert2(avctx->ch_layout.nb_channels < FF_ARRAY_ELEMS(ff_vorbis_ch_layouts));
 
-    if (!avctx->channel_layout) {
+    if (avctx->ch_layout.order == AV_CHANNEL_ORDER_UNSPEC) {
         av_log(avctx, AV_LOG_WARNING,
                "No channel layout specified. Opus encoder will use Vorbis "
-               "channel layout for %d channels.\n", avctx->channels);
-    } else if (avctx->channel_layout != ff_vorbis_channel_layouts[avctx->channels - 1]) {
-        char name[32];
-        av_get_channel_layout_string(name, sizeof(name), avctx->channels,
-                                     avctx->channel_layout);
-        av_log(avctx, AV_LOG_ERROR,
-               "Invalid channel layout %s for specified mapping family %d.\n",
-               name, mapping_family);
+               "channel layout for %d channels.\n", avctx->ch_layout.nb_channels);
+    } else {
+        AVChannelLayout chl;
+        av_channel_layout_copy(&chl, &ff_vorbis_ch_layouts[avctx->ch_layout.nb_channels - 1]);
 
-        return AVERROR(EINVAL);
+        if (av_channel_layout_compare(&avctx->ch_layout, &chl)) {
+            char name[32];
+
+            av_channel_layout_describe(&avctx->ch_layout, name, sizeof(name));
+            av_log(avctx, AV_LOG_ERROR,
+                   "Invalid channel layout %s for specified mapping family %d.\n",
+                   name ? name : "", mapping_family);
+
+            return AVERROR(EINVAL);
+        }
     }
 
     return 0;
@@ -238,7 +243,7 @@ static int libopus_validate_layout_and_get_channel_map(
         ret = libopus_check_max_channels(avctx, 8);
         if (ret == 0) {
             ret = libopus_check_vorbis_layout(avctx, mapping_family);
-            channel_map = ff_vorbis_channel_layout_offsets[avctx->channels - 1];
+            channel_map = ff_vorbis_channel_layout_offsets[avctx->ch_layout.nb_channels - 1];
         }
         break;
     case 255:
@@ -261,6 +266,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
     OpusMSEncoder *enc;
     uint8_t libopus_channel_mapping[255];
     int ret = OPUS_OK;
+    int channels = avctx->ch_layout.nb_channels;
     int av_ret;
     int coupled_stream_count, header_size, frame_size;
     int mapping_family;
@@ -348,17 +354,17 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
          * libopus multistream API to avoid surround masking. */
 
         /* Set the mapping family so that the value is correct in the header */
-        mapping_family = avctx->channels > 2 ? 1 : 0;
-        coupled_stream_count = opus_coupled_streams[avctx->channels - 1];
-        opus->stream_count   = avctx->channels - coupled_stream_count;
+        mapping_family = channels > 2 ? 1 : 0;
+        coupled_stream_count = opus_coupled_streams[channels - 1];
+        opus->stream_count   = channels - coupled_stream_count;
         memcpy(libopus_channel_mapping,
-               opus_vorbis_channel_map[avctx->channels - 1],
-               avctx->channels * sizeof(*libopus_channel_mapping));
+               opus_vorbis_channel_map[channels - 1],
+               channels * sizeof(*libopus_channel_mapping));
 
         enc = opus_multistream_encoder_create(
-            avctx->sample_rate, avctx->channels, opus->stream_count,
+            avctx->sample_rate, channels, opus->stream_count,
             coupled_stream_count,
-            libavcodec_libopus_channel_map[avctx->channels - 1],
+            libavcodec_libopus_channel_map[channels - 1],
             opus->opts.application, &ret);
     } else {
         /* Use the newer multistream API. The encoder will set the channel
@@ -366,7 +372,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
          * use surround masking analysis to save bits. */
         mapping_family = opus->opts.mapping_family;
         enc = opus_multistream_surround_encoder_create(
-            avctx->sample_rate, avctx->channels, mapping_family,
+            avctx->sample_rate, channels, mapping_family,
             &opus->stream_count, &coupled_stream_count, libopus_channel_mapping,
             opus->opts.application, &ret);
     }
@@ -385,10 +391,10 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
                "No bit rate set. Defaulting to %"PRId64" bps.\n", avctx->bit_rate);
     }
 
-    if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * avctx->channels) {
+    if (avctx->bit_rate < 500 || avctx->bit_rate > 256000 * channels) {
         av_log(avctx, AV_LOG_ERROR, "The bit rate %"PRId64" bps is unsupported. "
                "Please choose a value between 500 and %d.\n", avctx->bit_rate,
-               256000 * avctx->channels);
+               256000 * channels);
         ret = AVERROR(EINVAL);
         goto fail;
     }
@@ -400,7 +406,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
     }
 
     /* Header includes channel mapping table if and only if mapping family is NOT 0 */
-    header_size = 19 + (mapping_family == 0 ? 0 : 2 + avctx->channels);
+    header_size = 19 + (mapping_family == 0 ? 0 : 2 + channels);
     avctx->extradata = av_malloc(header_size + AV_INPUT_BUFFER_PADDING_SIZE);
     if (!avctx->extradata) {
         av_log(avctx, AV_LOG_ERROR, "Failed to allocate extradata.\n");
@@ -409,7 +415,7 @@ static av_cold int libopus_encode_init(AVCodecContext *avctx)
     }
     avctx->extradata_size = header_size;
 
-    opus->samples = av_calloc(frame_size, avctx->channels *
+    opus->samples = av_calloc(frame_size, channels *
                                av_get_bytes_per_sample(avctx->sample_fmt));
     if (!opus->samples) {
         av_log(avctx, AV_LOG_ERROR, "Failed to allocate samples buffer.\n");
@@ -456,7 +462,8 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
 {
     LibopusEncContext *opus = avctx->priv_data;
     const int bytes_per_sample = av_get_bytes_per_sample(avctx->sample_fmt);
-    const int sample_size      = avctx->channels * bytes_per_sample;
+    const int channels         = avctx->ch_layout.nb_channels;
+    const int sample_size      = channels * bytes_per_sample;
     uint8_t *audio;
     int ret;
     int discard_padding;
@@ -469,7 +476,7 @@ static int libopus_encode(AVCodecContext *avctx, AVPacket *avpkt,
             audio = opus->samples;
             libopus_copy_samples_with_channel_map(
                 audio, frame->data[0], opus->encoder_channel_map,
-                avctx->channels, frame->nb_samples, bytes_per_sample);
+                channels, frame->nb_samples, bytes_per_sample);
         } else if (frame->nb_samples < opus->opts.packet_size) {
             audio = opus->samples;
             memcpy(audio, frame->data[0], frame->nb_samples * sample_size);
diff --git a/libavcodec/vorbis.h b/libavcodec/vorbis.h
index 69ddbd2982..f80187feee 100644
--- a/libavcodec/vorbis.h
+++ b/libavcodec/vorbis.h
@@ -26,7 +26,10 @@
 extern const float ff_vorbis_floor1_inverse_db_table[256];
 extern const float * const ff_vorbis_vwin[8];
 extern const uint8_t ff_vorbis_channel_layout_offsets[8][8];
+#if FF_API_OLD_CHANNEL_LAYOUT
 extern const uint64_t ff_vorbis_channel_layouts[9];
+#endif
+extern const AVChannelLayout ff_vorbis_ch_layouts[9];
 
 typedef struct vorbis_floor1_entry {
     uint16_t x;
diff --git a/libavcodec/vorbis_data.c b/libavcodec/vorbis_data.c
index fd7e291de2..4f4ea03f15 100644
--- a/libavcodec/vorbis_data.c
+++ b/libavcodec/vorbis_data.c
@@ -34,6 +34,7 @@ const uint8_t ff_vorbis_channel_layout_offsets[8][8] = {
     { 0, 2, 1, 7, 5, 6, 3, 4 },
 };
 
+#if FF_API_OLD_CHANNEL_LAYOUT
 const uint64_t ff_vorbis_channel_layouts[9] = {
     AV_CH_LAYOUT_MONO,
     AV_CH_LAYOUT_STEREO,
@@ -45,6 +46,23 @@ const uint64_t ff_vorbis_channel_layouts[9] = {
     AV_CH_LAYOUT_7POINT1,
     0
 };
+#endif
+
+const AVChannelLayout ff_vorbis_ch_layouts[9] = {
+    AV_CHANNEL_LAYOUT_MONO,
+    AV_CHANNEL_LAYOUT_STEREO,
+    AV_CHANNEL_LAYOUT_SURROUND,
+    AV_CHANNEL_LAYOUT_QUAD,
+    AV_CHANNEL_LAYOUT_5POINT0_BACK,
+    AV_CHANNEL_LAYOUT_5POINT1_BACK,
+    {
+        .nb_channels = 7,
+        .order       = AV_CHANNEL_ORDER_NATIVE,
+        .u.mask      = AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER,
+    },
+    AV_CHANNEL_LAYOUT_7POINT1,
+    { 0 }
+};
 
 DECLARE_ALIGNED(16, static const float, vwin64)[32] = {
     0.0009460463F, 0.0085006468F, 0.0235352254F, 0.0458950567F,
-- 
2.34.1



More information about the ffmpeg-devel mailing list