GF_Err gf_m4a_parse_config(GF_BitStream *bs, GF_M4ADecSpecInfo *cfg, Bool size_known)
{
	u32 channel_configuration = 0;
	memset(cfg, 0, sizeof(GF_M4ADecSpecInfo));
	cfg->base_object_type = gf_bs_read_int(bs, 5);
	/*extended object type*/
	if (cfg->base_object_type==31) {
		cfg->base_object_type = 32 + gf_bs_read_int(bs, 6);
	}
	cfg->base_sr_index = gf_bs_read_int(bs, 4);
	if (cfg->base_sr_index == 0x0F) {
		cfg->base_sr = gf_bs_read_int(bs, 24);
	} else {
		cfg->base_sr = GF_M4ASampleRates[cfg->base_sr_index];
	}

	channel_configuration = gf_bs_read_int(bs, 4);

	if (channel_configuration) {
		cfg->nb_chan = GF_M4ANumChannels[channel_configuration-1];
	}

	if (cfg->base_object_type==5 || cfg->base_object_type==29) {
		if (cfg->base_object_type==29) {
			cfg->has_ps = 1;
			cfg->nb_chan = 1;
		}
		cfg->has_sbr = GF_TRUE;
		cfg->sbr_sr_index = gf_bs_read_int(bs, 4);
		if (cfg->sbr_sr_index == 0x0F) {
			cfg->sbr_sr = gf_bs_read_int(bs, 24);
		} else {
			cfg->sbr_sr = GF_M4ASampleRates[cfg->sbr_sr_index];
		}
		cfg->sbr_object_type = gf_bs_read_int(bs, 5);
	}

	/*object cfg*/
	switch (cfg->base_object_type) {
	case 1:
	case 2:
	case 3:
	case 4:
	case 6:
	case 7:
	case 17:
	case 19:
	case 20:
	case 21:
	case 22:
	case 23:
	{
		Bool ext_flag;
		/*frame length flag*/
		/*fl_flag = */gf_bs_read_int(bs, 1);
		/*depends on core coder*/
		if (gf_bs_read_int(bs, 1))
			/*delay = */gf_bs_read_int(bs, 14);
		ext_flag = gf_bs_read_int(bs, 1);

		if (! channel_configuration) {
			u32 i;
			cfg->program_config_element_present = 1;
			cfg->element_instance_tag = gf_bs_read_int(bs, 4);
			cfg->object_type = gf_bs_read_int(bs, 2);
			cfg->sampling_frequency_index = gf_bs_read_int(bs, 4);
			cfg->num_front_channel_elements = gf_bs_read_int(bs, 4);
			cfg->num_side_channel_elements = gf_bs_read_int(bs, 4);
			cfg->num_back_channel_elements = gf_bs_read_int(bs, 4);
			cfg->num_lfe_channel_elements = gf_bs_read_int(bs, 2);
			cfg->num_assoc_data_elements = gf_bs_read_int(bs, 3);
			cfg->num_valid_cc_elements = gf_bs_read_int(bs, 4);
			cfg-> mono_mixdown_present = (Bool) gf_bs_read_int(bs, 1);
			if (cfg->mono_mixdown_present) {
				cfg->mono_mixdown_element_number = gf_bs_read_int(bs, 4);
			}
			cfg->stereo_mixdown_present = gf_bs_read_int(bs, 1);
			if (cfg->stereo_mixdown_present) {
				cfg->stereo_mixdown_element_number = gf_bs_read_int(bs, 4);
			}
			cfg->matrix_mixdown_idx_present = gf_bs_read_int(bs, 1);
			if (cfg->matrix_mixdown_idx_present) {
				cfg->matrix_mixdown_idx = gf_bs_read_int(bs, 2);
				cfg->pseudo_surround_enable = gf_bs_read_int(bs, 1);
			}
			for (i = 0; i < cfg->num_front_channel_elements; i++) {
				cfg->front_element_is_cpe[i] = gf_bs_read_int(bs, 1);
				cfg->front_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}
			for (i = 0; i < cfg->num_side_channel_elements; i++) {
				cfg->side_element_is_cpe[i] = gf_bs_read_int(bs, 1);
				cfg->side_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}
			for (i = 0; i < cfg->num_back_channel_elements; i++) {
				cfg->back_element_is_cpe[i] = gf_bs_read_int(bs, 1);
				cfg->back_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}
			for (i = 0; i < cfg->num_lfe_channel_elements; i++) {
				cfg->lfe_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}
			for ( i = 0; i < cfg->num_assoc_data_elements; i++) {
				cfg->assoc_data_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}

			for (i = 0; i < cfg->num_valid_cc_elements; i++) {
				cfg->cc_element_is_ind_sw[i] = gf_bs_read_int(bs, 1);
				cfg->valid_cc_element_tag_select[i] = gf_bs_read_int(bs, 4);
			}
			gf_bs_align(bs);
			cfg->comment_field_bytes = gf_bs_read_int(bs, 8);
			gf_bs_read_data(bs, (char *) cfg->comments, cfg->comment_field_bytes);

			cfg->nb_chan = cfg->num_front_channel_elements + cfg->num_back_channel_elements + cfg->num_side_channel_elements + cfg->num_lfe_channel_elements;
		}

		if ((cfg->base_object_type == 6) || (cfg->base_object_type == 20)) {
			gf_bs_read_int(bs, 3);
		}
		if (ext_flag) {
			if (cfg->base_object_type == 22) {
				gf_bs_read_int(bs, 5);
				gf_bs_read_int(bs, 11);
			}
			if ((cfg->base_object_type == 17)
			        || (cfg->base_object_type == 19)
			        || (cfg->base_object_type == 20)
			        || (cfg->base_object_type == 23)
			   ) {
				gf_bs_read_int(bs, 1);
				gf_bs_read_int(bs, 1);
				gf_bs_read_int(bs, 1);
			}
			/*ext_flag = */gf_bs_read_int(bs, 1);
		}
	}
	break;
	}
	/*ER cfg*/
	switch (cfg->base_object_type) {
	case 17:
	case 19:
	case 20:
	case 21:
	case 22:
	case 23:
	case 24:
	case 25:
	case 26:
	case 27:
	{
		u32 epConfig = gf_bs_read_int(bs, 2);
		if ((epConfig == 2) || (epConfig == 3) ) {
		}
		if (epConfig == 3) {
			gf_bs_read_int(bs, 1);
		}
	}
	break;
	}

	if (size_known && (cfg->base_object_type != 5) && (cfg->base_object_type != 29) ) {
		while (gf_bs_available(bs)>=2) {
			u32 sync = gf_bs_peek_bits(bs, 11, 0);
			if (sync==0x2b7) {
				gf_bs_read_int(bs, 11);
				cfg->sbr_object_type = gf_bs_read_int(bs, 5);
				cfg->has_sbr = gf_bs_read_int(bs, 1);
				if (cfg->has_sbr) {
					cfg->sbr_sr_index = gf_bs_read_int(bs, 4);
					if (cfg->sbr_sr_index == 0x0F) {
						cfg->sbr_sr = gf_bs_read_int(bs, 24);
					} else {
						cfg->sbr_sr = GF_M4ASampleRates[cfg->sbr_sr_index];
					}
				}
			} else if (sync == 0x548) {
				gf_bs_read_int(bs, 11);
				cfg->has_ps = gf_bs_read_int(bs, 1);
				if (cfg->has_ps)
					cfg->nb_chan = 1;
			} else {
				break;
			}
		}
	}
	cfg->audioPL = gf_m4a_get_profile(cfg);
	return GF_OK;
}