/* * AAC decoder * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) * Copyright (c) 2008-2013 Alex Converse <alex.converse@gmail.com> * * AAC LATM decoder * Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz> * Copyright (c) 2010 Janne Grunau <janne-libav@jannau.net> * * AAC decoder fixed-point implementation * Copyright (c) 2013 * MIPS Technologies, Inc., California. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * AAC decoder * @author Oded Shimon ( ods15 ods15 dyndns org ) * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) * * AAC decoder fixed-point implementation * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) * @author Nedeljko Babic ( nedeljko.babic imgtec com ) */ /* * supported tools * * Support? Name * N (code in SoC repo) gain control * Y block switching * Y window shapes - standard * N window shapes - Low Delay * Y filterbank - standard * N (code in SoC repo) filterbank - Scalable Sample Rate * Y Temporal Noise Shaping * Y Long Term Prediction * Y intensity stereo * Y channel coupling * Y frequency domain prediction * Y Perceptual Noise Substitution * Y Mid/Side stereo * N Scalable Inverse AAC Quantization * N Frequency Selective Switch * N upsampling filter * Y quantization & coding - AAC * N quantization & coding - TwinVQ * N quantization & coding - BSAC * N AAC Error Resilience tools * N Error Resilience payload syntax * N Error Protection tool * N CELP * N Silence Compression * N HVXC * N HVXC 4kbits/s VR * N Structured Audio tools * N Structured Audio Sample Bank Format * N MIDI * N Harmonic and Individual Lines plus Noise * N Text-To-Speech Interface * Y Spectral Band Replication * Y (not in this code) Layer-1 * Y (not in this code) Layer-2 * Y (not in this code) Layer-3 * N SinuSoidal Coding (Transient, Sinusoid, Noise) * Y Parametric Stereo * N Direct Stream Transfer * Y (not in fixed point code) Enhanced AAC Low Delay (ER AAC ELD) * * Note: - HE AAC v1 comprises LC AAC with Spectral Band Replication. * - HE AAC v2 comprises LC AAC with Spectral Band Replication and Parametric Stereo. */ #include "libavutil/thread.h" static VLC vlc_scalefactors;static VLC vlc_spectral[11]; static int output_configure(AACContext *ac, uint8_t layout_map[MAX_ELEM_ID*4][3], int tags, enum OCStatus oc_type, int get_new_frame); #define overread_err "Input buffer exhausted before END element found\n" static int count_channels(uint8_t (*layout)[3], int tags){ int i, sum = 0; for (i = 0; i < tags; i++) { int syn_ele = layout[i][0]; int pos = layout[i][2]; sum += (1 + (syn_ele == TYPE_CPE)) * (pos != AAC_CHANNEL_OFF && pos != AAC_CHANNEL_CC); } return sum;} /** * 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 av_cold int che_configure(AACContext *ac, enum ChannelPosition che_pos, int type, int id, int *channels){ if (*channels >= MAX_CHANNELS) return AVERROR_INVALIDDATA; if (che_pos) { if (!ac->che[type][id]) { if (!(ac->che[type][id] = av_mallocz(sizeof(ChannelElement)))) return AVERROR(ENOMEM); AAC_RENAME(ff_aac_sbr_ctx_init)(ac, &ac->che[type][id]->sbr, type); } if (type != TYPE_CCE) { if (*channels >= MAX_CHANNELS - (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1))) { av_log(ac->avctx, AV_LOG_ERROR, "Too many channels\n"); return AVERROR_INVALIDDATA; } ac->output_element[(*channels)++] = &ac->che[type][id]->ch[0]; if (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) { ac->output_element[(*channels)++] = &ac->che[type][id]->ch[1]; } } } else { if (ac->che[type][id]) AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][id]->sbr); av_freep(&ac->che[type][id]); } return 0;} static int frame_configure_elements(AVCodecContext *avctx){ AACContext *ac = avctx->priv_data; int type, id, ch, ret; /* set channel pointers to internal buffers by default */ for (type = 0; type < 4; type++) { for (id = 0; id < MAX_ELEM_ID; id++) { ChannelElement *che = ac->che[type][id]; if (che) { che->ch[0].ret = che->ch[0].ret_buf; che->ch[1].ret = che->ch[1].ret_buf; } } } /* get output buffer */ av_frame_unref(ac->frame); if (!avctx->channels) return 1; ac->frame->nb_samples = 2048; if ((ret = ff_get_buffer(avctx, ac->frame, 0)) < 0) return ret; /* map output channel pointers to AVFrame data */ for (ch = 0; ch < avctx->channels; ch++) { if (ac->output_element[ch]) ac->output_element[ch]->ret = (INTFLOAT *)ac->frame->extended_data[ch]; } return 0;} struct elem_to_channel { uint64_t av_position; uint8_t syn_ele; uint8_t elem_id; uint8_t aac_position;}; static int assign_pair(struct elem_to_channel e2c_vec[MAX_ELEM_ID], uint8_t (*layout_map)[3], int offset, uint64_t left, uint64_t right, int pos){ if (layout_map[offset][0] == TYPE_CPE) { e2c_vec[offset] = (struct elem_to_channel) { .av_position = left | right, .syn_ele = TYPE_CPE, .elem_id = layout_map[offset][1], .aac_position = pos }; return 1; } else { e2c_vec[offset] = (struct elem_to_channel) { .av_position = left, .syn_ele = TYPE_SCE, .elem_id = layout_map[offset][1], .aac_position = pos }; e2c_vec[offset + 1] = (struct elem_to_channel) { .av_position = right, .syn_ele = TYPE_SCE, .elem_id = layout_map[offset + 1][1], .aac_position = pos }; return 2; }} static int count_paired_channels(uint8_t (*layout_map)[3], int tags, int pos, int *current){ int num_pos_channels = 0; int first_cpe = 0; int sce_parity = 0; int i; for (i = *current; i < tags; i++) { if (layout_map[i][2] != pos) break; if (layout_map[i][0] == TYPE_CPE) { if (sce_parity) { if (pos == AAC_CHANNEL_FRONT && !first_cpe) { sce_parity = 0; } else { return -1; } } num_pos_channels += 2; first_cpe = 1; } else { num_pos_channels++; sce_parity ^= 1; } } if (sce_parity && ((pos == AAC_CHANNEL_FRONT && first_cpe) || pos == AAC_CHANNEL_SIDE)) return -1; *current = i; return num_pos_channels;} static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags){ int i, n, total_non_cc_elements; struct elem_to_channel e2c_vec[4 * MAX_ELEM_ID] = { { 0 } }; int num_front_channels, num_side_channels, num_back_channels; uint64_t layout; if (FF_ARRAY_ELEMS(e2c_vec) < tags) return 0; i = 0; num_front_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_FRONT, &i); if (num_front_channels < 0) return 0; num_side_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_SIDE, &i); if (num_side_channels < 0) return 0; num_back_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_BACK, &i); if (num_back_channels < 0) return 0; if (num_side_channels == 0 && num_back_channels >= 4) { num_side_channels = 2; num_back_channels -= 2; } i = 0; if (num_front_channels & 1) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_FRONT_CENTER, .syn_ele = TYPE_SCE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_FRONT }; i++; num_front_channels--; } if (num_front_channels >= 4) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER, AAC_CHANNEL_FRONT); num_front_channels -= 2; } if (num_front_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_FRONT_LEFT, AV_CH_FRONT_RIGHT, AAC_CHANNEL_FRONT); num_front_channels -= 2; } while (num_front_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_FRONT); num_front_channels -= 2; } if (num_side_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_SIDE_LEFT, AV_CH_SIDE_RIGHT, AAC_CHANNEL_FRONT); num_side_channels -= 2; } while (num_side_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_SIDE); num_side_channels -= 2; } while (num_back_channels >= 4) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_BACK); num_back_channels -= 2; } if (num_back_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_BACK_LEFT, AV_CH_BACK_RIGHT, AAC_CHANNEL_BACK); num_back_channels -= 2; } if (num_back_channels) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_BACK_CENTER, .syn_ele = TYPE_SCE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_BACK }; i++; num_back_channels--; } if (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_LOW_FREQUENCY, .syn_ele = TYPE_LFE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE }; i++; } while (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { e2c_vec[i] = (struct elem_to_channel) { .av_position = UINT64_MAX, .syn_ele = TYPE_LFE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE }; i++; } // Must choose a stable sort total_non_cc_elements = n = i; do { int next_n = 0; for (i = 1; i < n; i++) if (e2c_vec[i - 1].av_position > e2c_vec[i].av_position) { FFSWAP(struct elem_to_channel, e2c_vec[i - 1], e2c_vec[i]); next_n = i; } n = next_n; } while (n > 0); layout = 0; for (i = 0; i < total_non_cc_elements; i++) { layout_map[i][0] = e2c_vec[i].syn_ele; layout_map[i][1] = e2c_vec[i].elem_id; layout_map[i][2] = e2c_vec[i].aac_position; if (e2c_vec[i].av_position != UINT64_MAX) { layout |= e2c_vec[i].av_position; } } return layout;} /** * Save current output configuration if and only if it has been locked. */static int push_output_configuration(AACContext *ac) { int pushed = 0; if (ac->oc[1].status == OC_LOCKED || ac->oc[0].status == OC_NONE) { ac->oc[0] = ac->oc[1]; pushed = 1; } ac->oc[1].status = OC_NONE; return pushed;} /** * Restore the previous output configuration if and only if the current * configuration is unlocked. */static void pop_output_configuration(AACContext *ac) { if (ac->oc[1].status != OC_LOCKED && ac->oc[0].status != OC_NONE) { ac->oc[1] = ac->oc[0]; ac->avctx->channels = ac->oc[1].channels; ac->avctx->channel_layout = ac->oc[1].channel_layout; output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, ac->oc[1].status, 0); }} /** * Configure output channel order based on the current program * configuration element. * * @return Returns error status. 0 - OK, !0 - error */static int output_configure(AACContext *ac, uint8_t layout_map[MAX_ELEM_ID * 4][3], int tags, enum OCStatus oc_type, int get_new_frame){ AVCodecContext *avctx = ac->avctx; int i, channels = 0, ret; uint64_t layout = 0; uint8_t id_map[TYPE_END][MAX_ELEM_ID] = {{ 0 }}; uint8_t type_counts[TYPE_END] = { 0 }; if (ac->oc[1].layout_map != layout_map) { memcpy(ac->oc[1].layout_map, layout_map, tags * sizeof(layout_map[0])); ac->oc[1].layout_map_tags = tags; } for (i = 0; i < tags; i++) { int type = layout_map[i][0]; int id = layout_map[i][1]; id_map[type][id] = type_counts[type]++; if (id_map[type][id] >= MAX_ELEM_ID) { avpriv_request_sample(ac->avctx, "Too large remapped id"); return AVERROR_PATCHWELCOME; } } // Try to sniff a reasonable channel order, otherwise output the // channels in the order the PCE declared them. if (avctx->request_channel_layout != AV_CH_LAYOUT_NATIVE) layout = sniff_channel_order(layout_map, tags); for (i = 0; i < tags; i++) { int type = layout_map[i][0]; int id = layout_map[i][1]; int iid = id_map[type][id]; int position = layout_map[i][2]; // Allocate or free elements depending on if they are in the // current program configuration. ret = che_configure(ac, position, type, iid, &channels); if (ret < 0) return ret; ac->tag_che_map[type][id] = ac->che[type][iid]; } if (ac->oc[1].m4ac.ps == 1 && channels == 2) { if (layout == AV_CH_FRONT_CENTER) { layout = AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT; } else { layout = 0; } } if (layout) avctx->channel_layout = layout; ac->oc[1].channel_layout = layout; avctx->channels = ac->oc[1].channels = channels; ac->oc[1].status = oc_type; if (get_new_frame) { if ((ret = frame_configure_elements(ac->avctx)) < 0) return ret; } return 0;} static void flush(AVCodecContext *avctx)Lines 1–500 of 3400. Load more
/* * AAC decoder * Copyright (c) 2005-2006 Oded Shimon ( ods15 ods15 dyndns org ) * Copyright (c) 2006-2007 Maxim Gavrilov ( maxim.gavrilov gmail com ) * Copyright (c) 2008-2013 Alex Converse <alex.converse@gmail.com> * * AAC LATM decoder * Copyright (c) 2008-2010 Paul Kendall <paul@kcbbs.gen.nz> * Copyright (c) 2010 Janne Grunau <janne-libav@jannau.net> * * AAC decoder fixed-point implementation * Copyright (c) 2013 * MIPS Technologies, Inc., California. * * This file is part of FFmpeg. * * FFmpeg is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. * * FFmpeg is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with FFmpeg; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */ /** * @file * AAC decoder * @author Oded Shimon ( ods15 ods15 dyndns org ) * @author Maxim Gavrilov ( maxim.gavrilov gmail com ) * * AAC decoder fixed-point implementation * @author Stanislav Ocovaj ( stanislav.ocovaj imgtec com ) * @author Nedeljko Babic ( nedeljko.babic imgtec com ) */ /* * supported tools * * Support? Name * N (code in SoC repo) gain control * Y block switching * Y window shapes - standard * N window shapes - Low Delay * Y filterbank - standard * N (code in SoC repo) filterbank - Scalable Sample Rate * Y Temporal Noise Shaping * Y Long Term Prediction * Y intensity stereo * Y channel coupling * Y frequency domain prediction * Y Perceptual Noise Substitution * Y Mid/Side stereo * N Scalable Inverse AAC Quantization * N Frequency Selective Switch * N upsampling filter * Y quantization & coding - AAC * N quantization & coding - TwinVQ * N quantization & coding - BSAC * N AAC Error Resilience tools * N Error Resilience payload syntax * N Error Protection tool * N CELP * N Silence Compression * N HVXC * N HVXC 4kbits/s VR * N Structured Audio tools * N Structured Audio Sample Bank Format * N MIDI * N Harmonic and Individual Lines plus Noise * N Text-To-Speech Interface * Y Spectral Band Replication * Y (not in this code) Layer-1 * Y (not in this code) Layer-2 * Y (not in this code) Layer-3 * N SinuSoidal Coding (Transient, Sinusoid, Noise) * Y Parametric Stereo * N Direct Stream Transfer * Y (not in fixed point code) Enhanced AAC Low Delay (ER AAC ELD) * * Note: - HE AAC v1 comprises LC AAC with Spectral Band Replication. * - HE AAC v2 comprises LC AAC with Spectral Band Replication and Parametric Stereo. */ #include "libavutil/thread.h" static VLC vlc_scalefactors; static VLC vlc_spectral[11]; static int output_configure(AACContext *ac, uint8_t layout_map[MAX_ELEM_ID*4][3], int tags, enum OCStatus oc_type, int get_new_frame); #define overread_err "Input buffer exhausted before END element found\n" static int count_channels(uint8_t (*layout)[3], int tags) { int i, sum = 0; for (i = 0; i < tags; i++) { int syn_ele = layout[i][0]; int pos = layout[i][2]; sum += (1 + (syn_ele == TYPE_CPE)) * (pos != AAC_CHANNEL_OFF && pos != AAC_CHANNEL_CC); } return sum; } /** * 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 av_cold int che_configure(AACContext *ac, enum ChannelPosition che_pos, int type, int id, int *channels) { if (*channels >= MAX_CHANNELS) return AVERROR_INVALIDDATA; if (che_pos) { if (!ac->che[type][id]) { if (!(ac->che[type][id] = av_mallocz(sizeof(ChannelElement)))) return AVERROR(ENOMEM); AAC_RENAME(ff_aac_sbr_ctx_init)(ac, &ac->che[type][id]->sbr, type); } if (type != TYPE_CCE) { if (*channels >= MAX_CHANNELS - (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1))) { av_log(ac->avctx, AV_LOG_ERROR, "Too many channels\n"); return AVERROR_INVALIDDATA; } ac->output_element[(*channels)++] = &ac->che[type][id]->ch[0]; if (type == TYPE_CPE || (type == TYPE_SCE && ac->oc[1].m4ac.ps == 1)) { ac->output_element[(*channels)++] = &ac->che[type][id]->ch[1]; } } } else { if (ac->che[type][id]) AAC_RENAME(ff_aac_sbr_ctx_close)(&ac->che[type][id]->sbr); av_freep(&ac->che[type][id]); } return 0; } static int frame_configure_elements(AVCodecContext *avctx) { AACContext *ac = avctx->priv_data; int type, id, ch, ret; /* set channel pointers to internal buffers by default */ for (type = 0; type < 4; type++) { for (id = 0; id < MAX_ELEM_ID; id++) { ChannelElement *che = ac->che[type][id]; if (che) { che->ch[0].ret = che->ch[0].ret_buf; che->ch[1].ret = che->ch[1].ret_buf; } } } /* get output buffer */ av_frame_unref(ac->frame); if (!avctx->channels) return 1; ac->frame->nb_samples = 2048; if ((ret = ff_get_buffer(avctx, ac->frame, 0)) < 0) return ret; /* map output channel pointers to AVFrame data */ for (ch = 0; ch < avctx->channels; ch++) { if (ac->output_element[ch]) ac->output_element[ch]->ret = (INTFLOAT *)ac->frame->extended_data[ch]; } return 0; } struct elem_to_channel { uint64_t av_position; uint8_t syn_ele; uint8_t elem_id; uint8_t aac_position; }; static int assign_pair(struct elem_to_channel e2c_vec[MAX_ELEM_ID], uint8_t (*layout_map)[3], int offset, uint64_t left, uint64_t right, int pos) { if (layout_map[offset][0] == TYPE_CPE) { e2c_vec[offset] = (struct elem_to_channel) { .av_position = left | right, .syn_ele = TYPE_CPE, .elem_id = layout_map[offset][1], .aac_position = pos }; return 1; } else { e2c_vec[offset] = (struct elem_to_channel) { .av_position = left, .syn_ele = TYPE_SCE, .elem_id = layout_map[offset][1], .aac_position = pos }; e2c_vec[offset + 1] = (struct elem_to_channel) { .av_position = right, .syn_ele = TYPE_SCE, .elem_id = layout_map[offset + 1][1], .aac_position = pos }; return 2; } } static int count_paired_channels(uint8_t (*layout_map)[3], int tags, int pos, int *current) { int num_pos_channels = 0; int first_cpe = 0; int sce_parity = 0; int i; for (i = *current; i < tags; i++) { if (layout_map[i][2] != pos) break; if (layout_map[i][0] == TYPE_CPE) { if (sce_parity) { if (pos == AAC_CHANNEL_FRONT && !first_cpe) { sce_parity = 0; } else { return -1; } } num_pos_channels += 2; first_cpe = 1; } else { num_pos_channels++; sce_parity ^= 1; } } if (sce_parity && ((pos == AAC_CHANNEL_FRONT && first_cpe) || pos == AAC_CHANNEL_SIDE)) return -1; *current = i; return num_pos_channels; } static uint64_t sniff_channel_order(uint8_t (*layout_map)[3], int tags) { int i, n, total_non_cc_elements; struct elem_to_channel e2c_vec[4 * MAX_ELEM_ID] = { { 0 } }; int num_front_channels, num_side_channels, num_back_channels; uint64_t layout; if (FF_ARRAY_ELEMS(e2c_vec) < tags) return 0; i = 0; num_front_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_FRONT, &i); if (num_front_channels < 0) return 0; num_side_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_SIDE, &i); if (num_side_channels < 0) return 0; num_back_channels = count_paired_channels(layout_map, tags, AAC_CHANNEL_BACK, &i); if (num_back_channels < 0) return 0; if (num_side_channels == 0 && num_back_channels >= 4) { num_side_channels = 2; num_back_channels -= 2; } i = 0; if (num_front_channels & 1) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_FRONT_CENTER, .syn_ele = TYPE_SCE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_FRONT }; i++; num_front_channels--; } if (num_front_channels >= 4) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_FRONT_LEFT_OF_CENTER, AV_CH_FRONT_RIGHT_OF_CENTER, AAC_CHANNEL_FRONT); num_front_channels -= 2; } if (num_front_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_FRONT_LEFT, AV_CH_FRONT_RIGHT, AAC_CHANNEL_FRONT); num_front_channels -= 2; } while (num_front_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_FRONT); num_front_channels -= 2; } if (num_side_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_SIDE_LEFT, AV_CH_SIDE_RIGHT, AAC_CHANNEL_FRONT); num_side_channels -= 2; } while (num_side_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_SIDE); num_side_channels -= 2; } while (num_back_channels >= 4) { i += assign_pair(e2c_vec, layout_map, i, UINT64_MAX, UINT64_MAX, AAC_CHANNEL_BACK); num_back_channels -= 2; } if (num_back_channels >= 2) { i += assign_pair(e2c_vec, layout_map, i, AV_CH_BACK_LEFT, AV_CH_BACK_RIGHT, AAC_CHANNEL_BACK); num_back_channels -= 2; } if (num_back_channels) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_BACK_CENTER, .syn_ele = TYPE_SCE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_BACK }; i++; num_back_channels--; } if (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { e2c_vec[i] = (struct elem_to_channel) { .av_position = AV_CH_LOW_FREQUENCY, .syn_ele = TYPE_LFE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE }; i++; } while (i < tags && layout_map[i][2] == AAC_CHANNEL_LFE) { e2c_vec[i] = (struct elem_to_channel) { .av_position = UINT64_MAX, .syn_ele = TYPE_LFE, .elem_id = layout_map[i][1], .aac_position = AAC_CHANNEL_LFE }; i++; } // Must choose a stable sort total_non_cc_elements = n = i; do { int next_n = 0; for (i = 1; i < n; i++) if (e2c_vec[i - 1].av_position > e2c_vec[i].av_position) { FFSWAP(struct elem_to_channel, e2c_vec[i - 1], e2c_vec[i]); next_n = i; } n = next_n; } while (n > 0); layout = 0; for (i = 0; i < total_non_cc_elements; i++) { layout_map[i][0] = e2c_vec[i].syn_ele; layout_map[i][1] = e2c_vec[i].elem_id; layout_map[i][2] = e2c_vec[i].aac_position; if (e2c_vec[i].av_position != UINT64_MAX) { layout |= e2c_vec[i].av_position; } } return layout; } /** * Save current output configuration if and only if it has been locked. */ static int push_output_configuration(AACContext *ac) { int pushed = 0; if (ac->oc[1].status == OC_LOCKED || ac->oc[0].status == OC_NONE) { ac->oc[0] = ac->oc[1]; pushed = 1; } ac->oc[1].status = OC_NONE; return pushed; } /** * Restore the previous output configuration if and only if the current * configuration is unlocked. */ static void pop_output_configuration(AACContext *ac) { if (ac->oc[1].status != OC_LOCKED && ac->oc[0].status != OC_NONE) { ac->oc[1] = ac->oc[0]; ac->avctx->channels = ac->oc[1].channels; ac->avctx->channel_layout = ac->oc[1].channel_layout; output_configure(ac, ac->oc[1].layout_map, ac->oc[1].layout_map_tags, ac->oc[1].status, 0); } } /** * Configure output channel order based on the current program * configuration element. * * @return Returns error status. 0 - OK, !0 - error */ static int output_configure(AACContext *ac, uint8_t layout_map[MAX_ELEM_ID * 4][3], int tags, enum OCStatus oc_type, int get_new_frame) { AVCodecContext *avctx = ac->avctx; int i, channels = 0, ret; uint64_t layout = 0; uint8_t id_map[TYPE_END][MAX_ELEM_ID] = {{ 0 }}; uint8_t type_counts[TYPE_END] = { 0 }; if (ac->oc[1].layout_map != layout_map) { memcpy(ac->oc[1].layout_map, layout_map, tags * sizeof(layout_map[0])); ac->oc[1].layout_map_tags = tags; } for (i = 0; i < tags; i++) { int type = layout_map[i][0]; int id = layout_map[i][1]; id_map[type][id] = type_counts[type]++; if (id_map[type][id] >= MAX_ELEM_ID) { avpriv_request_sample(ac->avctx, "Too large remapped id"); return AVERROR_PATCHWELCOME; } } // Try to sniff a reasonable channel order, otherwise output the // channels in the order the PCE declared them. if (avctx->request_channel_layout != AV_CH_LAYOUT_NATIVE) layout = sniff_channel_order(layout_map, tags); for (i = 0; i < tags; i++) { int type = layout_map[i][0]; int id = layout_map[i][1]; int iid = id_map[type][id]; int position = layout_map[i][2]; // Allocate or free elements depending on if they are in the // current program configuration. ret = che_configure(ac, position, type, iid, &channels); if (ret < 0) return ret; ac->tag_che_map[type][id] = ac->che[type][iid]; } if (ac->oc[1].m4ac.ps == 1 && channels == 2) { if (layout == AV_CH_FRONT_CENTER) { layout = AV_CH_FRONT_LEFT|AV_CH_FRONT_RIGHT; } else { layout = 0; } } if (layout) avctx->channel_layout = layout; ac->oc[1].channel_layout = layout; avctx->channels = ac->oc[1].channels = channels; ac->oc[1].status = oc_type; if (get_new_frame) { if ((ret = frame_configure_elements(ac->avctx)) < 0) return ret; } return 0; } static void flush(AVCodecContext *avctx)