FFmpeg/libavcodec/libaac_nextdec.c
2025-08-22 20:34:47 +07:00

171 lines
5.2 KiB
C

/*
* 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 <libaac.h>
#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",
};