[1/2] Add an AAC encoder by using the libvo-aacenc library

Message ID 1302167934-39279-1-git-send-email-martin@martin.st
State Superseded
Headers show

Commit Message

Martin Storsjö April 7, 2011, 9:18 a.m.
---
 Changelog                 |    1 +
 configure                 |    6 ++
 libavcodec/Makefile       |    1 +
 libavcodec/allcodecs.c    |    1 +
 libavcodec/libvo-aacenc.c |  132 +++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 141 insertions(+), 0 deletions(-)
 create mode 100644 libavcodec/libvo-aacenc.c

Comments

Jindrich Makovicka April 7, 2011, 11:16 a.m. | #1
On Thu, Apr 7, 2011 at 11:18, Martin Storsjö <martin@martin.st> wrote:

> +    memset(&params, 0, sizeof(params));
> +    params.sampleRate = avctx->sample_rate;
> +    params.bitRate = avctx->bit_rate;
> +    params.nChannels = avctx->channels;
> +    params.adtsUsed = 0;

I think adtsUsed should be set based on CODEC_FLAG_GLOBAL_HEADER ,
otherwise the AAC output muxed into MPEG-TS won't be playable.

i.e. params.adtsUsed = !(avctx->flags & CODEC_FLAG_GLOBAL_HEADER)
Martin Storsjö April 7, 2011, 11:25 a.m. | #2
On Thu, 7 Apr 2011, Jindřich Makovička wrote:

> On Thu, Apr 7, 2011 at 11:18, Martin Storsjö <martin@martin.st> wrote:
> 
> > +    memset(&params, 0, sizeof(params));
> > +    params.sampleRate = avctx->sample_rate;
> > +    params.bitRate = avctx->bit_rate;
> > +    params.nChannels = avctx->channels;
> > +    params.adtsUsed = 0;
> 
> I think adtsUsed should be set based on CODEC_FLAG_GLOBAL_HEADER ,
> otherwise the AAC output muxed into MPEG-TS won't be playable.
> 
> i.e. params.adtsUsed = !(avctx->flags & CODEC_FLAG_GLOBAL_HEADER)

Good point, fixed locally.

Actually, .ts files with data encoded with this encoder, without this fix, 
apprears to work with ffplay at least, but other decoders might of course 
not be so tolerant.

// Martin
Alex Converse April 7, 2011, 3 p.m. | #3
On Thu, Apr 7, 2011 at 2:18 AM, Martin Storsjö <martin@martin.st> wrote:
> ---
>  Changelog                 |    1 +
>  configure                 |    6 ++
>  libavcodec/Makefile       |    1 +
>  libavcodec/allcodecs.c    |    1 +
>  libavcodec/libvo-aacenc.c |  132 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 141 insertions(+), 0 deletions(-)
>  create mode 100644 libavcodec/libvo-aacenc.c
>

Perhaps we should remove faac then? Do we need two third party aac encoders?
Martin Storsjö April 7, 2011, 3:10 p.m. | #4
On Thu, 7 Apr 2011, Alex Converse wrote:

> On Thu, Apr 7, 2011 at 2:18 AM, Martin Storsjö <martin@martin.st> wrote:
> > ---
> >  Changelog                 |    1 +
> >  configure                 |    6 ++
> >  libavcodec/Makefile       |    1 +
> >  libavcodec/allcodecs.c    |    1 +
> >  libavcodec/libvo-aacenc.c |  132 +++++++++++++++++++++++++++++++++++++++++++++
> >  5 files changed, 141 insertions(+), 0 deletions(-)
> >  create mode 100644 libavcodec/libvo-aacenc.c
> >
> 
> Perhaps we should remove faac then? Do we need two third party aac encoders?

Probably not, if there aren't any particular features of libfaac that 
vo-aacenc doesn't have, that we care about. libfaac seems to support 
different profiles, and I'm not sure that the visualon code has support 
for that, at least not in the external api at the moment.

// Martin
Diego Biurrun April 7, 2011, 10:12 p.m. | #5
On Thu, Apr 07, 2011 at 12:18:53PM +0300, Martin Storsjö wrote:
> ---
>  Changelog                 |    1 +
>  configure                 |    6 ++
>  libavcodec/Makefile       |    1 +
>  libavcodec/allcodecs.c    |    1 +
>  libavcodec/libvo-aacenc.c |  132 +++++++++++++++++++++++++++++++++++++++++++++
>  5 files changed, 141 insertions(+), 0 deletions(-)
>  create mode 100644 libavcodec/libvo-aacenc.c

