libaacplus/ffmpeg-7-aac.patch
2025-08-03 23:51:00 +07:00

365 lines
13 KiB
Diff

diff -ruN ffmpeg-7.1.1/configure ffmpeg-7.1.1-custom/configure
--- ffmpeg-7.1.1/configure 2025-03-03 07:22:08.000000000 +0700
+++ ffmpeg-7.1.1-custom/configure 2025-07-14 08:24:16.313972645 +0700
@@ -213,6 +213,7 @@
--enable-jni enable JNI support [no]
--enable-ladspa enable LADSPA audio filtering [no]
--enable-lcms2 enable ICC profile support via LittleCMS 2 [no]
+ --enable-libaacplus enable AAC encoding using custom libaacplus [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]
@@ -1874,6 +1875,10 @@
libxvid
"
+EXTERNAL_LIBRARY_RESTRICTED_LIST="
+ libaacplus
+"
+
EXTERNAL_LIBRARY_NONFREE_LIST="
decklink
libfdk_aac
@@ -1896,6 +1901,7 @@
"
EXTERNAL_LIBRARY_LIST="
+ $EXTERNAL_LIBRARY_RESTRICTED_LIST
$EXTERNAL_LIBRARY_GPL_LIST
$EXTERNAL_LIBRARY_NONFREE_LIST
$EXTERNAL_LIBRARY_VERSION3_LIST
@@ -3512,6 +3518,7 @@
hevc_videotoolbox_encoder_select="atsc_a53 videotoolbox_encoder"
prores_videotoolbox_encoder_deps="pthreads"
prores_videotoolbox_encoder_select="videotoolbox_encoder"
+libaacplus_encoder_deps="libaacplus"
libaom_av1_decoder_deps="libaom"
libaom_av1_encoder_deps="libaom"
libaom_av1_encoder_select="extract_extradata_bsf dovi_rpuenc"
@@ -4502,7 +4509,7 @@
map "die_license_disabled version3" $EXTERNAL_LIBRARY_VERSION3_LIST $EXTERNAL_LIBRARY_GPLV3_LIST
enabled gpl && map "die_license_disabled_gpl nonfree" $EXTERNAL_LIBRARY_NONFREE_LIST
-map "die_license_disabled nonfree" $HWACCEL_LIBRARY_NONFREE_LIST
+map "die_license_disabled nonfree" $HWACCEL_LIBRARY_NONFREE_LIST $EXTERNAL_LIBRARY_RESTRICTED_LIST
enabled version3 && { enabled gpl && enable gplv3 || enable lgplv3; }
@@ -6865,6 +6872,7 @@
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 libaacplus && require_pkg_config libaacplus "aacplus >= 3.0.0" aacplus.h aacplusEncOpen
enabled libaom && require_pkg_config libaom "aom >= 2.0.0" aom/aom_codec.h aom_codec_version
enabled libaribb24 && { check_pkg_config libaribb24 "aribb24 > 1.0.3" "aribb24/aribb24.h" arib_instance_new ||
{ enabled gpl && require_pkg_config libaribb24 aribb24 "aribb24/aribb24.h" arib_instance_new; } ||
diff -ruN ffmpeg-7.1.1/libavcodec/allcodecs.c ffmpeg-7.1.1-custom/libavcodec/allcodecs.c
--- ffmpeg-7.1.1/libavcodec/allcodecs.c 2024-09-30 06:31:47.000000000 +0700
+++ ffmpeg-7.1.1-custom/libavcodec/allcodecs.c 2025-07-14 08:19:18.226168604 +0700
@@ -756,6 +756,7 @@
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_libaacplus_encoder;
extern FFCodec ff_libaom_av1_encoder;
/* preferred over libaribb24 */
extern const FFCodec ff_libaribcaption_decoder;
diff -ruN ffmpeg-7.1.1/libavcodec/libaacplus.c ffmpeg-7.1.1-custom/libavcodec/libaacplus.c
--- ffmpeg-7.1.1/libavcodec/libaacplus.c 1970-01-01 07:00:00.000000000 +0700
+++ ffmpeg-7.1.1-custom/libavcodec/libaacplus.c 2025-07-14 09:42:49.266275099 +0700
@@ -0,0 +1,284 @@
+/*
+ * Interface to libaacplus for aac encoding
+ * Copyright (c) 2010 tipok <piratfm@gmail.com>, 2021-2024 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 libaacplus encoder.
+ */
+
+#include <aacplus.h>
+
+#include "libavutil/channel_layout.h"
+#include "libavutil/common.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/opt.h"
+#include "avcodec.h"
+#include "audio_frame_queue.h"
+#include "codec_internal.h"
+#include "encode.h"
+#include "profiles.h"
+
+#define AACENC_BLOCKSIZE 1024
+#define CORE_DELAY (1600)
+/* (96-64) makes AAC still some 64 core samples too early wrt SBR ... maybe -32 would be even more correct, but 1024-32 would need additional SBR bitstream delay by one frame */
+#define CORE_INPUT_OFFSET_PS (0)
+/* ((1600 (core codec)*2 (multi rate) + 6*64 (sbr dec delay) - 2048 (sbr enc delay) + magic*/
+#define INPUT_DELAY ((CORE_DELAY) * 2 + 6 * 64 - (AACENC_BLOCKSIZE * 2) + 1)
+
+typedef struct aacPlusAudioContext
+{
+ const AVClass *class;
+ aacplusEncHandle aacplus_handle;
+ unsigned long max_output_bytes;
+ unsigned long samples_input;
+ int delay_sent;
+
+ AudioFrameQueue afq;
+} aacPlusAudioContext;
+
+static const AVOption aac_enc_options[] = {
+ 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 av_cold int aacPlus_encode_init(AVCodecContext *avctx)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+ aacplusEncConfiguration *aacplus_cfg;
+ int flag_aacplus = (avctx->profile != AV_PROFILE_AAC_LOW && avctx->profile != AV_PROFILE_UNKNOWN);
+
+ /* number of channels */
+ if (avctx->ch_layout.nb_channels < 1 || avctx->ch_layout.nb_channels > 2)
+ {
+ av_log(avctx, AV_LOG_ERROR, "encoding %d channel(s) is not allowed\n", avctx->ch_layout.nb_channels);
+ return AVERROR(EINVAL);
+ }
+
+ if (avctx->profile != AV_PROFILE_AAC_LOW && avctx->profile != AV_PROFILE_AAC_HE && avctx->profile != AV_PROFILE_UNKNOWN)
+ {
+ av_log(avctx, AV_LOG_ERROR, "invalid AAC profile: %d, only LC and HE-AAC were supported\n", avctx->profile);
+ return AVERROR(EINVAL);
+ }
+
+ s->aacplus_handle = aacplusEncOpen(avctx->sample_rate, avctx->ch_layout.nb_channels, &s->samples_input, &s->max_output_bytes, flag_aacplus);
+
+ if (!s->aacplus_handle)
+ {
+ av_log(avctx, AV_LOG_ERROR, "can't open encoder\n");
+ return AVERROR(EINVAL);
+ }
+
+ /* check aacplus version */
+ aacplus_cfg = aacplusEncGetCurrentConfiguration(s->aacplus_handle);
+
+ aacplus_cfg->bitRate = avctx->bit_rate;
+ aacplus_cfg->bandWidth = avctx->cutoff;
+ aacplus_cfg->outputFormat = !(avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER);
+ aacplus_cfg->inputFormat = avctx->sample_fmt == AV_SAMPLE_FMT_FLT ? AACPLUS_INPUT_FLOAT : AACPLUS_INPUT_16BIT;
+
+ if (!aacplusEncSetConfiguration(s->aacplus_handle, aacplus_cfg))
+ {
+ av_log(avctx, AV_LOG_ERROR, "libaacplus doesn't support this output format!\n");
+ return AVERROR(EINVAL);
+ }
+
+ avctx->frame_size = s->samples_input / avctx->ch_layout.nb_channels;
+ avctx->initial_padding = flag_aacplus ? INPUT_DELAY : CORE_DELAY;
+
+ ff_af_queue_init(avctx, &s->afq);
+
+ /* Set decoder specific info */
+ avctx->extradata_size = 0;
+ if (avctx->flags & AV_CODEC_FLAG_GLOBAL_HEADER)
+ {
+ unsigned char *buffer = NULL;
+ unsigned long decoder_specific_info_size;
+
+ if (aacplusEncGetDecoderSpecificInfo(s->aacplus_handle, &buffer, &decoder_specific_info_size) == 1)
+ {
+ avctx->extradata_size = decoder_specific_info_size;
+ avctx->extradata = av_mallocz(decoder_specific_info_size + AV_INPUT_BUFFER_PADDING_SIZE);
+
+ if (!avctx->extradata)
+ {
+ free(buffer);
+ return AVERROR(ENOMEM);
+ }
+
+ memcpy(avctx->extradata, buffer, decoder_specific_info_size);
+ }
+ else
+ {
+ return -1;
+ }
+ free(buffer);
+ }
+ return 0;
+}
+
+static int aacPlus_encode_frame(AVCodecContext *avctx, AVPacket *pkt,
+ const AVFrame *frame, int *got_packet)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+ int32_t *input_buffer;
+ int ret;
+ int discard_padding;
+
+ if ((ret = ff_alloc_packet(avctx, pkt, s->max_output_bytes)) < 0)
+ return ret;
+
+ if (!frame)
+ {
+ /* Flushing */
+ ret = aacplusEncEncode(s->aacplus_handle, NULL, 0, pkt->data, pkt->size);
+ if (!ret)
+ {
+ return ret; // 0 - EOF
+ }
+ else if (ret < 0)
+ {
+ av_log(avctx, AV_LOG_ERROR, "cannot flush");
+ return AVERROR(EINVAL);
+ }
+
+ pkt->size = ret;
+ }
+ else
+ {
+ /* Encoding */
+ input_buffer = (int32_t *)frame->data[0];
+ if ((ret = ff_af_queue_add(&s->afq, frame)) < 0)
+ return ret;
+
+ if ((ret = aacplusEncEncode(s->aacplus_handle, input_buffer, frame->nb_samples * avctx->ch_layout.nb_channels, pkt->data, pkt->size)) < 0)
+ {
+ av_log(avctx, AV_LOG_ERROR, "cannot encode");
+ return AVERROR(EINVAL);
+ }
+
+ pkt->size = ret;
+ }
+
+ 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);
+ }
+
+ avpkt->flags |= AV_PKT_FLAG_KEY;
+ *got_packet = 1;
+ return 0;
+}
+
+static void aacPlus_encode_flush(AVCodecContext *avctx)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+ uint8_t sink_null[32768];
+ int32_t encode_empty[32768] = {0};
+ int64_t pts, duration;
+
+ ff_af_queue_remove(&s->afq, s->afq.frame_count, &pts, &duration);
+ if (aacplusEncEncode(s->aacplus_handle, encode_empty, s->samples_input, sink_null, s->max_output_bytes) < 0)
+ av_log(avctx, AV_LOG_ERROR, "error occured when trying to flush");
+}
+
+static av_cold int aacPlus_encode_close(AVCodecContext *avctx)
+{
+ aacPlusAudioContext *s = avctx->priv_data;
+
+ if (s->aacplus_handle)
+ aacplusEncClose(s->aacplus_handle);
+
+ ff_af_queue_close(&s->afq);
+
+ return 0;
+}
+
+static const FFCodecDefault defaults[] = {
+ {"b", "128000"},
+ {NULL}};
+
+static const AVProfile profiles[] = {
+ {AV_PROFILE_AAC_LOW, "LC"},
+ {AV_PROFILE_AAC_HE, "HE-AAC"},
+ // {FF_PROFILE_AAC_HE_V2, "HE-AACv2"},
+ {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[2] = {
+ AV_CHANNEL_LAYOUT_MONO,
+ AV_CHANNEL_LAYOUT_STEREO
+};
+
+const FFCodec ff_libaacplus_encoder = {
+ .p.name = "libaac",
+ CODEC_LONG_NAME("custom 3GPP AAC+ encoder"),
+ .p.type = AVMEDIA_TYPE_AUDIO,
+ .p.id = AV_CODEC_ID_AAC,
+ .p.capabilities = AV_CODEC_CAP_SMALL_LAST_FRAME | AV_CODEC_CAP_DELAY | AV_CODEC_CAP_ENCODER_FLUSH,
+ .caps_internal = FF_CODEC_CAP_NOT_INIT_THREADSAFE,
+ .priv_data_size = sizeof(aacPlusAudioContext),
+ .init = aacPlus_encode_init,
+ FF_CODEC_ENCODE_CB(aacPlus_encode_frame),
+ .flush = aacPlus_encode_flush,
+ .close = aacPlus_encode_close,
+ .p.sample_fmts = (const enum AVSampleFormat[]){AV_SAMPLE_FMT_S16,
+ AV_SAMPLE_FMT_FLT,
+ AV_SAMPLE_FMT_NONE},
+ .p.priv_class = &aac_enc_class,
+ .defaults = defaults,
+ .p.profiles = profiles,
+ .p.supported_samplerates = aac_sample_rates,
+ .p.ch_layouts = aac_ch_layouts,
+ .p.wrapper_name = "libaac",
+};
diff -ruN ffmpeg-7.1.1/libavcodec/Makefile ffmpeg-7.1.1-custom/libavcodec/Makefile
--- ffmpeg-7.1.1/libavcodec/Makefile 2024-09-30 06:31:47.000000000 +0700
+++ ffmpeg-7.1.1-custom/libavcodec/Makefile 2025-07-14 08:20:08.984859732 +0700
@@ -261,6 +261,7 @@
OBJS-$(CONFIG_ATRAC9_DECODER) += atrac9dec.o
OBJS-$(CONFIG_AURA_DECODER) += cyuv.o
OBJS-$(CONFIG_AURA2_DECODER) += aura.o
+OBJS-$(CONFIG_LIBAACPLUS_ENCODER) += libaacplus.o
OBJS-$(CONFIG_AV1_DECODER) += av1dec.o av1_parse.o
OBJS-$(CONFIG_AV1_CUVID_DECODER) += cuviddec.o
OBJS-$(CONFIG_AV1_MEDIACODEC_DECODER) += mediacodecdec.o