This is an automated email from the git hooks/post-receive script.

Git pushed a commit to branch master
in repository ffmpeg.

commit ed923a7a897763471c65b507cea2ef661e1e1646
Author:     James Almer <[email protected]>
AuthorDate: Thu Aug 20 21:27:10 2026 -0300
Commit:     James Almer <[email protected]>
CommitDate: Sun Aug 23 13:35:21 2026 -0300

    avcodec/aacenc: add support for writing PCE layouts with height channels
    
    Fixes ticket #24218
    
    Signed-off-by: James Almer <[email protected]>
---
 libavcodec/aacenc.c | 145 +++++++++++++++++++++++++++++++++++++++++++++++++++-
 libavcodec/aacenc.h |   2 +
 2 files changed, 145 insertions(+), 2 deletions(-)

diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c
index d2b67d6b20..7e263a64ed 100644
--- a/libavcodec/aacenc.c
+++ b/libavcodec/aacenc.c
@@ -31,6 +31,7 @@
 #include <float.h>
 
 #include "libavutil/channel_layout.h"
+#include "libavutil/crc.h"
 #include "libavutil/libm.h"
 #include "libavutil/float_dsp.h"
 #include "libavutil/mem.h"
@@ -81,6 +82,9 @@
  *     which at this time requires that indices fully cover some range starting
  *     from 0 (SCE.1 SCE.0 is OK but not SCE.0 SCE.15).
  *
+ * - height: 0 for a base layer element, 1 for a top layer element, 2 for a 
bottom
+ *           layer element.
+ *
  * - config_map: total number of elements and their types. Beware, the way the
  *               types are ordered impacts the final channel ordering.
  *
@@ -296,6 +300,110 @@ static const AACPCEInfo aac_pce_configs[] = {
         .config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE },
         .reorder_map = { 2, 0, 1, 6, 7, 3, 4, 5 },
     },
