[FFmpeg-devel] [PATCH 1/1] avcodec/libhelix-aac: add aac decoding via libhelix.

wr.raywoo at gmail.com wr.raywoo at gmail.com
Sun May 18 14:34:51 EEST 2025


From: Ray Woo <wr.raywoo at gmail.com>

libhelix-aac decoder is a kind of fixed-point HE-AAC decoder developed by RealNetworks, 2005.
It behaviours well in embeded platforms where resources are limited.

Signed-off-by: Ray Woo <wr.raywoo at gmail.com>
---
 Changelog                    |   1 +
 configure                    |   6 ++
 doc/general_contents.texi    |  10 +++
 libavcodec/Makefile          |   1 +
 libavcodec/allcodecs.c       |   1 +
 libavcodec/libhelix-aacdec.c | 161 +++++++++++++++++++++++++++++++++++
 libavcodec/version.h         |   4 +-
 7 files changed, 182 insertions(+), 2 deletions(-)
 create mode 100644 libavcodec/libhelix-aacdec.c

diff --git a/Changelog b/Changelog
index 4217449438..0c852a082a 100644
--- a/Changelog
+++ b/Changelog
@@ -18,6 +18,7 @@ version <next>:
 - APV encoding support through a libopenapv wrapper
 - VVC decoder supports all content of SCC (Screen Content Coding):
   IBC (Inter Block Copy), Palette Mode and ACT (Adaptive Color Transform
+- libhelix-aac decoder
 
 
 version 7.1:
diff --git a/configure b/configure
index 0609dac4ab..13adc215a5 100755
--- a/configure
+++ b/configure
@@ -213,6 +213,7 @@ External library support:
   --enable-ladspa          enable LADSPA audio filtering [no]
   --enable-lcms2           enable ICC profile support via LittleCMS 2 [no]
   --enable-libaom          enable AV1 video encoding/decoding via libaom [no]
+  --enable-libhelix-aac    enable aac decoding via libhelix-aac for Arduino [no]
   --enable-libaribb24      enable ARIB text and caption decoding via libaribb24 [no]
   --enable-libaribcaption  enable ARIB text and caption decoding via libaribcaption [no]
   --enable-libass          enable libass subtitles rendering,
@@ -1938,6 +1939,7 @@ EXTERNAL_LIBRARY_LIST="
     libfreetype
     libfribidi
     libharfbuzz
+    libhelix_aac
     libglslang
     libgme
     libgsm
@@ -3579,6 +3581,7 @@ libgsm_decoder_deps="libgsm"
 libgsm_encoder_deps="libgsm"
 libgsm_ms_decoder_deps="libgsm"
 libgsm_ms_encoder_deps="libgsm"
+libhelix_aac_decoder_deps="libhelix_aac"
 libilbc_decoder_deps="libilbc"
 libilbc_encoder_deps="libilbc"
 libjxl_anim_decoder_deps="libjxl libjxl_threads"
@@ -6971,6 +6974,9 @@ enabled libfontconfig     && require_pkg_config libfontconfig fontconfig "fontco
 enabled libfreetype       && require_pkg_config libfreetype freetype2 "ft2build.h FT_FREETYPE_H" FT_Init_FreeType
 enabled libfribidi        && require_pkg_config libfribidi fribidi fribidi.h fribidi_version_info
 enabled libharfbuzz       && require_pkg_config libharfbuzz harfbuzz hb.h hb_buffer_create
+enabled libhelix-aac      && require libhelix-aac libhelix-aac/aacdec.h AACDecode -lhelix-aac -lstdc++ &&
+                             { check_lib libhelix-aac "libhelix-aac/aacdec.h" AACInitDecoder -lhelix-aac -lstdc++ ||
+                               die "ERROR: libhelix-aac not found"; }
 enabled libglslang && { check_lib spirv_compiler glslang/Include/glslang_c_interface.h glslang_initialize_process \
                             -lglslang -lMachineIndependent -lGenericCodeGen \
                             -lSPVRemapper -lSPIRV -lSPIRV-Tools-opt -lSPIRV-Tools -lpthread -lstdc++ -lm ||
diff --git a/doc/general_contents.texi b/doc/general_contents.texi
index 0e6b9570a4..201e57eb98 100644
--- a/doc/general_contents.texi
+++ b/doc/general_contents.texi
@@ -173,6 +173,16 @@ enable it.
 LCEVCdec is under the BSD-3-Clause-Clear License.
 @end float
 
+ at section libhelix-aac
+
+libelix-aac decoder is a fixed-point HE-AAC decoder developed by RealNetworks,
+which performs well for 32-bit fixed-point processors. FFmpeg can make use of the
+libhelix-aac library for aac decoding.
+
+Go to @url{https://github.com/pschatzmann/arduino-libhelix} and follow the
+instructions for installing the libhelix-aac library. Then pass
+ at code{--enable-libhelix-aac} to configure to enable it.
+
 @section libilbc
 
 iLBC is a narrowband speech codec that has been made freely available
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 77734dff24..c43a24d027 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -1143,6 +1143,7 @@ OBJS-$(CONFIG_LIBGSM_DECODER)             += libgsmdec.o
 OBJS-$(CONFIG_LIBGSM_ENCODER)             += libgsmenc.o
 OBJS-$(CONFIG_LIBGSM_MS_DECODER)          += libgsmdec.o
 OBJS-$(CONFIG_LIBGSM_MS_ENCODER)          += libgsmenc.o
+OBJS-$(CONFIG_LIBHELIX_AAC_DECODER)       += libhelix-aacdec.o mpeg4audio.o mpeg4audio_sample_rates.o
 OBJS-$(CONFIG_LIBILBC_DECODER)            += libilbc.o
 OBJS-$(CONFIG_LIBILBC_ENCODER)            += libilbc.o
 OBJS-$(CONFIG_LIBJXL_DECODER)             += libjxldec.o libjxl.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index cd4f6ecd59..c1fc526535 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -778,6 +778,7 @@ extern const FFCodec ff_libgsm_encoder;
 extern const FFCodec ff_libgsm_decoder;
 extern const FFCodec ff_libgsm_ms_encoder;
 extern const FFCodec ff_libgsm_ms_decoder;
+extern const FFCodec ff_libhelix_aac_decoder;
 extern const FFCodec ff_libilbc_encoder;
 extern const FFCodec ff_libilbc_decoder;
 extern const FFCodec ff_libjxl_anim_decoder;
diff --git a/libavcodec/libhelix-aacdec.c b/libavcodec/libhelix-aacdec.c
new file mode 100644
index 0000000000..8bae6aad7c
--- /dev/null
+++ b/libavcodec/libhelix-aacdec.c
@@ -0,0 +1,161 @@
+/*
+ * libhelix aac decoder
+ * Copyright (C) 2025  Ray Woo <wr.raywoo at gmail.com>
+ *
+ * This file is part of FFmpeg.
+ *
+ * FFmpeg is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * FFmpeg is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with FFmpeg; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+/**
+ * @file
+ * AAC decoder implementation using Helix lib
+ */
+
+#include "avcodec.h"
+#include "internal.h"
+#include "codec_internal.h"
+#include "decode.h"
+#include "get_bits.h"
+#include "mpeg4audio.h"
+#include "libavutil/intreadwrite.h"
+#include "libavutil/mem.h"
+
+#include <aacdec.h>
+#include <aaccommon.h>
+
+#define SYNCWORDH 0xff
+#define SYNCWORDL 0xf0
+#define LIBHELIX_AAC_MAX_CHANNELS 2
+#define LIBHELIX_AAC_MAX_NSAMPS   2048
+
+typedef struct HAACDecContext {
+    AVClass *class;
+    HAACDecoder context;
+    uint8_t *pcm;
+    int pcm_size;
+    MPEG4AudioConfig m4ac;
+} HAACDecContext;
+
+static av_cold int aac_decode_init(AVCodecContext *avctx)
+{
+    HAACDecContext *aac = avctx->priv_data;
+    GetBitContext gb;
+    int ret;
+
+    aac->context = AACInitDecoder();
+    if (!aac->context)
+        return AVERROR(ENOMEM);
+
+
+    avctx->sample_fmt = AV_SAMPLE_FMT_S16;
+    aac->pcm_size = LIBHELIX_AAC_MAX_NSAMPS * LIBHELIX_AAC_MAX_CHANNELS *
+                    av_get_bytes_per_sample(avctx->sample_fmt);
+
+    aac->pcm = av_malloc(aac->pcm_size);
+    if (!aac->pcm)
+        return AVERROR(ENOMEM);
+
+    if (avctx->extradata_size > 0) {
+        if ((ret = init_get_bits(&gb, avctx->extradata, avctx->extradata_size)) < 0)
+            return ret;
+
+        if ((ret = ff_mpeg4audio_get_config_gb(&aac->m4ac, &gb, 1, NULL)) < 0)
+            return ret;
+
+    }
+
+    return 0;
+}
+
+static int aac_decode_frame(AVCodecContext *avctx, AVFrame *frame,
+                            int *got_frame_ptr, AVPacket *avpkt)
+{
+    HAACDecContext *aac = avctx->priv_data;
+    AACFrameInfo info;
+    uint8_t *in_data;
+    int ret, in_size;
+
+    if (!aac)
+        return AVERROR(EIO);
+
+    in_data = avpkt->data;
+    in_size = avpkt->size;
+
+    if ((in_data[0] & SYNCWORDH) != SYNCWORDH || (in_data[1] & SYNCWORDL) != SYNCWORDL) {
+        info.sampRateCore = aac->m4ac.sample_rate ? aac->m4ac.sample_rate : avctx->sample_rate;
+        info.nChans  = aac->m4ac.channels ? aac->m4ac.channels : avctx->ch_layout.nb_channels;
+        info.profile = AAC_PROFILE_LC;
+        ret = AACSetRawBlockParams(aac->context, 0, &info);
+        if (ret < 0)
+            return ret;
+    }
+
+    ret = AACDecode(aac->context, &in_data, &in_size, (int16_t *)aac->pcm);
+    if (ret < 0) {
+        av_log(avctx, AV_LOG_ERROR, "%s error ret %d.\n", __func__, ret);
+        AACFlushCodec(aac->context);
+        return ret;
+    }
+
+    AACGetLastFrameInfo(aac->context, &info);
+
+    if (!avctx->sample_rate)
+         avctx->sample_rate = info.sampRateOut;
+
+    if (!avctx->ch_layout.nb_channels)
+         av_channel_layout_default(&avctx->ch_layout, info.nChans);
+
+    avctx->frame_size = info.outputSamps / info.nChans;
+
+    frame->nb_samples = avctx->frame_size;
+    if ((ret = ff_get_buffer(avctx, frame, 0)) < 0)
+        return ret;
+
+    memcpy(frame->extended_data[0], aac->pcm,
+           avctx->ch_layout.nb_channels * avctx->frame_size *
+           av_get_bytes_per_sample(avctx->sample_fmt));
+
+    *got_frame_ptr = 1;
+
+    return avpkt->size - in_size;
+}
+
+static av_cold int aac_decode_close(AVCodecContext *avctx)
+{
+    HAACDecContext *aac = avctx->priv_data;
+
+    if (aac->context)
+        AACFreeDecoder(aac->context);
+    av_freep(&aac->pcm);
+
+    return 0;
+}
+
+const FFCodec ff_libhelix_aac_decoder = {
+    .p.name            = "libhelix_aac",
+    .p.long_name       = NULL_IF_CONFIG_SMALL("libHelix AAC Decoder"),
+    .p.type            = AVMEDIA_TYPE_AUDIO,
+    .p.id              = AV_CODEC_ID_AAC,
+    .priv_data_size    = sizeof(HAACDecContext),
+    .init              = aac_decode_init,
+    FF_CODEC_DECODE_CB(aac_decode_frame),
+    .close             = aac_decode_close,
+    .p.capabilities    = AV_CODEC_CAP_CHANNEL_CONF | AV_CODEC_CAP_DR1,
+    .p.sample_fmts     = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_S16,
+                                                         AV_SAMPLE_FMT_NONE },
+    .p.ch_layouts      = (const AVChannelLayout[]) { AV_CHANNEL_LAYOUT_MONO,
+                                                     AV_CHANNEL_LAYOUT_STEREO, { 0 } },
+};
diff --git a/libavcodec/version.h b/libavcodec/version.h
index eedf4c5a92..06631ffa8c 100644
--- a/libavcodec/version.h
+++ b/libavcodec/version.h
@@ -29,8 +29,8 @@
 
 #include "version_major.h"
 
-#define LIBAVCODEC_VERSION_MINOR   3
-#define LIBAVCODEC_VERSION_MICRO 101
+#define LIBAVCODEC_VERSION_MINOR   4
+#define LIBAVCODEC_VERSION_MICRO 100
 
 #define LIBAVCODEC_VERSION_INT  AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \
                                                LIBAVCODEC_VERSION_MINOR, \
-- 
2.34.1



More information about the ffmpeg-devel mailing list