minor bump, docs update

> --- /dev/null
> +++ b/libavcodec/libvo-aacenc.c
> @@ -0,0 +1,132 @@
> +/*
> + * AAC encoder wrapper
> + * Copyright (c) 2010 Martin Storsjo

2011?

> +#include "avcodec.h"
> +#include <vo-aacenc/voAAC.h>
> +#include <vo-aacenc/cmnMemory.h>
> +#include "mpeg4audio.h"

Place system headers before local headers, separate by an empty line.

> +typedef struct AACContext {
> +    VO_AUDIO_CODECAPI codec_api;
> +    VO_HANDLE handle;
> +    VO_MEM_OPERATOR mem_operator;
> +    VO_CODEC_INIT_USERDATA user_data;
> +} AACContext;
> +
> +static av_cold int aac_encode_init(AVCodecContext *avctx)
> +{
> +    AACContext *s = avctx->priv_data;
> +    AACENC_PARAM params;
> +    int index;
> +
> +    memset(&params, 0, sizeof(params));

Why not initialize params to 0 instead?

> +    avctx->coded_frame = avcodec_alloc_frame();
> +    avctx->frame_size = 1024;

> +    s->mem_operator.Alloc = cmnMemAlloc;
> +    s->mem_operator.Copy = cmnMemCopy;
> +    s->mem_operator.Free = cmnMemFree;
> +    s->mem_operator.Set = cmnMemSet;
> +    s->mem_operator.Check = cmnMemCheck;
> +    s->user_data.memflag = VO_IMF_USERMEMOPERATOR;
> +    s->user_data.memData = &s->mem_operator;
> +    s->codec_api.Init(&s->handle, VO_AUDIO_CodingAAC, &s->user_data);

> +    params.sampleRate = avctx->sample_rate;
> +    params.bitRate = avctx->bit_rate;
> +    params.nChannels = avctx->channels;
> +    params.adtsUsed = 0;

> +    avctx->extradata_size = 2;
> +    avctx->extradata = av_mallocz(avctx->extradata_size +
> +                                  FF_INPUT_BUFFER_PADDING_SIZE);

nit: align the '='

> +static int aac_encode_frame(AVCodecContext *avctx,
> +                            unsigned char *frame/*out*/,
> +                            int buf_size, void *data/*in*/)
> +{
> +    AACContext *s = avctx->priv_data;
> +    VO_CODECBUFFER input, output;
> +    VO_AUDIO_OUTPUTINFO output_info;
> +
> +    memset(&input,       0, sizeof(input));
> +    memset(&output,      0, sizeof(output));
> +    memset(&output_info, 0, sizeof(output_info));

same, initialize to 0

Diego

Patch

diff --git a/Changelog b/Changelog
index ec09c28..6a255d4 100644
--- a/Changelog
+++ b/Changelog
@@ -83,6 +83,7 @@  version <next>:
 - Linux framebuffer input device added
 - Chronomaster DFA decoder
 - Mobotix MxPEG decoder
+- AAC encoding via libvo-aacenc
 
 
 version 0.6:
diff --git a/configure b/configure
index 92a809f..8880fba 100755
--- a/configure
+++ b/configure
@@ -178,6 +178,7 @@  External library support:
   --enable-libschroedinger enable Dirac support via libschroedinger [no]
   --enable-libspeex        enable Speex decoding via libspeex [no]
   --enable-libtheora       enable Theora encoding via libtheora [no]
+  --enable-libvo-aacenc    enable AAC encoding via libvo-aacenc [no]
   --enable-libvorbis       enable Vorbis encoding via libvorbis,
                            native implementation exists [no]
   --enable-libvpx          enable VP8 support via libvpx [no]
@@ -937,6 +938,7 @@  CONFIG_LIST="
     libschroedinger
     libspeex
     libtheora
+    libvo_aacenc
     libvorbis
     libvpx
     libx264
@@ -1384,6 +1386,7 @@  libschroedinger_decoder_deps="libschroedinger"
 libschroedinger_encoder_deps="libschroedinger"
 libspeex_decoder_deps="libspeex"
 libtheora_encoder_deps="libtheora"
+libvo_aacenc_encoder_deps="libvo_aacenc"
 libvorbis_encoder_deps="libvorbis"
 libvpx_decoder_deps="libvpx"
 libvpx_encoder_deps="libvpx"
@@ -2525,6 +2528,7 @@  die_license_disabled nonfree libfaac
 
 die_license_disabled version3 libopencore_amrnb
 die_license_disabled version3 libopencore_amrwb
+die_license_disabled version3 libvo_aacenc
 
 enabled version3 && { enabled gpl && enable gplv3 || enable lgplv3; }
 
@@ -2864,6 +2868,7 @@  enabled librtmp    && require_pkg_config librtmp librtmp/rtmp.h RTMP_Socket
 enabled libschroedinger && require_pkg_config schroedinger-1.0 schroedinger/schro.h schro_init
 enabled libspeex   && require  libspeex speex/speex.h speex_decoder_init -lspeex
 enabled libtheora  && require  libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg
+enabled libvo_aacenc && require libvo_aacenc vo-aacenc/voAAC.h voGetAACEncAPI -lvo-aacenc
 enabled libvorbis  && require  libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg
 enabled libvpx     && {
     enabled libvpx_decoder && { check_lib2 "vpx/vpx_decoder.h vpx/vp8dx.h" vpx_codec_dec_init_ver -lvpx ||
@@ -3132,6 +3137,7 @@  echo "libschroedinger enabled   ${libschroedinger-no}"
 echo "libspeex enabled          ${libspeex-no}"
 echo "libtheora enabled         ${libtheora-no}"
 echo "libva enabled             ${vaapi-no}"
+echo "libvo-aacenc support      ${libvo_aacenc-no}"
 echo "libvorbis enabled         ${libvorbis-no}"
 echo "libvpx enabled            ${libvpx-no}"
 echo "libx264 enabled           ${libx264-no}"
diff --git a/libavcodec/Makefile b/libavcodec/Makefile
index 837f7e2..e9c40e4 100644
--- a/libavcodec/Makefile
+++ b/libavcodec/Makefile
@@ -568,6 +568,7 @@  OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER)    += libschroedingerenc.o \
                                              libdirac_libschro.o
 OBJS-$(CONFIG_LIBSPEEX_DECODER)           += libspeexdec.o
 OBJS-$(CONFIG_LIBTHEORA_ENCODER)          += libtheoraenc.o
+OBJS-$(CONFIG_LIBVO_AACENC_ENCODER)       += libvo-aacenc.o mpeg4audio.o
 OBJS-$(CONFIG_LIBVORBIS_ENCODER)          += libvorbis.o vorbis_data.o
 OBJS-$(CONFIG_LIBVPX_DECODER)             += libvpxdec.o
 OBJS-$(CONFIG_LIBVPX_ENCODER)             += libvpxenc.o
diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c
index 7636392..e0323ac 100644
--- a/libavcodec/allcodecs.c
+++ b/libavcodec/allcodecs.c
@@ -366,6 +366,7 @@  void avcodec_register_all(void)
     REGISTER_ENCDEC  (LIBSCHROEDINGER, libschroedinger);
     REGISTER_DECODER (LIBSPEEX, libspeex);
     REGISTER_ENCODER (LIBTHEORA, libtheora);
+    REGISTER_ENCODER (LIBVO_AACENC, libvo_aacenc);
     REGISTER_ENCODER (LIBVORBIS, libvorbis);
     REGISTER_ENCDEC  (LIBVPX, libvpx);
     REGISTER_ENCODER (LIBX264, libx264);
diff --git a/libavcodec/libvo-aacenc.c b/libavcodec/libvo-aacenc.c
new file mode 100644
index 0000000..34389f1
--- /dev/null
+++ b/libavcodec/libvo-aacenc.c
@@ -0,0 +1,132 @@ 
+/*
+ * AAC encoder wrapper
+ * Copyright (c) 2010 Martin Storsjo
+ *
+ * This file is part of Libav.
+ *
+ * Libav 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.
+ *
+ * Libav 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 Libav; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#include "avcodec.h"
+#include <vo-aacenc/voAAC.h>
+#include <vo-aacenc/cmnMemory.h>
+#include "mpeg4audio.h"
+
+typedef struct AACContext {
+    VO_AUDIO_CODECAPI codec_api;
+    VO_HANDLE handle;
+    VO_MEM_OPERATOR mem_operator;
+    VO_CODEC_INIT_USERDATA user_data;
+} AACContext;
+
+static av_cold int aac_encode_init(AVCodecContext *avctx)
+{
+    AACContext *s = avctx->priv_data;
+    AACENC_PARAM params;
+    int index;
+
+    avctx->coded_frame = avcodec_alloc_frame();
+    avctx->frame_size = 1024;
+
+    voGetAACEncAPI(&s->codec_api);
+
+    s->mem_operator.Alloc = cmnMemAlloc;
+    s->mem_operator.Copy = cmnMemCopy;
+    s->mem_operator.Free = cmnMemFree;
+    s->mem_operator.Set = cmnMemSet;
+    s->mem_operator.Check = cmnMemCheck;
+    s->user_data.memflag = VO_IMF_USERMEMOPERATOR;
+    s->user_data.memData = &s->mem_operator;
+    s->codec_api.Init(&s->handle, VO_AUDIO_CodingAAC, &s->user_data);
+
+    memset(&params, 0, sizeof(params));
+    params.sampleRate = avctx->sample_rate;
+    params.bitRate = avctx->bit_rate;
+    params.nChannels = avctx->channels;
+    params.adtsUsed = 0;
+    if (s->codec_api.SetParam(s->handle, VO_PID_AAC_ENCPARAM, &params)
+        != VO_ERR_NONE) {
+        av_log(avctx, AV_LOG_ERROR, "Unable to set encoding parameters\n");
+        return AVERROR_UNKNOWN;
+    }
+
+    avctx->extradata_size = 2;
+    avctx->extradata = av_mallocz(avctx->extradata_size +
+                                  FF_INPUT_BUFFER_PADDING_SIZE);
+    if (!avctx->extradata)
+        return AVERROR(ENOMEM);
+
+    for (index = 0; index < 16; index++)
+        if (avctx->sample_rate == ff_mpeg4audio_sample_rates[index])
+            break;
+    if (index == 16) {
+        av_log(avctx, AV_LOG_ERROR, "Unsupported sample rate %d\n",
+                                    avctx->sample_rate);
+        return AVERROR_NOTSUPP;
+    }
+    avctx->extradata[0] = 0x02 << 3 | index >> 1;
+    avctx->extradata[1] = (index & 0x01) << 7 | avctx->channels << 3;
+    return 0;
+}
+
+static int aac_encode_close(AVCodecContext *avctx)
+{
+    AACContext *s = avctx->priv_data;
+
+    s->codec_api.Uninit(s->handle);
+    av_freep(&avctx->coded_frame);
+
+    return 0;
+}
+
+static int aac_encode_frame(AVCodecContext *avctx,
+                            unsigned char *frame/*out*/,
+                            int buf_size, void *data/*in*/)
+{
+    AACContext *s = avctx->priv_data;
+    VO_CODECBUFFER input, output;
+    VO_AUDIO_OUTPUTINFO output_info;
+
+    memset(&input,       0, sizeof(input));
+    memset(&output,      0, sizeof(output));
+    memset(&output_info, 0, sizeof(output_info));
+
+    input.Buffer = data;
+    input.Length = 2 * avctx->channels * avctx->frame_size;
+    output.Buffer = frame;
+    output.Length = buf_size;
+
+    s->codec_api.SetInputData(s->handle, &input);
+    if (s->codec_api.GetOutputData(s->handle, &output, &output_info)
+        != VO_ERR_NONE) {
+        av_log(avctx, AV_LOG_ERROR, "Unable to encode frame\n");
+        return AVERROR_UNKNOWN;
+    }
+    return output.Length;
+}
+
+AVCodec ff_libvo_aacenc_encoder = {
+    "libvo_aacenc",
+    CODEC_TYPE_AUDIO,
+    CODEC_ID_AAC,
+    sizeof(AACContext),
+    aac_encode_init,
+    aac_encode_frame,
+    aac_encode_close,
+    NULL,
+    .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE},
+    .long_name = NULL_IF_CONFIG_SMALL("libvo-aacenc AAC"),
+};
+