+    {
+        .layout = AV_CHANNEL_LAYOUT_5POINT1POINT2,
+        .num_ele = { 3, 0, 1, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
+        .index = { { 0, 0, 2 }, { 0 }, { 1 }, { 0 }, },
+        .height = { { 0, 0, 1 }, { 0 }, { 0 } },
+        .config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE, TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 3, 6, 7 },
+    },
+    {
+        // ITU-R BS.2051-3 Sound System C
+        .layout = AV_CHANNEL_LAYOUT_5POINT1POINT2_BACK,
+        .num_ele = { 3, 0, 1, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1 }, },
+        .index = { { 0, 0, 2 }, { 0 }, { 1 }, { 0 }, },
+        .height = { { 0, 0, 1 }, { 0 }, { 0 } },
+        .config_map = { 5, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE, TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 3, 6, 7 },
+    },
+    {
+        .layout = AV_CHANNEL_LAYOUT_5POINT1POINT4,
+        .num_ele = { 3, 0, 2, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1, 1 }, },
+        .index = { { 0, 0, 2 }, { 0 }, { 1, 3 }, { 0 }, },
+        .height = { { 0, 0, 1 }, { 0 }, { 0, 1 } },
+        .config_map = { 6, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE, TYPE_CPE, 
TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 3, 6, 7, 8, 9 },
+    },
+        // ITU-R BS.2051-3 Sound System D
+    {
+        .layout = {
+            .nb_channels = 10,
+            .order       = AV_CHANNEL_ORDER_NATIVE,
+            .u.mask      = AV_CH_LAYOUT_5POINT1POINT2_BACK | 
AV_CH_TOP_BACK_LEFT | AV_CH_TOP_BACK_RIGHT,
+        },
+        .num_ele = { 3, 0, 2, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1, 1 }, },
+        .index = { { 0, 0, 2 }, { 0 }, { 1, 3 }, { 0 }, },
+        .height = { { 0, 0, 1 }, { 0 }, { 0, 1 } },
+        .config_map = { 6, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE, TYPE_CPE, 
TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 3, 6, 7, 8, 9 },
+    },
+    {
+        // ITU-R BS.2051-3 Sound System E
+        .layout = {
+            .nb_channels = 11,
+            .order       = AV_CHANNEL_ORDER_NATIVE,
+            .u.mask      = AV_CH_LAYOUT_5POINT1POINT4 | 
AV_CH_BOTTOM_FRONT_CENTER,
+        },
+        .num_ele = { 4, 0, 2, 1 },
+        .pairing = { { 0, 1, 1, 0 }, { 0 }, { 1, 1 }, },
+        .index = { { 0, 0, 2, 1 }, { 0 }, { 1, 3 }, { 0 }, },
+        .height = { { 0, 0, 1, 2 }, { 0 }, { 0, 1 } },
+        .config_map = { 7, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_LFE, TYPE_CPE, 
TYPE_CPE, TYPE_SCE },
+        .reorder_map = { 2, 0, 1, 4, 5, 3, 6, 7, 8, 9, 10 },
+    },
+    {
+        .layout = AV_CHANNEL_LAYOUT_7POINT1POINT2,
+        .num_ele = { 3, 0, 2, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1, 1 }, },
+        .index = { { 0, 0, 3 }, { 0 }, { 2, 1 }, { 0 } },
+        .height = { { 0, 0, 1 }, { 0 }, { 0, 0 } },
+        .config_map = { 6, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE, 
TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 6, 7, 3, 8, 9 },
+    },
+    {
+        // ITU-R BS.2051-3 Sound System F
+        .layout = AV_CHANNEL_LAYOUT_7POINT2POINT3,
+        .num_ele = { 3, 0, 3, 2 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1, 1, 0 }, },
+        .index = { { 0, 0, 3 }, { 0 }, { 2, 1, 1 }, { 0, 1 } },
+        .height = { { 0, 0, 1 }, { 0 }, { 0, 0, 1 } },
+        .config_map = { 8, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE, 
TYPE_LFE, TYPE_CPE, TYPE_SCE },
+        .reorder_map = { 2, 0, 1, 4, 5, 6, 7, 3, 11, 8, 9, 10 },
+    },
+    {
+        // ITU-R BS.2051-3 Sound System J
+        .layout = AV_CHANNEL_LAYOUT_7POINT1POINT4,
+        .num_ele = { 3, 0, 3, 1 },
+        .pairing = { { 0, 1, 1 }, { 0 }, { 1, 1, 1 }, },
+        .index = { { 0, 0, 3 }, { 0 }, { 2, 1, 4 }, { 0 } },
+        .height = { { 0, 0, 1 }, { 0 }, { 0, 0, 1 } },
+        .config_map = { 7, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_LFE, 
TYPE_CPE, TYPE_CPE },
+        .reorder_map = { 2, 0, 1, 4, 5, 6, 7, 3, 8, 9, 10, 11 },
+    },
+    {
+        // ITU-R BS.2051-3 Sound System G
+        .layout = AV_CHANNEL_LAYOUT_9POINT1POINT4,
+        .num_ele = { 4, 0, 3, 1 },
+        .pairing = { { 0, 1, 1, 1 }, { 0 }, { 1, 1, 1 }, },
+        .index = { { 0, 0, 1, 4 }, { 0 }, { 2, 3, 5 }, { 0 } },
+        .height = { { 0, 0, 0, 1 }, { 0 }, { 0, 0, 1 } },
+        .config_map = { 8, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_CPE, 
TYPE_LFE, TYPE_CPE, TYPE_CPE },
+        .reorder_map = { 2, 6, 7, 0, 1, 8, 9, 4, 5, 3, 10, 11, 12, 13 },
+    },
+    {
+        .layout = AV_CHANNEL_LAYOUT_9POINT1POINT6,
+        .num_ele = { 4, 1, 3, 1 },
+        .pairing = { { 0, 1, 1, 1 }, { 1 }, { 1, 1, 1 }, },
+        .index = { { 0, 0, 1, 4 }, { 5 }, { 2, 3, 6 }, { 0 } },
+        .height = { { 0, 0, 0, 1 }, { 1 }, { 0, 0, 1 } },
+        .config_map = { 9, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_CPE, 
TYPE_LFE, TYPE_CPE, TYPE_CPE, TYPE_CPE },
+        .reorder_map = { 2, 6, 7, 0, 1, 8, 9, 4, 5, 3, 10, 11, 14, 15, 12, 13 
},
+    },
 };
 
 static void put_pce(PutBitContext *pb, AVCodecContext *avctx)
