Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions code/include/IAMF_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -253,13 +253,29 @@ int IAMF_layout_binaural_channels_count(void);
char *IAMF_decoder_get_codec_capability(void);

/**
* @brief Set target normalization loudness value, then loudness will be
* adjusted to the setting target.
* @param [in] handle : iamf decoder handle.
* @param [in] loundness : target normalization loudness in LKFS.
* 0 dose not do normalization,
* others(<0) target value of normalization.
* @return @ref IAErrCode.
* @brief Set loudness normalization target for IAMF decoder
*
* This function configures the target loudness for loudness normalization
* according to EBU R128 standard. Normalization ensures consistent loudness
* across different audio sources.
*
* @param [in] handle : IAMF decoder handle
* @param [in] loudness : Target loudness in dB (LKFS):
* - loudness = 0.0f: DISABLE loudness normalization (use original loudness)
* - loudness < 0: Enable normalization to target loudness
* * Common values: -23.0 (EBU R128), -24.0 (ATSC A/85)
* * Example: -16.0 (YouTube), -14.0 (Spotify)
* - loudness > 0: INVALID (returns IAMF_ERR_BAD_ARG)
*
* @return @ref IAErrCode. IAMF_OK on success, error code on failure.
*
* @note IMPORTANT: loudness = 0.0f is a SPECIAL FLAG to disable normalization.
* It does NOT mean normalize to 0 dB (which would be digital full scale).
* To disable normalization, explicitly set loudness = 0.0f.
*
* @note Normalization is only applied if the presentation is active.
*
* @see EBU R128 Technical Recommendation EBU - TECH 3344
*/
int IAMF_decoder_set_normalization_loudness(IAMF_DecoderHandle handle,
float loudness);
Expand Down
9 changes: 0 additions & 9 deletions code/src/iamf_dec/iamf_audio_block.c
Original file line number Diff line number Diff line change
Expand Up @@ -358,15 +358,6 @@ int iamf_audio_block_trim(iamf_audio_block_t* block) {
return 0;
}

