PR #24225 opened by James Almer (jamrial) URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24225 Patch URL: https://code.ffmpeg.org/FFmpeg/FFmpeg/pulls/24225.patch
Fixes ticket #24218 >From 18e0b99acbf575ce2313fedd5d6a8eb7a26105a2 Mon Sep 17 00:00:00 2001 From: James Almer <[email protected]> Date: Thu, 20 Aug 2026 21:27:10 -0300 Subject: [PATCH] avcodec/aacenc: add support for writing PCE layouts with height channels Fixes ticket #24218 Signed-off-by: James Almer <[email protected]> --- libavcodec/aacenc.c | 102 +++++++++++++++++++++++++++++++++++++++++++- libavcodec/aacenc.h | 2 + 2 files changed, 102 insertions(+), 2 deletions(-) diff --git a/libavcodec/aacenc.c b/libavcodec/aacenc.c index d2b67d6b20..956e589836 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" @@ -296,6 +297,70 @@ 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_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_BACK, + .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 }, + }, + { + .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 }, + }, + { + .layout = AV_CHANNEL_LAYOUT_7POINT1POINT4_BACK, + .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 }, + }, + { + .layout = AV_CHANNEL_LAYOUT_9POINT1POINT4_BACK, + .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 }, + }, + { /* Meant for order 2/mixed ambisonics */ + .layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 9, + .u.mask = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER }, + .num_ele = { 2, 1, 3, 0 }, + .pairing = { { 0, 1 }, { 0 }, { 1, 1, 0 }, }, + .index = { { 0, 0 }, { 2 }, { 1, 2, 1 }, }, + .height = { { 0, 0, 0 }, { 1 }, { 0, 0, 0 } }, + .config_map = { 6, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_SCE }, + .reorder_map = { 2, 0, 1, 6, 7, 3, 4, 5, 8 }, + }, }; static void put_pce(PutBitContext *pb, AVCodecContext *avctx) @@ -331,8 +396,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 +1645,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 +1697,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 -- 2.52.0 _______________________________________________ ffmpeg-devel mailing list -- [email protected] To unsubscribe send an email to [email protected]