@@ -331,8 +439,28 @@ static void put_pce(PutBitContext *pb, AVCodecContext 
*avctx)
     }
 
     align_put_bits(pb);
-    put_bits(pb, 8, strlen(aux_data));
-    ff_put_string(pb, aux_data, 0);
+    if (s->needs_height_ext) {
+        const AVCRC *crc_ctx = av_crc_get_table(AV_CRC_8_ATM);
+        PutBitContext height_pb;
+        uint8_t buf[16];
+        int bits = 8 + pce->num_ele[0] * 2 + pce->num_ele[1] * 2 + 
pce->num_ele[2] * 2;
+        int bytes = (bits + 7) / 8;
+
+        init_put_bits(&height_pb, buf, bytes);
+        put_bits(&height_pb, 8, 0xAC);
+        for (i = 0; i < 3; i++)
+            for (j = 0; j < pce->num_ele[i]; j++)
+                put_bits(&height_pb, 2, pce->height[i][j]);
+        flush_put_bits(&height_pb);
+
+        put_bits(pb, 8, bytes + 1);
+        ff_copy_bits(pb, buf, bits);
+        align_put_bits(pb);
+        put_bits(pb, 8, av_crc(crc_ctx, 0xFF, buf, bytes));
+    } else {
+        put_bits(pb, 8, strlen(aux_data));
+        ff_put_string(pb, aux_data, 0);
+    }
 }
 
 /**
@@ -1560,6 +1688,18 @@ static av_cold int alloc_buffers(AVCodecContext *avctx, 
AACEncContext *s)
     return 0;
 }
 
+static av_cold int check_height_ext(AVCodecContext *avctx, AACEncContext *s)
+{
+    for (int i = 0; i < avctx->ch_layout.nb_channels; i++) {
+        enum AVChannel ch = 
av_channel_layout_channel_from_index(&avctx->ch_layout, i);
+        if (ch >= AV_CHAN_TOP_FRONT_LEFT && ch <= AV_CHAN_TOP_BACK_RIGHT)
+            return 1;
+        // Layouts with TOP_SIDE channels also include the above.
+    }
+
+    return 0;
+}
+
 static av_cold int aac_encode_init(AVCodecContext *avctx)
 {
     AACEncContext *s = avctx->priv_data;
@@ -1600,6 +1740,7 @@ static av_cold int aac_encode_init(AVCodecContext *avctx)
         s->pce = aac_pce_configs[i];
         s->reorder_map = s->pce.reorder_map;
         s->chan_map = s->pce.config_map;
+        s->needs_height_ext = check_height_ext(avctx, s);
         chcfg = 0;
     } else {
         s->reorder_map = aac_chan_maps[chcfg - 1];
diff --git a/libavcodec/aacenc.h b/libavcodec/aacenc.h
index ec04465a6d..1ad2b7bc96 100644
--- a/libavcodec/aacenc.h
+++ b/libavcodec/aacenc.h
@@ -248,6 +248,7 @@ typedef struct AACPCEInfo {
     uint8_t num_ele[4];                          ///< front, side, back, lfe
     uint8_t pairing[3][8];                       ///< front, side, back
     uint8_t index[4][8];                         ///< front, side, back, lfe
+    uint8_t height[3][8];                        ///< front, side, back
     uint8_t config_map[16];                      ///< configs the encoder's 
channel specific settings
     uint8_t reorder_map[16];                     ///< maps channels from lavc 
to aac order
 } AACPCEInfo;
@@ -269,6 +270,7 @@ typedef struct AACEncContext {
 
     int profile;                                 ///< copied from avctx
     int needs_pce;                               ///< flag for non-standard 
layout
+    int needs_height_ext;                        ///< flag for PCE height 
extension
     LPCContext lpc;                              ///< used by TNS
     int samplerate_index;                        ///< MPEG-4 samplerate index
     int channels;                                ///< channel count

-- 
To stop receiving notification emails like this one, please contact
[email protected].
_______________________________________________
ffmpeg-cvslog mailing list -- [email protected]
To unsubscribe send an email to [email protected]

Reply via email to