Created
June 29, 2012 15:36
-
-
Save astrataro/3018658 to your computer and use it in GitHub Desktop.
ffmpeg: support libfdk_aac
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/configure b/configure | |
index f43a70d..aa0d186 100755 | |
--- a/configure | |
+++ b/configure | |
@@ -178,6 +178,7 @@ External library support: | |
--enable-libdc1394 enable IIDC-1394 grabbing using libdc1394 | |
and libraw1394 [no] | |
--enable-libfaac enable FAAC support via libfaac [no] | |
+ --enable-libfdk-aac enable AAC support via libfdk-aac [no] | |
--enable-libfreetype enable libfreetype [no] | |
--enable-libgsm enable GSM support via libgsm [no] | |
--enable-libilbc enable iLBC de/encoding via libilbc [no] | |
@@ -1050,6 +1051,7 @@ CONFIG_LIST=" | |
libcelt | |
libdc1394 | |
libfaac | |
+ libfdk_aac | |
libfreetype | |
libgsm | |
libilbc | |
@@ -1600,6 +1602,7 @@ h264_parser_select="golomb h264dsp h264pred" | |
libaacplus_encoder_deps="libaacplus" | |
libcelt_decoder_deps="libcelt" | |
libfaac_encoder_deps="libfaac" | |
+libfdk_aac_encoder_deps="libfdk_aac" | |
libgsm_decoder_deps="libgsm" | |
libgsm_encoder_deps="libgsm" | |
libgsm_ms_decoder_deps="libgsm" | |
@@ -3286,6 +3289,7 @@ enabled libcelt && require libcelt celt/celt.h celt_decode -lcelt0 && | |
{ check_lib celt/celt.h celt_decoder_create_custom -lcelt0 || | |
die "ERROR: libcelt version must be >= 0.11.0."; } | |
enabled libfaac && require2 libfaac "stdint.h faac.h" faacEncGetVersion -lfaac | |
+enabled libfdk_aac && require libfdk_aac fdk-aac/aacenc_lib.h aacEncOpen "-lfdk-aac -lstdc++" | |
enabled libfreetype && require_pkg_config freetype2 "ft2build.h freetype/freetype.h" FT_Init_FreeType | |
enabled libgsm && require libgsm gsm/gsm.h gsm_create -lgsm | |
enabled libilbc && require libilbc ilbc.h WebRtcIlbcfix_InitDecode -lilbc | |
@@ -3662,6 +3666,7 @@ echo "libcdio support ${libcdio-no}" | |
echo "libcelt enabled ${libcelt-no}" | |
echo "libdc1394 support ${libdc1394-no}" | |
echo "libfaac enabled ${libfaac-no}" | |
+echo "libfdk-aac enabled ${libfdk_aac-no}" | |
echo "libgsm enabled ${libgsm-no}" | |
echo "libilbc enabled ${libilbc-no}" | |
echo "libmodplug enabled ${libmodplug-no}" | |
diff --git a/libavcodec/Makefile b/libavcodec/Makefile | |
index 95bcb17..53144d7 100644 | |
--- a/libavcodec/Makefile | |
+++ b/libavcodec/Makefile | |
@@ -658,6 +658,7 @@ OBJS-$(CONFIG_WTV_DEMUXER) += mpeg4audio.o mpegaudiodata.o | |
OBJS-$(CONFIG_LIBAACPLUS_ENCODER) += libaacplus.o | |
OBJS-$(CONFIG_LIBCELT_DECODER) += libcelt_dec.o | |
OBJS-$(CONFIG_LIBFAAC_ENCODER) += libfaac.o audio_frame_queue.o | |
+OBJS-$(CONFIG_LIBFDK_AAC_ENCODER) += libfdk-aacenc.o audio_frame_queue.o | |
OBJS-$(CONFIG_LIBGSM_DECODER) += libgsm.o | |
OBJS-$(CONFIG_LIBGSM_ENCODER) += libgsm.o | |
OBJS-$(CONFIG_LIBGSM_MS_DECODER) += libgsm.o | |
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c | |
index 8c2bd2b..725f981 100644 | |
--- a/libavcodec/allcodecs.c | |
+++ b/libavcodec/allcodecs.c | |
@@ -411,6 +411,7 @@ void avcodec_register_all(void) | |
/* external libraries */ | |
REGISTER_DECODER (LIBCELT, libcelt); | |
REGISTER_ENCODER (LIBFAAC, libfaac); | |
+ REGISTER_ENCODER (LIBFDK_AAC, libfdk_aac); | |
REGISTER_ENCDEC (LIBGSM, libgsm); | |
REGISTER_ENCDEC (LIBGSM_MS, libgsm_ms); | |
REGISTER_ENCDEC (LIBILBC, libilbc); | |
diff --git a/libavcodec/avcodec.h b/libavcodec/avcodec.h | |
index 625bdc6..9187815 100644 | |
--- a/libavcodec/avcodec.h | |
+++ b/libavcodec/avcodec.h | |
@@ -2808,6 +2808,13 @@ typedef struct AVCodecContext { | |
#define FF_PROFILE_AAC_LOW 1 | |
#define FF_PROFILE_AAC_SSR 2 | |
#define FF_PROFILE_AAC_LTP 3 | |
+#define FF_PROFILE_AAC_SBR 5 | |
+#define FF_PROFILE_AAC_LD 23 | |
+#define FF_PROFILE_AAC_SBR_PS 29 | |
+#define FF_PROFILE_AAC_ELD 39 | |
+#define FF_PROFILE_AAC_MPEG2_LC 129 | |
+#define FF_PROFILE_AAC_MPEG2_SBR 132 | |
+#define FF_PROFILE_AAC_MPEG2_SBR_PS 156 | |
#define FF_PROFILE_DTS 20 | |
#define FF_PROFILE_DTS_ES 30 | |
diff --git a/libavcodec/options_table.h b/libavcodec/options_table.h | |
index f4d4619..aa3df97 100644 | |
--- a/libavcodec/options_table.h | |
+++ b/libavcodec/options_table.h | |
@@ -324,6 +324,13 @@ static const AVOption options[]={ | |
{"aac_low", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_LOW }, INT_MIN, INT_MAX, A|E, "profile"}, | |
{"aac_ssr", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_SSR }, INT_MIN, INT_MAX, A|E, "profile"}, | |
{"aac_ltp", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_LTP }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_sbr", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_SBR }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_ld", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_LD }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_sbr_ps", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_SBR_PS }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_eld", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_ELD }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_mpeg2_low", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_MPEG2_LC }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_mpeg2_sbr", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_MPEG2_SBR }, INT_MIN, INT_MAX, A|E, "profile"}, | |
+{"aac_mpeg2_sbr_ps", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_AAC_MPEG2_SBR_PS }, INT_MIN, INT_MAX, A|E, "profile"}, | |
{"dts", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_DTS }, INT_MIN, INT_MAX, A|E, "profile"}, | |
{"dts_es", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_DTS_ES }, INT_MIN, INT_MAX, A|E, "profile"}, | |
{"dts_96_24", NULL, 0, AV_OPT_TYPE_CONST, {.dbl = FF_PROFILE_DTS_96_24 }, INT_MIN, INT_MAX, A|E, "profile"}, | |
diff --git a/libavcodec/libfdk-aacenc.c b/libavcodec/libfdk-aacenc.c | |
new file mode 100644 | |
index 0000000..662cd96 | |
--- /dev/null | |
+++ b/libavcodec/libfdk-aacenc.c | |
@@ -0,0 +1,290 @@ | |
+/* | |
+ * AAC encoder wrapper | |
+ * Copyright (c) 2012 Martin Storsjo | |
+ * | |
+ * 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 | |
+ */ | |
+ | |
+#include <fdk-aac/aacenc_lib.h> | |
+ | |
+#include "avcodec.h" | |
+#include "audio_frame_queue.h" | |
+#include "internal.h" | |
+#include "libavutil/opt.h" | |
+ | |
+typedef struct AACContext { | |
+ const AVClass *class; | |
+ HANDLE_AACENCODER handle; | |
+ int afterburner; | |
+ int eld_sbr; | |
+ | |
+ AudioFrameQueue afq; | |
+} AACContext; | |
+ | |
+static const AVOption aac_enc_options[] = { | |
+ { "afterburner", "Afterburner (improved quality)", offsetof(AACContext, afterburner), AV_OPT_TYPE_INT, { 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, | |
+ { "eld_sbr", "Enable SBR for ELD (for SBR in other configurations, use the -profile parameter)", offsetof(AACContext, eld_sbr), AV_OPT_TYPE_INT, { 0 }, 0, 1, AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM }, | |
+ { NULL } | |
+}; | |
+ | |
+static const AVClass aac_enc_class = { | |
+ "libfdk_aac", av_default_item_name, aac_enc_options, LIBAVUTIL_VERSION_INT | |
+}; | |
+ | |
+static const char *aac_get_error(AACENC_ERROR err) | |
+{ | |
+ switch (err) { | |
+ case AACENC_OK: | |
+ return "No error"; | |
+ case AACENC_INVALID_HANDLE: | |
+ return "Invalid handle"; | |
+ case AACENC_MEMORY_ERROR: | |
+ return "Memory allocation error"; | |
+ case AACENC_UNSUPPORTED_PARAMETER: | |
+ return "Unsupported parameter"; | |
+ case AACENC_INVALID_CONFIG: | |
+ return "Invalid config"; | |
+ case AACENC_INIT_ERROR: | |
+ return "Initialization error"; | |
+ case AACENC_INIT_AAC_ERROR: | |
+ return "AAC library initialization error"; | |
+ case AACENC_INIT_SBR_ERROR: | |
+ return "SBR library initialization error"; | |
+ case AACENC_INIT_TP_ERROR: | |
+ return "Transport library initialization error"; | |
+ case AACENC_INIT_META_ERROR: | |
+ return "Metadata library initialization error"; | |
+ case AACENC_ENCODE_ERROR: | |
+ return "Encoding error"; | |
+ case AACENC_ENCODE_EOF: | |
+ return "End of file"; | |
+ default: | |
+ return "Unknown error"; | |
+ } | |
+} | |
+ | |
+static int aac_encode_close(AVCodecContext *avctx) | |
+{ | |
+ AACContext *s = avctx->priv_data; | |
+ | |
+ if (s->handle) | |
+ aacEncClose(&s->handle); | |
+#if FF_API_OLD_ENCODE_AUDIO | |
+ av_freep(&avctx->coded_frame); | |
+#endif | |
+ av_freep(&avctx->extradata); | |
+ ff_af_queue_close(&s->afq); | |
+ | |
+ return 0; | |
+} | |
+ | |
+static av_cold int aac_encode_init(AVCodecContext *avctx) | |
+{ | |
+ AACContext *s = avctx->priv_data; | |
+ int ret = AVERROR(EINVAL); | |
+ AACENC_InfoStruct info = { 0 }; | |
+ CHANNEL_MODE mode; | |
+ AACENC_ERROR err; | |
+ int aot = FF_PROFILE_AAC_LOW; | |
+ | |
+ if ((err = aacEncOpen(&s->handle, 0, avctx->channels)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to open the encoder: %s\n", aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if (avctx->profile != FF_PROFILE_UNKNOWN) | |
+ aot = avctx->profile; | |
+ | |
+ aot = aot < FF_PROFILE_AAC_SBR ? aot + 1 : avctx->profile; /* with a workaround for FF_PROFILE_AAC to AOT mapping */ | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_AOT, aot)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set the AOT %d: %s\n", aot, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if (aot == FF_PROFILE_AAC_ELD && s->eld_sbr) { | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_SBR_MODE, 1)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to enable SBR for ELD: %s\n", aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_SAMPLERATE, avctx->sample_rate)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set the sample rate %d: %s\n", avctx->sample_rate, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ switch (avctx->channels) { | |
+ case 1: mode = MODE_1; break; | |
+ case 2: mode = MODE_2; break; | |
+ case 3: mode = MODE_1_2; break; | |
+ case 4: mode = MODE_1_2_1; break; | |
+ case 5: mode = MODE_1_2_2; break; | |
+ case 6: mode = MODE_1_2_2_1; break; | |
+ default: | |
+ av_log(avctx, AV_LOG_ERROR, "Unsupported number of channels %d\n", avctx->channels); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELMODE, mode)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set channel mode %d: %s\n", mode, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_CHANNELORDER, 1)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set wav channel order %d: %s\n", mode, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_BITRATE, avctx->bit_rate)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set the bitrate %d: %s\n", avctx->bit_rate, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_TRANSMUX, avctx->flags & CODEC_FLAG_GLOBAL_HEADER ? 0 : 2)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set the transmux format: %s\n", aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_SIGNALING_MODE, avctx->flags & CODEC_FLAG_GLOBAL_HEADER ? 2 : 0)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set signaling mode: %s\n", aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncoder_SetParam(s->handle, AACENC_AFTERBURNER, s->afterburner)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to set afterburner to %d: %s\n", s->afterburner, aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+ if ((err = aacEncEncode(s->handle, NULL, NULL, NULL, NULL)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to initialize the encoder: %s\n", aac_get_error(err)); | |
+ return AVERROR(EINVAL); | |
+ } | |
+ | |
+ if ((err = aacEncInfo(s->handle, &info)) != AACENC_OK) { | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to get encoder info: %s\n", aac_get_error(err)); | |
+ goto error; | |
+ } | |
+ | |
+#if FF_API_OLD_ENCODE_AUDIO | |
+ avctx->coded_frame = avcodec_alloc_frame(); | |
+ if (!avctx->coded_frame) | |
+ return AVERROR(ENOMEM); | |
+#endif | |
+ avctx->frame_size = info.frameLength; | |
+ avctx->delay = info.encoderDelay; | |
+ ff_af_queue_init(avctx, &s->afq); | |
+ | |
+ if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { | |
+ avctx->extradata_size = info.confSize; | |
+ avctx->extradata = av_mallocz(avctx->extradata_size + | |
+ FF_INPUT_BUFFER_PADDING_SIZE); | |
+ if (!avctx->extradata) { | |
+ ret = AVERROR(ENOMEM); | |
+ goto error; | |
+ } | |
+ | |
+ memcpy(avctx->extradata, info.confBuf, info.confSize); | |
+ } | |
+ return 0; | |
+error: | |
+ aac_encode_close(avctx); | |
+ return ret; | |
+} | |
+ | |
+static int aac_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, | |
+ const AVFrame *frame, int *got_packet_ptr) | |
+{ | |
+ AACContext *s = avctx->priv_data; | |
+ AACENC_BufDesc in_buf = { 0 }, out_buf = { 0 }; | |
+ AACENC_InArgs in_args = { 0 }; | |
+ AACENC_OutArgs out_args = { 0 }; | |
+ int in_buffer_identifier = IN_AUDIO_DATA; | |
+ int in_buffer_size, in_buffer_element_size; | |
+ int out_buffer_identifier = OUT_BITSTREAM_DATA; | |
+ int out_buffer_size, out_buffer_element_size; | |
+ void *in_ptr, *out_ptr; | |
+ int ret; | |
+ AACENC_ERROR err; | |
+ | |
+ /* handle end-of-stream small frame and flushing */ | |
+ if (!frame) { | |
+ in_args.numInSamples = -1; | |
+ } else { | |
+ in_ptr = frame->data[0]; | |
+ in_buffer_size = 2 * avctx->channels * frame->nb_samples; | |
+ in_buffer_element_size = 2; | |
+ | |
+ in_args.numInSamples = avctx->channels * frame->nb_samples; | |
+ in_buf.numBufs = 1; | |
+ in_buf.bufs = &in_ptr; | |
+ in_buf.bufferIdentifiers = &in_buffer_identifier; | |
+ in_buf.bufSizes = &in_buffer_size; | |
+ in_buf.bufElSizes = &in_buffer_element_size; | |
+ | |
+ /* add current frame to the queue */ | |
+ if ((ret = ff_af_queue_add(&s->afq, frame) < 0)) | |
+ return ret; | |
+ } | |
+ | |
+ if ((ret = ff_alloc_packet2(avctx, avpkt, FFMAX(8192, 768 * avctx->channels)))) { | |
+ av_log(avctx, AV_LOG_ERROR, "Error getting output packet\n"); | |
+ return ret; | |
+ } | |
+ | |
+ out_ptr = avpkt->data; | |
+ out_buffer_size = avpkt->size; | |
+ out_buffer_element_size = 1; | |
+ out_buf.numBufs = 1; | |
+ out_buf.bufs = &out_ptr; | |
+ out_buf.bufferIdentifiers = &out_buffer_identifier; | |
+ out_buf.bufSizes = &out_buffer_size; | |
+ out_buf.bufElSizes = &out_buffer_element_size; | |
+ | |
+ if ((err = aacEncEncode(s->handle, &in_buf, &out_buf, &in_args, &out_args)) != AACENC_OK) { | |
+ if (!frame && err == AACENC_ENCODE_EOF) | |
+ return 0; | |
+ av_log(avctx, AV_LOG_ERROR, "Unable to encode frame: %s\n", aac_get_error(err)); | |
+ return AVERROR(EINVAL); | |
+ } | |
+ | |
+ if (!out_args.numOutBytes) | |
+ return 0; | |
+ | |
+ /* Get the next frame pts/duration */ | |
+ ff_af_queue_remove(&s->afq, avctx->frame_size, &avpkt->pts, | |
+ &avpkt->duration); | |
+ | |
+ avpkt->size = out_args.numOutBytes; | |
+ *got_packet_ptr = 1; | |
+ return 0; | |
+} | |
+ | |
+AVCodec ff_libfdk_aac_encoder = { | |
+ .name = "libfdk_aac", | |
+ .type = AVMEDIA_TYPE_AUDIO, | |
+ .id = CODEC_ID_AAC, | |
+ .priv_data_size = sizeof(AACContext), | |
+ .init = aac_encode_init, | |
+ .encode2 = aac_encode_frame, | |
+ .close = aac_encode_close, | |
+ .capabilities = CODEC_CAP_SMALL_LAST_FRAME | CODEC_CAP_DELAY, | |
+ .sample_fmts = (const enum AVSampleFormat[]){ AV_SAMPLE_FMT_S16, | |
+ AV_SAMPLE_FMT_NONE }, | |
+ .long_name = NULL_IF_CONFIG_SMALL("Fraunhofer FDK AAC"), | |
+ .priv_class = &aac_enc_class, | |
+}; | |
-- | |
1.7.10.msysgit.1 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment