This is an automated email from the git hooks/post-receive script. Git pushed a commit to branch master in repository ffmpeg.
commit 71b59582e2aae5193693138ddcb3703802d4bc8c Author: Lynne <[email protected]> AuthorDate: Fri Apr 17 18:13:40 2026 +0200 Commit: Lynne <[email protected]> CommitDate: Wed Jun 10 18:04:22 2026 +0900 aacdec_usac: implement basic DRC parameter decoding --- libavcodec/aac/aacdec.h | 13 +++++ libavcodec/aac/aacdec_usac.c | 136 +++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 145 insertions(+), 4 deletions(-) diff --git a/libavcodec/aac/aacdec.h b/libavcodec/aac/aacdec.h index c67246e287..cf55bbe6c0 100644 --- a/libavcodec/aac/aacdec.h +++ b/libavcodec/aac/aacdec.h @@ -98,6 +98,12 @@ enum AACUSACLoudnessExt { UNIDRCLOUDEXT_EQ = 0x1, }; +enum AACUSACDRCExt { + UNIDRCCONFEXT_TERM = 0x0, + UNIDRCCONFEXT_PARAM_DRC = 0x1, + UNIDRCCONFEXT_V1 = 0x2, +}; + // Supposed to be equal to AAC_RENAME() in case of USE_FIXED. #define RENAME_FIXED(name) name ## _fixed @@ -377,6 +383,13 @@ typedef struct AACUsacElemConfig { uint32_t pl_data_offset; uint8_t *pl_buf; } ext; + + struct { + struct { + int lower; + int upper; + } loudness; + } drc; } AACUsacElemConfig; typedef struct AACUSACConfig { diff --git a/libavcodec/aac/aacdec_usac.c b/libavcodec/aac/aacdec_usac.c index 4041e8892c..3de82e2266 100644 --- a/libavcodec/aac/aacdec_usac.c +++ b/libavcodec/aac/aacdec_usac.c @@ -49,7 +49,7 @@ static inline uint32_t get_escaped_value(GetBitContext *gb, int nb1, int nb2, in return val; } -/* ISO/IEC 23003-3, Table 74 — bsOutputChannelPos */ +/* ISO/IEC 23003-3, Table 74: bsOutputChannelPos */ static const enum AVChannel usac_ch_pos_to_av[64] = { [0] = AV_CHAN_FRONT_LEFT, [1] = AV_CHAN_FRONT_RIGHT, @@ -227,7 +227,7 @@ static int decode_usac_element_pair(AACDecContext *ac, e->mps.phase_coding = get_bits1(gb); /* bsPhaseCoding */ e->mps.otts_bands_phase_present = get_bits1(gb); - int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109 — Default value of bsOttBandsPhase + int otts_bands_phase = ((int[]){0,10,10,7,5,3,2,2})[e->mps.freq_res]; // Table 109: Default value of bsOttBandsPhase if (e->mps.otts_bands_phase_present) { /* bsOttBandsPhasePresent */ otts_bands_phase = get_bits(gb, 5); /* bsOttBandsPhase */ if (otts_bands_phase > numBands) @@ -253,6 +253,114 @@ static int decode_usac_element_pair(AACDecContext *ac, return 0; } +/* ISO/IEC 23003-4, Table 62: channelLayout() */ +static int decode_drc_channel_layout(GetBitContext *gb) +{ + int base_channel_count = get_bits(gb, 7); /* baseChannelCount */ + if (get_bits1(gb)) { /* layoutSignallingPresent */ + if (get_bits(gb, 8) == 0) /* definedLayout == 0 */ + for (int i = 0; i < base_channel_count; i++) + skip_bits(gb, 7); /* speakerPosition */ + } + return base_channel_count; +} + +/* ISO/IEC 23003-4, Table 63: downmixInstructions() */ +static void skip_drc_downmix_instructions(GetBitContext *gb, int base_channel_count) +{ + int target_channel_count; + skip_bits(gb, 7); /* downmixId */ + target_channel_count = get_bits(gb, 7); /* targetChannelCount */ + skip_bits(gb, 8); /* targetLayout */ + if (get_bits1(gb)) /* downmixCoefficientsPresent */ + skip_bits_long(gb, 4 * target_channel_count * base_channel_count); +} + +/* ISO/IEC 23003-4, Table 70: drcInstructionsBasic(), common with the + * uniDrc variant up to the loudness-target fields. */ +static void decode_drc_instructions_basic(AACUsacElemConfig *e, GetBitContext *gb) +{ + int set_effects; + + skip_bits(gb, 6); /* drcSetId */ + skip_bits(gb, 4); /* drcLocation */ + skip_bits(gb, 7); /* downmixId */ + if (get_bits1(gb)) { /* additionalDownmixIdPresent */ + int add_downmix_cnt = get_bits(gb, 3); /* additionalDownmixIdCount */ + for (int j = 0; j < add_downmix_cnt; j++) + skip_bits(gb, 7); /* additionalDownmixId */ + } + + set_effects = get_bits(gb, 16); /* drcSetEffect */ + if ((set_effects & (3 << 10)) == 0) { + if (get_bits1(gb)) /* limiterPeakTargetPresent */ + skip_bits(gb, 8); /* bsLimiterPeakTarget */ + } + + if (get_bits1(gb)) { /* drcSetTargetLoudnessPresent */ + e->drc.loudness.upper = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueUpper */ + if (get_bits1(gb)) /* drcSetTargetLoudnessValueLowerPresent */ + e->drc.loudness.lower = get_bits(gb, 6); /* bsDrcSetTargetLoudnessValueLower */ + } +} + +/* ISO/IEC 23003-4, Table 57: uniDrcConfig() */ +static int decode_drc_config(AACDecContext *ac, AACUsacElemConfig *e, + GetBitContext *gb) +{ + int nb_downmix_instr, nb_coeff_basic = 0, nb_instr_basic = 0; + int nb_coeff_uni, nb_instr_uni; + int base_channel_count; + + e->drc.loudness.lower = -1; + e->drc.loudness.upper = -1; + + if (get_bits1(gb)) /* sampleRatePresent */ + skip_bits(gb, 18); /* bsSampleRate */ + + nb_downmix_instr = get_bits(gb, 7); /* downmixInstructionsCount */ + + if (get_bits1(gb)) { /* drcDescriptionBasicPresent */ + nb_coeff_basic = get_bits(gb, 3); /* drcCoefficientsBasicCount */ + nb_instr_basic = get_bits(gb, 4); /* drcInstructionsBasicCount */ + } + + nb_coeff_uni = get_bits(gb, 3); /* drcCoefficientsUniDrcCount */ + nb_instr_uni = get_bits(gb, 6); /* drcInstructionsUniDrcCount */ + + if (nb_coeff_uni || nb_instr_uni) { + avpriv_report_missing_feature(ac->avctx, + "AAC USAC uniDrc DRC processing"); + return AVERROR_PATCHWELCOME; + } + + base_channel_count = decode_drc_channel_layout(gb); + + for (int i = 0; i < nb_downmix_instr; i++) + skip_drc_downmix_instructions(gb, base_channel_count); + + for (int i = 0; i < nb_coeff_basic; i++) + skip_bits(gb, 4 + 7); /* drcLocation, drcCharacteristic */ + + for (int i = 0; i < nb_instr_basic; i++) + decode_drc_instructions_basic(e, gb); + + if (get_bits1(gb)) { /* uniDrcConfigExtPresent */ + enum AACUSACDRCExt type; + while ((type = get_bits(gb, 4)) != UNIDRCCONFEXT_TERM) { + uint8_t size_bits = get_bits(gb, 4) + 4; /* bitSizeLen */ + uint32_t bit_size = get_bits_long(gb, size_bits) + 1; /* extBitSize */ + switch (type) { + default: + skip_bits_long(gb, bit_size); + break; + } + } + } + + return 0; +} + static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e, GetBitContext *gb) { @@ -276,9 +384,25 @@ static int decode_usac_extension(AACDecContext *ac, AACUsacElemConfig *e, break; case ID_EXT_ELE_SAOC: break; - case ID_EXT_ELE_UNI_DRC: - break; #endif + case ID_EXT_ELE_UNI_DRC: { + int start = get_bits_count(gb); + int ret = decode_drc_config(ac, e, gb); + int skip = 8*ext_config_len - (get_bits_count(gb) - start); + if (ret == AVERROR_PATCHWELCOME) { + /* Unsupported uniDrcConfig(): ignore the DRC metadata and treat + * the element as fill so the stream stays decodable. */ + e->ext.type = ID_EXT_ELE_FILL; + ret = 0; + } + if (ret < 0) + return ret; + if (skip < 0) + return AVERROR_INVALIDDATA; + /* The config is byte-padded to usacExtElementConfigLength */ + skip_bits_long(gb, skip); + break; + } case ID_EXT_ELE_FILL: break; /* This is what the spec does */ case ID_EXT_ELE_AUDIOPREROLL: @@ -1828,6 +1952,10 @@ static int parse_ext_ele(AACDecContext *ac, AACUsacElemConfig *e, case ID_EXT_ELE_AUDIOPREROLL: ret = parse_audio_preroll(ac, gb2); break; + case ID_EXT_ELE_UNI_DRC: + /* uniDrcGain() payload: DRC is not applied, just consume the + * bits via skip_bits_long below. */ + break; default: /* This should never happen */ av_assert0(0); _______________________________________________ ffmpeg-cvslog mailing list -- [email protected] To unsubscribe send an email to [email protected]
