From 398c0b2936d1af7dc31bb842f31d95c06cca0e45 Mon Sep 17 00:00:00 2001 From: "yilun.zhang" Date: Tue, 4 Aug 2026 10:01:58 +0800 Subject: [PATCH 1/2] Fix some bugs and improve memory safety across decoder Signed-off-by: yilun.zhang --- code/dep_codecs/CMakeLists.txt | 6 +- code/src/iamf_dec/audio_effect_peak_limiter.c | 6 +- code/src/iamf_dec/audio_effect_peak_limiter.h | 9 +- .../codec/aac/aac_multistream_decoder.c | 2 +- .../src/iamf_dec/codec/aac/iamf_aac_decoder.c | 9 +- .../codec/flac/flac_multistream_decoder.c | 26 ++- .../iamf_dec/codec/flac/iamf_flac_decoder.c | 12 +- .../iamf_dec/codec/opus/iamf_opus_decoder.c | 17 +- .../codec/opus/opus_multistream2_decoder.c | 11 +- .../src/iamf_dec/codec/pcm/iamf_pcm_decoder.c | 4 +- code/src/iamf_dec/common/cbuffer.h | 5 - code/src/iamf_dec/demixer.c | 14 +- code/src/iamf_dec/iamf_audio_block.c | 44 ++-- code/src/iamf_dec/iamf_core_decoder.c | 21 +- code/src/iamf_dec/iamf_database.c | 210 +++++++++++++----- code/src/iamf_dec/iamf_database.h | 9 +- code/src/iamf_dec/iamf_decoder.c | 179 +++++++++------ code/src/iamf_dec/iamf_layout.c | 4 +- code/src/iamf_dec/iamf_post_processor.c | 5 +- code/src/iamf_dec/iamf_presentation.c | 25 ++- code/src/iamf_dec/iamf_private_definitions.h | 3 +- code/src/iamf_dec/iamf_renderer.c | 52 ++--- code/src/iamf_dec/iamf_string.c | 14 +- code/src/iamf_dec/iamf_string.h | 1 - code/src/iamf_dec/iamf_synchronizer.c | 15 +- code/src/iamf_dec/iamf_utils.c | 20 +- code/src/iamf_dec/iamf_utils.h | 14 +- code/src/iamf_dec/obu/animated_parameter.c | 2 - code/src/iamf_dec/obu/animated_parameter.h | 2 +- code/src/iamf_dec/obu/audio_element_obu.c | 21 +- code/src/iamf_dec/obu/codec_config_obu.c | 2 +- .../src/iamf_dec/obu/ia_sequence_header_obu.c | 6 +- code/src/iamf_dec/obu/iamf_obu.c | 2 +- code/src/iamf_dec/obu/metadata_obu.c | 2 +- code/src/iamf_dec/obu/mix_presentation_obu.c | 8 +- code/src/iamf_dec/obu/parameter_base.c | 5 +- code/src/iamf_dec/obu/parameter_block_obu.c | 2 +- .../src/iamf_dec/obu/temporal_delimiter_obu.c | 1 - 38 files changed, 470 insertions(+), 320 deletions(-) diff --git a/code/dep_codecs/CMakeLists.txt b/code/dep_codecs/CMakeLists.txt index fd725085..a46370f9 100755 --- a/code/dep_codecs/CMakeLists.txt +++ b/code/dep_codecs/CMakeLists.txt @@ -7,7 +7,7 @@ include(ExternalProject) ExternalProject_Add( dep_opus URL https://downloads.xiph.org/releases/opus/opus-1.4.tar.gz - CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} -DCMAKE_POLICY_VERSION_MINIMUM=3.5 ) # Fetch fdk-aac(2.0.3) library @@ -17,7 +17,7 @@ ExternalProject_Add( GIT_REPOSITORY https://github.com/mstorsjo/fdk-aac.git GIT_TAG 716f4394641d53f0d79c9ddac3fa93b03a49f278 PATCH_COMMAND ${CMAKE_COMMAND} -E make_directory /libSBRdec/include/log && ${CMAKE_COMMAND} -E echo "void android_errorWriteLog(int i, const char *string){}" > /libSBRdec/include/log/log.h - CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} ) # Fetch flac library @@ -25,5 +25,5 @@ include(ExternalProject) ExternalProject_Add( dep_flac URL https://downloads.xiph.org/releases/flac/flac-1.4.2.tar.xz - CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DWITH_OGG=OFF -DBUILD_CXXLIBS=OFF -DINSTALL_MANPAGES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} + CMAKE_ARGS -DBUILD_SHARED_LIBS=OFF -DWITH_OGG=OFF -DBUILD_CXXLIBS=OFF -DINSTALL_MANPAGES=OFF -DCMAKE_POSITION_INDEPENDENT_CODE=ON -DCMAKE_BUILD_TYPE=Release -DCMAKE_INSTALL_PREFIX=${DEP_CODECS_DIR} -DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE} ) diff --git a/code/src/iamf_dec/audio_effect_peak_limiter.c b/code/src/iamf_dec/audio_effect_peak_limiter.c index a13107e3..b106d9fb 100755 --- a/code/src/iamf_dec/audio_effect_peak_limiter.c +++ b/code/src/iamf_dec/audio_effect_peak_limiter.c @@ -50,8 +50,9 @@ void audio_effect_peak_limiter_uninit(AudioEffectPeakLimiter* ths) { } void audio_effect_peak_limiter_destroy(AudioEffectPeakLimiter* ths) { + if (!ths) return; audio_effect_peak_limiter_uninit(ths); - if (ths) free(ths); + free(ths); } // threshold_db: Peak threshold in dB @@ -90,7 +91,6 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, float peak; float channel_peak = 0.0f; float gain; - int k; float peakMax = 0.0f; float* audioBlock = outblock; float out; @@ -103,7 +103,7 @@ int audio_effect_peak_limiter_process_block(AudioEffectPeakLimiter* ths, #define DB_IDX(i) ((i) % ths->delayBufferSize) - for (k = 0; k < frame_size; k++) { + for (int k = 0; k < frame_size; k++) { peak = 0.0f; idx = k + ths->entryIndex; #ifndef OLD_CODE diff --git a/code/src/iamf_dec/audio_effect_peak_limiter.h b/code/src/iamf_dec/audio_effect_peak_limiter.h index fd15260f..e469b3fc 100755 --- a/code/src/iamf_dec/audio_effect_peak_limiter.h +++ b/code/src/iamf_dec/audio_effect_peak_limiter.h @@ -30,9 +30,6 @@ This software module is out of scope and not part of the IAMF Final Deliverable. #define USE_TRUEPEAK 0 -#define MAX_OUTPUT_CHANNELS 24 -#define MAX_DELAYSIZE 4096 - #if USE_TRUEPEAK #include "audio_true_peak_meter.h" #endif @@ -76,15 +73,15 @@ AudioEffectPeakLimiter* audio_effect_peak_limiter_create(void); /** * @brief Initialize the peak limiter. * @param [in] ths : the peak limiter handle - * @param [in] threashold_db : peak threshold in dB + * @param [in] threshold_db : peak threshold in dB * @param [in] sample_rate : sample rate of audio signal * @param [in] num_channels : number of channels in frame * @param [in] atk_sec : attack duration in seconds - * @param [in] atk_sec : release duration in seconds + * @param [in] rel_sec : release duration in seconds * @param [in] delay_size : number of samples in delay buffer */ void audio_effect_peak_limiter_init(AudioEffectPeakLimiter* ths, - float threashold_db, int sample_rate, + float threshold_db, int sample_rate, int num_channels, float atk_sec, float rel_sec, int delay_size); diff --git a/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c index 8f6b0c24..b5dad549 100755 --- a/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c +++ b/code/src/iamf_dec/codec/aac/aac_multistream_decoder.c @@ -49,7 +49,7 @@ struct AacMsDecoder { }; typedef void (*func_aac_copy_channel_out_t)(void *dst, const void *src, - int frame_size, int channes); + int frame_size, int channels); void aac_copy_channel_out_short_plane(void *dst, const void *src, int frame_size, int channels) { diff --git a/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c b/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c index 07e82e21..77a93555 100755 --- a/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c +++ b/code/src/iamf_dec/codec/aac/iamf_aac_decoder.c @@ -88,8 +88,8 @@ static int iamf_aac_init(iamf_codec_context_t *ths) { ck_audio_frame_planar, &ret); if (!ctx->dec) return IAMF_ERR_INVALID_STATE; - ctx->out = (short *)malloc(sizeof(short) * def_max_aac_frame_size * - (ths->streams + ths->coupled_streams)); + ctx->out = def_malloc( + short, (def_max_aac_frame_size) * (ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_aac_close(ths); return IAMF_ERR_ALLOC_FAIL; @@ -136,9 +136,8 @@ int iamf_aac_close(iamf_codec_context_t *ths) { aac_multistream_decoder_close(dec); ctx->dec = 0; } - if (ctx->out) { - free(ctx->out); - } + def_free(ctx->out); + ctx->out = 0; return IAMF_OK; } diff --git a/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c index 32c81508..ca57a586 100755 --- a/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c +++ b/code/src/iamf_dec/codec/flac/flac_multistream_decoder.c @@ -13,7 +13,7 @@ /** * @file flac_multistream_decoder.c * @brief FLAC decoder. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -47,7 +47,7 @@ typedef struct FlacDecoderHandle { uint8_t *packet; uint32_t packet_size; uint32_t fs; - int buffer[def_max_flac_frame_size]; + int buffer[def_max_flac_frame_size * 2]; } flac_decoder_handle_t; typedef struct FlacMsDecoder { @@ -146,17 +146,28 @@ static int flac_header_set_channels(uint8_t *h, uint32_t size, int n) { static int flac_multistream_decode_native(flac_ms_decoder_t *st, uint8_t *buffer[], uint32_t size[], void *pcm, int frame_size) { - flac_decoder_handle_t *handle = NULL; char *out = (char *)pcm; int ss = 0; + if (st->streams < 1) { + error("invalid streams count: %d", st->streams); + return IAMF_ERR_BAD_ARG; + } + for (int i = 0; i < st->streams; ++i) { + flac_decoder_handle_t *handle = &st->handles[i]; trace("stream %d", i); - handle = &st->handles[i]; handle->packet = buffer[i]; handle->packet_size = size[i]; + handle->fs = 0; if (!FLAC__stream_decoder_process_single(handle->dec)) { + error("flac decode failed at stream %d", i); + return IAMF_ERR_INTERNAL; + } + + if (handle->fs == 0) { + error("no output from stream %d (write callback not invoked)", i); return IAMF_ERR_INTERNAL; } @@ -167,11 +178,8 @@ static int flac_multistream_decode_native(flac_ms_decoder_t *st, memcpy(out, handle->buffer, ss); out += ss; } - if (!handle) { - return IAMF_ERR_BAD_ARG; - } else { - return handle->fs; - } + + return st->handles[st->streams - 1].fs; } flac_ms_decoder_t *flac_multistream_decoder_open(uint8_t *config, uint32_t size, diff --git a/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c b/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c index 39c75c36..7a2f100c 100755 --- a/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c +++ b/code/src/iamf_dec/codec/flac/iamf_flac_decoder.c @@ -13,7 +13,7 @@ /** * @file IAMF_flac_decoder.c * @brief flac codec. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -64,11 +64,11 @@ static int iamf_flac_init(iamf_codec_context_t *ths) { return IAMF_ERR_INTERNAL; } - ctx->scale_i2f = 1 << (bits - 1); + ctx->scale_i2f = (float)(1u << (bits - 1)); debug("the scale of i%d to float : %f", bits, ctx->scale_i2f); ctx->out = def_malloc( - int, def_max_flac_frame_size *(ths->streams + ths->coupled_streams)); + int, (def_max_flac_frame_size) * (ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_flac_close(ths); return IAMF_ERR_ALLOC_FAIL; @@ -108,9 +108,9 @@ int iamf_flac_close(iamf_codec_context_t *ths) { flac_multistream_decoder_close(dec); ctx->dec = 0; } - if (ctx->out) { - free(ctx->out); - } + + def_free(ctx->out); + ctx->out = 0; return IAMF_OK; } diff --git a/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c b/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c index 83de5f92..e54c214c 100755 --- a/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c +++ b/code/src/iamf_dec/codec/opus/iamf_opus_decoder.c @@ -72,7 +72,6 @@ static int iamf_opus_close(iamf_codec_context_t *ths); * */ static int iamf_opus_init(iamf_codec_context_t *ths) { iamf_opus_context_t *ctx = (iamf_opus_context_t *)ths->priv; - int ec = IAMF_OK; int ret = 0; ths->sample_rate = 48000; @@ -81,18 +80,18 @@ static int iamf_opus_init(iamf_codec_context_t *ths) { ths->coupled_streams, ck_audio_frame_planar, &ret); if (!ctx->dec) { - error("fail to open opus decoder."); - ec = IAMF_ERR_INVALID_STATE; + error("fail to open opus decoder, error=%d.", ret); + return IAMF_ERR_INVALID_STATE; } - ctx->out = (short *)malloc(sizeof(short) * def_max_opus_frame_size * - (ths->streams + ths->coupled_streams)); + ctx->out = def_malloc( + short, (def_max_opus_frame_size) * (ths->streams + ths->coupled_streams)); if (!ctx->out) { iamf_opus_close(ths); return IAMF_ERR_ALLOC_FAIL; } - return ec; + return IAMF_OK; } static int iamf_opus_decode(iamf_codec_context_t *ths, uint8_t *buf[], @@ -125,9 +124,9 @@ int iamf_opus_close(iamf_codec_context_t *ths) { ctx->dec = 0; } - if (ctx->out) { - free(ctx->out); - } + def_free(ctx->out); + ctx->out = 0; + return IAMF_OK; } diff --git a/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c index 95ff4c11..dcb84622 100755 --- a/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c +++ b/code/src/iamf_dec/codec/opus/opus_multistream2_decoder.c @@ -13,7 +13,7 @@ /** * @file opus_multistream2_decoder.c * @brief opus decoder. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -135,7 +135,8 @@ static int opus_multistream2_decoder_decode_native( trace("stream %d decoded result %d", s, ret); if (ret <= 0) { - return ret; + error("opus_decode failed for stream %d: %d", s, ret); + return IAMF_ERR_INVALID_PACKET; } frame_size = ret; if (s < st->coupled_streams) { @@ -207,14 +208,12 @@ int opus_multistream2_decode(Opus_Ms2_Decoder_t *st, uint8_t *buffer[], return opus_multistream2_decoder_decode_native( st, buffer, (opus_int32 *)size, pcm, frame_size, opus_copy_channel_out_short_plane); - warning("flag is 0x%x, is not implmented.", st->flags); + warning("flag is 0x%x, is not implemented.", st->flags); return IAMF_ERR_UNIMPLEMENTED; } void opus_multistream2_decoder_destroy(Opus_Ms2_Decoder_t *st) { - if (st->buffer) { - free(st->buffer); - } + def_free(st->buffer); free(st); } #endif \ No newline at end of file diff --git a/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c b/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c index 4cbcd23a..f6581bc1 100755 --- a/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c +++ b/code/src/iamf_dec/codec/pcm/iamf_pcm_decoder.c @@ -13,7 +13,7 @@ /** * @file IAMF_pcm_decoder.c * @brief pcm codec. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -55,7 +55,7 @@ static uint32_t readu24be(uint8_t *data, int offset) { } static int reads24be(uint8_t *data, int offset) { - uint32_t ret = readu16le(data, offset) << 8 | data[offset + 2]; + uint32_t ret = readu16be(data, offset) << 8 | data[offset + 2]; int iret = ret << 8; return (iret >> 8); } diff --git a/code/src/iamf_dec/common/cbuffer.h b/code/src/iamf_dec/common/cbuffer.h index 2ac111b2..300153d3 100755 --- a/code/src/iamf_dec/common/cbuffer.h +++ b/code/src/iamf_dec/common/cbuffer.h @@ -33,11 +33,6 @@ typedef struct CBufferWrap { uint32_t size; } buffer_wrap_t; -typedef struct CBufferIOWrap { - buffer_t* buf; - io_context_t ioctx; -} buffer_io_wrap_t; - buffer_wrap_t* buffer_wrap_default_new(); buffer_wrap_t* buffer_wrap_new(uint32_t size); diff --git a/code/src/iamf_dec/demixer.c b/code/src/iamf_dec/demixer.c index fd8af87a..3ee8e015 100755 --- a/code/src/iamf_dec/demixer.c +++ b/code/src/iamf_dec/demixer.c @@ -13,7 +13,7 @@ /** * @file demixer.c * @brief Demixer. - * @version 0.1 + * @version 2.0.0 * @date Created 03/03/2023 **/ @@ -68,7 +68,6 @@ struct Demixer { float *start_window; float *stop_window; float *large_buffer; - float ch_last_sf[ck_iamf_channel_count]; float ch_last_sfavg[ck_iamf_channel_count]; iamf_loudspeaker_layout_t layout; @@ -469,7 +468,7 @@ static int dmx_demix(Demixer *ths) { } static void dmx_rms(Demixer *ths) { - float N = 7; // 7 frame + float N = 7.0f; // 7 frame float sf, sfavg; float filtBuf; float *out; @@ -483,7 +482,8 @@ static void dmx_rms(Demixer *ths) { out = ths->ch_data[ch]; if (N > 0) { - sfavg = (2 / (N + 1)) * sf + (1 - 2 / (N + 1)) * ths->ch_last_sfavg[ch]; + sfavg = (2.0f / (N + 1.0f)) * sf + + (1.0f - 2.0f / (N + 1.0f)) * ths->ch_last_sfavg[ch]; } else { sfavg = sf; } @@ -497,7 +497,6 @@ static void dmx_rms(Demixer *ths) { out[i] *= filtBuf; } - ths->ch_last_sf[ch] = sf; ths->ch_last_sfavg[ch] = sfavg; } } @@ -538,7 +537,6 @@ Demixer *demixer_open(uint32_t frame_size) { } for (int i = 0; i < ck_iamf_channel_count; ++i) { - ths->ch_last_sf[i] = 1.0; ths->ch_last_sfavg[i] = 1.0; } } @@ -558,7 +556,7 @@ void demixer_close(Demixer *ths) { def_free(ths->start_window); def_free(ths->stop_window); def_free(ths->large_buffer); - free(ths); + def_free(ths); } } @@ -648,7 +646,7 @@ int demixer_set_demixing_info(Demixer *ths, int mode, int w_idx) { int demixer_set_recon_gain(Demixer *ths, int count, iamf_channel_t *chs, float *recon_gain, uint32_t flags) { - if (flags && flags ^ ths->chs_recon_gain_list.flags) { + if (flags != ths->chs_recon_gain_list.flags) { for (int i = 0; i < count; ++i) { ths->chs_recon_gain_list.ch_recon_gain[i].ch = chs[i]; } diff --git a/code/src/iamf_dec/iamf_audio_block.c b/code/src/iamf_dec/iamf_audio_block.c index 6081c573..5d1b9f17 100755 --- a/code/src/iamf_dec/iamf_audio_block.c +++ b/code/src/iamf_dec/iamf_audio_block.c @@ -76,15 +76,13 @@ iamf_audio_block_t* iamf_audio_block_new(uint32_t id, int iamf_audio_block_resize(iamf_audio_block_t* block, uint32_t capacity_per_channel, uint32_t num_channels) { - if (!block) return IAMF_ERR_BAD_ARG; - - if (block->num_samples_per_channel > 0) return IAMF_ERR_INVALID_STATE; - - if (!num_channels || !capacity_per_channel) return IAMF_ERR_BAD_ARG; + if (!block || block->num_samples_per_channel > 0 || !num_channels || + !capacity_per_channel) + return -22; - if (block->capacity_per_channel * block->num_samples_per_channel > + if (block->capacity_per_channel * block->num_channels >= capacity_per_channel * num_channels) - return IAMF_OK; + return 0; float* new_data = def_mallocz(float, (num_channels * capacity_per_channel)); if (!new_data) return -12; @@ -99,7 +97,7 @@ int iamf_audio_block_resize(iamf_audio_block_t* block, block->num_channels = num_channels; block->capacity_per_channel = capacity_per_channel; - return IAMF_OK; + return 0; } void iamf_audio_block_delete(iamf_audio_block_t* block) { @@ -174,10 +172,16 @@ int iamf_audio_block_channels_concat(iamf_audio_block_t* dst, // if (dst->interleaved) return -38; + if (!src[0]) return -22; num_samples = src[0]->num_samples_per_channel; - for (int i = 0; i < n; ++i) { - if (!src[i] || num_samples > dst->capacity_per_channel || - src[i]->num_samples_per_channel != num_samples + + if (num_samples > dst->capacity_per_channel) { + warning("iamf_audio_block_channels_concat: capacity exceeded!"); + return -22; + } + + for (int i = 1; i < n; ++i) { + if (!src[i] || src[i]->num_samples_per_channel != num_samples // || dst->interleaved != src[i]->interleaved ) { warning("iamf_audio_block_channels_concat error!"); @@ -308,8 +312,9 @@ iamf_audio_block_t* iamf_audio_block_samples_concat( for (int i = 0; i < n; ++i) { ablock = blocks[i]; - num_samples += - (ablock->num_samples_per_channel - ablock->skip - ablock->padding); + uint32_t trim_sum = ablock->skip + ablock->padding; + if (trim_sum < ablock->num_samples_per_channel) + num_samples += ablock->num_samples_per_channel - trim_sum; } ablock = iamf_audio_block_new(0, num_samples, num_channels); @@ -317,8 +322,10 @@ iamf_audio_block_t* iamf_audio_block_samples_concat( for (int c = 0; c < num_channels; ++c) { uint32_t off = 0; for (int i = 0; i < n; ++i) { - uint32_t samples = blocks[i]->num_samples_per_channel - - blocks[i]->skip - blocks[i]->padding; + uint32_t trim_sum = blocks[i]->skip + blocks[i]->padding; + uint32_t samples = (trim_sum < blocks[i]->num_samples_per_channel) + ? (blocks[i]->num_samples_per_channel - trim_sum) + : 0; memcpy(ablock->data + c * num_samples + off, blocks[i]->data + c * blocks[i]->num_samples_per_channel + blocks[i]->skip, @@ -360,8 +367,11 @@ int iamf_audio_block_trim(iamf_audio_block_t* block) { uint32_t iamf_audio_block_available_samples(iamf_audio_block_t* block) { if (!block) return 0; - return block->num_samples_per_channel - block->skip - block->padding - - block->second_skip - block->second_padding; + uint32_t trim_total = + block->skip + block->padding + block->second_skip + block->second_padding; + return block->num_samples_per_channel > trim_total + ? block->num_samples_per_channel - trim_total + : 0; } int iamf_audio_block_partial_copy_data(iamf_audio_block_t* dst, diff --git a/code/src/iamf_dec/iamf_core_decoder.c b/code/src/iamf_dec/iamf_core_decoder.c index 65613011..9f3b5c7f 100755 --- a/code/src/iamf_dec/iamf_core_decoder.c +++ b/code/src/iamf_dec/iamf_core_decoder.c @@ -171,22 +171,23 @@ iamf_core_decoder_t *iamf_core_decoder_open(iamf_codec_id_t cid) { void iamf_core_decoder_close(iamf_core_decoder_t *ths) { if (ths) { if (ths->ctx) { - if (ths->cdec) ths->cdec->close(ths->ctx); - if (ths->ctx->priv) free(ths->ctx->priv); - free(ths->ctx); + if (ths->ctx->priv) { + if (ths->cdec) ths->cdec->close(ths->ctx); + def_free(ths->ctx->priv); + } + def_free(ths->ctx); } if (ths->matrix) { if (ths->ambisonics == ck_stream_mode_ambisonics_projection) { FloatMatrix *fm = ths->matrix; - if (fm->matrix) free(fm->matrix); + def_free(fm->matrix); } - free(ths->matrix); + def_free(ths->matrix); } - if (ths->buffer) free(ths->buffer); - - free(ths); + def_free(ths->buffer); + def_free(ths); } } @@ -230,7 +231,7 @@ int iamf_core_decoder_set_streams_info(iamf_core_decoder_t *ths, uint32_t mode, count = matrix->row * matrix->column; factors = def_mallocz(float, count); if (!factors) { - free(matrix); + def_free(matrix); return IAMF_ERR_ALLOC_FAIL; } matrix->matrix = factors; @@ -245,7 +246,7 @@ int iamf_core_decoder_set_streams_info(iamf_core_decoder_t *ths, uint32_t mode, if (!matrix) return IAMF_ERR_ALLOC_FAIL; if (channels != mapping_size) { - free(matrix); + def_free(matrix); error("Invalid ambisonics mono info."); return IAMF_ERR_BAD_ARG; } diff --git a/code/src/iamf_dec/iamf_database.c b/code/src/iamf_dec/iamf_database.c index f9033f78..41f5ec42 100755 --- a/code/src/iamf_dec/iamf_database.c +++ b/code/src/iamf_dec/iamf_database.c @@ -116,7 +116,7 @@ static int _iadb_parameter_block_manager_add(parameter_block_manager_t *manager, } else if (base->type == ck_iamf_parameter_type_mix_gain) { vector_push(manager->mix_gains, def_value_wrap_instance_ptr(block)); } else if (base->type == ck_iamf_parameter_type_momentary_loudness) { - vector_push(manager->coordinates, def_value_wrap_instance_ptr(block)); + vector_push(manager->loudness_params, def_value_wrap_instance_ptr(block)); } else if (iamf_parameter_type_is_coordinate(base->type)) { vector_push(manager->coordinates, def_value_wrap_instance_ptr(block)); } else { @@ -306,8 +306,10 @@ static int _iadb_parameter_block_manager_init( manager->recon_gains = vector_new(); manager->mix_gains = vector_new(); manager->coordinates = vector_new(); + manager->loudness_params = vector_new(); if (!manager->parameter_blocks || !manager->demixing_infos || - !manager->recon_gains || !manager->mix_gains || !manager->coordinates) { + !manager->recon_gains || !manager->mix_gains || !manager->coordinates || + !manager->loudness_params) { error("Failed to allocate memory for parameter blocks."); return IAMF_ERR_ALLOC_FAIL; } @@ -323,6 +325,7 @@ static void _iadb_parameter_block_manager_uninit( if (manager->recon_gains) vector_free(manager->recon_gains, 0); if (manager->mix_gains) vector_free(manager->mix_gains, 0); if (manager->coordinates) vector_free(manager->coordinates, 0); + if (manager->loudness_params) vector_free(manager->loudness_params, 0); memset(manager, 0, sizeof(parameter_block_manager_t)); } @@ -479,15 +482,39 @@ static int _iadb_descriptors_codec_config_obu_check_profile( n, iamf_profile_type_string(profile), descriptors->num_lpcm_codec, iamf_codec_type_string(iamf_codec_type_get(cco->codec_id)), cco->codec_id); - if ((n > def_max_codec_configs) || + if ((n >= def_max_codec_configs) || (n && !descriptors->num_lpcm_codec && cco->codec_id != ck_iamf_codec_id_lpcm)) { warning("Too many codec configs or no LPCM codec config."); ret = def_error; } - // TODO: The frame sizes and the sample rates identified (implicitly or + // The frame sizes and the sample rates identified (implicitly or // explicitly) by the two Codec Config OBUs SHALL be the same. + if (n >= 1) { + audio_codec_parameter_t new_param; + iamf_codec_config_obu_get_parameter(cco, &new_param); + + for (int i = 0; i < n; ++i) { + iamf_codec_config_obu_t *existing = def_value_wrap_type_ptr( + iamf_codec_config_obu_t, + vector_at(descriptors->codec_config_obus, i)); + audio_codec_parameter_t existing_param; + iamf_codec_config_obu_get_parameter(existing, &existing_param); + + if (new_param.frame_size != existing_param.frame_size || + new_param.sample_rate != existing_param.sample_rate) { + error( + "Codec Config OBU %u: frame_size (%u vs %u) or sample_rate " + "(%u vs %u) mismatch with Codec Config OBU %u.", + cco->codec_config_id, new_param.frame_size, + existing_param.frame_size, new_param.sample_rate, + existing_param.sample_rate, existing->codec_config_id); + ret = def_error; + break; + } + } + } } break; default: break; @@ -500,59 +527,134 @@ static int _iadb_descriptors_mix_presentation_obu_check_profile( iamf_profile_t profile) { int ret = def_pass; - // TODO: If num_sub_mixes = 1 in all Mix Presentation OBUs, there SHALL be - // only one unique Codec Config OBU. - // TODO: Every Audio Substreams used in the first sub-mix of all Mix - // Presentation OBUs SHALL be coded using the same Codec Config OBU. - switch (profile) { - case ck_iamf_profile_base_advanced: { - uint32_t element_flags = 0; - uint32_t k = array_size(mpo->sub_mixes); - uint32_t m = vector_size(descriptors->mix_presentation_obus); + case ck_iamf_profile_base_advanced: + case ck_iamf_profile_advanced_1: + case ck_iamf_profile_advanced_2: { + // Constraint 1 (§6.2): If num_sub_mixes = 1, there SHALL be only one + // unique Codec Config OBU. + { + uint32_t num_sub_mixes = array_size(mpo->sub_mixes); + uint32_t num_codec_configs = + vector_size(descriptors->codec_config_obus); + if (num_sub_mixes == 1 && num_codec_configs > 1) { + error( + "Mix Presentation OBU %u has num_sub_mixes=1 but %u Codec " + "Config OBUs exist.", + mpo->mix_presentation_id, num_codec_configs); + ret = def_error; + } + } - for (int s = 0; s < k; ++s) { - obu_sub_mix_t *sub = - def_value_wrap_type_ptr(obu_sub_mix_t, array_at(mpo->sub_mixes, s)); - int n = array_size(sub->audio_element_configs); + // Constraint 2 (§6.2): Every Audio Substream used in the first sub-mix + // of all Mix Presentation OBUs SHALL be coded using the same Codec + // Config OBU. + { + uint32_t num_sub_mixes = array_size(mpo->sub_mixes); + if (num_sub_mixes >= 1) { + obu_sub_mix_t *first_sub = def_value_wrap_type_ptr( + obu_sub_mix_t, array_at(mpo->sub_mixes, 0)); + int num_configs = array_size(first_sub->audio_element_configs); + + if (num_configs > 0) { + obu_audio_element_config_t *first_aec = def_value_wrap_type_ptr( + obu_audio_element_config_t, + array_at(first_sub->audio_element_configs, 0)); - for (int i = 0; i < n; ++i) { - value_wrap_t v; - obu_audio_element_config_t *aec = - def_value_wrap_type_ptr(obu_audio_element_config_t, - array_at(sub->audio_element_configs, i)); - - int idx = vector_find(descriptors->audio_element_obus, - def_value_wrap_instance_u32(aec->element_id), - _iadb_audio_element_obu_find, &v); - iamf_audio_element_obu_t *aeo = def_value_wrap_type_ptr( - iamf_audio_element_obu_t, - vector_at(descriptors->audio_element_obus, idx)); - if (aeo->audio_element_type == ck_audio_element_type_object_based) - element_flags |= 1; - else - element_flags |= 2; + value_wrap_t v; + int idx = + vector_find(descriptors->audio_element_obus, + def_value_wrap_instance_u32(first_aec->element_id), + _iadb_audio_element_obu_find, &v); + if (idx < 0) { + warning("Audio element %u not found for Mix Presentation %u.", + first_aec->element_id, mpo->mix_presentation_id); + } else { + iamf_audio_element_obu_t *first_aeo = + def_value_wrap_type_ptr(iamf_audio_element_obu_t, &v); + uint32_t ref_codec_config_id = first_aeo->codec_config_id; + + for (int i = 1; i < num_configs; ++i) { + obu_audio_element_config_t *aec = def_value_wrap_type_ptr( + obu_audio_element_config_t, + array_at(first_sub->audio_element_configs, i)); + + idx = vector_find(descriptors->audio_element_obus, + def_value_wrap_instance_u32(aec->element_id), + _iadb_audio_element_obu_find, &v); + if (idx < 0) { + warning("Audio element %u not found for Mix Presentation %u.", + aec->element_id, mpo->mix_presentation_id); + continue; + } + + iamf_audio_element_obu_t *aeo = + def_value_wrap_type_ptr(iamf_audio_element_obu_t, &v); + if (aeo->codec_config_id != ref_codec_config_id) { + error( + "Mix Presentation OBU %u: audio element %u uses " + "codec_config_id %u, but first audio element %u uses " + "%u. All audio substreams in the first sub-mix SHALL " + "use the same Codec Config OBU.", + mpo->mix_presentation_id, aec->element_id, + aeo->codec_config_id, first_aec->element_id, + ref_codec_config_id); + ret = def_error; + break; + } + } + } + } } } - if (!m && element_flags == 3) { - error( - "Object-based can't with channel-based or secen-based elements in " - "Mix Presentation OBU %u.", - mpo->mix_presentation_id); - ret = def_error; - } else if (m && element_flags & 1) { - error("Mix Presentation OBU %u with object-based must be first.", - mpo->mix_presentation_id); - ret = def_error; - } + if (profile == ck_iamf_profile_base_advanced) { + uint32_t element_flags = 0; + uint32_t k = array_size(mpo->sub_mixes); + uint32_t m = vector_size(descriptors->mix_presentation_obus); - if (ret != def_pass) - warning( - "Mix Presentation OBU %u, element flags 0x%x(b01-obj, b10-chn), " - "mix count %u", - mpo->mix_presentation_id, element_flags, m); + for (int s = 0; s < k; ++s) { + obu_sub_mix_t *sub = def_value_wrap_type_ptr( + obu_sub_mix_t, array_at(mpo->sub_mixes, s)); + int n = array_size(sub->audio_element_configs); + for (int i = 0; i < n; ++i) { + value_wrap_t v; + obu_audio_element_config_t *aec = def_value_wrap_type_ptr( + obu_audio_element_config_t, + array_at(sub->audio_element_configs, i)); + + int idx = vector_find(descriptors->audio_element_obus, + def_value_wrap_instance_u32(aec->element_id), + _iadb_audio_element_obu_find, &v); + iamf_audio_element_obu_t *aeo = def_value_wrap_type_ptr( + iamf_audio_element_obu_t, + vector_at(descriptors->audio_element_obus, idx)); + if (aeo->audio_element_type == ck_audio_element_type_object_based) + element_flags |= 1; + else + element_flags |= 2; + } + } + + if (!m && element_flags == 3) { + error( + "Object-based can't with channel-based or secen-based elements " + "in Mix Presentation OBU %u.", + mpo->mix_presentation_id); + ret = def_error; + } else if (m && element_flags & 1) { + error("Mix Presentation OBU %u with object-based must be first.", + mpo->mix_presentation_id); + ret = def_error; + } + + if (ret != def_pass) + warning( + "Mix Presentation OBU %u, element flags 0x%x(b01-obj, " + "b10-chn), mix count %u", + mpo->mix_presentation_id, element_flags, m); + } } break; default: break; @@ -1266,8 +1368,14 @@ int iamf_database_get_audio_element_demix_mode(iamf_database_t *database, return def_dmx_mode_none; } - // Convert fraction_t offset to uint32_t for the existing function - uint32_t offset_samples = iamf_fraction_transform(offset, 1); + // Convert fraction_t offset from audio sample rate domain to parameter_rate + // domain for correct subblock lookup + parameter_block_t *pbk = + iamf_database_get_parameter_block(database, ae->demixing_info_id); + if (!pbk) return def_dmx_mode_none; + + uint32_t offset_samples = + iamf_fraction_transform(offset, pbk->base->parameter_rate); return iamf_database_get_demix_mode(database, ae->demixing_info_id, offset_samples); diff --git a/code/src/iamf_dec/iamf_database.h b/code/src/iamf_dec/iamf_database.h index 1e382409..2e407040 100755 --- a/code/src/iamf_dec/iamf_database.h +++ b/code/src/iamf_dec/iamf_database.h @@ -98,10 +98,11 @@ typedef struct DBCartesiansParameterBlock { typedef struct DBParameterBlockManager { vector_t *parameter_blocks; // vector - vector_t *demixing_infos; // vector - vector_t *recon_gains; // vector - vector_t *mix_gains; // vector - vector_t *coordinates; // vector + vector_t *demixing_infos; // vector + vector_t *recon_gains; // vector + vector_t *mix_gains; // vector + vector_t *coordinates; // vector (polar/cartesian) + vector_t *loudness_params; // vector (momentary_loudness) } parameter_block_manager_t; typedef struct IamfDescriptors { diff --git a/code/src/iamf_dec/iamf_decoder.c b/code/src/iamf_dec/iamf_decoder.c index f57c6a1b..6153290c 100755 --- a/code/src/iamf_dec/iamf_decoder.c +++ b/code/src/iamf_dec/iamf_decoder.c @@ -194,12 +194,21 @@ static int iamf_decoder_priv_decode(iamf_decoder_t *self, const uint8_t *data, } if (audio_block) { - uint32_t _2nd_skip = audio_block->second_skip; - frame_duration.numerator -= _2nd_skip; - frame_duration.numerator -= audio_block->second_padding; + if (frame_duration.numerator >= + audio_block->second_skip + audio_block->second_padding) { + frame_duration.numerator -= audio_block->second_skip; + frame_duration.numerator -= audio_block->second_padding; + } else { + warning( + "Trimming values exceed frame size: skip=%u, padding=%u, frame=%u", + audio_block->second_skip, audio_block->second_padding, + frame_duration.numerator); + frame_duration.numerator = 0; + } iamf_database_time_elapse(&self->ctx.database, frame_duration); - if (_2nd_skip > 0) ctx->cache.decoder = _2nd_skip; + if (audio_block->second_skip > 0) + ctx->cache.decoder = audio_block->second_skip; audio_block->padding += audio_block->second_padding; audio_block->second_padding = 0; @@ -369,6 +378,13 @@ int iamf_decoder_priv_update_frame_info(iamf_decoder_t *self) { array_at(sub_mix->audio_element_configs, j)); audio_element = iamf_database_get_audio_element( database, audio_element_config->element_id); + if (!audio_element || !audio_element->codec_config) { + warning( + "Audio element %u or its codec config not found in database, " + "skipping.", + audio_element_config->element_id); + continue; + } codec_config = audio_element->codec_config; if (!sample_rate) { sample_rate = codec_config->codec_param.sample_rate; @@ -672,14 +688,13 @@ static iamf_parser_state_t iamf_decoder_priv_process_data_obus( iamf_audio_block_t *audio_block = iamf_element_reconstructor_process(self->reconstructor); if (audio_block) { - uint32_t _2nd_skip = audio_block->second_skip; fraction_t frame_duration = self->ctx.frame_duration; #if SR iamf_rec_stream_log(audio_block->id, audio_block->num_channels, audio_block->data, audio_block->capacity_per_channel); #endif - frame_duration.numerator -= _2nd_skip; + frame_duration.numerator -= audio_block->second_skip; ret = iamf_presentation_add_audio_block(presentation, audio_block); if (ret > 0) { state = ck_iamf_parser_state_stop; @@ -849,7 +864,7 @@ int IAMF_decoder_decode(IAMF_DecoderHandle handle, const uint8_t *data, uint32_t read = 0; int ret = IAMF_OK; - if (!self) return IAMF_ERR_BAD_ARG; + if (!self || !pcm) return IAMF_ERR_BAD_ARG; trace("decode iamf decoder. data %p, size %d, statue %d", data, size, self->ctx.status); if (self->ctx.status != ck_iamf_decoder_status_parse_2) @@ -900,6 +915,7 @@ int IAMF_decoder_set_mix_presentation_id(IAMF_DecoderHandle handle, iamf_decoder_t *self = (iamf_decoder_t *)handle; iamf_decoder_context_t *ctx; uint32_t id = def_lsb_32bits(id64); + int ret = IAMF_OK; if (!self || id64 > UINT32_MAX) return IAMF_ERR_BAD_ARG; @@ -918,9 +934,9 @@ int IAMF_decoder_set_mix_presentation_id(IAMF_DecoderHandle handle, info("set new mix presentation id %" PRId64 ".", ctx->mix_presentation_id); if (ctx->status > ck_iamf_decoder_status_configure) - iamf_decoder_priv_configure(self, 0, 0, 0); + ret = iamf_decoder_priv_configure(self, 0, 0, 0); - return IAMF_OK; + return ret; } int64_t IAMF_decoder_get_mix_presentation_id(IAMF_DecoderHandle handle) { @@ -943,30 +959,30 @@ int IAMF_layout_binaural_channels_count() { return 2; } char *IAMF_decoder_get_codec_capability() { char *ccs_str = def_mallocz(char, def_ccs_str_size); - char cc_str[def_cc_str_size]; + int offset = 0; if (!ccs_str) return 0; - snprintf(cc_str, def_cc_str_size, "iamf.%.03d.%.03d.ipcm", - def_iamf_profile_default, def_iamf_profile_default); - strncat(ccs_str, cc_str, def_cc_str_size); + offset += snprintf(ccs_str + offset, def_ccs_str_size - offset, + "iamf.%.03d.%.03d.ipcm", def_iamf_profile_default, + def_iamf_profile_default); #ifdef CONFIG_OPUS_CODEC - snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.Opus", - def_iamf_profile_default, def_iamf_profile_default); - strncat(ccs_str, cc_str, def_cc_str_size); + offset += snprintf(ccs_str + offset, def_ccs_str_size - offset, + ";iamf.%.03d.%.03d.Opus", def_iamf_profile_default, + def_iamf_profile_default); #endif #ifdef CONFIG_AAC_CODEC - snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.mp4a.40.2", - def_iamf_profile_default, def_iamf_profile_default); - strncat(ccs_str, cc_str, def_cc_str_size); + offset += snprintf(ccs_str + offset, def_ccs_str_size - offset, + ";iamf.%.03d.%.03d.mp4a.40.2", def_iamf_profile_default, + def_iamf_profile_default); #endif #ifdef CONFIG_FLAC_CODEC - snprintf(cc_str, def_cc_str_size, ";iamf.%.03d.%.03d.fLaC", - def_iamf_profile_default, def_iamf_profile_default); - strncat(ccs_str, cc_str, def_cc_str_size); + offset += snprintf(ccs_str + offset, def_ccs_str_size - offset, + ";iamf.%.03d.%.03d.fLaC", def_iamf_profile_default, + def_iamf_profile_default); #endif return ccs_str; @@ -1353,6 +1369,10 @@ IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { } } } + } else { + error("Failed to allocate audio elements array (%u elements).", + info->iamf_stream_info.audio_element_count); + info->iamf_stream_info.audio_element_count = 0; } } @@ -1391,69 +1411,76 @@ IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { info->iamf_stream_info.mix_presentations[i].num_audio_elements = total_audio_elements; - uint32_t element_idx = 0; - for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) { - obu_sub_mix_t *sub = def_value_wrap_optional_ptr( - array_at(mpo->sub_mixes, sub_idx)); - - if (sub) { - int num_audio_elements = array_size(sub->audio_element_configs); - - for (int elem_idx = 0; elem_idx < num_audio_elements; - ++elem_idx) { - audio_element_config = def_value_wrap_optional_ptr( - array_at(sub->audio_element_configs, elem_idx)); - - if (audio_element_config && - element_idx < total_audio_elements) { - // Set element ID - info->iamf_stream_info.mix_presentations[i] - .elements[element_idx] - .eid = audio_element_config->element_id; - - info->iamf_stream_info.mix_presentations[i] - .elements[element_idx] - .mode = audio_element_config->rendering_config - .headphones_rendering_mode; - info->iamf_stream_info.mix_presentations[i] - .elements[element_idx] - .profile = audio_element_config->rendering_config - .binaural_filter_profile; - - // Check for gain offset range - if ((audio_element_config->rendering_config.flags & - def_rendering_config_flag_element_gain_offset) && - (audio_element_config->rendering_config - .element_gain_offset_type == - ck_element_gain_offset_type_range)) { + if (info->iamf_stream_info.mix_presentations[i].elements) { + uint32_t element_idx = 0; + for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) { + obu_sub_mix_t *sub = def_value_wrap_optional_ptr( + array_at(mpo->sub_mixes, sub_idx)); + + if (sub) { + int num_audio_elements = + array_size(sub->audio_element_configs); + + for (int elem_idx = 0; elem_idx < num_audio_elements; + ++elem_idx) { + audio_element_config = def_value_wrap_optional_ptr( + array_at(sub->audio_element_configs, elem_idx)); + + if (audio_element_config && + element_idx < total_audio_elements) { + // Set element ID info->iamf_stream_info.mix_presentations[i] .elements[element_idx] - .gain_offset_range = - def_mallocz(iamf_element_gain_offset_range_t, 1); - if (info->iamf_stream_info.mix_presentations[i] - .elements[element_idx] - .gain_offset_range) { + .eid = audio_element_config->element_id; + + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .mode = audio_element_config->rendering_config + .headphones_rendering_mode; + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .profile = audio_element_config->rendering_config + .binaural_filter_profile; + + // Check for gain offset range + if ((audio_element_config->rendering_config.flags & + def_rendering_config_flag_element_gain_offset) && + (audio_element_config->rendering_config + .element_gain_offset_type == + ck_element_gain_offset_type_range)) { info->iamf_stream_info.mix_presentations[i] .elements[element_idx] - .gain_offset_range->min = - audio_element_config->rendering_config - .element_gain_offset_db.min; + .gain_offset_range = + def_mallocz(iamf_element_gain_offset_range_t, 1); + if (info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range) { + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range->min = + audio_element_config->rendering_config + .element_gain_offset_db.min; + info->iamf_stream_info.mix_presentations[i] + .elements[element_idx] + .gain_offset_range->max = + audio_element_config->rendering_config + .element_gain_offset_db.max; + } + } else { info->iamf_stream_info.mix_presentations[i] .elements[element_idx] - .gain_offset_range->max = - audio_element_config->rendering_config - .element_gain_offset_db.max; + .gain_offset_range = 0; } - } else { - info->iamf_stream_info.mix_presentations[i] - .elements[element_idx] - .gain_offset_range = 0; - } - element_idx++; + element_idx++; + } } } } + } else { + error("Failed to allocate elements array for MP %u.", i); + info->iamf_stream_info.mix_presentations[i].num_audio_elements = + 0; } } else { info->iamf_stream_info.mix_presentations[i].elements = 0; @@ -1461,6 +1488,10 @@ IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { } } } + } else { + error("Failed to allocate mix presentations array (%u presentations).", + info->iamf_stream_info.mix_presentation_count); + info->iamf_stream_info.mix_presentation_count = 0; } } diff --git a/code/src/iamf_dec/iamf_layout.c b/code/src/iamf_dec/iamf_layout.c index 7bcb549d..8d4023e1 100755 --- a/code/src/iamf_dec/iamf_layout.c +++ b/code/src/iamf_dec/iamf_layout.c @@ -419,7 +419,7 @@ static const iamf_layout_info_t iamf_layouts[] = { ck_iamf_layout_flag_expanded, .channels = 17, .surround = 7, - .height = 9, + .height = 5, .bottom = 4, .lfe1 = 3, .lfe2 = def_lfe_none, @@ -500,6 +500,8 @@ const iamf_layout_info_t *iamf_loudspeaker_layout_get_info( int iamf_loudspeaker_layout_get_decoding_channels( iamf_loudspeaker_layout_t type, iamf_channel_t *channels, uint32_t count) { const iamf_layout_info_t *info = iamf_loudspeaker_layout_get_info(type); + if (!info) return IAMF_ERR_BAD_ARG; + if (count < info->channels) return IAMF_ERR_BUFFER_TOO_SMALL; for (uint32_t i = 0; i < info->channels; ++i) channels[i] = info->channel_layout[info->decoding_map[i]]; return info->channels; diff --git a/code/src/iamf_dec/iamf_post_processor.c b/code/src/iamf_dec/iamf_post_processor.c index 802530a8..03401c3e 100755 --- a/code/src/iamf_dec/iamf_post_processor.c +++ b/code/src/iamf_dec/iamf_post_processor.c @@ -13,7 +13,7 @@ /** * @file iamf_post_processor.c * @brief IAMF post processor implementation. - * @version 0.1 + * @version 2.0.0 * @date Created 12/11/2025 **/ @@ -33,7 +33,6 @@ #define def_limiter_attack_sec 0.001f #define def_limiter_release_sec 0.200f #define def_limiter_look_ahead_sec 0.005f -#define def_limiter_look_ahead 240 typedef enum EStatus { ck_status_none, @@ -247,7 +246,7 @@ int iamf_post_processor_process(iamf_post_processor_t *self, iamf_audio_block_t **out) { iamf_audio_block_t *last = in; - if (self->status != ck_status_process) return 0; + if (self->status != ck_status_process) return IAMF_ERR_INVALID_STATE; if (self->resampler) { iamf_audio_block_t *next = iamf_post_processor_priv_resample(self, last); diff --git a/code/src/iamf_dec/iamf_presentation.c b/code/src/iamf_dec/iamf_presentation.c index 5d317823..c506a911 100755 --- a/code/src/iamf_dec/iamf_presentation.c +++ b/code/src/iamf_dec/iamf_presentation.c @@ -171,7 +171,7 @@ static uint32_t iamf_presentation_priv_generate_unique_gain_offset_id( // If conflict, try different offsets for (uint32_t offset = 1; offset < 0xFFFF; offset++) { - candidate_id += offset; + candidate_id = self->id + offset; if (!iamf_presentation_priv_pid_conflicts(self, element_id, candidate_id)) { debug( "Generated unique gain offset ID: original_id=%u, unique_id=%u, " @@ -927,13 +927,13 @@ static int iamf_presentation_priv_update_element_positions( float durations = 0.0f; uint32_t rate = iamf_database_get_parameter_rate(self->database, position_param_id); - polars_parameter_subblock_t* polars_subblocks = - def_polars_parameter_subblock_ptr(*subblock); for (int j = 0; j < n; j++) { + polars_parameter_subblock_t* polars_subblock = + def_polars_parameter_subblock_ptr(subblock[j]); uint32_t approximate_durations = durations + 0.5f; float duration = iamf_fraction_transform_float( - def_fraction_instance(polars_subblocks[j].base.subblock_duration, + def_fraction_instance(polars_subblock->base.subblock_duration, rate), element->sampling_rate); durations += duration; @@ -941,7 +941,7 @@ static int iamf_presentation_priv_update_element_positions( iamf_renderer_update_element_animated_polar_positions( &self->renderer, element->element_id, position_param_id, - polars_subblocks->polars, polars_subblocks->num_polars, duration); + polars_subblock->polars, polars_subblock->num_polars, duration); durations += duration; } @@ -1007,25 +1007,25 @@ static int iamf_presentation_priv_update_element_positions( } if (n > 0) { - cartesians_parameter_subblock_t* cartesians_subblocks = - def_cartesians_parameter_subblock_ptr(*subblock); float durations = 0.0f; uint32_t rate = iamf_database_get_parameter_rate(self->database, position_param_id); for (int j = 0; j < n; j++) { + cartesians_parameter_subblock_t* cartesians_subblock = + def_cartesians_parameter_subblock_ptr(subblock[j]); uint32_t approximate_durations = durations + 0.5f; float duration = iamf_fraction_transform_float( - def_fraction_instance( - cartesians_subblocks[j].base.subblock_duration, rate), + def_fraction_instance(cartesians_subblock->base.subblock_duration, + rate), element->sampling_rate); durations += duration; duration = durations + 0.5f - approximate_durations; iamf_renderer_update_element_animated_cartesian_positions( &self->renderer, element->element_id, - cartesians_subblocks->cartesians, - cartesians_subblocks->num_cartesians, duration); + cartesians_subblock->cartesians, + cartesians_subblock->num_cartesians, duration); durations += duration; } @@ -1073,8 +1073,9 @@ static int iamf_presentation_priv_update_element_positions( static int iamf_presentation_priv_update_output_mix_gain( iamf_presentation_t* self, iamf_audio_block_t* block, fraction_t num_samples_frac) { - int num_gains = vector_size(self->output_mix_gain_ids); if (!self || !block) return IAMF_ERR_BAD_ARG; + + int num_gains = vector_size(self->output_mix_gain_ids); if (num_gains <= 0) return IAMF_ERR_INTERNAL; for (int g = 0; g < num_gains; g++) { diff --git a/code/src/iamf_dec/iamf_private_definitions.h b/code/src/iamf_dec/iamf_private_definitions.h index 93a652b3..cd419482 100755 --- a/code/src/iamf_dec/iamf_private_definitions.h +++ b/code/src/iamf_dec/iamf_private_definitions.h @@ -76,7 +76,6 @@ #define def_default_recon_gain 1.0f #define def_ccs_str_size 1024 -#define def_cc_str_size 128 #define def_q78_num_bits 16 #define def_azimuth_num_bits 9 #define def_elevation_num_bits 8 @@ -88,7 +87,7 @@ #define def_max_audio_objects 2 -#define def_max_opus_frame_size 960 * 6 +#define def_max_opus_frame_size (960 * 6) #define def_max_aac_frame_size 2048 #define def_max_flac_frame_size 32768 diff --git a/code/src/iamf_dec/iamf_renderer.c b/code/src/iamf_dec/iamf_renderer.c index d6266749..e0ff5d49 100755 --- a/code/src/iamf_dec/iamf_renderer.c +++ b/code/src/iamf_dec/iamf_renderer.c @@ -245,7 +245,7 @@ int iamf_renderer_update_element_animated_gain(iamf_renderer_t* self, uint32_t id, uint32_t pid, animated_float32_t animated_gain, uint32_t number) { - oar_metadata_t gain; + oar_metadata_t gain = {0}; if (!self || !self->oar) return IAMF_ERR_BAD_ARG; @@ -258,8 +258,8 @@ int iamf_renderer_update_element_animated_gain(iamf_renderer_t* self, gain.duration = number; debug( - "display pid %d: gain %d: animation type %d: start %f, end %f, control " - "%f, control_relative_time %f, duration %d", + "display pid %u: gain %u: animation type %d: start %f, end %f, control " + "%f, control_relative_time %f, duration %u", pid, pid, animated_gain.animation_type, animated_gain.data.start, animated_gain.data.end, animated_gain.data.control, animated_gain.data.control_relative_time, number); @@ -272,7 +272,7 @@ int iamf_renderer_update_element_animated_gain(iamf_renderer_t* self, int iamf_renderer_update_element_downmix_mode(iamf_renderer_t* self, uint32_t id, int mode, int period) { - oar_metadata_t dmx; + oar_metadata_t dmx = {0}; dmx.type = ck_metadata_iamf_downmix_mode; dmx.iamf_downmix_mode.mode = mode; dmx.duration = period; @@ -285,7 +285,7 @@ int iamf_renderer_update_animated_gain(iamf_renderer_t* self, uint32_t pid, uint32_t group_index, animated_float32_t animated_gain, uint32_t number) { - oar_metadata_t gain; + oar_metadata_t gain = {0}; if (!self || !self->oar || group_index >= def_max_sub_mixes || self->gids[group_index] == def_i32_id_none) @@ -300,8 +300,8 @@ int iamf_renderer_update_animated_gain(iamf_renderer_t* self, uint32_t pid, gain.duration = number; debug( - "display gid %d: gain %d: animation type %d: start %f, end %f, control " - "%f, control_relative_time %f, duration %d", + "display gid %d: gain %u: animation type %d: start %f, end %f, control " + "%f, control_relative_time %f, duration %u", self->gids[group_index], pid, animated_gain.animation_type, animated_gain.data.start, animated_gain.data.end, animated_gain.data.control, animated_gain.data.control_relative_time, @@ -316,7 +316,7 @@ int iamf_renderer_update_animated_gain(iamf_renderer_t* self, uint32_t pid, int iamf_renderer_update_element_animated_polar_positions( iamf_renderer_t* self, uint32_t id, uint32_t pid, animated_polar_t* positions, uint32_t number, uint32_t duration) { - oar_metadata_t metadata; + oar_metadata_t metadata = {0}; if (!self || !self->oar || !positions) return IAMF_ERR_BAD_ARG; if (number == 0) return IAMF_ERR_BAD_ARG; @@ -324,21 +324,24 @@ int iamf_renderer_update_element_animated_polar_positions( metadata.type = ck_metadata_object_positions; metadata.object_positions.param_type = ck_param_animated; metadata.object_positions.position_type = ck_polar; + metadata.object_positions.num_objects = + number < def_max_number_of_objects ? number : def_max_number_of_objects; + metadata.duration = duration; // Count valid positions and copy animated polar positions - uint32_t i = 0; - for (; i < number && i < def_max_number_of_objects; i++) { + for (uint32_t i = 0; i < metadata.object_positions.num_objects; i++) { metadata.object_positions.animated_polar_positions[i] = positions[i]; debug( - "Update animated polar positions for element %u-%u: num_objects=%u, " - "duration=%u, index=%u, azimuth=%f, elevation=%f, distance=%f", - id, pid, metadata.object_positions.num_objects, duration, i, - positions[i].azimuth.start, positions[i].elevation.start, + "Update animated polar positions for element %u-%u: index=%u, " + "azimuth=%f, elevation=%f, distance=%f", + id, pid, i, positions[i].azimuth.start, positions[i].elevation.start, positions[i].distance.start); } - metadata.object_positions.num_objects = i; - metadata.duration = duration; + debug( + "Update animated polar positions for element %u-%u: num_objects=%u, " + "duration=%u", + id, pid, metadata.object_positions.num_objects, metadata.duration); return oar_update_audio_element_metadata(self->oar, id, &metadata) == ck_oar_ok @@ -349,7 +352,7 @@ int iamf_renderer_update_element_animated_polar_positions( int iamf_renderer_update_element_animated_cartesian_positions( iamf_renderer_t* self, uint32_t id, animated_cartesian_t* positions, uint32_t number, uint32_t duration) { - oar_metadata_t metadata; + oar_metadata_t metadata = {0}; if (!self || !self->oar || !positions) return IAMF_ERR_BAD_ARG; if (number == 0) return IAMF_ERR_BAD_ARG; @@ -357,25 +360,24 @@ int iamf_renderer_update_element_animated_cartesian_positions( metadata.type = ck_metadata_object_positions; metadata.object_positions.param_type = ck_param_animated; metadata.object_positions.position_type = ck_cartesian; + metadata.object_positions.num_objects = + number < def_max_number_of_objects ? number : def_max_number_of_objects; + metadata.duration = duration; // Count valid positions and copy animated cartesian positions - uint32_t i = 0; - for (; i < number && i < def_max_number_of_objects; i++) { + for (uint32_t i = 0; i < metadata.object_positions.num_objects; i++) { metadata.object_positions.animated_cartesian_positions[i] = positions[i]; debug( - "Update animated cartesian positions for element %u: index=%u, x=%f," + "Update animated cartesian positions for element %u: index=%u, x=%f, " "y=%f, z=%f", id, i, positions[i].x.start, positions[i].y.start, positions[i].z.start); } - metadata.object_positions.num_objects = i; - - metadata.duration = duration; debug( "Update animated cartesian positions for element %u: num_objects=%u, " "duration=%u", - id, metadata.object_positions.num_objects, duration); + id, metadata.object_positions.num_objects, metadata.duration); return oar_update_audio_element_metadata(self->oar, id, &metadata) == ck_oar_ok @@ -415,7 +417,7 @@ int iamf_renderer_set_head_rotation(iamf_renderer_t* self, if (!self || !quaternion) return IAMF_ERR_BAD_ARG; if (!self->oar) return IAMF_ERR_INTERNAL; - oar_metadata_t metadata; + oar_metadata_t metadata = {0}; metadata.type = ck_metadata_head_rotation; metadata.head_rotation = *quaternion; metadata.duration = 0; diff --git a/code/src/iamf_dec/iamf_string.c b/code/src/iamf_dec/iamf_string.c index d8c96b58..445947ad 100755 --- a/code/src/iamf_dec/iamf_string.c +++ b/code/src/iamf_dec/iamf_string.c @@ -23,13 +23,13 @@ #include "iamf_utils.h" static const char* _g_error_code_strings[] = {"Ok", - "Bad argments", + "Bad arguments", "Buffer too small", "Internal error", "Invalid packet", "Invalid state", "Unimplemented", - "Memory allocation failure" + "Memory allocation failure", "Pending"}; const char* iamf_error_code_string(int errno_) { @@ -75,10 +75,8 @@ const char* iamf_obu_header_flag2_string(iamf_obu_type_t type) { return "optional_fields_flag"; } else if (type == ck_iamf_obu_temporal_delimiter) { return "is_not_key_frame"; - } else if ((type > ck_iamf_obu_temporal_delimiter && - type < ck_iamf_obu_metadata) || - (type >= ck_iamf_obu_audio_frame && - type <= ck_iamf_obu_audio_frame_id17)) { + } else if (type >= ck_iamf_obu_audio_frame && + type <= ck_iamf_obu_audio_frame_id17) { return "obu_trimming_status_flag"; } else { return "reserved"; @@ -178,7 +176,9 @@ static const char* _g_channel_strings[] = { "sr5", "hl", "hr", "wl", "wr", "hsl", "hsr"}; const char* iamf_channel_name(iamf_channel_t ch) { - return ch < ck_iamf_channel_count ? _g_channel_strings[ch] : "none"; + return ch > ck_iamf_channel_none && ch < ck_iamf_channel_count + ? _g_channel_strings[ch] + : "none"; } const char* iamf_layout_string(iamf_layout_t layout) { diff --git a/code/src/iamf_dec/iamf_string.h b/code/src/iamf_dec/iamf_string.h index 6d0b18e5..d03f09c6 100755 --- a/code/src/iamf_dec/iamf_string.h +++ b/code/src/iamf_dec/iamf_string.h @@ -34,7 +34,6 @@ const char *iamf_sound_system_string(iamf_sound_system_t sound_system); const char *iamf_loudspeaker_layout_string(iamf_loudspeaker_layout_t layout); const char *iamf_expanded_loudspeaker_layout_string( iamf_expanded_loudspeaker_layout_t layout); -const char *iamf_layout_type_string(iamf_layout_type_t type); const char *iamf_layout_string(iamf_layout_t layout); const char *iamf_channel_name(iamf_channel_t ch); diff --git a/code/src/iamf_dec/iamf_synchronizer.c b/code/src/iamf_dec/iamf_synchronizer.c index 36a4785e..b4690b9f 100755 --- a/code/src/iamf_dec/iamf_synchronizer.c +++ b/code/src/iamf_dec/iamf_synchronizer.c @@ -34,7 +34,6 @@ typedef struct AudioBlocksCache { uint32_t id; queue_t* audio_blocks; - uint32_t delay; uint32_t skip; } audio_blocks_cache_t; @@ -72,7 +71,6 @@ static audio_blocks_cache_t* audio_blocks_cache_new(uint32_t id) { // Initialize the cache new_cache->id = id; - new_cache->delay = 0; // Default delay // Create queue for audio blocks new_cache->audio_blocks = queue_new(); @@ -109,6 +107,9 @@ static int audio_block_cache_required_data(audio_blocks_cache_t* cache, if (!cblock) { warning("Failed to get audio block from cache for ID %u", cache->id); ret = IAMF_ERR_INTERNAL; + value_wrap_t v; + queue_pop(cache->audio_blocks, &v); + continue; } _offset = cache->skip + cblock->skip + cblock->second_skip; @@ -136,13 +137,8 @@ static int audio_block_cache_required_data(audio_blocks_cache_t* cache, } while (!queue_is_empty(cache->audio_blocks) && needed_samples > 0); - if (ret == IAMF_OK && !needed_samples) { - if (block->skip) cache->delay += block->skip; - if (block->second_skip) cache->delay += block->second_skip; - } - - debug("cache info: ID %u, delay %u, skip %u, blocks %d", cache->id, - cache->delay, cache->skip, queue_length(cache->audio_blocks)); + debug("cache info: ID %u, skip %u, blocks %d", cache->id, cache->skip, + queue_length(cache->audio_blocks)); return ret; } @@ -344,6 +340,7 @@ int iamf_synchronizer_sync_audio_blocks(iamf_synchronizer_t* synchronizer, if (audio_block_cache_required_data(cache, &required_block) != IAMF_OK) { warning("Failed to get required data from cache for ID %u", block->id); + def_free(required_block.data); continue; } diff --git a/code/src/iamf_dec/iamf_utils.c b/code/src/iamf_dec/iamf_utils.c index 81a168b4..f1f1a45e 100755 --- a/code/src/iamf_dec/iamf_utils.c +++ b/code/src/iamf_dec/iamf_utils.c @@ -71,7 +71,7 @@ int bit1_count(uint32_t value) { } static float q16_1xy_float(int16_t q, int frac) { - return ((float)q) * powf(2.0f, (float)-frac); + return ((float)q) / (float)(1 << frac); } float iamf_q15_to_float(int16_t q) { return q16_1xy_float(q, 15); } @@ -81,12 +81,12 @@ float iamf_gain_q78_to_linear(int16_t q78) { } static float iamf_divide_255f(uint8_t val) { return ((float)val / 255.0f); } -float iamf_recon_gain_linear(int8_t gain) { return iamf_divide_255f(gain); } -float iamf_divide_128f(uint8_t val) { return ((float)val / (powf(2.0f, 8.f))); } +float iamf_recon_gain_linear(uint8_t gain) { return iamf_divide_255f(gain); } +float iamf_divide_256f(uint8_t val) { return ((float)val / 256.0f); } float f32_db_to_linear(float db) { return powf(10.0f, 0.05f * db); } -int iamf_ambisionisc_get_order(uint32_t channels) { +int iamf_ambisonics_get_order(uint32_t channels) { if (channels == 1) return 0; if (channels == 4) return 1; if (channels == 9) return 2; @@ -114,21 +114,19 @@ float iamf_fraction_transform_float(fraction_t f, uint32_t dem) { } int16_t iamf_u32_to_i16(uint32_t v, uint32_t num_bits) { + if (num_bits == 0 || num_bits >= 16) return (int16_t)v; int16_t val = (int16_t)v; - if (num_bits >= 16) return val; val <<= (16 - num_bits); val >>= (16 - num_bits); return val; } float iamf_u32_to_f32(uint32_t v, uint32_t bits) { - float val = (float)v; - if (bits) val /= ((1 << bits) - 1); - return val; + if (bits == 0 || bits > 31) return (float)v; + return (float)v / ((1u << bits) - 1); } float iamf_i16_to_f32(int16_t v, uint32_t bits) { - float val = (float)v; - if (bits) val /= ((1 << (bits - 1)) - 1); - return val; + if (bits <= 1 || bits > 31) return (float)v; + return (float)v / ((1 << (bits - 1)) - 1); } diff --git a/code/src/iamf_dec/iamf_utils.h b/code/src/iamf_dec/iamf_utils.h index d5300ccc..2545b62d 100755 --- a/code/src/iamf_dec/iamf_utils.h +++ b/code/src/iamf_dec/iamf_utils.h @@ -17,8 +17,8 @@ * @date Created 03/03/2023 **/ -#ifndef __IAMF_UITLS_H__ -#define __IAMF_UITLS_H__ +#ifndef __IAMF_UTILS_H__ +#define __IAMF_UTILS_H__ #include #include @@ -29,7 +29,7 @@ #include "iamf_types.h" #include "oar_base.h" -iamf_codec_type_t iamf_codec_type_get(uint32_t codec_id); +iamf_codec_type_t iamf_codec_type_get(iamf_codec_id_t codec_id); int iamf_codec_type_check(iamf_codec_type_t cid); int iamf_codec_id_check(iamf_codec_id_t cid); @@ -45,11 +45,11 @@ int bit1_count(uint32_t value); float iamf_q15_to_float(int16_t q); float iamf_gain_q78_to_db(int16_t q78); float iamf_gain_q78_to_linear(int16_t q78); -float iamf_recon_gain_linear(int8_t gain); -float iamf_divide_128f(uint8_t val); +float iamf_recon_gain_linear(uint8_t gain); +float iamf_divide_256f(uint8_t val); float f32_db_to_linear(float db); -int iamf_ambisionisc_get_order(uint32_t channels); +int iamf_ambisonics_get_order(uint32_t channels); int iamf_sound_system_check(iamf_sound_system_t ss); // int iamf_layout_is_equal(iamf_layout_t a, iamf_layout_t b); @@ -60,4 +60,4 @@ int16_t iamf_u32_to_i16(uint32_t v, uint32_t bits); float iamf_u32_to_f32(uint32_t v, uint32_t bits); float iamf_i16_to_f32(int16_t v, uint32_t bits); -#endif /* __IAMF_UITLS_H__ */ +#endif /* __IAMF_UTILS_H__ */ diff --git a/code/src/iamf_dec/obu/animated_parameter.c b/code/src/iamf_dec/obu/animated_parameter.c index ca5070f4..bb8b3cff 100755 --- a/code/src/iamf_dec/obu/animated_parameter.c +++ b/code/src/iamf_dec/obu/animated_parameter.c @@ -19,8 +19,6 @@ #include "animated_parameter.h" -#include - #include "iamf_private_definitions.h" #include "iamf_utils.h" diff --git a/code/src/iamf_dec/obu/animated_parameter.h b/code/src/iamf_dec/obu/animated_parameter.h index b39b1a09..d56c8ca0 100755 --- a/code/src/iamf_dec/obu/animated_parameter.h +++ b/code/src/iamf_dec/obu/animated_parameter.h @@ -80,7 +80,7 @@ int animated_parameter_data_read_bits(bits_io_context_t *bits_r, (dst)->end = convert_func((src)->end, (num_bits)); \ (dst)->control = convert_func((src)->control, (num_bits)); \ (dst)->control_relative_time = \ - iamf_divide_128f((src)->control_relative_time); \ + iamf_divide_256f((src)->control_relative_time); \ } while (0) #endif // __ANIMATED_PARAMETER_H__ diff --git a/code/src/iamf_dec/obu/audio_element_obu.c b/code/src/iamf_dec/obu/audio_element_obu.c index 5a5f5e93..e352f247 100755 --- a/code/src/iamf_dec/obu/audio_element_obu.c +++ b/code/src/iamf_dec/obu/audio_element_obu.c @@ -183,12 +183,13 @@ int _obu_ae_common_init(iamf_audio_element_obu_t *obu, uint32_t id, type = ior_leb128_u32(r); if (type != ck_iamf_parameter_type_demixing && type != ck_iamf_parameter_type_recon_gain) { - uint32_t size = ior_leb128_u32(r); - ior_skip(r, size); - warning( - "Don't support parameter type(%u) in Audio Element OBU(%u), " - "parameter definition bytes %u.", - type, obu->audio_element_id, size); + warning("Don't support parameter type(%u) in Audio Element OBU(%u), ", + type, obu->audio_element_id); + if (type >= (uint32_t)ck_iamf_parameter_type_count) { + uint32_t size = ior_leb128_u32(r); + ior_skip(r, size); + debug("Skip parameter(%u) definition bytes %u.", type, size); + } continue; } @@ -456,6 +457,12 @@ static int _obu_ae_channel_based_check(channel_based_audio_element_obu_t *cae) { obu_channel_layer_config_t *layer_config = def_value_wrap_optional_ptr( array_at(cae->channel_audio_layer_configs, i)); + if (!layer_config) { + warning("Element (%u) Layer %d: layer config is NULL, skip.", + cae->base.audio_element_id, i); + continue; + } + if (cae->max_valid_layers == i) { channels += (layer_config->substream_count + layer_config->coupled_substream_count); @@ -514,7 +521,7 @@ static int _obu_ae_scene_based_check(scene_based_audio_element_obu_t *sae) { warning("Scene based audio element(%u) has parameter.", sae->base.audio_element_id); - if (iamf_ambisionisc_get_order(sae->output_channel_count) < 0 || + if (iamf_ambisonics_get_order(sae->output_channel_count) < 0 || sae->output_channel_count < channels) { warning( "Invalid output channel count %d or invalid input channels %d in " diff --git a/code/src/iamf_dec/obu/codec_config_obu.c b/code/src/iamf_dec/obu/codec_config_obu.c index bae3a06b..4f73f433 100755 --- a/code/src/iamf_dec/obu/codec_config_obu.c +++ b/code/src/iamf_dec/obu/codec_config_obu.c @@ -113,7 +113,7 @@ static int _obu_cc_codec_id_check(uint32_t codec_id) { #define def_opus_version_max 15 static int _obu_cc_decoder_config_check(uint32_t codec, buffer_wrap_t *buffer) { if (iamf_codec_type_get(codec) == ck_iamf_codec_type_opus) { - if (buffer && buffer->data[0] > def_opus_version_max) { + if (buffer && buffer->data && buffer->data[0] > def_opus_version_max) { warning("Opus config invalid: version %u should less than %u.", buffer->data[0], def_opus_version_max); return def_error; diff --git a/code/src/iamf_dec/obu/ia_sequence_header_obu.c b/code/src/iamf_dec/obu/ia_sequence_header_obu.c index 56219221..21e7a1a2 100755 --- a/code/src/iamf_dec/obu/ia_sequence_header_obu.c +++ b/code/src/iamf_dec/obu/ia_sequence_header_obu.c @@ -63,11 +63,11 @@ iamf_sequence_header_obu_t *iamf_sequence_header_obu_new(io_context_t *ioc) { } void iamf_sequence_header_obu_free(iamf_sequence_header_obu_t *obu) { - free(obu); + def_free(obu); } -static int _obu_sh_valid_profile(uint8_t primary, uint8_t addional) { - return primary < def_iamf_profile_count && primary <= addional; +static int _obu_sh_valid_profile(uint8_t primary, uint8_t additional) { + return primary < def_iamf_profile_count && primary <= additional; } int _obu_sh_check(iamf_sequence_header_obu_t *obu) { diff --git a/code/src/iamf_dec/obu/iamf_obu.c b/code/src/iamf_dec/obu/iamf_obu.c index b05677c0..526a2cc4 100755 --- a/code/src/iamf_dec/obu/iamf_obu.c +++ b/code/src/iamf_dec/obu/iamf_obu.c @@ -127,7 +127,7 @@ static int _iamf_obu_raw_parse_body(io_context_t *ior, if (header->obu_type >= ck_iamf_obu_audio_frame && header->obu_type <= ck_iamf_obu_audio_frame_id17) { *obu = (iamf_obu_t *)iamf_audio_frame_obu_new(ior, header); - } else if (header->obu_type != ck_iamf_obu_temporal_delimiter) { + } else { warning("Reserved OBU type %u", header->obu_type); } break; diff --git a/code/src/iamf_dec/obu/metadata_obu.c b/code/src/iamf_dec/obu/metadata_obu.c index db62ac9b..9ea08fe5 100755 --- a/code/src/iamf_dec/obu/metadata_obu.c +++ b/code/src/iamf_dec/obu/metadata_obu.c @@ -170,7 +170,7 @@ iamf_metadata_obu_t *iamf_metadata_obu_new(io_context_t *ior) { } #if SUPPORT_VERIFIER - vlog_obu(ck_iamf_obu_metadata, obu, 0, 0); + if (obu) vlog_obu(ck_iamf_obu_metadata, obu, 0, 0); #endif return obu; diff --git a/code/src/iamf_dec/obu/mix_presentation_obu.c b/code/src/iamf_dec/obu/mix_presentation_obu.c index 8b1a2816..e10f2d7e 100755 --- a/code/src/iamf_dec/obu/mix_presentation_obu.c +++ b/code/src/iamf_dec/obu/mix_presentation_obu.c @@ -713,9 +713,9 @@ int _obu_mp_check(iamf_mix_presentation_obu_t *obu) { return def_error; } - for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { obu_audio_element_config_t *aelem_config = - def_value_wrap_optional_ptr(array_at(sub->audio_element_configs, i)); + def_value_wrap_optional_ptr(array_at(sub->audio_element_configs, j)); if (aelem_config->rendering_config.headphones_rendering_mode > HEADPHONES_RENDERING_MODE_HEAD_LOCKED) { @@ -729,9 +729,9 @@ int _obu_mp_check(iamf_mix_presentation_obu_t *obu) { } n = array_size(sub->loudness_layouts); - for (int i = 0; i < n; ++i) { + for (int j = 0; j < n; ++j) { iamf_layout_t *layout = - def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, i)); + def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, j)); if (layout->type == ck_iamf_layout_type_loudspeakers_ss_convention && !iamf_sound_system_check(layout->sound_system)) { warning("Find unsupported sound system %d in mix presentation %u.", diff --git a/code/src/iamf_dec/obu/parameter_base.c b/code/src/iamf_dec/obu/parameter_base.c index 8b6c1659..90ca3053 100755 --- a/code/src/iamf_dec/obu/parameter_base.c +++ b/code/src/iamf_dec/obu/parameter_base.c @@ -409,5 +409,8 @@ momentary_loudness_parameter_base_t *_obu_pb_momentary_loudness_new( } void _obu_pb_clear(parameter_base_t *param) { - if (param->subblock_durations) array_free(param->subblock_durations, 0); + if (param->subblock_durations) { + array_free(param->subblock_durations, 0); + param->subblock_durations = 0; + } } diff --git a/code/src/iamf_dec/obu/parameter_block_obu.c b/code/src/iamf_dec/obu/parameter_block_obu.c index c876473b..b415a02a 100755 --- a/code/src/iamf_dec/obu/parameter_block_obu.c +++ b/code/src/iamf_dec/obu/parameter_block_obu.c @@ -188,7 +188,7 @@ static int _obu_pb_animated_parameter_gain_db(animated_float32_t *dst, dst->data.control = iamf_gain_q78_to_db(iamf_u32_to_i16(src->data.control, def_q78_num_bits)); dst->data.control_relative_time = - iamf_divide_128f(src->data.control_relative_time); + iamf_divide_256f(src->data.control_relative_time); return IAMF_OK; } diff --git a/code/src/iamf_dec/obu/temporal_delimiter_obu.c b/code/src/iamf_dec/obu/temporal_delimiter_obu.c index 384c20b5..f6e1c3bb 100755 --- a/code/src/iamf_dec/obu/temporal_delimiter_obu.c +++ b/code/src/iamf_dec/obu/temporal_delimiter_obu.c @@ -20,7 +20,6 @@ #include "temporal_delimiter_obu.h" #include "iamf_private_definitions.h" -#include "iamf_string.h" #undef def_log_tag #define def_log_tag "OBU_TD" From 8c19fd02e5793f82b60fdabf2231d36f623f2cc7 Mon Sep 17 00:00:00 2001 From: "yilun.zhang" Date: Wed, 5 Aug 2026 16:58:18 +0800 Subject: [PATCH 2/2] Fix safety bugs in IAMF decoder source 1. Add NULL check to get_rendering_channels() for symmetry with get_decoding_channels() 2. Fix signedness bug in _get_new_channels() causing out-of-bounds access 3. Add idx < 0 guard in base_advanced profile check branch --- code/src/iamf_dec/iamf_database.c | 10 +++++++--- code/src/iamf_dec/iamf_element_reconstructor.c | 13 ++++++++----- code/src/iamf_dec/iamf_layout.c | 1 + code/src/iamf_dec/iamf_string.c | 7 +++---- 4 files changed, 19 insertions(+), 12 deletions(-) diff --git a/code/src/iamf_dec/iamf_database.c b/code/src/iamf_dec/iamf_database.c index 41f5ec42..c3c821bb 100755 --- a/code/src/iamf_dec/iamf_database.c +++ b/code/src/iamf_dec/iamf_database.c @@ -627,9 +627,13 @@ static int _iadb_descriptors_mix_presentation_obu_check_profile( int idx = vector_find(descriptors->audio_element_obus, def_value_wrap_instance_u32(aec->element_id), _iadb_audio_element_obu_find, &v); - iamf_audio_element_obu_t *aeo = def_value_wrap_type_ptr( - iamf_audio_element_obu_t, - vector_at(descriptors->audio_element_obus, idx)); + if (idx < 0) { + warning("Audio element %u not found for Mix Presentation %u.", + aec->element_id, mpo->mix_presentation_id); + continue; + } + iamf_audio_element_obu_t *aeo = + def_value_wrap_type_ptr(iamf_audio_element_obu_t, &v); if (aeo->audio_element_type == ck_audio_element_type_object_based) element_flags |= 1; else diff --git a/code/src/iamf_dec/iamf_element_reconstructor.c b/code/src/iamf_dec/iamf_element_reconstructor.c index 7f0f452a..58d53583 100755 --- a/code/src/iamf_dec/iamf_element_reconstructor.c +++ b/code/src/iamf_dec/iamf_element_reconstructor.c @@ -241,7 +241,7 @@ static void _reconstructor_delete_all_audio_frame_obus( static int _get_new_channels(iamf_loudspeaker_layout_t last, iamf_loudspeaker_layout_t cur, iamf_channel_t* new_chs, uint32_t count) { - uint32_t chs = 0; + int chs = 0; /** * In ChannelGroup for Channel audio: The order conforms to following rules: @@ -260,6 +260,7 @@ static int _get_new_channels(iamf_loudspeaker_layout_t last, if (last == ck_iamf_loudspeaker_layout_none) { chs = iamf_loudspeaker_layout_get_decoding_channels(cur, new_chs, count); + if (chs < 0) return chs; } else if (iamf_audio_layer_base_layout_check(last) && iamf_audio_layer_base_layout_check(cur)) { const iamf_layout_info_t* info1 = iamf_loudspeaker_layout_get_info(last); @@ -311,10 +312,10 @@ static int _get_new_channels(iamf_loudspeaker_layout_t last, } } - if (chs > count) { + if (chs > (int)count) { error("too much new channels %d, we only need less than %d channels", chs, count); - chs = IAMF_ERR_BUFFER_TOO_SMALL; + return IAMF_ERR_BUFFER_TOO_SMALL; } return chs; } @@ -326,8 +327,10 @@ static int _get_target_layout_channels_order(channel_based_reconstructor_t* cbr, for (int i = 0; i <= cbr->target_layout_index; ++i) { if (i) type = cbr->group_infos[i - 1].layout; - chs += _get_new_channels(type, cbr->group_infos[i].layout, &order[chs], - max - chs); + int ret = _get_new_channels(type, cbr->group_infos[i].layout, &order[chs], + max - chs); + if (ret < 0) return ret; + chs += ret; } return chs; } diff --git a/code/src/iamf_dec/iamf_layout.c b/code/src/iamf_dec/iamf_layout.c index 8d4023e1..d3f360bc 100755 --- a/code/src/iamf_dec/iamf_layout.c +++ b/code/src/iamf_dec/iamf_layout.c @@ -510,6 +510,7 @@ int iamf_loudspeaker_layout_get_decoding_channels( int iamf_loudspeaker_layout_get_rendering_channels( iamf_loudspeaker_layout_t type, iamf_channel_t *channels, uint32_t count) { const iamf_layout_info_t *info = iamf_loudspeaker_layout_get_info(type); + if (!info) return IAMF_ERR_BAD_ARG; if (count < info->channels) return IAMF_ERR_BUFFER_TOO_SMALL; for (uint32_t i = 0; i < info->channels; ++i) channels[i] = info->channel_layout[i]; diff --git a/code/src/iamf_dec/iamf_string.c b/code/src/iamf_dec/iamf_string.c index 445947ad..9ff05fea 100755 --- a/code/src/iamf_dec/iamf_string.c +++ b/code/src/iamf_dec/iamf_string.c @@ -170,10 +170,9 @@ const char* iamf_expanded_loudspeaker_layout_string( } static const char* _g_channel_strings[] = { - "none", "l7/l5/l", "r7/r5/r", "c", "lfe", "sl7/sl", "sr7/sr", - "bl7/bl", "br7/br", "hfl", "hfr", "hbl", "hbr", "mono", - "l2", "r2", "tl", "tr", "l3", "r3", "sl5", - "sr5", "hl", "hr", "wl", "wr", "hsl", "hsr"}; + "none", "l7/l5/l", "r7/r5/r", "c", "lfe", "sl7/sl", "sr7/sr", "bl7/bl", + "br7/br", "hfl", "hfr", "hbl", "hbr", "mono", "l2", "r2", + "tl", "tr", "l3", "r3", "sl5", "sr5", "hl", "hr"}; const char* iamf_channel_name(iamf_channel_t ch) { return ch > ck_iamf_channel_none && ch < ck_iamf_channel_count