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
23 changes: 21 additions & 2 deletions code/include/IAMF_decoder.h
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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 */
Expand Down
1 change: 0 additions & 1 deletion code/include/IAMF_defines.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
159 changes: 145 additions & 14 deletions code/src/iamf_dec/iamf_decoder.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down
2 changes: 0 additions & 2 deletions code/src/iamf_dec/iamf_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
115 changes: 107 additions & 8 deletions code/test/tools/iamfdec/src/test_iamfdec.c
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand Down
Loading