diff --git a/code/include/IAMF_decoder.h b/code/include/IAMF_decoder.h index 8a5b443b..0d8d4997 100755 --- a/code/include/IAMF_decoder.h +++ b/code/include/IAMF_decoder.h @@ -78,7 +78,22 @@ typedef struct IamfMixPresentationInfo { iamf_element_presentation_info_t *elements; } iamf_mix_presentation_info_t; -#define IAMF_MAX_CODECS 2 +/** + * @brief Audio element detailed information structure + * + * This structure contains detailed information for each audio element, + * including element type, codec ID, layout information and channel count. + */ +typedef struct IamfAudioElementInfo { + uint32_t element_id; /**< Audio element ID */ + IAMF_CodecID codec_id; /**< Codec ID */ + IAMF_AudioElementType element_type; /**< Audio element type */ + + // Layout information - unified field + IAChannelLayoutType channel_layout; /**< Channel layout type */ + + uint32_t num_channels; /**< Number of channels */ +} iamf_audio_element_info_t; /** * @brief IAMF stream information structure. @@ -95,11 +110,15 @@ typedef struct IAMF_StreamInfo { IA_Profile primary_profile; /**< Primary IAMF profile */ IA_Profile additional_profile; /**< Additional IAMF profile */ - IAMF_CodecID codec_ids[IAMF_MAX_CODECS]; IAMF_SamplingRate sampling_rate; /**< Output sampling rate */ /**< Number of samples per channel per frame */ uint32_t samples_per_channel_in_frame; + /**< Number of audio elements */ + uint32_t audio_element_count; + /**< Array of audio element detailed information */ + iamf_audio_element_info_t *audio_elements; + /**< Number of available mix presentations */ uint32_t mix_presentation_count; /**< Array of mix presentation information */ diff --git a/code/include/IAMF_defines.h b/code/include/IAMF_defines.h index eb8a62ee..817c12ee 100755 --- a/code/include/IAMF_defines.h +++ b/code/include/IAMF_defines.h @@ -119,7 +119,6 @@ typedef enum IAMF_LoudspeakerLayoutType { IA_CHANNEL_LAYOUT_BINAURAL, // binaural IA_CHANNEL_LAYOUT_COUNT, - // expanded layout for version 1.1. /// @brief The low-frequency effects subset (LFE) of 7.1.4ch IA_CHANNEL_LAYOUT_EXPANDED_LFE = 0x10, /// @brief The surround subset (Ls/Rs) of 5.1.4ch diff --git a/code/src/iamf_dec/iamf_decoder.c b/code/src/iamf_dec/iamf_decoder.c index f809be10..f57c6a1b 100755 --- a/code/src/iamf_dec/iamf_decoder.c +++ b/code/src/iamf_dec/iamf_decoder.c @@ -1047,8 +1047,8 @@ int IAMF_decoder_set_sampling_rate(IAMF_DecoderHandle handle, uint32_t rate) { if (!self) return IAMF_ERR_BAD_ARG; - for (int i = 0; - i < sizeof(valid_sampling_rates) / sizeof(IAMF_SamplingRate); ++i) { + for (int i = 0; i < sizeof(valid_sampling_rates) / sizeof(IAMF_SamplingRate); + ++i) { if (rate == valid_sampling_rates[i]) { if (rate != self->ctx.sampling_rate) self->ctx.sampling_rate = rate; ret = IAMF_OK; @@ -1209,27 +1209,152 @@ IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { codec_config_t *db_codec_config = def_value_wrap_type_ptr( codec_config_t, vector_at(database->codec_configs, 0)); - info->iamf_stream_info.codec_ids[0] = - def_iamf_codec_id_cast(db_codec_config->codec_param.type); - info->iamf_stream_info.codec_ids[1] = - def_iamf_codec_id_cast(ck_iamf_codec_type_none); info->iamf_stream_info.sampling_rate = db_codec_config->codec_param.sample_rate; info->iamf_stream_info.samples_per_channel_in_frame = db_codec_config->codec_param.frame_size; + // Check if any audio element uses Opus codec to set the sampling rate int num_codec_configs = vector_size(database->codec_configs); - if (num_codec_configs > 1) { + for (int i = 0; i < num_codec_configs; i++) { db_codec_config = def_value_wrap_type_ptr( - codec_config_t, vector_at(database->codec_configs, 1)); - info->iamf_stream_info.codec_ids[1] = db_codec_config->codec_param.type; + codec_config_t, vector_at(database->codec_configs, i)); + if (db_codec_config && + def_iamf_codec_id_cast(db_codec_config->codec_param.type) == + IAMF_CODEC_OPUS) { + info->iamf_stream_info.sampling_rate = SAMPLING_RATE_48000; + break; + } } - if (info->iamf_stream_info.codec_ids[0] == - def_iamf_codec_id_cast(ck_iamf_codec_type_opus) || - info->iamf_stream_info.codec_ids[1] == - def_iamf_codec_id_cast(ck_iamf_codec_type_opus)) - info->iamf_stream_info.sampling_rate = SAMPLING_RATE_48000; + // Get the total number of audio elements directly from the database + info->iamf_stream_info.audio_element_count = + vector_size(database->audio_elements); + + // Allocate and fill audio element information array directly from database + if (info->iamf_stream_info.audio_element_count > 0) { + info->iamf_stream_info.audio_elements = def_mallocz( + iamf_audio_element_info_t, info->iamf_stream_info.audio_element_count); + + if (info->iamf_stream_info.audio_elements) { + // Fill audio element information directly from database + for (int i = 0; i < info->iamf_stream_info.audio_element_count; ++i) { + audio_element_t *audio_element = def_value_wrap_type_ptr( + audio_element_t, vector_at(database->audio_elements, i)); + + if (audio_element && audio_element->audio_element_obu) { + // Fill basic information + info->iamf_stream_info.audio_elements[i].element_id = + audio_element->id; + info->iamf_stream_info.audio_elements[i].element_type = + (IAMF_AudioElementType) + audio_element->audio_element_obu->audio_element_type; + + // Set codec ID + if (audio_element->codec_config) { + info->iamf_stream_info.audio_elements[i].codec_id = + def_iamf_codec_id_cast( + audio_element->codec_config->codec_param.type); + } else { + info->iamf_stream_info.audio_elements[i].codec_id = + IAMF_CODEC_UNKNOWN; + } + + // Fill channel layout based on element type + switch (audio_element->audio_element_obu->audio_element_type) { + case ck_audio_element_type_channel_based: { + channel_based_audio_element_obu_t *channel_element = + def_channel_based_audio_element_obu_ptr( + audio_element->audio_element_obu); + + if (channel_element && + array_size(channel_element->channel_audio_layer_configs) > + 0) { + obu_channel_layer_config_t *layer_config = + def_value_wrap_optional_ptr( + array_at(channel_element->channel_audio_layer_configs, + channel_element->max_valid_layers - 1)); + + if (layer_config) { + iamf_loudspeaker_layout_t correct_layout = + iamf_audio_layer_layout_get( + layer_config->loudspeaker_layout, + layer_config->expanded_loudspeaker_layout); + + // Set channel layout directly using type conversion + info->iamf_stream_info.audio_elements[i].channel_layout = + (IAChannelLayoutType)correct_layout; + + // Try to get channel count from layout info + const iamf_layout_info_t *layout_info = + iamf_loudspeaker_layout_get_info(correct_layout); + + if (layout_info) { + // Use the exact channel count from layout info + info->iamf_stream_info.audio_elements[i].num_channels = + layout_info->channels; + } else { + // Fallback: accumulate channels from all valid layers + info->iamf_stream_info.audio_elements[i].num_channels = 0; + + for (int layer_idx = 0; + layer_idx < channel_element->max_valid_layers; + ++layer_idx) { + obu_channel_layer_config_t *current_layer = + def_value_wrap_optional_ptr(array_at( + channel_element->channel_audio_layer_configs, + layer_idx)); + + if (current_layer) { + info->iamf_stream_info.audio_elements[i].num_channels += + current_layer->substream_count + + current_layer->coupled_substream_count; + } + } + } + } + } + break; + } + + case ck_audio_element_type_scene_based: { + scene_based_audio_element_obu_t *scene_element = + def_scene_based_audio_element_obu_ptr( + audio_element->audio_element_obu); + + if (scene_element) { + // Set default channel layout + info->iamf_stream_info.audio_elements[i].channel_layout = + IA_CHANNEL_LAYOUT_NONE; + + // Set number of channels + info->iamf_stream_info.audio_elements[i].num_channels = + scene_element->output_channel_count; + } + break; + } + + case ck_audio_element_type_object_based: { + object_based_audio_element_obu_t *object_element = + def_object_based_audio_element_obu_ptr( + audio_element->audio_element_obu); + + if (object_element) { + // Set default channel layout + info->iamf_stream_info.audio_elements[i].channel_layout = + IA_CHANNEL_LAYOUT_NONE; + + // Set number of objects as channel count + info->iamf_stream_info.audio_elements[i].num_channels = + object_element->num_objects; + } + break; + } + } + } + } + } + } info->iamf_stream_info.mix_presentation_count = vector_size(database->descriptors.mix_presentation_obus); @@ -1345,6 +1470,12 @@ IAMF_StreamInfo *IAMF_decoder_get_stream_info(IAMF_DecoderHandle handle) { void IAMF_decoder_free_stream_info(iamf_stream_info_t *info) { if (!info) return; + // Free audio element array + if (info->iamf_stream_info.audio_elements) { + def_free(info->iamf_stream_info.audio_elements); + } + + // Free mix presentation information if (info->iamf_stream_info.mix_presentations) { for (uint32_t i = 0; i < info->iamf_stream_info.mix_presentation_count; ++i) { diff --git a/code/src/iamf_dec/iamf_utils.h b/code/src/iamf_dec/iamf_utils.h index 540f38f6..d5300ccc 100755 --- a/code/src/iamf_dec/iamf_utils.h +++ b/code/src/iamf_dec/iamf_utils.h @@ -36,8 +36,6 @@ int iamf_codec_id_check(iamf_codec_id_t cid); int iamf_audio_layer_base_layout_check(iamf_loudspeaker_layout_t type); int iamf_audio_layer_expanded_layout_check( iamf_expanded_loudspeaker_layout_t type); -iamf_expanded_loudspeaker_layout_t iamf_audio_layer_expanded_layout_get( - iamf_loudspeaker_layout_t type); iamf_loudspeaker_layout_t iamf_audio_layer_layout_get( iamf_loudspeaker_layout_t base, iamf_expanded_loudspeaker_layout_t expanded); diff --git a/code/test/tools/iamfdec/src/test_iamfdec.c b/code/test/tools/iamfdec/src/test_iamfdec.c index 955ca0bc..12b47009 100755 --- a/code/test/tools/iamfdec/src/test_iamfdec.c +++ b/code/test/tools/iamfdec/src/test_iamfdec.c @@ -570,6 +570,92 @@ static const char *binaural_filter_profile_string( } } +static const char *element_type_string(IAMF_AudioElementType element_type) { + switch (element_type) { + case AUDIO_ELEMENT_CHANNEL_BASED: + return "CHANNEL_BASED"; + case AUDIO_ELEMENT_SCENE_BASED: + return "SCENE_BASED"; + case AUDIO_ELEMENT_OBJECT_BASED: + return "OBJECT_BASED"; + default: + return "UNKNOWN"; + } +} + +static const char *channel_layout_string(IAChannelLayoutType channel_layout) { + switch (channel_layout) { + // Basic layouts + case IA_CHANNEL_LAYOUT_MONO: + return "MONO (1.0.0)"; + case IA_CHANNEL_LAYOUT_STEREO: + return "STEREO (2.0.0)"; + case IA_CHANNEL_LAYOUT_510: + return "5.1.0"; + case IA_CHANNEL_LAYOUT_512: + return "5.1.2"; + case IA_CHANNEL_LAYOUT_514: + return "5.1.4"; + case IA_CHANNEL_LAYOUT_710: + return "7.1.0"; + case IA_CHANNEL_LAYOUT_712: + return "7.1.2"; + case IA_CHANNEL_LAYOUT_714: + return "7.1.4"; + case IA_CHANNEL_LAYOUT_312: + return "3.1.2"; + case IA_CHANNEL_LAYOUT_BINAURAL: + return "BINAURAL"; + case IA_CHANNEL_LAYOUT_NONE: + return "NONE"; + + // Expanded layouts + case IA_CHANNEL_LAYOUT_EXPANDED_LFE: + return "EXPANDED_LFE"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_S: + return "EXPANDED_STEREO_S"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_SS: + return "EXPANDED_STEREO_SS"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_RS: + return "EXPANDED_STEREO_RS"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TF: + return "EXPANDED_STEREO_TF"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TB: + return "EXPANDED_STEREO_TB"; + case IA_CHANNEL_LAYOUT_EXPANDED_TOP_4CH: + return "EXPANDED_TOP_4CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_3CH: + return "EXPANDED_3CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_916: + return "EXPANDED_916 (9.1.6)"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_F: + return "EXPANDED_STEREO_F"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_SI: + return "EXPANDED_STEREO_SI"; + case IA_CHANNEL_LAYOUT_EXPANDED_STEREO_TPSI: + return "EXPANDED_STEREO_TPSI"; + case IA_CHANNEL_LAYOUT_EXPANDED_TOP_6CH: + return "EXPANDED_TOP_6CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_A293: + return "EXPANDED_A293"; + case IA_CHANNEL_LAYOUT_EXPANDED_LFE_PAIR: + return "EXPANDED_LFE_PAIR"; + case IA_CHANNEL_LAYOUT_EXPANDED_BOTTOM_3CH: + return "EXPANDED_BOTTOM_3CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_7154: + return "EXPANDED_7154"; + case IA_CHANNEL_LAYOUT_EXPANDED_BOTTOM_4CH: + return "EXPANDED_BOTTOM_4CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_TOP_1CH: + return "EXPANDED_TOP_1CH"; + case IA_CHANNEL_LAYOUT_EXPANDED_TOP_5CH: + return "EXPANDED_TOP_5CH"; + + default: + return "UNKNOWN"; + } +} + void iamf_decoder_output_info(IAMF_DecoderHandle handle, decoder_args_t *das, IAMF_StreamInfo *stream_info) { if (!handle) { @@ -645,20 +731,33 @@ static void print_complete_stream_info(IAMF_StreamInfo *info) { info->iamf_stream_info.additional_profile, profile_string(info->iamf_stream_info.additional_profile)); - fprintf(stdout, "\n--- Codec Information ---\n"); - for (int i = 0; - i < IAMF_MAX_CODECS && info->iamf_stream_info.codec_ids[i] != 0; i++) { - fprintf(stdout, "Codec %d: %d (%s)\n", i, - info->iamf_stream_info.codec_ids[i], - codec_string(info->iamf_stream_info.codec_ids[i])); - } - fprintf(stdout, "\n--- Audio Parameters ---\n"); fprintf(stdout, "Sampling rate: %u Hz\n", info->iamf_stream_info.sampling_rate); fprintf(stdout, "Samples per channel per frame: %u\n", info->iamf_stream_info.samples_per_channel_in_frame); + // Display new audio elements information + fprintf(stdout, "\n--- Audio Elements Information ---\n"); + fprintf(stdout, "Number of audio elements: %u\n", + info->iamf_stream_info.audio_element_count); + + if (info->iamf_stream_info.audio_elements) { + for (uint32_t i = 0; i < info->iamf_stream_info.audio_element_count; i++) { + iamf_audio_element_info_t *elem = + &info->iamf_stream_info.audio_elements[i]; + fprintf(stdout, "\n Audio Element %u:\n", i); + fprintf(stdout, " Element ID: %u\n", elem->element_id); + fprintf(stdout, " Codec ID: %d (%s)\n", elem->codec_id, + codec_string(elem->codec_id)); + fprintf(stdout, " Element Type: %d (%s)\n", elem->element_type, + element_type_string(elem->element_type)); + fprintf(stdout, " Channel Layout: %d (%s)\n", elem->channel_layout, + channel_layout_string(elem->channel_layout)); + fprintf(stdout, " Number of Channels: %u\n", elem->num_channels); + } + } + fprintf(stdout, "\n--- Mix Presentations ---\n"); fprintf(stdout, "Number of mix presentations: %u\n", info->iamf_stream_info.mix_presentation_count);