/* * AAC encoder * Copyright (C) 2008 Konstantin Shishkov * * 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 encoder */ /*********************************** * TODOs: * add sane pulse detection ***********************************/#include <float.h> #include "libavutil/channel_layout.h"#include "libavutil/libm.h"#include "libavutil/float_dsp.h"#include "libavutil/mem.h"#include "libavutil/opt.h"#include "avcodec.h"#include "codec_internal.h"#include "encode.h"#include "put_bits.h"#include "mpeg4audio.h"#include "sinewin.h"#include "profiles.h"#include "version.h" #include "aac.h"#include "aactab.h"#include "aacenc.h"#include "aacenctab.h"#include "aacenc_utils.h" #include "psymodel.h" /** * List of PCE (Program Configuration Element) for the channel layouts listed * in channel_layout.h * * For those wishing in the future to add other layouts: * * - num_ele: number of elements in each group of front, side, back, lfe channels * (an element is of type SCE (single channel), CPE (channel pair) for * the first 3 groups; and is LFE for LFE group). * * - pairing: 0 for an SCE element or 1 for a CPE; does not apply to LFE group * * - index: there are three independent indices for SCE, CPE and LFE; * they are incremented irrespective of the group to which the element belongs; * they are not reset when going from one group to another * * Example: for 7.0 channel layout, * .pairing = { { 1, 0 }, { 1 }, { 1 }, }, (3 CPE and 1 SCE in front group) * .index = { { 0, 0 }, { 1 }, { 2 }, }, * (index is 0 for the single SCE but goes from 0 to 2 for the CPEs) * * The index order impacts the channel ordering. But is otherwise arbitrary * (the sequence could have been 2, 0, 1 instead of 0, 1, 2). * * Spec allows for discontinuous indices, e.g. if one has a total of two SCE, * SCE.0 SCE.15 is OK per spec; BUT it won't be decoded by our AAC decoder * which at this time requires that indices fully cover some range starting * from 0 (SCE.1 SCE.0 is OK but not SCE.0 SCE.15). * * - config_map: total number of elements and their types. Beware, the way the * types are ordered impacts the final channel ordering. * * - reorder_map: reorders the channels. * */static const AACPCEInfo aac_pce_configs[] = { { .layout = AV_CHANNEL_LAYOUT_MONO, .num_ele = { 1, 0, 0, 0 }, .pairing = { { 0 }, }, .index = { { 0 }, }, .config_map = { 1, TYPE_SCE, }, .reorder_map = { 0 }, }, { .layout = AV_CHANNEL_LAYOUT_STEREO, .num_ele = { 1, 0, 0, 0 }, .pairing = { { 1 }, }, .index = { { 0 }, }, .config_map = { 1, TYPE_CPE, }, .reorder_map = { 0, 1 }, }, { .layout = AV_CHANNEL_LAYOUT_2POINT1, .num_ele = { 1, 0, 0, 1 }, .pairing = { { 1 }, }, .index = { { 0 },{ 0 },{ 0 },{ 0 } }, .config_map = { 2, TYPE_CPE, TYPE_LFE }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_2_1, .num_ele = { 1, 0, 1, 0 }, .pairing = { { 1 },{ 0 },{ 0 } }, .index = { { 0 },{ 0 },{ 0 }, }, .config_map = { 2, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_SURROUND, .num_ele = { 2, 0, 0, 0 }, .pairing = { { 1, 0 }, }, .index = { { 0, 0 }, }, .config_map = { 2, TYPE_CPE, TYPE_SCE, }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_3POINT1, .num_ele = { 2, 0, 0, 1 }, .pairing = { { 1, 0 }, }, .index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_4POINT0, .num_ele = { 2, 0, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 0 }, }, .index = { { 0, 0 }, { 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_4POINT1, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 0 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, { 0 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_2_2, .num_ele = { 1, 1, 0, 0 }, .pairing = { { 1 }, { 1 }, }, .index = { { 0 }, { 1 }, }, .config_map = { 2, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_QUAD, .num_ele = { 1, 0, 1, 0 }, .pairing = { { 1 }, { 0 }, { 1 }, }, .index = { { 0 }, { 0 }, { 1 } }, .config_map = { 2, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT0, .num_ele = { 2, 1, 0, 0 }, .pairing = { { 1, 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT1, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT0_BACK, .num_ele = { 2, 0, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 } }, .index = { { 0, 0 }, { 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT1_BACK, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT0, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 0 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT0_FRONT, .num_ele = { 2, 1, 0, 0 }, .pairing = { { 1, 1 }, { 1 } }, .index = { { 1, 0 }, { 2 }, }, .config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_HEXAGONAL, .num_ele = { 2, 0, 2, 0 }, .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, .index = { { 0, 0 },{ 0 },{ 1, 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, .index = { { 0, 0 },{ 1 },{ 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1_BACK, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1_FRONT, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT0, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT0_FRONT, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 },{ 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_OCTAGONAL, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 2, 1 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { /* Meant for order 2/mixed ambisonics */ .layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 9, .u.mask = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER }, .num_ele = { 2, 2, 2, 0 }, .pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1, 1 }, { 2, 2 } }, .config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, }, { /* Meant for order 2/mixed ambisonics */ .layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 10, .u.mask = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER }, .num_ele = { 2, 2, 2, 0 }, .pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, }, .index = { { 0, 1 }, { 2, 0 }, { 3, 1 } }, .config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, }, { .layout = AV_CHANNEL_LAYOUT_HEXADECAGONAL, .num_ele = { 4, 2, 4, 0 }, .pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, }, .index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } }, .config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, },}; static void put_pce(PutBitContext *pb, AVCodecContext *avctx){ int i, j; AACEncContext *s = avctx->priv_data; AACPCEInfo *pce = &s->pce; const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT; const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT; put_bits(pb, 4, 0); put_bits(pb, 2, avctx->profile); put_bits(pb, 4, s->samplerate_index); put_bits(pb, 4, pce->num_ele[0]); /* Front */ put_bits(pb, 4, pce->num_ele[1]); /* Side */ put_bits(pb, 4, pce->num_ele[2]); /* Back */ put_bits(pb, 2, pce->num_ele[3]); /* LFE */ put_bits(pb, 3, 0); /* Assoc data */ put_bits(pb, 4, 0); /* CCs */ put_bits(pb, 1, 0); /* Stereo mixdown */ put_bits(pb, 1, 0); /* Mono mixdown */ put_bits(pb, 1, 0); /* Something else */ for (i = 0; i < 4; i++) { for (j = 0; j < pce->num_ele[i]; j++) { if (i < 3) put_bits(pb, 1, pce->pairing[i][j]); put_bits(pb, 4, pce->index[i][j]); } } align_put_bits(pb); put_bits(pb, 8, strlen(aux_data)); ff_put_string(pb, aux_data, 0);} /** * Make AAC audio config object. * @see 1.6.2.1 "Syntax - AudioSpecificConfig" */static int put_audio_specific_config(AVCodecContext *avctx){ PutBitContext pb; AACEncContext *s = avctx->priv_data; int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); const int max_size = 32; avctx->extradata = av_mallocz(max_size); if (!avctx->extradata) return AVERROR(ENOMEM); init_put_bits(&pb, avctx->extradata, max_size); put_bits(&pb, 5, s->profile+1); //profile put_bits(&pb, 4, s->samplerate_index); //sample rate index put_bits(&pb, 4, channels); //GASpecificConfig put_bits(&pb, 1, 0); //frame length - 1024 samples put_bits(&pb, 1, 0); //does not depend on core coder put_bits(&pb, 1, 0); //is not extension if (s->needs_pce) put_pce(&pb, avctx); //Explicitly Mark SBR absent put_bits(&pb, 11, 0x2b7); //sync extension put_bits(&pb, 5, AOT_SBR); put_bits(&pb, 1, 0); flush_put_bits(&pb); avctx->extradata_size = put_bytes_output(&pb); return 0;} void ff_quantize_band_cost_cache_init(struct AACEncContext *s){ ++s->quantize_band_cost_cache_generation; if (s->quantize_band_cost_cache_generation == 0) { memset(s->quantize_band_cost_cache, 0, sizeof(s->quantize_band_cost_cache)); s->quantize_band_cost_cache_generation = 1; }} #define WINDOW_FUNC(type) \static void apply_ ##type ##_window(AVFloatDSPContext *fdsp, \ SingleChannelElement *sce, \ const float *audio) WINDOW_FUNC(only_long){ const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; float *out = sce->ret_buf; fdsp->vector_fmul (out, audio, lwindow, 1024); fdsp->vector_fmul_reverse(out + 1024, audio + 1024, pwindow, 1024);} WINDOW_FUNC(long_start){ const float *lwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; float *out = sce->ret_buf; fdsp->vector_fmul(out, audio, lwindow, 1024); memcpy(out + 1024, audio + 1024, sizeof(out[0]) * 448); fdsp->vector_fmul_reverse(out + 1024 + 448, audio + 1024 + 448, swindow, 128); memset(out + 1024 + 576, 0, sizeof(out[0]) * 448);} WINDOW_FUNC(long_stop){ const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *swindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; float *out = sce->ret_buf; memset(out, 0, sizeof(out[0]) * 448); fdsp->vector_fmul(out + 448, audio + 448, swindow, 128); memcpy(out + 576, audio + 576, sizeof(out[0]) * 448); fdsp->vector_fmul_reverse(out + 1024, audio + 1024, lwindow, 1024);} WINDOW_FUNC(eight_short){ const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; const float *in = audio + 448; float *out = sce->ret_buf; int w; for (w = 0; w < 8; w++) { fdsp->vector_fmul (out, in, w ? pwindow : swindow, 128); out += 128; in += 128; fdsp->vector_fmul_reverse(out, in, swindow, 128); out += 128; }} static void (*const apply_window[4])(AVFloatDSPContext *fdsp, SingleChannelElement *sce, const float *audio) = { [ONLY_LONG_SEQUENCE] = apply_only_long_window, [LONG_START_SEQUENCE] = apply_long_start_window, [EIGHT_SHORT_SEQUENCE] = apply_eight_short_window, [LONG_STOP_SEQUENCE] = apply_long_stop_window}; static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce, float *audio){ int i; float *output = sce->ret_buf; apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, audio); if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) s->mdct1024_fn(s->mdct1024, sce->coeffs, output, sizeof(float)); else for (i = 0; i < 1024; i += 128) s->mdct128_fn(s->mdct128, &sce->coeffs[i], output + i*2, sizeof(float)); memcpy(audio, audio + 1024, sizeof(audio[0]) * 1024); memcpy(sce->pcoeffs, sce->coeffs, sizeof(sce->pcoeffs));} /** * Encode ics_info element. * @see Table 4.6 (syntax of ics_info) */static void put_ics_info(AACEncContext *s, IndividualChannelStream *info){ int w; put_bits(&s->pb, 1, 0); // ics_reserved bitLines 1–500 of 1438. Load more
/* * AAC encoder * Copyright (C) 2008 Konstantin Shishkov * * 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 encoder */ /*********************************** * TODOs: * add sane pulse detection ***********************************/ #include <float.h> #include "libavutil/channel_layout.h" #include "libavutil/libm.h" #include "libavutil/float_dsp.h" #include "libavutil/mem.h" #include "libavutil/opt.h" #include "avcodec.h" #include "codec_internal.h" #include "encode.h" #include "put_bits.h" #include "mpeg4audio.h" #include "sinewin.h" #include "profiles.h" #include "version.h" #include "aac.h" #include "aactab.h" #include "aacenc.h" #include "aacenctab.h" #include "aacenc_utils.h" #include "psymodel.h" /** * List of PCE (Program Configuration Element) for the channel layouts listed * in channel_layout.h * * For those wishing in the future to add other layouts: * * - num_ele: number of elements in each group of front, side, back, lfe channels * (an element is of type SCE (single channel), CPE (channel pair) for * the first 3 groups; and is LFE for LFE group). * * - pairing: 0 for an SCE element or 1 for a CPE; does not apply to LFE group * * - index: there are three independent indices for SCE, CPE and LFE; * they are incremented irrespective of the group to which the element belongs; * they are not reset when going from one group to another * * Example: for 7.0 channel layout, * .pairing = { { 1, 0 }, { 1 }, { 1 }, }, (3 CPE and 1 SCE in front group) * .index = { { 0, 0 }, { 1 }, { 2 }, }, * (index is 0 for the single SCE but goes from 0 to 2 for the CPEs) * * The index order impacts the channel ordering. But is otherwise arbitrary * (the sequence could have been 2, 0, 1 instead of 0, 1, 2). * * Spec allows for discontinuous indices, e.g. if one has a total of two SCE, * SCE.0 SCE.15 is OK per spec; BUT it won't be decoded by our AAC decoder * which at this time requires that indices fully cover some range starting * from 0 (SCE.1 SCE.0 is OK but not SCE.0 SCE.15). * * - config_map: total number of elements and their types. Beware, the way the * types are ordered impacts the final channel ordering. * * - reorder_map: reorders the channels. * */ static const AACPCEInfo aac_pce_configs[] = { { .layout = AV_CHANNEL_LAYOUT_MONO, .num_ele = { 1, 0, 0, 0 }, .pairing = { { 0 }, }, .index = { { 0 }, }, .config_map = { 1, TYPE_SCE, }, .reorder_map = { 0 }, }, { .layout = AV_CHANNEL_LAYOUT_STEREO, .num_ele = { 1, 0, 0, 0 }, .pairing = { { 1 }, }, .index = { { 0 }, }, .config_map = { 1, TYPE_CPE, }, .reorder_map = { 0, 1 }, }, { .layout = AV_CHANNEL_LAYOUT_2POINT1, .num_ele = { 1, 0, 0, 1 }, .pairing = { { 1 }, }, .index = { { 0 },{ 0 },{ 0 },{ 0 } }, .config_map = { 2, TYPE_CPE, TYPE_LFE }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_2_1, .num_ele = { 1, 0, 1, 0 }, .pairing = { { 1 },{ 0 },{ 0 } }, .index = { { 0 },{ 0 },{ 0 }, }, .config_map = { 2, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_SURROUND, .num_ele = { 2, 0, 0, 0 }, .pairing = { { 1, 0 }, }, .index = { { 0, 0 }, }, .config_map = { 2, TYPE_CPE, TYPE_SCE, }, .reorder_map = { 0, 1, 2 }, }, { .layout = AV_CHANNEL_LAYOUT_3POINT1, .num_ele = { 2, 0, 0, 1 }, .pairing = { { 1, 0 }, }, .index = { { 0, 0 }, { 0 }, { 0 }, { 0 }, }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_LFE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_4POINT0, .num_ele = { 2, 0, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 0 }, }, .index = { { 0, 0 }, { 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_4POINT1, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 0 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, { 0 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_2_2, .num_ele = { 1, 1, 0, 0 }, .pairing = { { 1 }, { 1 }, }, .index = { { 0 }, { 1 }, }, .config_map = { 2, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_QUAD, .num_ele = { 1, 0, 1, 0 }, .pairing = { { 1 }, { 0 }, { 1 }, }, .index = { { 0 }, { 0 }, { 1 } }, .config_map = { 2, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT0, .num_ele = { 2, 1, 0, 0 }, .pairing = { { 1, 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT1, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT0_BACK, .num_ele = { 2, 0, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 } }, .index = { { 0, 0 }, { 0 }, { 1 } }, .config_map = { 3, TYPE_CPE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4 }, }, { .layout = AV_CHANNEL_LAYOUT_5POINT1_BACK, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT0, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 0 }, }, .index = { { 0, 0 }, { 1 }, { 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT0_FRONT, .num_ele = { 2, 1, 0, 0 }, .pairing = { { 1, 1 }, { 1 } }, .index = { { 1, 0 }, { 2 }, }, .config_map = { 3, TYPE_CPE, TYPE_CPE, TYPE_CPE, }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_HEXAGONAL, .num_ele = { 2, 0, 2, 0 }, .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, .index = { { 0, 0 },{ 0 },{ 1, 1 } }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, }, .reorder_map = { 0, 1, 2, 3, 4, 5 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 },{ 0 },{ 1, 0 }, }, .index = { { 0, 0 },{ 1 },{ 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1_BACK, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_6POINT1_FRONT, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT0, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT0_FRONT, .num_ele = { 2, 1, 1, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1 }, }, .index = { { 0, 0 }, { 1 }, { 2 }, }, .config_map = { 4, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 },{ 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_7POINT1_WIDE_BACK, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 0 }, { 1, 1 }, }, .index = { { 0, 0 }, { 1 }, { 1, 2 }, { 0 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_SCE, TYPE_CPE, TYPE_CPE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { .layout = AV_CHANNEL_LAYOUT_OCTAGONAL, .num_ele = { 2, 1, 2, 0 }, .pairing = { { 1, 0 }, { 1 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1 }, { 2, 1 } }, .config_map = { 5, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7 }, }, { /* Meant for order 2/mixed ambisonics */ .layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 9, .u.mask = AV_CH_LAYOUT_OCTAGONAL | AV_CH_TOP_CENTER }, .num_ele = { 2, 2, 2, 0 }, .pairing = { { 1, 0 }, { 1, 0 }, { 1, 0 }, }, .index = { { 0, 0 }, { 1, 1 }, { 2, 2 } }, .config_map = { 6, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8 }, }, { /* Meant for order 2/mixed ambisonics */ .layout = { .order = AV_CHANNEL_ORDER_NATIVE, .nb_channels = 10, .u.mask = AV_CH_LAYOUT_6POINT0_FRONT | AV_CH_BACK_CENTER | AV_CH_BACK_LEFT | AV_CH_BACK_RIGHT | AV_CH_TOP_CENTER }, .num_ele = { 2, 2, 2, 0 }, .pairing = { { 1, 1 }, { 1, 0 }, { 1, 0 }, }, .index = { { 0, 1 }, { 2, 0 }, { 3, 1 } }, .config_map = { 6, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }, }, { .layout = AV_CHANNEL_LAYOUT_HEXADECAGONAL, .num_ele = { 4, 2, 4, 0 }, .pairing = { { 1, 0, 1, 0 }, { 1, 1 }, { 1, 0, 1, 0 }, }, .index = { { 0, 0, 1, 1 }, { 2, 3 }, { 4, 2, 5, 3 } }, .config_map = { 10, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_CPE, TYPE_CPE, TYPE_SCE, TYPE_CPE, TYPE_SCE }, .reorder_map = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, }, }; static void put_pce(PutBitContext *pb, AVCodecContext *avctx) { int i, j; AACEncContext *s = avctx->priv_data; AACPCEInfo *pce = &s->pce; const int bitexact = avctx->flags & AV_CODEC_FLAG_BITEXACT; const char *aux_data = bitexact ? "Lavc" : LIBAVCODEC_IDENT; put_bits(pb, 4, 0); put_bits(pb, 2, avctx->profile); put_bits(pb, 4, s->samplerate_index); put_bits(pb, 4, pce->num_ele[0]); /* Front */ put_bits(pb, 4, pce->num_ele[1]); /* Side */ put_bits(pb, 4, pce->num_ele[2]); /* Back */ put_bits(pb, 2, pce->num_ele[3]); /* LFE */ put_bits(pb, 3, 0); /* Assoc data */ put_bits(pb, 4, 0); /* CCs */ put_bits(pb, 1, 0); /* Stereo mixdown */ put_bits(pb, 1, 0); /* Mono mixdown */ put_bits(pb, 1, 0); /* Something else */ for (i = 0; i < 4; i++) { for (j = 0; j < pce->num_ele[i]; j++) { if (i < 3) put_bits(pb, 1, pce->pairing[i][j]); put_bits(pb, 4, pce->index[i][j]); } } align_put_bits(pb); put_bits(pb, 8, strlen(aux_data)); ff_put_string(pb, aux_data, 0); } /** * Make AAC audio config object. * @see 1.6.2.1 "Syntax - AudioSpecificConfig" */ static int put_audio_specific_config(AVCodecContext *avctx) { PutBitContext pb; AACEncContext *s = avctx->priv_data; int channels = (!s->needs_pce)*(s->channels - (s->channels == 8 ? 1 : 0)); const int max_size = 32; avctx->extradata = av_mallocz(max_size); if (!avctx->extradata) return AVERROR(ENOMEM); init_put_bits(&pb, avctx->extradata, max_size); put_bits(&pb, 5, s->profile+1); //profile put_bits(&pb, 4, s->samplerate_index); //sample rate index put_bits(&pb, 4, channels); //GASpecificConfig put_bits(&pb, 1, 0); //frame length - 1024 samples put_bits(&pb, 1, 0); //does not depend on core coder put_bits(&pb, 1, 0); //is not extension if (s->needs_pce) put_pce(&pb, avctx); //Explicitly Mark SBR absent put_bits(&pb, 11, 0x2b7); //sync extension put_bits(&pb, 5, AOT_SBR); put_bits(&pb, 1, 0); flush_put_bits(&pb); avctx->extradata_size = put_bytes_output(&pb); return 0; } void ff_quantize_band_cost_cache_init(struct AACEncContext *s) { ++s->quantize_band_cost_cache_generation; if (s->quantize_band_cost_cache_generation == 0) { memset(s->quantize_band_cost_cache, 0, sizeof(s->quantize_band_cost_cache)); s->quantize_band_cost_cache_generation = 1; } } #define WINDOW_FUNC(type) \ static void apply_ ##type ##_window(AVFloatDSPContext *fdsp, \ SingleChannelElement *sce, \ const float *audio) WINDOW_FUNC(only_long) { const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; float *out = sce->ret_buf; fdsp->vector_fmul (out, audio, lwindow, 1024); fdsp->vector_fmul_reverse(out + 1024, audio + 1024, pwindow, 1024); } WINDOW_FUNC(long_start) { const float *lwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; float *out = sce->ret_buf; fdsp->vector_fmul(out, audio, lwindow, 1024); memcpy(out + 1024, audio + 1024, sizeof(out[0]) * 448); fdsp->vector_fmul_reverse(out + 1024 + 448, audio + 1024 + 448, swindow, 128); memset(out + 1024 + 576, 0, sizeof(out[0]) * 448); } WINDOW_FUNC(long_stop) { const float *lwindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_long_1024 : ff_sine_1024; const float *swindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; float *out = sce->ret_buf; memset(out, 0, sizeof(out[0]) * 448); fdsp->vector_fmul(out + 448, audio + 448, swindow, 128); memcpy(out + 576, audio + 576, sizeof(out[0]) * 448); fdsp->vector_fmul_reverse(out + 1024, audio + 1024, lwindow, 1024); } WINDOW_FUNC(eight_short) { const float *swindow = sce->ics.use_kb_window[0] ? ff_aac_kbd_short_128 : ff_sine_128; const float *pwindow = sce->ics.use_kb_window[1] ? ff_aac_kbd_short_128 : ff_sine_128; const float *in = audio + 448; float *out = sce->ret_buf; int w; for (w = 0; w < 8; w++) { fdsp->vector_fmul (out, in, w ? pwindow : swindow, 128); out += 128; in += 128; fdsp->vector_fmul_reverse(out, in, swindow, 128); out += 128; } } static void (*const apply_window[4])(AVFloatDSPContext *fdsp, SingleChannelElement *sce, const float *audio) = { [ONLY_LONG_SEQUENCE] = apply_only_long_window, [LONG_START_SEQUENCE] = apply_long_start_window, [EIGHT_SHORT_SEQUENCE] = apply_eight_short_window, [LONG_STOP_SEQUENCE] = apply_long_stop_window }; static void apply_window_and_mdct(AACEncContext *s, SingleChannelElement *sce, float *audio) { int i; float *output = sce->ret_buf; apply_window[sce->ics.window_sequence[0]](s->fdsp, sce, audio); if (sce->ics.window_sequence[0] != EIGHT_SHORT_SEQUENCE) s->mdct1024_fn(s->mdct1024, sce->coeffs, output, sizeof(float)); else for (i = 0; i < 1024; i += 128) s->mdct128_fn(s->mdct128, &sce->coeffs[i], output + i*2, sizeof(float)); memcpy(audio, audio + 1024, sizeof(audio[0]) * 1024); memcpy(sce->pcoeffs, sce->coeffs, sizeof(sce->pcoeffs)); } /** * Encode ics_info element. * @see Table 4.6 (syntax of ics_info) */ static void put_ics_info(AACEncContext *s, IndividualChannelStream *info) { int w; put_bits(&s->pb, 1, 0); // ics_reserved bit