int iamf_audio_block_gain(iamf_audio_block_t* block, float gain) {
if (!block) return -22;
if (gain == def_default_loudness_gain) return 0;
int num_samples = block->num_channels * block->num_samples_per_channel;

for (int i = 0; i < num_samples; ++i) block->data[i] *= gain;
return 0;
}

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 -
Expand Down
1 change: 0 additions & 1 deletion code/src/iamf_dec/iamf_audio_block.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,6 @@ int iamf_audio_block_partial_copy_data(iamf_audio_block_t* dst,
iamf_audio_block_t* iamf_audio_block_samples_concat(
iamf_audio_block_t* blocks[], uint32_t n);
int iamf_audio_block_trim(iamf_audio_block_t* block);
int iamf_audio_block_gain(iamf_audio_block_t* block, float gain);
uint32_t iamf_audio_block_available_samples(iamf_audio_block_t* block);

#endif //__IAMF_AUDIO_BLOCK_H__
90 changes: 13 additions & 77 deletions code/src/iamf_dec/iamf_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -148,65 +148,6 @@ static sample_format_t _get_sample_format(uint32_t bit_depth, int interleaved) {
return ck_sample_format_i16_interleaved;
}

static float iamf_mix_presentation_get_best_loudness(
iamf_mix_presentation_obu_t *obj, iamf_layout_t *layout) {
obu_sub_mix_t *sub;
float loudness_lkfs = def_default_loudness_lkfs;
iamf_layout_t highest_layout =
def_sound_system_layout_instance(SOUND_SYSTEM_NONE);

int num_sub_mixes = array_size(obj->sub_mixes);

for (int sub_idx = 0; sub_idx < num_sub_mixes; ++sub_idx) {
sub = def_value_wrap_optional_ptr(array_at(obj->sub_mixes, sub_idx));
if (!sub) continue;

int n = array_size(sub->loudness_layouts);
if (n <= 0) continue;

for (int i = 0; i < n; ++i) {
iamf_layout_t *loudness_layout =
def_value_wrap_optional_ptr(array_at(sub->loudness_layouts, i));
if (!loudness_layout) continue;

if (iamf_layout_is_equal(*layout, *loudness_layout)) {
obu_loudness_info_t *li =
def_value_wrap_optional_ptr(array_at(sub->loudness, i));
if (li) {
loudness_lkfs =
iamf_gain_q78_to_db(def_lsb_16bits(li->integrated_loudness));
info(
"selected loudness %f db from exact match layout in sub_mix[%d] "
"<- 0x%x",
loudness_lkfs, sub_idx, def_lsb_16bits(li->integrated_loudness));
return loudness_lkfs;
}
}

if (iamf_layout_is_equal(highest_layout, def_sound_system_layout_instance(
SOUND_SYSTEM_NONE)) ||
iamf_layout_higher_check(*loudness_layout, highest_layout, 1)) {
obu_loudness_info_t *li =
def_value_wrap_optional_ptr(array_at(sub->loudness, i));
if (li) {
highest_layout = *loudness_layout;
loudness_lkfs =
iamf_gain_q78_to_db(def_lsb_16bits(li->integrated_loudness));
debug(
"selected loudness %f db from highest layout in sub_mix[%d] <- "
"0x%x",
loudness_lkfs, sub_idx, def_lsb_16bits(li->integrated_loudness));
}
}
}
}

debug("selected loudness %f db from highest layout %s", loudness_lkfs,
iamf_layout_string(highest_layout));

return loudness_lkfs;
}

static int iamf_decoder_priv_decode(iamf_decoder_t *self, const uint8_t *data,
int32_t size, uint32_t *rsize, void *pcm) {
iamf_decoder_context_t *ctx = &self->ctx;
Expand Down Expand Up @@ -538,7 +479,6 @@ int iamf_decoder_priv_configure(iamf_decoder_t *self, const uint8_t *data,
ctx->head_tracking_enabled);
}

// Set element gain offset to presentation.
if (ctx->element_gains && hash_map_size(ctx->element_gains) > 0) {
hash_map_iterator_t *iter = hash_map_iterator_new(ctx->element_gains);
if (iter) {
Expand All @@ -563,15 +503,12 @@ int iamf_decoder_priv_configure(iamf_decoder_t *self, const uint8_t *data,
} while (!hash_map_iterator_next(iter));
hash_map_iterator_delete(iter);
}
// Clear element gains after applying to presentation
hash_map_delete(ctx->element_gains, 0);
ctx->element_gains = 0;
info("Cleared element gains after applying to presentation %u",
mpo->mix_presentation_id);
}

// Check if the sampling rate of the stream in presentation matches the
// configured sampling rate
int in_sampling_rate =
iamf_presentation_get_sampling_rate(self->presentation);
if (in_sampling_rate == ctx->sampling_rate) {
Expand All @@ -589,14 +526,8 @@ int iamf_decoder_priv_configure(iamf_decoder_t *self, const uint8_t *data,
ret = iamf_decoder_priv_update_frame_info(self);
if (ret == IAMF_OK) {
self->ctx.status = ck_iamf_decoder_status_parse_2;
self->ctx.loudness_lkfs =
iamf_mix_presentation_get_best_loudness(mpo, &self->ctx.layout);
if (self->ctx.normalized_loudness_lkfs != def_default_loudness_lkfs) {
iamf_presentation_set_loudness_gain(
self->presentation,
f32_db_to_linear(self->ctx.normalized_loudness_lkfs -
self->ctx.loudness_lkfs));
}
iamf_presentation_set_loudness(self->presentation,
self->ctx.normalized_loudness_lkfs);
}
}
} else {
Expand Down Expand Up @@ -818,7 +749,6 @@ IAMF_DecoderHandle IAMF_decoder_open(void) {

ctx->sampling_rate = def_default_sampling_rate;
ctx->mix_presentation_id = def_i64_id_none;
ctx->loudness_lkfs = def_default_loudness_lkfs;
ctx->normalized_loudness_lkfs = def_default_loudness_lkfs;
ctx->limiter_threshold_db = def_limiter_max_true_peak;
ctx->enable_limiter = 1;
Expand Down Expand Up @@ -1046,13 +976,19 @@ int IAMF_decoder_set_normalization_loudness(IAMF_DecoderHandle handle,
float loudness) {
iamf_decoder_t *self = (iamf_decoder_t *)handle;
if (!self) return IAMF_ERR_BAD_ARG;

if (loudness > 0) {
error("Invalid loudness value: %.2f dB. Loudness must be 0 or negative.",
loudness);
return IAMF_ERR_BAD_ARG;
}

if (self->ctx.normalized_loudness_lkfs != loudness) {
self->ctx.normalized_loudness_lkfs = loudness;
if (self->ctx.status > ck_iamf_decoder_status_configure) {
iamf_presentation_set_loudness_gain(
self->presentation,
f32_db_to_linear(self->ctx.normalized_loudness_lkfs -
self->ctx.loudness_lkfs));

if (self->ctx.status > ck_iamf_decoder_status_configure &&
self->presentation) {
iamf_presentation_set_loudness(self->presentation, loudness);
}
}
return IAMF_OK;
Expand Down
1 change: 0 additions & 1 deletion code/src/iamf_dec/iamf_decoder_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ struct IAMF_DecoderContext {

hash_map_t *element_gains;

float loudness_lkfs;
float normalized_loudness_lkfs;
float limiter_threshold_db;
int enable_limiter;
Expand Down
Loading
Loading