3400 lines · 122.5 KB · C
RawDownload
/* * 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.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t