static ChannelElement *get_che(AACContext *ac, int type, int elem_id)
{
- static const int8_t tags_per_config[16] = { 0, 1, 1, 2, 3, 3, 4, 5, 0, 0, 0, 0, 0, 0, 0, 0 };
if (ac->tag_che_map[type][elem_id]) {
return ac->tag_che_map[type][elem_id];
}
}
}
+/**
+ * Check for the channel element in the current channel position configuration.
+ * If it exists, make sure the appropriate element is allocated and map the
+ * channel order to match the internal FFmpeg channel layout.
+ *
+ * @param che_pos current channel position configuration
+ * @param type channel element type
+ * @param id channel element id
+ * @param channels count of the number of channels in the configuration
+ *
+ * @return Returns error status. 0 - OK, !0 - error
+ */
+static int che_configure(AACContext *ac,
+ enum ChannelPosition che_pos[4][MAX_ELEM_ID],
+ int type, int id,
+ int *channels)
+{
+ if (che_pos[type][id]) {
+ if (!ac->che[type][id] && !(ac->che[type][id] = av_mallocz(sizeof(ChannelElement))))
+ return AVERROR(ENOMEM);
+ if (type != TYPE_CCE) {
+ ac->output_data[(*channels)++] = ac->che[type][id]->ch[0].ret;
+ if (type == TYPE_CPE) {
+ ac->output_data[(*channels)++] = ac->che[type][id]->ch[1].ret;
+ }
+ }
+ } else
+ av_freep(&ac->che[type][id]);
+ return 0;
+}
+
/**
* Configure output channel order based on the current program configuration element.
*
static int output_configure(AACContext *ac,
enum ChannelPosition che_pos[4][MAX_ELEM_ID],
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID],
- int channel_config)
+ int channel_config, enum OCStatus oc_type)
{
AVCodecContext *avctx = ac->avccontext;
- int i, type, channels = 0;
+ int i, type, channels = 0, ret;
memcpy(che_pos, new_che_pos, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
- /* Allocate or free elements depending on if they are in the
- * current program configuration.
- *
- * Set up default 1:1 output mapping.
- *
- * For a 5.1 stream the output order will be:
- * [ Center ] [ Front Left ] [ Front Right ] [ LFE ] [ Surround Left ] [ Surround Right ]
- */
-
- for (i = 0; i < MAX_ELEM_ID; i++) {
- for (type = 0; type < 4; type++) {
- if (che_pos[type][i]) {
- if (!ac->che[type][i] && !(ac->che[type][i] = av_mallocz(sizeof(ChannelElement))))
- return AVERROR(ENOMEM);
- if (type != TYPE_CCE) {
- ac->output_data[channels++] = ac->che[type][i]->ch[0].ret;
- if (type == TYPE_CPE) {
- ac->output_data[channels++] = ac->che[type][i]->ch[1].ret;
- }
- }
- } else
- av_freep(&ac->che[type][i]);
+ if (channel_config) {
+ for (i = 0; i < tags_per_config[channel_config]; i++) {
+ if ((ret = che_configure(ac, che_pos,
+ aac_channel_layout_map[channel_config - 1][i][0],
+ aac_channel_layout_map[channel_config - 1][i][1],
+ &channels)))
+ return ret;
}
- }
- if (channel_config) {
memset(ac->tag_che_map, 0, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0]));
ac->tags_mapped = 0;
+
+ avctx->channel_layout = aac_channel_layout[channel_config - 1];
} else {
+ /* Allocate or free elements depending on if they are in the
+ * current program configuration.
+ *
+ * Set up default 1:1 output mapping.
+ *
+ * For a 5.1 stream the output order will be:
+ * [ Center ] [ Front Left ] [ Front Right ] [ LFE ] [ Surround Left ] [ Surround Right ]
+ */
+
+ for (i = 0; i < MAX_ELEM_ID; i++) {
+ for (type = 0; type < 4; type++) {
+ if ((ret = che_configure(ac, che_pos, type, i, &channels)))
+ return ret;
+ }
+ }
+
memcpy(ac->tag_che_map, ac->che, 4 * MAX_ELEM_ID * sizeof(ac->che[0][0]));
ac->tags_mapped = 4 * MAX_ELEM_ID;
+
+ avctx->channel_layout = 0;
}
avctx->channels = channels;
- ac->output_configured = 1;
+ ac->output_configured = oc_type;
return 0;
}
if ((ret = set_default_channel_config(ac, new_che_pos, channel_config)))
return ret;
}
- if ((ret = output_configure(ac, ac->che_pos, new_che_pos, channel_config)))
+ if ((ret = output_configure(ac, ac->che_pos, new_che_pos, channel_config, OC_GLOBAL_HDR)))
return ret;
if (extension_flag) {
// 32768 - Required to scale values to the correct range for the bias method
// for float to int16 conversion.
- if (ac->dsp.float_to_int16 == ff_float_to_int16_c) {
+ if (ac->dsp.float_to_int16_interleave == ff_float_to_int16_interleave_c) {
ac->add_bias = 385.0f;
ac->sf_scale = 1. / (-1024. * 32768.);
ac->sf_offset = 0;
for (g = 0; g < ics->num_window_groups; g++) {
int k = 0;
while (k < ics->max_sfb) {
- uint8_t sect_len = k;
+ uint8_t sect_end = k;
int sect_len_incr;
int sect_band_type = get_bits(gb, 4);
if (sect_band_type == 12) {
return -1;
}
while ((sect_len_incr = get_bits(gb, bits)) == (1 << bits) - 1)
- sect_len += sect_len_incr;
- sect_len += sect_len_incr;
- if (sect_len > ics->max_sfb) {
+ sect_end += sect_len_incr;
+ sect_end += sect_len_incr;
+ if (sect_end > ics->max_sfb) {
av_log(ac->avccontext, AV_LOG_ERROR,
"Number of bands (%d) exceeds limit (%d).\n",
- sect_len, ics->max_sfb);
+ sect_end, ics->max_sfb);
return -1;
}
- for (; k < sect_len; k++) {
+ for (; k < sect_end; k++) {
band_type [idx] = sect_band_type;
- band_type_run_end[idx++] = sect_len;
+ band_type_run_end[idx++] = sect_end;
}
}
}
} else if (cur_band_type == NOISE_BT) {
for (group = 0; group < ics->group_len[g]; group++) {
float scale;
- float band_energy = 0;
- for (k = offsets[i]; k < offsets[i + 1]; k++) {
+ float band_energy;
+ float *cf = coef + group * 128 + offsets[i];
+ int len = offsets[i+1] - offsets[i];
+
+ for (k = 0; k < len; k++) {
ac->random_state = lcg_random(ac->random_state);
- coef[group * 128 + k] = ac->random_state;
- band_energy += coef[group * 128 + k] * coef[group * 128 + k];
+ cf[k] = ac->random_state;
}
+
+ band_energy = ac->dsp.scalarproduct_float(cf, cf, len);
scale = sf[idx] / sqrtf(band_energy);
- for (k = offsets[i]; k < offsets[i + 1]; k++) {
- coef[group * 128 + k] *= scale;
- }
+ ac->dsp.vector_fmul_scalar(cf, cf, scale, len);
}
} else {
for (group = 0; group < ics->group_len[g]; group++) {
+ const float *vq[96];
+ const float **vqp = vq;
+ float *cf = coef + (group << 7) + offsets[i];
+ int len = offsets[i + 1] - offsets[i];
+
for (k = offsets[i]; k < offsets[i + 1]; k += dim) {
const int index = get_vlc2(gb, vlc_spectral[cur_band_type - 1].table, 6, 3);
const int coef_tmp_idx = (group << 7) + k;
return -1;
}
vq_ptr = &ff_aac_codebook_vectors[cur_band_type - 1][index * dim];
+ *vqp++ = vq_ptr;
if (is_cb_unsigned) {
if (vq_ptr[0])
coef[coef_tmp_idx ] = sign_lookup[get_bits1(gb)];
} else
coef[coef_tmp_idx + j] *= vq_ptr[j];
}
- } else {
- coef[coef_tmp_idx ] *= vq_ptr[0];
- coef[coef_tmp_idx + 1] *= vq_ptr[1];
- if (dim == 4) {
- coef[coef_tmp_idx + 2] *= vq_ptr[2];
- coef[coef_tmp_idx + 3] *= vq_ptr[3];
- }
}
- } else {
- coef[coef_tmp_idx ] = vq_ptr[0];
- coef[coef_tmp_idx + 1] = vq_ptr[1];
- if (dim == 4) {
- coef[coef_tmp_idx + 2] = vq_ptr[2];
- coef[coef_tmp_idx + 3] = vq_ptr[3];
- }
- }
- coef[coef_tmp_idx ] *= sf[idx];
- coef[coef_tmp_idx + 1] *= sf[idx];
- if (dim == 4) {
- coef[coef_tmp_idx + 2] *= sf[idx];
- coef[coef_tmp_idx + 3] *= sf[idx];
}
}
+
+ if (is_cb_unsigned && cur_band_type != ESC_BT) {
+ ac->dsp.vector_fmul_sv_scalar[dim>>2](
+ cf, cf, vq, sf[idx], len);
+ } else if (cur_band_type == ESC_BT) {
+ ac->dsp.vector_fmul_scalar(cf, cf, sf[idx], len);
+ } else { /* !is_cb_unsigned */
+ ac->dsp.sv_fmul_scalar[dim>>2](cf, vq, sf[idx], len);
+ }
}
}
}
/**
* Mid/Side stereo decoding; reference: 4.6.8.1.3.
*/
-static void apply_mid_side_stereo(ChannelElement *cpe)
+static void apply_mid_side_stereo(AACContext *ac, ChannelElement *cpe)
{
const IndividualChannelStream *ics = &cpe->ch[0].ics;
float *ch0 = cpe->ch[0].coeffs;
float *ch1 = cpe->ch[1].coeffs;
- int g, i, k, group, idx = 0;
+ int g, i, group, idx = 0;
const uint16_t *offsets = ics->swb_offset;
for (g = 0; g < ics->num_window_groups; g++) {
for (i = 0; i < ics->max_sfb; i++, idx++) {
if (cpe->ms_mask[idx] &&
cpe->ch[0].band_type[idx] < NOISE_BT && cpe->ch[1].band_type[idx] < NOISE_BT) {
for (group = 0; group < ics->group_len[g]; group++) {
- for (k = offsets[i]; k < offsets[i + 1]; k++) {
- float tmp = ch0[group * 128 + k] - ch1[group * 128 + k];
- ch0[group * 128 + k] += ch1[group * 128 + k];
- ch1[group * 128 + k] = tmp;
- }
+ ac->dsp.butterflies_float(ch0 + group * 128 + offsets[i],
+ ch1 + group * 128 + offsets[i],
+ offsets[i+1] - offsets[i]);
}
}
}
if (common_window) {
if (ms_present)
- apply_mid_side_stereo(cpe);
+ apply_mid_side_stereo(ac, cpe);
if (ac->m4ac.object_type == AOT_AAC_MAIN) {
apply_prediction(ac, &cpe->ch[0]);
apply_prediction(ac, &cpe->ch[1]);
size = ff_aac_parse_header(gb, &hdr_info);
if (size > 0) {
- if (!ac->output_configured && hdr_info.chan_config) {
+ if (ac->output_configured != OC_LOCKED && hdr_info.chan_config) {
enum ChannelPosition new_che_pos[4][MAX_ELEM_ID];
memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
ac->m4ac.chan_config = hdr_info.chan_config;
if (set_default_channel_config(ac, new_che_pos, hdr_info.chan_config))
return -7;
- if (output_configure(ac, ac->che_pos, new_che_pos, 1))
+ if (output_configure(ac, ac->che_pos, new_che_pos, hdr_info.chan_config, OC_TRIAL_FRAME))
return -7;
+ } else if (ac->output_configured != OC_LOCKED) {
+ ac->output_configured = OC_NONE;
}
+ if (ac->output_configured != OC_LOCKED)
+ ac->m4ac.sbr = -1;
ac->m4ac.sample_rate = hdr_info.sample_rate;
ac->m4ac.sampling_index = hdr_info.sampling_index;
ac->m4ac.object_type = hdr_info.object_type;
+ if (!ac->avccontext->sample_rate)
+ ac->avccontext->sample_rate = hdr_info.sample_rate;
if (hdr_info.num_aac_frames == 1) {
if (!hdr_info.crc_absent)
skip_bits(gb, 16);
memset(new_che_pos, 0, 4 * MAX_ELEM_ID * sizeof(new_che_pos[0][0]));
if ((err = decode_pce(ac, new_che_pos, &gb)))
break;
- if (ac->output_configured)
+ if (ac->output_configured > OC_TRIAL_PCE)
av_log(avccontext, AV_LOG_ERROR,
"Not evaluating a further program_config_element as this construct is dubious at best.\n");
else
- err = output_configure(ac, ac->che_pos, new_che_pos, 0);
+ err = output_configure(ac, ac->che_pos, new_che_pos, 0, OC_TRIAL_PCE);
break;
}
ac->dsp.float_to_int16_interleave(data, (const float **)ac->output_data, 1024, avccontext->channels);
+ if (ac->output_configured)
+ ac->output_configured = OC_LOCKED;
+
return buf_size;
}
aac_decode_close,
aac_decode_frame,
.long_name = NULL_IF_CONFIG_SMALL("Advanced Audio Coding"),
- .sample_fmts = (enum SampleFormat[]) {
+ .sample_fmts = (const enum SampleFormat[]) {
SAMPLE_FMT_S16,SAMPLE_FMT_NONE
},
+ .channel_layouts = aac_channel_layout,
};