diff --git a/.gitignore b/.gitignore index db72140..6a5acaa 100644 --- a/.gitignore +++ b/.gitignore @@ -42,4 +42,5 @@ _start-cmd.bat wiki .cache/ -unused/ \ No newline at end of file +unused/ +externals/libxaac/ \ No newline at end of file diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index 3141162..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "externals/libxaac"] - path = externals/libxaac - url = https://code.ucomsite.my.id/wrapper/libxaac diff --git a/CMakeLists.txt b/CMakeLists.txt index 5951f45..80e3980 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -207,10 +207,10 @@ endif() # Project modules # +include(externals/externals.txt) add_subdirectory(source) add_subdirectory(docs) add_subdirectory(deploy) -add_subdirectory(externals) # # Deployment (global project files) diff --git a/externals/CMakeLists.txt b/externals/CMakeLists.txt deleted file mode 100644 index fc04fa9..0000000 --- a/externals/CMakeLists.txt +++ /dev/null @@ -1,17 +0,0 @@ -# Always build externals as static libraries, even when libaac-next is built as shared -if (BUILD_SHARED_LIBS) - set(BUILD_SHARED_LIBS OFF) - set(CMAKE_POSITION_INDEPENDENT_CODE ON) - set_property(DIRECTORY PROPERTY EXCLUDE_FROM_ALL ON) -endif() - -# Allow options shadowing with normal variables when subproject use old cmake policy -set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - -# Disable tests in all externals supporting the standard option name -set(BUILD_TESTING OFF) - -# For libraries that already come with a CMakeLists file, -# simply add the directory to that file as a subdirectory -# to have CMake automatically recognize them. -add_subdirectory(libxaac) \ No newline at end of file diff --git a/externals/externals.txt b/externals/externals.txt new file mode 100644 index 0000000..c9ef275 --- /dev/null +++ b/externals/externals.txt @@ -0,0 +1,15 @@ +include(ExternalProject) +ExternalProject_Add(libxaac + URL https://github.com/ittiam-systems/libxaac/archive/ae572598c3d9f4757fd743553750981c673ddfb5.zip + DOWNLOAD_EXTRACT_TIMESTAMP OFF + UPDATE_DISCONNECTED 1 + CMAKE_ARGS -DCMAKE_BUILD_TYPE=Release + SOURCE_DIR "${CMAKE_SOURCE_DIR}/externals/libxaac/" + BINARY_DIR "" + INSTALL_COMMAND "" + TEST_COMMAND "" + PATCH_COMMAND patch -p1 < "${CMAKE_SOURCE_DIR}/patch/libxaac.patch" +) + +ExternalProject_Get_Property(libxaac BINARY_DIR) +set(XAAC_BIN_DIR ${BINARY_DIR}) diff --git a/externals/libxaac b/externals/libxaac index 80a67bd..388435c 160000 --- a/externals/libxaac +++ b/externals/libxaac @@ -1 +1 @@ -Subproject commit 80a67bda85225d6c4a1b122691004dec170c0612 +Subproject commit 388435c8f8f43fe0e44bf0d31dd3965283f119ec diff --git a/ffmpeg-git-s16only.patch b/ffmpeg-git-s16only.patch new file mode 100644 index 0000000..e07cf16 --- /dev/null +++ b/ffmpeg-git-s16only.patch @@ -0,0 +1,554 @@ +diff --git a/configure b/configure +index e1809a3e58..fa4fbfb1cb 100755 +--- a/configure ++++ b/configure +@@ -212,6 +212,7 @@ External library support: + --enable-jni enable JNI support [no] + --enable-ladspa enable LADSPA audio filtering [no] + --enable-lcms2 enable ICC profile support via LittleCMS 2 [no] ++ --enable-libaac-next enable AAC encoding using libaac-next [no] + --enable-libaom enable AV1 video encoding/decoding via libaom [no] + --enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no] + --enable-libaribcaption enable ARIB text and caption decoding via libaribcaption [no] +@@ -1901,6 +1902,7 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" + + EXTERNAL_LIBRARY_VERSION3_LIST=" + gmp ++ libaac_next + libaribb24 + liblensfun + libopencore_amrnb +@@ -3592,6 +3594,9 @@ hevc_videotoolbox_encoder_deps="pthreads" + hevc_videotoolbox_encoder_select="atsc_a53 videotoolbox_encoder" + prores_videotoolbox_encoder_deps="pthreads" + prores_videotoolbox_encoder_select="videotoolbox_encoder" ++libaac_next_decoder_deps="libaac_next" ++libaac_next_encoder_deps="libaac_next" ++libaac_next_encoder_select="audio_frame_queue" + libaom_av1_decoder_deps="libaom" + libaom_av1_encoder_deps="libaom" + libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc" +@@ -7016,6 +7021,7 @@ enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gn + enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } + enabled ladspa && require_headers "ladspa.h dlfcn.h" + enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext ++enabled libaac_next && require_pkg_config libaac_next "libaac >= 1.0.0" libaac.h aac_encode_open + enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version + enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode + enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index fb22541f8d..740a008131 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1144,6 +1144,8 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o ++OBJS-$(CONFIG_LIBAAC_NEXT_ENCODER) += libaac_nextenc.o ++OBJS-$(CONFIG_LIBAAC_NEXT_DECODER) += libaac_nextdec.o + OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o + OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o + OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index f5ec2e01e8..8fcd1a806c 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -766,6 +766,8 @@ extern const FFCodec ff_pcm_mulaw_at_encoder; + extern const FFCodec ff_pcm_mulaw_at_decoder; + extern const FFCodec ff_qdmc_at_decoder; + extern const FFCodec ff_qdm2_at_decoder; ++extern const FFCodec ff_libaac_next_encoder; ++extern const FFCodec ff_libaac_next_decoder; + extern FFCodec ff_libaom_av1_encoder; + /* preferred over libaribb24 */ + extern const FFCodec ff_libaribcaption_decoder; +diff --git a/libavcodec/libaac_nextdec.c b/libavcodec/libaac_nextdec.c +new file mode 100644 +index 0000000000..61345ec021 +--- /dev/null ++++ b/libavcodec/libaac_nextdec.c +@@ -0,0 +1,171 @@ ++/* ++ * Libaac-next decoder (libxaac based) ++ * Copyright (c) 2025 Wrapper ++ * ++ * 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 ++ * Interface to libaac-next decoder. ++ */ ++ ++#include "avcodec.h" ++#include ++#include "libavcodec/codec_id.h" ++#include "libavutil/channel_layout.h" ++#include "libavutil/error.h" ++#include "libavutil/log.h" ++#include "libavutil/opt.h" ++#include "avcodec.h" ++#include "codec_internal.h" ++#include "decode.h" ++#include "libavutil/samplefmt.h" ++#include "libavutil/mem.h" ++ ++typedef struct { ++ AVClass *class; ++ AACDecode *decoder; ++ int error_conceal; ++ int esbr; ++ unsigned char *decode_buffer; ++} libaacDecodeCTX; ++ ++static const AVChannelLayout aac_ch_layouts[7] = { ++ AV_CHANNEL_LAYOUT_MONO, ++ AV_CHANNEL_LAYOUT_STEREO, ++ AV_CHANNEL_LAYOUT_SURROUND, ++ AV_CHANNEL_LAYOUT_4POINT0, ++ AV_CHANNEL_LAYOUT_5POINT0_BACK, ++ AV_CHANNEL_LAYOUT_5POINT1_BACK, ++ { 0 }, ++}; ++ ++static const AVOption aac_dec_options[] = { ++ { "conceal", "Error concealment", offsetof(libaacDecodeCTX, error_conceal), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, ++ { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacDecodeCTX, esbr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, ++ { NULL } ++}; ++ ++static const AVClass aac_dec_class = { ++ .class_name = "libaac", ++ .item_name = av_default_item_name, ++ .option = aac_dec_options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static void aac_dec_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { ++ AVCodecContext *ctx = (AVCodecContext *)handle; ++ av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); ++} ++ ++static av_cold int libaac_decode_init(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ AACDecodeSettings cfg = {0}; ++ ++ cfg.bitsPerSamples = 16; ++ cfg.errorConceal = s->error_conceal; ++ cfg.eSBR = s->esbr; ++ cfg.frameSize = 0; ++ cfg.asc = avctx->extradata; ++ cfg.ascSize = avctx->extradata_size; ++ cfg.errorHandleCtx = avctx; ++ cfg.errorHandler = aac_dec_error_handler; ++ ++ s->decoder = aac_decode_open(cfg); ++ if (!s->decoder) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ s->decode_buffer = av_mallocz(4096 * 8); ++ if (!s->decode_buffer) ++ { ++ return AVERROR(ENOMEM); ++ } ++ ++ avctx->sample_fmt = AV_SAMPLE_FMT_S16; ++ return 0; ++} ++ ++static av_cold int libaac_decode_close(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ ++ if (s->decoder) ++ aac_decode_close(s->decoder); ++ ++ return 0; ++} ++ ++static int libaac_decode_frame(AVCodecContext *avctx, AVFrame *frame, ++ int *got_frame_ptr, AVPacket *avpkt) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ uint32_t decode_size, read_size; ++ int ret; ++ ++ ret = aac_decode(s->decoder, avpkt->data, avpkt->size, s->decode_buffer, &decode_size, &read_size); ++ if (ret < 0) ++ return AVERROR_EXTERNAL; ++ ++ avctx->sample_rate = s->decoder->sampleRate; ++ avctx->profile = s->decoder->aot - 1; ++ avctx->ch_layout = aac_ch_layouts[s->decoder->noChannels - 1]; ++ avctx->frame_size = 1024; ++ ++ if (decode_size <= 0) ++ return AVERROR_EOF; ++ ++ frame->nb_samples = decode_size / av_get_bytes_per_sample(avctx->sample_fmt) / avctx->ch_layout.nb_channels; ++ ++ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) ++ return ret; ++ ++ av_log(avctx, AV_LOG_TRACE, "aac decode size: %d, decode buf: %d\n", decode_size, avctx->ch_layout.nb_channels * frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt)); ++ memcpy(frame->data[0], s->decode_buffer, decode_size); ++ ++ *got_frame_ptr = 1; ++ return read_size; ++} ++ ++static av_cold void libaac_decode_flush(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ ++ if (!s->decoder) ++ return; ++ ++ aac_decode_flush_buffer(s->decoder); ++} ++ ++const FFCodec ff_libaac_next_decoder = { ++ .p.name = "libaac", ++ CODEC_LONG_NAME("custom libxaac-based AAC decoder"), ++ .p.type = AVMEDIA_TYPE_AUDIO, ++ .p.id = AV_CODEC_ID_AAC, ++ .priv_data_size = sizeof(libaacDecodeCTX), ++ .init = libaac_decode_init, ++ FF_CODEC_DECODE_CB(libaac_decode_frame), ++ .close = libaac_decode_close, ++ .flush = libaac_decode_flush, ++ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, ++ .p.priv_class = &aac_dec_class, ++ .p.wrapper_name = "libaac", ++}; +diff --git a/libavcodec/libaac_nextenc.c b/libavcodec/libaac_nextenc.c +new file mode 100755 +index 0000000000..f9d7706285 +--- /dev/null ++++ b/libavcodec/libaac_nextenc.c +@@ -0,0 +1,307 @@ ++/* ++ * Libaac-next encoder (libxaac based) ++ * Copyright (c) 2025 Wrapper ++ * ++ * 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 ++ * Interface to libaac-next encoder. ++ */ ++ ++#include ++ ++#include "libavutil/channel_layout.h" ++#include "libavutil/internal.h" ++#include "libavutil/intreadwrite.h" ++#include "libavutil/log.h" ++#include "libavutil/opt.h" ++#include "libavutil/mem.h" ++#include "avcodec.h" ++#include "defs.h" ++#include "audio_frame_queue.h" ++#include "codec_internal.h" ++#include "encode.h" ++#include "libavutil/samplefmt.h" ++#include "profiles.h" ++ ++typedef struct ++{ ++ const AVClass *class; ++ AACContext *encoder; ++ int delay_sent; ++ int flush_delay; ++ ++ int eld_v2; ++ int esbr; ++ int frame_length; ++ int iq; ++ int tns; ++ ++ AudioFrameQueue afq; ++} libaacEncodeCTX; ++ ++static const AVOption aac_enc_options[] = { ++ { "eld_v2", "Enable ELDv2 (LD-MPS extension for ELD stereo signals)", offsetof(libaacEncodeCTX, eld_v2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacEncodeCTX, esbr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "frame_length", "The desired frame length", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1024, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "iq", "Inverse quantization", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "tns", "Temporal Noise Shaping", offsetof(libaacEncodeCTX, tns), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ FF_AAC_PROFILE_OPTS ++ { NULL } ++}; ++ ++static const AVClass aac_enc_class = { ++ .class_name = "libaac", ++ .item_name = av_default_item_name, ++ .option = aac_enc_options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static void aac_enc_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { ++ AVCodecContext *ctx = (AVCodecContext *)handle; ++ av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); ++} ++ ++static av_cold int libaac_encode_init(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ AACSettings cfg = {0}; ++ ++ /* number of channels */ ++ if (avctx->ch_layout.nb_channels < 1 || avctx->ch_layout.nb_channels > 6) ++ { ++ av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->ch_layout.nb_channels); ++ return AVERROR(EINVAL); ++ } ++ ++ cfg.sampleRate = avctx->sample_rate; ++ cfg.noChannels = avctx->ch_layout.nb_channels; ++ cfg.bitsPerSamples = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 32 : 16; ++ cfg.bitrate = avctx->bit_rate; ++ cfg.adts = !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER); ++ cfg.cutoff = avctx->cutoff; ++ switch (avctx->profile) { ++ case AV_PROFILE_AAC_LOW: ++ case AV_PROFILE_UNKNOWN: ++ cfg.profile = AAC_LC; ++ break; ++ ++ case AV_PROFILE_AAC_HE: ++ cfg.profile = AAC_HE; ++ break; ++ ++ case AV_PROFILE_AAC_HE_V2: ++ cfg.profile = AAC_HEV2; ++ break; ++ ++ case AV_PROFILE_AAC_LD: ++ cfg.profile = AAC_LD; ++ break; ++ ++ case AV_PROFILE_AAC_ELD: ++ cfg.profile = AAC_ELD; ++ break; ++ ++ default: ++ av_log(avctx, AV_LOG_ERROR, "unsupported profile, supported profiles are LC, HE, HEv2, LD and ELD\n"); ++ return AVERROR(EINVAL); ++ } ++ cfg.tns = s->tns; ++ cfg.frameSize = s->frame_length; ++ cfg.eSBR = s->esbr; ++ cfg.iq = s->iq; ++ ++ cfg.errorHandleCtx = avctx; ++ cfg.errorHandler = aac_enc_error_handler; ++ ++ s->encoder = aac_encode_open(cfg); ++ ++ if (!s->encoder) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ avctx->frame_size = s->encoder->no_samples / avctx->ch_layout.nb_channels; ++ avctx->initial_padding = s->encoder->inputDelay; ++ s->flush_delay = s->encoder->inputDelay; ++ ++ av_log(avctx, AV_LOG_TRACE, "frame size: %d, initial delay: %d\n", avctx->frame_size, avctx->initial_padding); ++ ++ ff_af_queue_init(avctx, &s->afq); ++ ++ /* Set decoder specific info */ ++ avctx->extradata_size = 0; ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ++ { ++ avctx->extradata = av_mallocz(s->encoder->ascSize + AV_INPUT_BUFFER_PADDING_SIZE); ++ ++ if (!avctx->extradata) ++ { ++ return AVERROR(ENOMEM); ++ } ++ ++ avctx->extradata_size = s->encoder->ascSize; ++ memcpy(avctx->extradata, s->encoder->asc, s->encoder->ascSize); ++ } ++ return 0; ++} ++ ++static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ++ const AVFrame *frame, int *got_packet) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ int ret; ++ int discard_padding; ++ ++ if ((ret = ff_alloc_packet(avctx, pkt, s->encoder->max_out_bytes)) < 0) ++ return ret; ++ ++ if (!frame) ++ { ++ av_log(avctx, AV_LOG_TRACE, "flush_delay: %d\n", s->flush_delay); ++ ++ if (s->flush_delay <= 0) ++ return 0; ++ ++ /* Flushing */ ++ if ((ret = aac_encode(s->encoder, NULL, 0, pkt->data, (unsigned int *)&pkt->size)) < 0) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ s->flush_delay -= avctx->frame_size; ++ } ++ else ++ { ++ /* Encoding */ ++ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) ++ return ret; ++ ++ int encodeSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels * frame->nb_samples; ++ av_log(avctx, AV_LOG_TRACE, "encode size: %d\n", encodeSize); ++ ++ if ((ret = aac_encode(s->encoder, frame->data[0], encodeSize, pkt->data, (unsigned int *)&pkt->size)) < 0) ++ { ++ return AVERROR(EINVAL); ++ } ++ } ++ ++ ff_af_queue_remove(&s->afq, avctx->frame_size, &pkt->pts, &pkt->duration); ++ ++ /* discard padding copied from fdkaac encoder */ ++ discard_padding = avctx->frame_size - pkt->duration; ++ ++ // Check if subtraction resulted in an overflow ++ if ((discard_padding < avctx->frame_size) != (pkt->duration > 0)) ++ { ++ av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n"); ++ return AVERROR(EINVAL); ++ } ++ ++ if ((!s->delay_sent && avctx->initial_padding > 0) || discard_padding > 0) ++ { ++ uint8_t *side_data = ++ av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); ++ if (!side_data) ++ return AVERROR(ENOMEM); ++ if (!s->delay_sent) ++ { ++ AV_WL32(side_data, avctx->initial_padding); ++ s->delay_sent = 1; ++ } ++ AV_WL32(side_data + 4, discard_padding); ++ } ++ ++ pkt->flags |= AV_PKT_FLAG_KEY; ++ *got_packet = 1; ++ return 0; ++} ++ ++static void libaac_encode_flush(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ uint8_t sink_null[32768]; ++ int64_t pts, duration; ++ uint32_t out_bytes; ++ ++ av_log(avctx, AV_LOG_TRACE, "encoder flush\n"); ++ ff_af_queue_remove(&s->afq, s->afq.frame_count, &pts, &duration); ++ aac_encode(s->encoder, NULL, 0, sink_null, &out_bytes); ++} ++ ++static av_cold int libaac_encode_close(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ ++ if (s->encoder) ++ aac_encode_close(s->encoder); ++ ++ ff_af_queue_close(&s->afq); ++ ++ return 0; ++} ++ ++static const FFCodecDefault defaults[] = { ++ {"b", "128000"}, ++ {NULL}}; ++ ++static const AVProfile libaac_profiles[] = { ++ { AV_PROFILE_AAC_LOW, "LC" }, ++ { AV_PROFILE_AAC_HE, "HE-AAC" }, ++ { AV_PROFILE_AAC_HE_V2, "HE-AACv2" }, ++ { AV_PROFILE_AAC_LD, "LD" }, ++ { AV_PROFILE_AAC_ELD, "ELD" }, ++ {AV_PROFILE_UNKNOWN}, ++}; ++ ++static const int aac_sample_rates[] = { ++ 96000, 88200, 64000, 48000, 44100, 32000, ++ 24000, 22050, 16000, 12000, 11025, 8000, 0 ++}; ++ ++static const AVChannelLayout aac_ch_layouts[7] = { ++ AV_CHANNEL_LAYOUT_MONO, ++ AV_CHANNEL_LAYOUT_STEREO, ++ AV_CHANNEL_LAYOUT_SURROUND, ++ AV_CHANNEL_LAYOUT_4POINT0, ++ AV_CHANNEL_LAYOUT_5POINT0_BACK, ++ AV_CHANNEL_LAYOUT_5POINT1_BACK, ++ { 0 }, ++}; ++ ++const FFCodec ff_libaac_next_encoder = { ++ .p.name = "libaac", ++ CODEC_LONG_NAME("custom libxaac-based AAC encoder"), ++ .p.type = AVMEDIA_TYPE_AUDIO, ++ .p.id = AV_CODEC_ID_AAC, ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_FLUSH, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, ++ .priv_data_size = sizeof(libaacEncodeCTX), ++ .init = libaac_encode_init, ++ FF_CODEC_ENCODE_CB(libaac_encode_frame), ++ .flush = libaac_encode_flush, ++ .close = libaac_encode_close, ++ CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_S16), ++ .p.priv_class = &aac_enc_class, ++ .defaults = defaults, ++ .p.profiles = libaac_profiles, ++ CODEC_SAMPLERATES_ARRAY(aac_sample_rates), ++ .p.wrapper_name = "libaac", ++ CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts), ++}; diff --git a/ffmpeg-git.patch b/ffmpeg-git.patch new file mode 100644 index 0000000..56faf72 --- /dev/null +++ b/ffmpeg-git.patch @@ -0,0 +1,554 @@ +diff --git a/configure b/configure +index e1809a3e58..fa4fbfb1cb 100755 +--- a/configure ++++ b/configure +@@ -212,6 +212,7 @@ External library support: + --enable-jni enable JNI support [no] + --enable-ladspa enable LADSPA audio filtering [no] + --enable-lcms2 enable ICC profile support via LittleCMS 2 [no] ++ --enable-libaac-next enable AAC encoding using libaac-next [no] + --enable-libaom enable AV1 video encoding/decoding via libaom [no] + --enable-libaribb24 enable ARIB text and caption decoding via libaribb24 [no] + --enable-libaribcaption enable ARIB text and caption decoding via libaribcaption [no] +@@ -1901,6 +1902,7 @@ EXTERNAL_LIBRARY_NONFREE_LIST=" + + EXTERNAL_LIBRARY_VERSION3_LIST=" + gmp ++ libaac_next + libaribb24 + liblensfun + libopencore_amrnb +@@ -3592,6 +3594,9 @@ hevc_videotoolbox_encoder_deps="pthreads" + hevc_videotoolbox_encoder_select="atsc_a53 videotoolbox_encoder" + prores_videotoolbox_encoder_deps="pthreads" + prores_videotoolbox_encoder_select="videotoolbox_encoder" ++libaac_next_decoder_deps="libaac_next" ++libaac_next_encoder_deps="libaac_next" ++libaac_next_encoder_select="audio_frame_queue" + libaom_av1_decoder_deps="libaom" + libaom_av1_encoder_deps="libaom" + libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc" +@@ -7016,6 +7021,7 @@ enabled gnutls && require_pkg_config gnutls gnutls gnutls/gnutls.h gn + enabled jni && { [ $target_os = "android" ] && check_headers jni.h && enabled pthreads || die "ERROR: jni not found"; } + enabled ladspa && require_headers "ladspa.h dlfcn.h" + enabled lcms2 && require_pkg_config lcms2 "lcms2 >= 2.13" lcms2.h cmsCreateContext ++enabled libaac_next && require_pkg_config libaac_next "libaac >= 1.0.0" libaac.h aac_encode_open + enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version + enabled liboapv && require_pkg_config liboapv "oapv >= 0.2.0.0" "oapv/oapv.h" oapve_encode + enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new || +diff --git a/libavcodec/Makefile b/libavcodec/Makefile +index fb22541f8d..740a008131 100644 +--- a/libavcodec/Makefile ++++ b/libavcodec/Makefile +@@ -1144,6 +1144,8 @@ OBJS-$(CONFIG_ALAC_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_ILBC_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_PCM_ALAW_AT_ENCODER) += audiotoolboxenc.o + OBJS-$(CONFIG_PCM_MULAW_AT_ENCODER) += audiotoolboxenc.o ++OBJS-$(CONFIG_LIBAAC_NEXT_ENCODER) += libaac_nextenc.o ++OBJS-$(CONFIG_LIBAAC_NEXT_DECODER) += libaac_nextdec.o + OBJS-$(CONFIG_LIBAOM_AV1_DECODER) += libaomdec.o libaom.o + OBJS-$(CONFIG_LIBAOM_AV1_ENCODER) += libaomenc.o libaom.o + OBJS-$(CONFIG_LIBARIBB24_DECODER) += libaribb24.o ass.o +diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c +index f5ec2e01e8..8fcd1a806c 100644 +--- a/libavcodec/allcodecs.c ++++ b/libavcodec/allcodecs.c +@@ -766,6 +766,8 @@ extern const FFCodec ff_pcm_mulaw_at_encoder; + extern const FFCodec ff_pcm_mulaw_at_decoder; + extern const FFCodec ff_qdmc_at_decoder; + extern const FFCodec ff_qdm2_at_decoder; ++extern const FFCodec ff_libaac_next_encoder; ++extern const FFCodec ff_libaac_next_decoder; + extern FFCodec ff_libaom_av1_encoder; + /* preferred over libaribb24 */ + extern const FFCodec ff_libaribcaption_decoder; +diff --git a/libavcodec/libaac_nextdec.c b/libavcodec/libaac_nextdec.c +new file mode 100644 +index 0000000000..61345ec021 +--- /dev/null ++++ b/libavcodec/libaac_nextdec.c +@@ -0,0 +1,171 @@ ++/* ++ * Libaac-next decoder (libxaac based) ++ * Copyright (c) 2025 Wrapper ++ * ++ * 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 ++ * Interface to libaac-next decoder. ++ */ ++ ++#include "avcodec.h" ++#include ++#include "libavcodec/codec_id.h" ++#include "libavutil/channel_layout.h" ++#include "libavutil/error.h" ++#include "libavutil/log.h" ++#include "libavutil/opt.h" ++#include "avcodec.h" ++#include "codec_internal.h" ++#include "decode.h" ++#include "libavutil/samplefmt.h" ++#include "libavutil/mem.h" ++ ++typedef struct { ++ AVClass *class; ++ AACDecode *decoder; ++ int error_conceal; ++ int esbr; ++ unsigned char *decode_buffer; ++} libaacDecodeCTX; ++ ++static const AVChannelLayout aac_ch_layouts[7] = { ++ AV_CHANNEL_LAYOUT_MONO, ++ AV_CHANNEL_LAYOUT_STEREO, ++ AV_CHANNEL_LAYOUT_SURROUND, ++ AV_CHANNEL_LAYOUT_4POINT0, ++ AV_CHANNEL_LAYOUT_5POINT0_BACK, ++ AV_CHANNEL_LAYOUT_5POINT1_BACK, ++ { 0 }, ++}; ++ ++static const AVOption aac_dec_options[] = { ++ { "conceal", "Error concealment", offsetof(libaacDecodeCTX, error_conceal), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, ++ { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacDecodeCTX, esbr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_DECODING_PARAM }, ++ { NULL } ++}; ++ ++static const AVClass aac_dec_class = { ++ .class_name = "libaac", ++ .item_name = av_default_item_name, ++ .option = aac_dec_options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static void aac_dec_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { ++ AVCodecContext *ctx = (AVCodecContext *)handle; ++ av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); ++} ++ ++static av_cold int libaac_decode_init(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ AACDecodeSettings cfg = {0}; ++ ++ cfg.bitsPerSamples = 16; ++ cfg.errorConceal = s->error_conceal; ++ cfg.eSBR = s->esbr; ++ cfg.frameSize = 0; ++ cfg.asc = avctx->extradata; ++ cfg.ascSize = avctx->extradata_size; ++ cfg.errorHandleCtx = avctx; ++ cfg.errorHandler = aac_dec_error_handler; ++ ++ s->decoder = aac_decode_open(cfg); ++ if (!s->decoder) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ s->decode_buffer = av_mallocz(4096 * 8); ++ if (!s->decode_buffer) ++ { ++ return AVERROR(ENOMEM); ++ } ++ ++ avctx->sample_fmt = AV_SAMPLE_FMT_S16; ++ return 0; ++} ++ ++static av_cold int libaac_decode_close(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ ++ if (s->decoder) ++ aac_decode_close(s->decoder); ++ ++ return 0; ++} ++ ++static int libaac_decode_frame(AVCodecContext *avctx, AVFrame *frame, ++ int *got_frame_ptr, AVPacket *avpkt) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ uint32_t decode_size, read_size; ++ int ret; ++ ++ ret = aac_decode(s->decoder, avpkt->data, avpkt->size, s->decode_buffer, &decode_size, &read_size); ++ if (ret < 0) ++ return AVERROR_EXTERNAL; ++ ++ avctx->sample_rate = s->decoder->sampleRate; ++ avctx->profile = s->decoder->aot - 1; ++ avctx->ch_layout = aac_ch_layouts[s->decoder->noChannels - 1]; ++ avctx->frame_size = 1024; ++ ++ if (decode_size <= 0) ++ return AVERROR_EOF; ++ ++ frame->nb_samples = decode_size / av_get_bytes_per_sample(avctx->sample_fmt) / avctx->ch_layout.nb_channels; ++ ++ if ((ret = ff_get_buffer(avctx, frame, 0)) < 0) ++ return ret; ++ ++ av_log(avctx, AV_LOG_TRACE, "aac decode size: %d, decode buf: %d\n", decode_size, avctx->ch_layout.nb_channels * frame->nb_samples * av_get_bytes_per_sample(avctx->sample_fmt)); ++ memcpy(frame->data[0], s->decode_buffer, decode_size); ++ ++ *got_frame_ptr = 1; ++ return read_size; ++} ++ ++static av_cold void libaac_decode_flush(AVCodecContext *avctx) ++{ ++ libaacDecodeCTX *s = avctx->priv_data; ++ ++ if (!s->decoder) ++ return; ++ ++ aac_decode_flush_buffer(s->decoder); ++} ++ ++const FFCodec ff_libaac_next_decoder = { ++ .p.name = "libaac", ++ CODEC_LONG_NAME("custom libxaac-based AAC decoder"), ++ .p.type = AVMEDIA_TYPE_AUDIO, ++ .p.id = AV_CODEC_ID_AAC, ++ .priv_data_size = sizeof(libaacDecodeCTX), ++ .init = libaac_decode_init, ++ FF_CODEC_DECODE_CB(libaac_decode_frame), ++ .close = libaac_decode_close, ++ .flush = libaac_decode_flush, ++ .p.capabilities = AV_CODEC_CAP_DR1 | AV_CODEC_CAP_CHANNEL_CONF, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, ++ .p.priv_class = &aac_dec_class, ++ .p.wrapper_name = "libaac", ++}; +diff --git a/libavcodec/libaac_nextenc.c b/libavcodec/libaac_nextenc.c +new file mode 100755 +index 0000000000..f9d7706285 +--- /dev/null ++++ b/libavcodec/libaac_nextenc.c +@@ -0,0 +1,307 @@ ++/* ++ * Libaac-next encoder (libxaac based) ++ * Copyright (c) 2025 Wrapper ++ * ++ * 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 ++ * Interface to libaac-next encoder. ++ */ ++ ++#include ++ ++#include "libavutil/channel_layout.h" ++#include "libavutil/internal.h" ++#include "libavutil/intreadwrite.h" ++#include "libavutil/log.h" ++#include "libavutil/opt.h" ++#include "libavutil/mem.h" ++#include "avcodec.h" ++#include "defs.h" ++#include "audio_frame_queue.h" ++#include "codec_internal.h" ++#include "encode.h" ++#include "libavutil/samplefmt.h" ++#include "profiles.h" ++ ++typedef struct ++{ ++ const AVClass *class; ++ AACContext *encoder; ++ int delay_sent; ++ int flush_delay; ++ ++ int eld_v2; ++ int esbr; ++ int frame_length; ++ int iq; ++ int tns; ++ ++ AudioFrameQueue afq; ++} libaacEncodeCTX; ++ ++static const AVOption aac_enc_options[] = { ++ { "eld_v2", "Enable ELDv2 (LD-MPS extension for ELD stereo signals)", offsetof(libaacEncodeCTX, eld_v2), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "esbr", "Enable the use of Enhanced SBR", offsetof(libaacEncodeCTX, esbr), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "frame_length", "The desired frame length", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1024, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "iq", "Inverse quantization", offsetof(libaacEncodeCTX, frame_length), AV_OPT_TYPE_INT, { .i64 = 2 }, 0, 2, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ { "tns", "Temporal Noise Shaping", offsetof(libaacEncodeCTX, tns), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, ++ FF_AAC_PROFILE_OPTS ++ { NULL } ++}; ++ ++static const AVClass aac_enc_class = { ++ .class_name = "libaac", ++ .item_name = av_default_item_name, ++ .option = aac_enc_options, ++ .version = LIBAVUTIL_VERSION_INT, ++}; ++ ++static void aac_enc_error_handler(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle) { ++ AVCodecContext *ctx = (AVCodecContext *)handle; ++ av_log(ctx, AV_LOG_ERROR, "%s: %s (0x%08X)\n", section, errorMsg, errorCode); ++} ++ ++static av_cold int libaac_encode_init(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ AACSettings cfg = {0}; ++ ++ /* number of channels */ ++ if (avctx->ch_layout.nb_channels < 1 || avctx->ch_layout.nb_channels > 6) ++ { ++ av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->ch_layout.nb_channels); ++ return AVERROR(EINVAL); ++ } ++ ++ cfg.sampleRate = avctx->sample_rate; ++ cfg.noChannels = avctx->ch_layout.nb_channels; ++ cfg.bitsPerSamples = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? 32 : 16; ++ cfg.bitrate = avctx->bit_rate; ++ cfg.adts = !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER); ++ cfg.cutoff = avctx->cutoff; ++ switch (avctx->profile) { ++ case AV_PROFILE_AAC_LOW: ++ case AV_PROFILE_UNKNOWN: ++ cfg.profile = AAC_LC; ++ break; ++ ++ case AV_PROFILE_AAC_HE: ++ cfg.profile = AAC_HE; ++ break; ++ ++ case AV_PROFILE_AAC_HE_V2: ++ cfg.profile = AAC_HEV2; ++ break; ++ ++ case AV_PROFILE_AAC_LD: ++ cfg.profile = AAC_LD; ++ break; ++ ++ case AV_PROFILE_AAC_ELD: ++ cfg.profile = AAC_ELD; ++ break; ++ ++ default: ++ av_log(avctx, AV_LOG_ERROR, "unsupported profile, supported profiles are LC, HE, HEv2, LD and ELD\n"); ++ return AVERROR(EINVAL); ++ } ++ cfg.tns = s->tns; ++ cfg.frameSize = s->frame_length; ++ cfg.eSBR = s->esbr; ++ cfg.iq = s->iq; ++ ++ cfg.errorHandleCtx = avctx; ++ cfg.errorHandler = aac_enc_error_handler; ++ ++ s->encoder = aac_encode_open(cfg); ++ ++ if (!s->encoder) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ avctx->frame_size = s->encoder->no_samples / avctx->ch_layout.nb_channels; ++ avctx->initial_padding = s->encoder->inputDelay; ++ s->flush_delay = s->encoder->inputDelay; ++ ++ av_log(avctx, AV_LOG_TRACE, "frame size: %d, initial delay: %d\n", avctx->frame_size, avctx->initial_padding); ++ ++ ff_af_queue_init(avctx, &s->afq); ++ ++ /* Set decoder specific info */ ++ avctx->extradata_size = 0; ++ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER) ++ { ++ avctx->extradata = av_mallocz(s->encoder->ascSize + AV_INPUT_BUFFER_PADDING_SIZE); ++ ++ if (!avctx->extradata) ++ { ++ return AVERROR(ENOMEM); ++ } ++ ++ avctx->extradata_size = s->encoder->ascSize; ++ memcpy(avctx->extradata, s->encoder->asc, s->encoder->ascSize); ++ } ++ return 0; ++} ++ ++static int libaac_encode_frame(AVCodecContext *avctx, AVPacket *pkt, ++ const AVFrame *frame, int *got_packet) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ int ret; ++ int discard_padding; ++ ++ if ((ret = ff_alloc_packet(avctx, pkt, s->encoder->max_out_bytes)) < 0) ++ return ret; ++ ++ if (!frame) ++ { ++ av_log(avctx, AV_LOG_TRACE, "flush_delay: %d\n", s->flush_delay); ++ ++ if (s->flush_delay <= 0) ++ return 0; ++ ++ /* Flushing */ ++ if ((ret = aac_encode(s->encoder, NULL, 0, pkt->data, (unsigned int *)&pkt->size)) < 0) ++ { ++ return AVERROR(EINVAL); ++ } ++ ++ s->flush_delay -= avctx->frame_size; ++ } ++ else ++ { ++ /* Encoding */ ++ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0) ++ return ret; ++ ++ int encodeSize = av_get_bytes_per_sample(avctx->sample_fmt) * avctx->ch_layout.nb_channels * frame->nb_samples; ++ av_log(avctx, AV_LOG_TRACE, "encode size: %d\n", encodeSize); ++ ++ if ((ret = aac_encode(s->encoder, frame->data[0], encodeSize, pkt->data, (unsigned int *)&pkt->size)) < 0) ++ { ++ return AVERROR(EINVAL); ++ } ++ } ++ ++ ff_af_queue_remove(&s->afq, avctx->frame_size, &pkt->pts, &pkt->duration); ++ ++ /* discard padding copied from fdkaac encoder */ ++ discard_padding = avctx->frame_size - pkt->duration; ++ ++ // Check if subtraction resulted in an overflow ++ if ((discard_padding < avctx->frame_size) != (pkt->duration > 0)) ++ { ++ av_log(avctx, AV_LOG_ERROR, "discard padding overflow\n"); ++ return AVERROR(EINVAL); ++ } ++ ++ if ((!s->delay_sent && avctx->initial_padding > 0) || discard_padding > 0) ++ { ++ uint8_t *side_data = ++ av_packet_new_side_data(pkt, AV_PKT_DATA_SKIP_SAMPLES, 10); ++ if (!side_data) ++ return AVERROR(ENOMEM); ++ if (!s->delay_sent) ++ { ++ AV_WL32(side_data, avctx->initial_padding); ++ s->delay_sent = 1; ++ } ++ AV_WL32(side_data + 4, discard_padding); ++ } ++ ++ pkt->flags |= AV_PKT_FLAG_KEY; ++ *got_packet = 1; ++ return 0; ++} ++ ++static void libaac_encode_flush(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ uint8_t sink_null[32768]; ++ int64_t pts, duration; ++ uint32_t out_bytes; ++ ++ av_log(avctx, AV_LOG_TRACE, "encoder flush\n"); ++ ff_af_queue_remove(&s->afq, s->afq.frame_count, &pts, &duration); ++ aac_encode(s->encoder, NULL, 0, sink_null, &out_bytes); ++} ++ ++static av_cold int libaac_encode_close(AVCodecContext *avctx) ++{ ++ libaacEncodeCTX *s = avctx->priv_data; ++ ++ if (s->encoder) ++ aac_encode_close(s->encoder); ++ ++ ff_af_queue_close(&s->afq); ++ ++ return 0; ++} ++ ++static const FFCodecDefault defaults[] = { ++ {"b", "128000"}, ++ {NULL}}; ++ ++static const AVProfile libaac_profiles[] = { ++ { AV_PROFILE_AAC_LOW, "LC" }, ++ { AV_PROFILE_AAC_HE, "HE-AAC" }, ++ { AV_PROFILE_AAC_HE_V2, "HE-AACv2" }, ++ { AV_PROFILE_AAC_LD, "LD" }, ++ { AV_PROFILE_AAC_ELD, "ELD" }, ++ {AV_PROFILE_UNKNOWN}, ++}; ++ ++static const int aac_sample_rates[] = { ++ 96000, 88200, 64000, 48000, 44100, 32000, ++ 24000, 22050, 16000, 12000, 11025, 8000, 0 ++}; ++ ++static const AVChannelLayout aac_ch_layouts[7] = { ++ AV_CHANNEL_LAYOUT_MONO, ++ AV_CHANNEL_LAYOUT_STEREO, ++ AV_CHANNEL_LAYOUT_SURROUND, ++ AV_CHANNEL_LAYOUT_4POINT0, ++ AV_CHANNEL_LAYOUT_5POINT0_BACK, ++ AV_CHANNEL_LAYOUT_5POINT1_BACK, ++ { 0 }, ++}; ++ ++const FFCodec ff_libaac_next_encoder = { ++ .p.name = "libaac", ++ CODEC_LONG_NAME("custom libxaac-based AAC encoder"), ++ .p.type = AVMEDIA_TYPE_AUDIO, ++ .p.id = AV_CODEC_ID_AAC, ++ .p.capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_FLUSH, ++ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE, ++ .priv_data_size = sizeof(libaacEncodeCTX), ++ .init = libaac_encode_init, ++ FF_CODEC_ENCODE_CB(libaac_encode_frame), ++ .flush = libaac_encode_flush, ++ .close = libaac_encode_close, ++ CODEC_SAMPLEFMTS(AV_SAMPLE_FMT_FLT, AV_SAMPLE_FMT_S16), ++ .p.priv_class = &aac_enc_class, ++ .defaults = defaults, ++ .p.profiles = libaac_profiles, ++ CODEC_SAMPLERATES_ARRAY(aac_sample_rates), ++ .p.wrapper_name = "libaac", ++ CODEC_CH_LAYOUTS_ARRAY(aac_ch_layouts), ++}; diff --git a/patch/libxaac.patch b/patch/libxaac.patch index 2145e71..4487f89 100644 --- a/patch/libxaac.patch +++ b/patch/libxaac.patch @@ -1,3 +1,13 @@ +diff --git a/CMakeLists.txt b/CMakeLists.txt +index 82539b7..4996c67 100644 +--- a/CMakeLists.txt ++++ b/CMakeLists.txt +@@ -27,3 +27,5 @@ include("${XAAC_ROOT}/encoder/libxaacenc.cmake") + include("${XAAC_ROOT}/test/encoder/xaacenc.cmake") + include("${XAAC_ROOT}/fuzzer/xaac_enc_fuzzer.cmake") + ++set_property(TARGET libxaacenc PROPERTY POSITION_INDEPENDENT_CODE 1) ++set_property(TARGET libxaacdec PROPERTY POSITION_INDEPENDENT_CODE 1) diff --git a/cmake/utils.cmake b/cmake/utils.cmake index 5d9cd37..3196501 100644 --- a/cmake/utils.cmake @@ -11,7 +21,7 @@ index 5d9cd37..3196501 100644 # Adds libraries needed for executables diff --git a/decoder/ixheaacd_api.c b/decoder/ixheaacd_api.c -index 5e6a0ac..c4ae8e0 100644 +index 5e6a0ac..3504a10 100644 --- a/decoder/ixheaacd_api.c +++ b/decoder/ixheaacd_api.c @@ -579,7 +579,7 @@ IA_ERRORCODE ixheaacd_dec_api(pVOID p_ia_xheaac_dec_obj, WORD32 i_cmd, @@ -23,6 +33,23 @@ index 5e6a0ac..c4ae8e0 100644 p_obj_exhaacplus_dec->aac_config.ui_pcm_wdsz = 16; return (IA_XHEAAC_DEC_CONFIG_NONFATAL_INVALID_PCM_WDSZ); } +@@ -940,6 +940,7 @@ IA_ERRORCODE ixheaacd_dec_api(pVOID p_ia_xheaac_dec_obj, WORD32 i_cmd, + } else { + *pui_value = p_obj_exhaacplus_dec->p_state_aac->audio_object_type; + } ++ if (*pui_value == AOT_AAC_LC) *pui_value = p_obj_exhaacplus_dec->p_state_aac->init_sbr_flag ? (p_obj_exhaacplus_dec->p_state_aac->init_ps_flag ? AOT_PS : AOT_SBR) : AOT_AAC_LC; + } else { + *pui_value = AOT_AAC_LC; + } +@@ -2530,6 +2531,8 @@ IA_ERRORCODE ixheaacd_dec_init( + p_obj_exhaacplus_dec->aac_config.ui_n_channels = num_channels_1; + p_obj_exhaacplus_dec->aac_config.ui_samp_freq = sample_rate; + p_state_enhaacplus_dec->ui_init_done = 1; ++ p_state_enhaacplus_dec->init_sbr_flag = sbr_present_flag; ++ p_state_enhaacplus_dec->init_ps_flag = !p_obj_exhaacplus_dec->aac_config.ui_channel_mode; + + memcpy(it_bit_buff, &temp_bit_buff, sizeof(struct ia_bit_buf_struct)); + diff --git a/decoder/ixheaacd_decode_main.c b/decoder/ixheaacd_decode_main.c index 982a6aa..d827687 100644 --- a/decoder/ixheaacd_decode_main.c @@ -56,8 +83,21 @@ index 982a6aa..d827687 100644 } else { WORD8 *out_24bit = (WORD8 *)out_buf; for (i = 0; i < num; i++) { +diff --git a/decoder/ixheaacd_struct_def.h b/decoder/ixheaacd_struct_def.h +index fea3b56..8518407 100644 +--- a/decoder/ixheaacd_struct_def.h ++++ b/decoder/ixheaacd_struct_def.h +@@ -162,6 +162,8 @@ typedef struct ia_aac_dec_state_struct { + UWORD32 ui_input_over; + UWORD32 header_dec_done; + WORD32 frame_counter; ++ WORD32 init_sbr_flag; ++ WORD32 init_ps_flag; + ia_aac_decoder_struct *pstr_aac_dec_info[MAX_BS_ELEMENT]; + + UWORD32 ch_config; diff --git a/encoder/ixheaace_api.c b/encoder/ixheaace_api.c -index 6d5c47e..22fe7e4 100644 +index 6d5c47e..749cac6 100644 --- a/encoder/ixheaace_api.c +++ b/encoder/ixheaace_api.c @@ -831,7 +831,7 @@ static IA_ERRORCODE ixheaace_set_config_params(ixheaace_api_struct *pstr_api_str @@ -89,11 +129,20 @@ index 6d5c47e..22fe7e4 100644 } pstr_api_struct->config[0].aac_config.full_bandwidth = pstr_input_config->aac_config.full_bandwidth; -+ pstr_api_struct->config[0].aac_config.band_width = ++ pstr_api_struct->config[0].aac_config.band_width = + pstr_input_config->aac_config.bandwidth; } return IA_NO_ERROR; +@@ -2474,7 +2478,7 @@ static IA_ERRORCODE ia_enhaacplus_enc_init(ixheaace_api_struct *pstr_api_struct, + pstr_aac_config->bit_rate, + (pstr_api_struct->pstr_state->mps_enable + ? 1 +- : pstr_api_struct->config[ele_idx].chmode_nchannels), ++ : pstr_aac_config->num_out_channels), + pstr_aac_config->sample_rate, &core_sample_rate, + pstr_api_struct->spectral_band_replication_tabs.ptr_qmf_tab, + pstr_api_struct->pstr_state->aot)) { @@ -2692,6 +2696,7 @@ static IA_ERRORCODE ia_enhaacplus_enc_execute(ixheaace_api_struct *pstr_api_stru iexheaac_encoder_str **pstr_aac_enc; iaace_config *pstr_aac_config; @@ -315,143 +364,49 @@ index eb9e882..e85b300 100644 const FLOAT32 tns_coeff_3_borders[8]; const FLOAT32 tns_coeff_4[16]; diff --git a/encoder/ixheaace_sbr_freq_scaling.c b/encoder/ixheaace_sbr_freq_scaling.c -index 7eec5a9..192907e 100644 +index 7eec5a9..1f08fbd 100644 --- a/encoder/ixheaace_sbr_freq_scaling.c +++ b/encoder/ixheaace_sbr_freq_scaling.c -@@ -158,31 +158,31 @@ static WORD32 ixheaace_get_start_freq(WORD32 fs, WORD32 start_freq) { - WORD32 minimum_k0; +@@ -231,16 +231,16 @@ static WORD32 ixheaace_get_stop_freq(WORD32 fs, WORD32 stop_freq) { switch (fs) { -- case 16000: -+ case 8000: - minimum_k0 = 24; + case 16000: +- k1_min = ixheaace_stop_freq_16k[0]; +- v_stop_freq = (WORD32 *)&ixheaace_stop_freq_16k[0]; ++ k1_min = ixheaace_usac_stop_freq_16k[0]; ++ v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_16k[0]; break; -- case 22050: -+ case 11025: - minimum_k0 = 17; + case 22050: +- k1_min = ixheaace_stop_freq_22k[0]; +- v_stop_freq = (WORD32 *)&ixheaace_stop_freq_22k[0]; ++ k1_min = ixheaace_usac_stop_freq_22k[0]; ++ v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_22k[0]; break; -- case 24000: -+ case 12000: - minimum_k0 = 16; + case 24000: +- k1_min = ixheaace_stop_freq_24k[0]; +- v_stop_freq = (WORD32 *)&ixheaace_stop_freq_24k[0]; ++ k1_min = ixheaace_usac_stop_freq_24k[0]; ++ v_stop_freq = (WORD32 *)&ixheaace_usac_stop_freq_24k[0]; break; -- case 32000: -+ case 16000: - minimum_k0 = 16; - break; -- case 44100: -+ case 22050: - minimum_k0 = 12; - break; -- case 48000: -+ case 24000: - minimum_k0 = 11; - break; -- case 64000: -+ case 32000: - minimum_k0 = 10; - break; -- case 88200: -+ case 44100: - minimum_k0 = 7; - break; -- case 96000: -+ case 48000: - minimum_k0 = 7; - break; - default: -@@ -190,30 +190,30 @@ static WORD32 ixheaace_get_start_freq(WORD32 fs, WORD32 start_freq) { - } - - switch (fs) { -- case 16000: { -+ case 8000: { - return (minimum_k0 + vector_offset_16k[start_freq]); - } break; - -- case 22050: { -+ case 11025: { - return (minimum_k0 + vector_offset_22k[start_freq]); - } break; - -- case 24000: { -+ case 12000: { - return (minimum_k0 + vector_offset_24k[start_freq]); - } break; - -- case 32000: { -+ case 16000: { - return (minimum_k0 + vector_offset_32k[start_freq]); - } break; - -- case 44100: -- case 48000: -- case 64000: { -+ case 22050: -+ case 24000: -+ case 32000: { - return (minimum_k0 + vector_offset_44_48_64[start_freq]); - } break; - -- case 88200: -- case 96000: { -+ case 44100: -+ case 48000: { - return (minimum_k0 + vector_offset_88_96[start_freq]); - } break; - -@@ -230,36 +230,54 @@ static WORD32 ixheaace_get_stop_freq(WORD32 fs, WORD32 stop_freq) { - WORD32 v_dstop[13]; - - switch (fs) { -- case 16000: -+ case 8000: - k1_min = ixheaace_stop_freq_16k[0]; - v_stop_freq = (WORD32 *)&ixheaace_stop_freq_16k[0]; - break; -- case 22050: -+ case 11025: - k1_min = ixheaace_stop_freq_22k[0]; - v_stop_freq = (WORD32 *)&ixheaace_stop_freq_22k[0]; - break; -- case 24000: -+ case 12000: - k1_min = ixheaace_stop_freq_24k[0]; - v_stop_freq = (WORD32 *)&ixheaace_stop_freq_24k[0]; - break; -- case 32000: -+ case 16000: + case 32000: k1_min = 32; - - v_stop_freq = (WORD32 *)vector_stop_freq_32; - break; - -- case 44100: -+ case 22050: - k1_min = 23; - - v_stop_freq = (WORD32 *)vector_stop_freq_44; - break; - -- case 48000: -+ case 24000: - k1_min = 21; - +@@ -260,6 +260,24 @@ static WORD32 ixheaace_get_stop_freq(WORD32 fs, WORD32 stop_freq) { v_stop_freq = (WORD32 *)vector_stop_freq_48; break; -+ case 32000: ++ case 64000: + k1_min = 20; + + v_stop_freq = (WORD32 *)vector_stop_freq_64; + break; + -+ case 44100: ++ case 88200: + k1_min = 15; + + v_stop_freq = (WORD32 *)vector_stop_freq_88; + break; + -+ case 48000: ++ case 96000: + k1_min = 13; + + v_stop_freq = (WORD32 *)vector_stop_freq_96; @@ -461,7 +416,7 @@ index 7eec5a9..192907e 100644 v_stop_freq = (WORD32 *)vector_stop_freq_32; k1_min = 21; /* illegal fs */ diff --git a/encoder/ixheaace_sbr_main.c b/encoder/ixheaace_sbr_main.c -index 893d215..9e13b13 100644 +index 893d215..62928da 100644 --- a/encoder/ixheaace_sbr_main.c +++ b/encoder/ixheaace_sbr_main.c @@ -100,7 +100,7 @@ FLOAT32 *ixheaace_get_hbe_resample_buffer(ixheaace_pstr_sbr_enc pstr_env_enc) { @@ -489,15 +444,41 @@ index 893d215..9e13b13 100644 *ptr_core_sr = sample_rate_input / 2; +@@ -965,7 +967,7 @@ ixheaace_env_open(ixheaace_pstr_sbr_enc *pstr_env_encoder, ixheaace_pstr_sbr_cfg + pstr_env_enc->str_sbr_cfg.stereo_mode = + (params->codec_settings.num_channels == 2) ? params->stereo_mode : IXHEAACE_SBR_MODE_MONO; + +- if (params->codec_settings.sample_freq <= 24000) { ++ if (1) { + pstr_env_enc->str_sbr_hdr.sample_rate_mode = IXHEAACE_DUAL_RATE; + if (params->sbr_codec == USAC_SBR) { + pstr_env_enc->str_sbr_cfg.sample_freq = 2 * params->codec_settings.sample_freq; +diff --git a/encoder/ixheaace_sbr_noise_floor_est.c b/encoder/ixheaace_sbr_noise_floor_est.c +index c5fcd99..344d2b0 100644 +--- a/encoder/ixheaace_sbr_noise_floor_est.c ++++ b/encoder/ixheaace_sbr_noise_floor_est.c +@@ -136,8 +136,10 @@ static VOID ia_enhaacplus_enc_qmf_based_noise_floor_detection( + mean_org += ton_org; + mean_sbr += ton_sbr; + } +- mean_org /= (stop_channel - start_channel); +- mean_sbr /= (stop_channel - start_channel); ++ if ((stop_channel - start_channel) > 0) { ++ mean_org /= (stop_channel - start_channel); ++ mean_sbr /= (stop_channel - start_channel); ++ } + } + + if (mean_org < SBR_TON_MEAN_P0009 && mean_sbr < SBR_TON_MEAN_P0009) { diff --git a/encoder/ixheaace_sbr_rom.c b/encoder/ixheaace_sbr_rom.c -index 90e94c5..435fc2e 100644 +index 90e94c5..bb52192 100644 --- a/encoder/ixheaace_sbr_rom.c +++ b/encoder/ixheaace_sbr_rom.c @@ -48,6 +48,9 @@ const WORD32 vector_offset_def[] = {0, 1, 2, 3, 4, 5, 6, 7, 9, 11, 13, 16, 20, 2 const WORD32 vector_stop_freq_32[14] = {32, 34, 36, 38, 40, 42, 44, 46, 49, 52, 55, 58, 61, 64}; const WORD32 vector_stop_freq_44[14] = {23, 25, 27, 29, 32, 34, 37, 40, 43, 47, 51, 55, 59, 64}; const WORD32 vector_stop_freq_48[14] = {21, 23, 25, 27, 30, 32, 35, 38, 42, 45, 49, 54, 59, 64}; -+const WORD32 vector_stop_freq_64[14] = {20, 22, 24, 26, 28, 31, 34, 37, 41, 45, 49, 54, 59, 64}; ++const WORD32 vector_stop_freq_64[14] = {20, 22, 24, 26, 29, 31, 34, 37, 41, 45, 49, 54, 59, 64}; +const WORD32 vector_stop_freq_88[14] = {15, 17, 19, 21, 23, 26, 29, 33, 37, 41, 46, 51, 57, 64}; +const WORD32 vector_stop_freq_96[14] = {13, 15, 17, 19, 21, 24, 27, 31, 35, 39, 44, 50, 57, 64}; @@ -511,13 +492,13 @@ index 90e94c5..435fc2e 100644 {{{{8000, 10000, {7, 11}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, {10000, 12000, {11, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, {12000, 48001, {14, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, -@@ -738,6 +742,238 @@ const ixheaace_str_qmf_tabs ixheaace_qmf_tab = { +@@ -738,6 +742,200 @@ const ixheaace_str_qmf_tabs ixheaace_qmf_tab = { {0}}} }, +#else + {{{ -+ /*** 8000hz 1ch ***/ ++ /*** 8000hz 1ch SBR_AAC ***/ + {8000, 10000, {7, 11}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {10000, 12000, {11, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {12000, 16000, {14, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -526,7 +507,7 @@ index 90e94c5..435fc2e 100644 + {32000, 48001, {14, 15}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 8000hz 2ch ***/ ++ /*** 8000hz 2ch SBR_AAC ***/ + {16000, 24000, {6, 9}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {9, 11}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 36000, {11, 11}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -538,7 +519,7 @@ index 90e94c5..435fc2e 100644 + {0}}}, + + {{ -+ /*** 11025hz 1ch ***/ ++ /*** 11025hz 1ch SBR_AAC ***/ + {8000, 10000, {5, 6}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {10000, 12000, {8, 12}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {12000, 16000, {12, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -546,10 +527,10 @@ index 90e94c5..435fc2e 100644 + {20000, 24000, {13, 13}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {24000, 32000, {14, 14}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {32000, 48000, {15, 15}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {48000, 64001, {15, 15}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {48000, 66001, {15, 15}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 11025hz 2ch ***/ ++ /*** 11025hz 2ch SBR_AAC ***/ + {16000, 24000, {7, 9}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {10, 10}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 36000, {12, 12}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -557,11 +538,11 @@ index 90e94c5..435fc2e 100644 + {44000, 52000, {14, 13}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {52000, 60000, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {60000, 76000, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 128001, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {76000, 132301, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 12000hz 1ch ***/ ++ /*** 12000hz 1ch SBR_AAC ***/ + {8000, 10000, {4, 6}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {10000, 12000, {7, 11}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {12000, 16000, {11, 12}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -569,10 +550,10 @@ index 90e94c5..435fc2e 100644 + {20000, 24000, {12, 12}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {24000, 32000, {13, 13}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {32000, 48000, {14, 14}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {48000, 64001, {15, 15}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {48000, 72001, {15, 15}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 12000hz 2ch ***/ ++ /*** 12000hz 2ch SBR_AAC ***/ + {16000, 24000, {6, 9}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {9, 10}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 36000, {11, 12}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -580,11 +561,11 @@ index 90e94c5..435fc2e 100644 + {44000, 52000, {13, 13}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {52000, 60000, {14, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {60000, 76000, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 128001, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {76000, 144001, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 16000hz 1ch ***/ ++ /*** 16000hz 1ch SBR_AAC ***/ + {6000, 8000, {0, 0}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {8000, 10000, {1, 0}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {10000, 12000, {2, 6}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -594,10 +575,10 @@ index 90e94c5..435fc2e 100644 + {22000, 28000, {10, 12}, 2, {2, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {28000, 36000, {12, 13}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {36000, 44000, {14, 13}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {44000, 64001, {15, 13}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {44000, 96001, {15, 13}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 16000hz 2ch ***/ ++ /*** 16000hz 2ch SBR_AAC ***/ + {16000, 24000, {4, 1}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {8, 10}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 36000, {10, 12}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -605,11 +586,11 @@ index 90e94c5..435fc2e 100644 + {44000, 52000, {15, 13}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {52000, 60000, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {60000, 76000, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 128001, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {76000, 192001, {15, 13}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 22050hz 1ch ***/ ++ /*** 22050hz 1ch SBR_AAC ***/ + {8000, 11369, {1, 1}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {11369, 16000, {3, 4}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {16000, 18000, {3, 5}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -617,12 +598,10 @@ index 90e94c5..435fc2e 100644 + {22000, 28000, {7, 8}, 2, {2, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {28000, 36000, {10, 9}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {36000, 44000, {11, 10}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {44000, 52000, {13, 11}, 1, {2, 0, 0}, IXHEAACE_SBR_MODE_MONO}, -+ {52000, 68000, {14, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {68000, 96001, {14, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, ++ {44000, 132151, {13, 12}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 22050hz 2ch ***/ ++ /*** 22050hz 2ch SBR_AAC ***/ + {16000, 24000, {2, 1}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {5, 6}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 32000, {5, 8}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -631,11 +610,11 @@ index 90e94c5..435fc2e 100644 + {44000, 52000, {12, 9}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {52000, 60000, {13, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {60000, 101000, {14, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {101000, 128001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {101000, 264601, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 24000hz 1ch ***/ ++ /*** 24000hz 1ch SBR_AAC ***/ + {8000, 12000, {1, 1}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {12000, 16000, {3, 4}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {16000, 18000, {3, 5}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -643,12 +622,10 @@ index 90e94c5..435fc2e 100644 + {22000, 28000, {7, 8}, 2, {2, 0, 6}, IXHEAACE_SBR_MODE_MONO}, + {28000, 36000, {10, 9}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {36000, 44000, {11, 10}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {44000, 52000, {13, 11}, 1, {3, 0, 0}, IXHEAACE_SBR_MODE_MONO}, -+ {52000, 68000, {15, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {68000, 96001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, ++ {44000, 144001, {13, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 24000hz 2ch ***/ ++ /*** 24000hz 2ch SBR_AAC ***/ + {16000, 24000, {2, 1}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {24000, 28000, {5, 6}, 3, {1, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {28000, 36000, {7, 8}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, @@ -656,92 +633,58 @@ index 90e94c5..435fc2e 100644 + {44000, 52000, {12, 9}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {52000, 60000, {13, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, + {60000, 76000, {14, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 128001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {76000, 288001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 32000hz 1ch ***/ ++ /*** 32000hz 1ch SBR_AAC ***/ + {24000, 36000, {4, 4}, 3, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {36000, 60000, {7, 6}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {60000, 72000, {9, 8}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {72000, 100000, {11, 10}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {100000, 160001, {13, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {100000, 192001, {13, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 32000hz 2ch ***/ ++ /*** 32000hz 2ch SBR_AAC ***/ + {32000, 60000, {4, 4}, 3, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {60000, 80000, {11, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {80000, 112000, {12, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {112000, 144000, {13, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {144000, 256001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {60000, 80000, {7, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, ++ {80000, 112000, {9, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {112000, 144000, {11, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {144000, 384001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 44100hz 1ch ***/ -+ {12000, 16000, {0, 0}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {16000, 22000, {1, 1}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {22000, 30000, {2, 3}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {30000, 36000, {4, 4}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {36000, 40000, {5, 4}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {40000, 48000, {6, 5}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {48000, 60000, {7, 6}, 1, {3, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {60000, 72000, {9, 6}, 1, {3, 0, 0}, IXHEAACE_SBR_MODE_MONO}, -+ {72000, 88000, {10, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {88000, 160001, {12, 9}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {160001, 288001, {13, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, ++ /*** 44100hz 1ch SBR_AAC ***/ ++ {24000, 36000, {4, 4}, 3, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {36000, 60000, {7, 6}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {60000, 72000, {9, 8}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {72000, 100000, {11, 10}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {100000, 264601, {13, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 44100hz 2ch ***/ -+ {12000, 16000, {0, 0}, 0, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {16000, 22000, {1, 0}, 0, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {22000, 26000, {2, 1}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {26000, 30000, {3, 3}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {30000, 34000, {3, 3}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {34000, 38000, {4, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {38000, 44000, {5, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {44000, 52000, {6, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {52000, 60000, {8, 5}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {60000, 68000, {9, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {68000, 76000, {10, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 90000, {11, 7}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {90000, 112000, {11, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {112000, 132000, {12, 9}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {132000, 180000, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {180000, 288001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ /*** 44100hz 2ch SBR_AAC ***/ ++ {32000, 60000, {4, 4}, 3, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, ++ {60000, 80000, {7, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, ++ {80000, 112000, {9, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {112000, 144000, {11, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {144000, 529201, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, + + {{ -+ /*** 48000hz 1ch ***/ -+ {12000, 16000, {0, 0}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {16000, 22000, {1, 1}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {22000, 30000, {2, 3}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {30000, 36000, {4, 4}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {36000, 40000, {5, 4}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {40000, 48000, {6, 5}, 0, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {48000, 60000, {7, 6}, 1, {3, 0, 3}, IXHEAACE_SBR_MODE_MONO}, -+ {60000, 72000, {9, 6}, 1, {3, 0, 0}, IXHEAACE_SBR_MODE_MONO}, -+ {72000, 88000, {10, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {88000, 160001, {12, 9}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, -+ {160001, 288001, {13, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_MONO}, ++ /*** 48000hz 1ch SBR_AAC ***/ ++ {24000, 36000, {4, 9}, 3, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {36000, 60000, {7, 10}, 2, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {60000, 72000, {9, 10}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {72000, 100000, {11, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, ++ {100000, 288001, {13, 11}, 1, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, + {0}}, + { -+ /*** 48000hz 2ch ***/ -+ {12000, 16000, {0, 0}, 0, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {16000, 22000, {0, 0}, 0, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, -+ {22000, 26000, {1, 1}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {26000, 30000, {2, 3}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {30000, 34000, {3, 3}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {34000, 38000, {4, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {38000, 44000, {2, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {44000, 52000, {6, 4}, 0, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {52000, 60000, {8, 5}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {60000, 68000, {9, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {68000, 76000, {10, 6}, 2, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {76000, 90000, {11, 7}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {90000, 112000, {11, 8}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {112000, 132000, {12, 9}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {132000, 180000, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, -+ {180000, 288001, {15, 12}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ /*** 48000hz 2ch SBR_AAC ***/ ++ {32000, 60000, {4, 9}, 3, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, ++ {60000, 80000, {7, 10}, 2, {2, 0, -3}, IXHEAACE_SBR_MODE_SWITCH_LRC}, ++ {80000, 112000, {9, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {112000, 144000, {11, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, ++ {144000, 576001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}} + + }, @@ -750,7 +693,7 @@ index 90e94c5..435fc2e 100644 {{{{0}}}, {{{0}}}, -@@ -824,7 +1060,146 @@ const ixheaace_str_qmf_tabs ixheaace_qmf_tab = { +@@ -824,7 +1022,146 @@ const ixheaace_str_qmf_tabs ixheaace_qmf_tab = { {144000, 176000, {12, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, {176000, 256001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, {0}}}} @@ -762,7 +705,7 @@ index 90e94c5..435fc2e 100644 + {{ + /*** 12000hz 1ch ***/ + {8000, 32000, {1, 0}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, -+ {0}}, ++ {0}}, + { + {0}}}, + @@ -816,7 +759,7 @@ index 90e94c5..435fc2e 100644 + {76000, 82000, {12, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {82000, 128001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, -+ + + {{ + /*** 24000hz 1ch ***/ + {8000, 12000, {1, 1}, 3, {1, 0, 6}, IXHEAACE_SBR_MODE_MONO}, @@ -858,7 +801,7 @@ index 90e94c5..435fc2e 100644 + {112000, 144000, {11, 10}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {144000, 256001, {13, 11}, 1, {3, 0, -3}, IXHEAACE_SBR_MODE_LEFT_RIGHT}, + {0}}}, - ++ + {{ + /*** 44100hz 1ch ***/ + {24000, 36000, {4, 9}, 3, {2, 0, 3}, IXHEAACE_SBR_MODE_MONO}, diff --git a/source/examples/aacdec/CMakeLists.txt b/source/examples/aacdec/CMakeLists.txt index b450984..16edb4e 100644 --- a/source/examples/aacdec/CMakeLists.txt +++ b/source/examples/aacdec/CMakeLists.txt @@ -55,6 +55,10 @@ set_target_properties(${target} # # Include directories # +target_link_directories(${target} + PRIVATE + ${XAAC_BIN_DIR} +) target_include_directories(${target} PRIVATE diff --git a/source/examples/aacdec/aacdec.cpp b/source/examples/aacdec/aacdec.cpp index 9f4a322..4fff675 100644 --- a/source/examples/aacdec/aacdec.cpp +++ b/source/examples/aacdec/aacdec.cpp @@ -78,6 +78,7 @@ int main(int argc, char *argv[]) { ap.add_argument("input"); ap.add_argument("output"); + ap.add_argument("-c", "--conceal").help("Error concealment").flag(); ap.add_argument("-e", "--enhanced-sbr").help("Enhanced SBR").flag(); ap.add_argument("-f", "--frame-size").help("Frame size").default_value(0).scan<'i', int>(); @@ -91,12 +92,14 @@ int main(int argc, char *argv[]) { auto inFile = ap.get("input"); auto outFile = ap.get("output"); + auto errorConceal = ap.get("-c"); auto eSBR = ap.get("-e"); auto frameSize = ap.get("-f"); AACDecodeSettings aacConf = {}; aacConf.bitsPerSamples = 16; aacConf.eSBR = eSBR; + aacConf.errorConceal = errorConceal; aacConf.frameSize = frameSize; FILE * inpFile = fopen(inFile.c_str(), "rb"); @@ -176,6 +179,7 @@ int main(int argc, char *argv[]) { int16_t *outBuf = new int16_t[decoder->outBufSize / sizeof(int16_t)]; uint32_t outSize; uint32_t nBytes; + int32_t res = 0; ProgressBar bar{ option::BarWidth{50}, @@ -246,6 +250,7 @@ int main(int argc, char *argv[]) { int ret = aac_decode(decoder, readBuf, bufReadSize, (uint8_t *)outBuf, &outSize, &nBytes); if (ret == -1) { std::cerr << "Decode frame " << adtsCount << " failed" << std::endl; + res = 1; break; } @@ -278,7 +283,9 @@ int main(int argc, char *argv[]) { } outpFile.save(outFile); + aac_decode_close(decoder); + return res; #if 0 #if 0 AACFileReader inData("asc.es", 4096); diff --git a/source/examples/aacenc/CMakeLists.txt b/source/examples/aacenc/CMakeLists.txt index 4f624cb..1af95e8 100644 --- a/source/examples/aacenc/CMakeLists.txt +++ b/source/examples/aacenc/CMakeLists.txt @@ -67,6 +67,10 @@ target_include_directories(${target} # # Libraries # +target_link_directories(${target} + PRIVATE + ${XAAC_BIN_DIR} +) target_link_libraries(${target} PRIVATE diff --git a/source/libaac/CMakeLists.txt b/source/libaac/CMakeLists.txt index 216b88c..3ca996d 100644 --- a/source/libaac/CMakeLists.txt +++ b/source/libaac/CMakeLists.txt @@ -59,6 +59,8 @@ add_library(${target} ${headers} ) +add_dependencies(${target} libxaac) + # Create namespaced alias add_library(${META_PROJECT_NAME}::${target} ALIAS ${target}) @@ -128,14 +130,20 @@ target_include_directories(${target} # # Libraries # +target_link_directories(${target} + PRIVATE + ${XAAC_BIN_DIR} +) target_link_libraries(${target} PRIVATE - libxaacenc - libxaacdec + $<$:xaacenc> + $<$:xaacdec> PUBLIC ${DEFAULT_LIBRARIES} + $<$>:xaacenc> + $<$>:xaacdec> INTERFACE ) @@ -227,5 +235,13 @@ install(EXPORT ${target}-export ) # pkg-config +if (BUILD_SHARED_LIBS) + set(LIBAAC_LINKERS "-l${target}") +else() + set(LIBAAC_LINKERS "-l${target} -lxaacenc -lxaacdec -lm") + install(FILES ${PROJECT_BINARY_DIR}/libxaac-prefix/src/libxaac-build/libxaacdec.a DESTINATION ${INSTALL_LIB}/ COMPONENT dev) + install(FILES ${PROJECT_BINARY_DIR}/libxaac-prefix/src/libxaac-build/libxaacenc.a DESTINATION ${INSTALL_LIB}/ COMPONENT dev) +endif() + configure_file(pkg-config.pc.in ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${META_PROJECT_NAME}.pc @ONLY) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/pkgconfig/${META_PROJECT_NAME}.pc DESTINATION ${INSTALL_LIB}/pkgconfig COMPONENT dev) \ No newline at end of file diff --git a/source/libaac/include/aacnext/libaac.h b/source/libaac/include/aacnext/libaac.h index 513b8a0..480aea2 100644 --- a/source/libaac/include/aacnext/libaac.h +++ b/source/libaac/include/aacnext/libaac.h @@ -24,6 +24,8 @@ typedef struct { uint32_t ascSize; // AudioSpecific config size uint32_t in_buf_offset; // Input buffer offset int32_t inputDelay; // Input delay + void (* errorHandler)(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle); // Error handler + void * errorHandleCtx; // Error handler object } AACContext; typedef struct { @@ -38,6 +40,8 @@ typedef struct { uint32_t frameSize; // Custom frame size bool eSBR; // Enhanced SBR uint32_t iq; // Inverse quant + void (* errorHandler)(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle); // Error handler + void * errorHandleCtx; // Error handler object } AACSettings; AACNEXT_API AACContext * aac_encode_open(AACSettings info); @@ -63,6 +67,8 @@ typedef struct { uint32_t sbrMode; // SBR mode bool eSBR; // Enhanced SBR uint64_t frameCounter; // Frame counter + void (* errorHandler)(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle); // Error handler + void * errorHandleCtx; // Error handler object } AACDecode; typedef struct { @@ -71,11 +77,16 @@ typedef struct { uint64_t noChannels; // Number of channels int32_t bitsPerSamples; // Bits per samples uint32_t frameSize; // Frame size - bool eSBR; // Enhanced SBR + int32_t eSBR; // Enhanced SBR + int32_t errorConceal; // Error concealment + void (* errorHandler)(uint32_t errorCode, const char *section, const char *errorMsg, bool isFatal, void *handle); // Error handler + void * errorHandleCtx; // Error handler object } AACDecodeSettings; AACNEXT_API AACDecode * aac_decode_open(AACDecodeSettings cfg); AACNEXT_API int aac_decode(AACDecode *aacd, unsigned char *inData, unsigned int inDataSize, unsigned char *outData, unsigned int *outSize, unsigned int *bytesRead); +AACNEXT_API void aac_decode_reset(AACDecode *aacd); +AACNEXT_API void aac_decode_flush_buffer(AACDecode *aacd); AACNEXT_API void aac_decode_close(AACDecode *aacd); #ifdef __cplusplus diff --git a/source/libaac/pkg-config.pc.in b/source/libaac/pkg-config.pc.in index ee70d20..4415c7a 100644 --- a/source/libaac/pkg-config.pc.in +++ b/source/libaac/pkg-config.pc.in @@ -7,5 +7,5 @@ toolsdir=${exec_prefix}/bin Name: @PROJECT_NAME@ Description: @PROJECT_DESCRIPTION@ Version: @PROJECT_VERSION@ -Libs: -L${libdir} -l@target@ +Libs: -L${libdir} @LIBAAC_LINKERS@ Cflags: -I${includedir} diff --git a/source/libaac/source/libaac.c b/source/libaac/source/libaac.c index b0f37fb..ad148dc 100644 --- a/source/libaac/source/libaac.c +++ b/source/libaac/source/libaac.c @@ -313,14 +313,18 @@ void aac_encode_strerror(unsigned int error, char *errorStr, int *isFatal) { } } -int aac_encode_handle_error(IA_ERRORCODE ret, const char *section) { +int aac_encode_handle_error(AACContext * aac, IA_ERRORCODE ret, const char *section) { char strerror[8192] = {0}; int isFatal; if (ret == IA_NO_ERROR) return 0; aac_encode_strerror(ret, strerror, &isFatal); - fprintf(stderr, "libaac%s %s: %s\n", isFatal ? " fatal error:" : "", section, strerror); + if (aac->errorHandler == NULL) { + fprintf(stderr, "libaac%s %s: %s\n", isFatal ? " fatal error:" : "", section, strerror); + } else { + aac->errorHandler(ret, section, strerror, isFatal, aac->errorHandleCtx); + } return isFatal; } @@ -431,8 +435,11 @@ AACContext * aac_encode_open(AACSettings info) { aac_in_config->ui_pcm_wd_sz = info.bitsPerSamples; // Fixed point only although float computing is possible aac_in_config->aac_config.length = 0; + aac->errorHandler = info.errorHandler; + aac->errorHandleCtx = info.errorHandleCtx; + ret = ixheaace_create(aac->pstr_in_cfg, aac->pstr_out_cfg); - if (aac_encode_handle_error(ret, "init-encoder")) goto fail; + if (aac_encode_handle_error(aac, ret, "init-encoder")) goto fail; aac->no_samples = aac_out_config->input_size / (aac_in_config->ui_pcm_wd_sz == 32 ? 4 : 2); aac->max_out_bytes = aac_out_config->mem_info_table[IA_MEMTYPE_OUTPUT].ui_size; @@ -477,7 +484,7 @@ int aac_encode(AACContext *aac, unsigned char *inData, unsigned int inDataSize, aac->in_buf_offset = 0; IA_ERRORCODE ret = ixheaace_process(aac_out_config->pv_ia_process_api_obj, aac->pstr_in_cfg, aac->pstr_out_cfg); - if (aac_encode_handle_error(ret, "encode")) return -1; + if (aac_encode_handle_error(aac, ret, "encode")) return -1; memcpy(outData, aac_out_buf, aac_out_config->i_out_bytes); *outSize = aac_out_config->i_out_bytes; @@ -650,14 +657,18 @@ void aac_decode_strerror(unsigned int error, char *errorStr, int *isFatal) { } } -int aac_decode_handle_error(IA_ERRORCODE ret, const char *section) { +int aac_decode_handle_error(AACDecode * aacDec, IA_ERRORCODE ret, const char *section) { char strerror[8192] = {0}; int isFatal; if (ret == IA_NO_ERROR) return 0; aac_decode_strerror(ret, strerror, &isFatal); - fprintf(stderr, "libaac%s %s: %s\n", isFatal ? " fatal error:" : "", section, strerror); + if (aacDec->errorHandler == NULL) { + fprintf(stderr, "libaac%s %s: %s\n", isFatal ? " fatal error:" : "", section, strerror); + } else { + aacDec->errorHandler(ret, section, strerror, isFatal, aacDec->errorHandleCtx); + } return isFatal; } @@ -679,27 +690,33 @@ AACDecode * aac_decode_open(AACDecodeSettings cfg) { if (aacDec->apiObj == NULL) goto fail; /* 02 - API Init */ + aacDec->errorHandler = cfg.errorHandler; + aacDec->errorHandleCtx = cfg.errorHandleCtx; + ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_PRE_CONFIG_PARAMS, NULL); - if (aac_decode_handle_error(ret, "preconfig")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "preconfig")) goto fail; /* 03 - Configuration starts here */ int isMP4 = cfg.ascSize > 0; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4, &isMP4); - if (aac_decode_handle_error(ret, "updating mp4 flag")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "updating mp4 flag")) goto fail; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_PCM_WDSZ, &cfg.bitsPerSamples); - if (aac_decode_handle_error(ret, "updating bits per samples")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "updating bits per samples")) goto fail; int is480FrameSize = cfg.frameSize == 480; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_FRAMESIZE, &is480FrameSize); - if (aac_decode_handle_error(ret, "updating frame length (ld)")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "updating frame length (ld)")) goto fail; int is960FrameSize = cfg.frameSize == 960; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_FRAMELENGTH_FLAG, &is960FrameSize); - if (aac_decode_handle_error(ret, "updating frame length")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "updating frame length")) goto fail; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_XHEAAC_DEC_CONFIG_PARAM_ESBR, &cfg.eSBR); - if (aac_decode_handle_error(ret, "updating esbr")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "updating esbr")) goto fail; + + ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_XHEAAC_DEC_CONFIG_ERROR_CONCEALMENT, &cfg.errorConceal); + if (aac_decode_handle_error(aacDec, ret, "updating error conceal")) goto fail; aacDec->eSBR = cfg.eSBR; aacDec->asc = cfg.asc; @@ -708,32 +725,32 @@ AACDecode * aac_decode_open(AACDecodeSettings cfg) { /* 04 - Decoder Memory */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_GET_MEMTABS_SIZE, 0, &mem_info_size); - if (aac_decode_handle_error(ret, "memtab size")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "memtab size")) goto fail; aacDec->memInfoTab = malloc(mem_info_size); if (aacDec->memInfoTab == NULL) goto fail; ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_MEMTABS_PTR, 0, aacDec->memInfoTab); - if (aac_decode_handle_error(ret, "set memtabs ptr")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "set memtabs ptr")) goto fail; /* 05 - Post Config */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_API_POST_CONFIG_PARAMS, NULL); - if (aac_decode_handle_error(ret, "postconfig")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "postconfig")) goto fail; for (int i = 0; i < 4; i++) { int ui_size = 0, ui_alignment = 0, ui_type = 0; /* Get memory size */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_GET_MEM_INFO_SIZE, i, &ui_size); - if (aac_decode_handle_error(ret, "get meminfo 1")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "get meminfo 1")) goto fail; /* Get memory alignment */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_GET_MEM_INFO_ALIGNMENT, i, &ui_alignment); - if (aac_decode_handle_error(ret, "get meminfo 2")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "get meminfo 2")) goto fail; /* Get memory type */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_GET_MEM_INFO_TYPE, i, &ui_type); - if (aac_decode_handle_error(ret, "get meminfo 3")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "get meminfo 3")) goto fail; ui_alignment = (ui_alignment + sizeof(void *) - 1) / sizeof(void *); ui_alignment = ui_alignment * sizeof(void *); @@ -746,7 +763,7 @@ AACDecode * aac_decode_open(AACDecodeSettings cfg) { /* Set the buffer pointer */ ret = ixheaacd_dec_api(aacDec->apiObj, IA_API_CMD_SET_MEM_PTR, i, temp); - if (aac_decode_handle_error(ret, "set meminfo")) goto fail; + if (aac_decode_handle_error(aacDec, ret, "set meminfo")) goto fail; aacDec->memBuffer[i] = temp; @@ -763,7 +780,7 @@ AACDecode * aac_decode_open(AACDecodeSettings cfg) { fail: if (aacDec) { - for (int i = 0; i < 4; i++) free(aacDec->memBuffer[i]); + for (int i = 0; i < 4; i++) free_global(aacDec->memBuffer[i]); free(aacDec->memInfoTab); free(aacDec->apiObj); @@ -777,29 +794,33 @@ void aac_decode_write_buffer(AACDecode *aacd, unsigned char *data, unsigned int memcpy(aacd->inBuf, data, dataSize); ret = ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_SET_INPUT_BYTES, 0, &dataSize); - aac_decode_handle_error(ret, "upload buffer"); + aac_decode_handle_error(aacd, ret, "upload buffer"); } int aac_decode_init(AACDecode *aacd, bool *isInitDone, unsigned int *noBytes) { IA_ERRORCODE ret; + int done; ret = ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_PROCESS, NULL); - ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, isInitDone); + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_INIT_DONE_QUERY, &done); ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, noBytes); + *isInitDone = done; return ret; } int aac_decode_execute(AACDecode *aacd, bool *isDone, unsigned int *noBytesIn, int *preroll) { IA_ERRORCODE ret; + int done; ret = ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DO_EXECUTE, NULL); - ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY, isDone); + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_EXECUTE, IA_CMD_TYPE_DONE_QUERY, &done); ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_GET_CURIDX_INPUT_BUF, 0, noBytesIn); ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_GET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_GET_NUM_PRE_ROLL_FRAMES, preroll); + *isDone = done; return ret; } @@ -814,7 +835,7 @@ int aac_decode(AACDecode *aacd, unsigned char *inData, unsigned int inDataSize, if (aacd->ascSize > 0 && !aacd->ascDone) { aac_decode_write_buffer(aacd, aacd->asc, aacd->ascSize); ret = aac_decode_init(aacd, &aacd->isInitDone, bytesRead); - if (aac_decode_handle_error(ret, "init-decoder")) return -1; + if (aac_decode_handle_error(aacd, ret, "init-decoder")) return -1; aacd->ascDone = 1; timeInited++; @@ -822,7 +843,7 @@ int aac_decode(AACDecode *aacd, unsigned char *inData, unsigned int inDataSize, aac_decode_write_buffer(aacd, inData, inDataSize); ret = aac_decode_init(aacd, &aacd->isInitDone, bytesRead); - if (aac_decode_handle_error(ret, "init-decoder")) return -1; + if (aac_decode_handle_error(aacd, ret, "init-decoder")) return -1; if (ret == IA_XHEAAC_DEC_EXE_NONFATAL_INSUFFICIENT_INPUT_BYTES) return 0; @@ -855,14 +876,14 @@ int aac_decode(AACDecode *aacd, unsigned char *inData, unsigned int inDataSize, aac_decode_write_buffer(aacd, inData, inDataSize); ret = aac_decode_execute(aacd, &isDecodeDone, bytesRead, &prerolls); - if (aac_decode_handle_error(ret, "decode")) return -1; + if (aac_decode_handle_error(aacd, ret, "decode")) return -1; int prerollOffset = 0; *outSize = 0; do { ret = ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_GET_OUTPUT_BYTES, 0, &outByteTemp); - if (aac_decode_handle_error(ret, "preroll handling")) return -1; + if (aac_decode_handle_error(aacd, ret, "preroll handling")) return -1; if (aacd->sbrMode && (aacd->aot < 23) && aacd->eSBR) { if (aacd->frameCounter > 0) @@ -882,9 +903,31 @@ int aac_decode(AACDecode *aacd, unsigned char *inData, unsigned int inDataSize, return 1; } +void aac_decode_reset(AACDecode *aacd) { + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_GA_HDR, NULL); + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_GA_HDR, NULL); + + aacd->isInitDone = false; + aacd->ascDone = false; + + int isMP4 = aacd->ascSize > 0; + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4, &isMP4); +} + +void aac_decode_flush_buffer(AACDecode *aacd) { + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, NULL); + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INIT, IA_CMD_TYPE_FLUSH_MEM, NULL); + + aacd->isInitDone = false; + aacd->ascDone = false; + + int isMP4 = aacd->ascSize > 0; + ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_SET_CONFIG_PARAM, IA_ENHAACPLUS_DEC_CONFIG_PARAM_ISMP4, &isMP4); +} + void aac_decode_close(AACDecode *aacd) { ixheaacd_dec_api(aacd->apiObj, IA_API_CMD_INPUT_OVER, 0, NULL); - for (int i = 0; i < 4; i++) free(aacd->memBuffer[i]); + for (int i = 0; i < 4; i++) free_global(aacd->memBuffer[i]); free(aacd->memInfoTab); free(aacd->apiObj);