From f5f98727b361c62d3962cef37a100db95d62b702 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 1 Aug 2012 14:33:34 +0000 Subject: [PATCH] libtwolame MP2 encoding support Signed-off-by: Paul B Mahol --- Changelog | 1 + configure | 5 + doc/general.texi | 9 ++ libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/libtwolame.c | 196 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 213 insertions(+) create mode 100644 libavcodec/libtwolame.c diff --git a/Changelog b/Changelog index 1837130d20..b7db8edde6 100644 --- a/Changelog +++ b/Changelog @@ -40,6 +40,7 @@ version next: - flite filter - Canopus Lossless Codec decoder - bitmap subtitles in filters (experimental and temporary) +- MP2 encoding via TwoLAME version 0.11: diff --git a/configure b/configure index befa1079c7..a092351b1a 100755 --- a/configure +++ b/configure @@ -202,6 +202,7 @@ External library support: --enable-libspeex enable Speex de/encoding via libspeex [no] --enable-libstagefright-h264 enable H.264 decoding via libstagefright [no] --enable-libtheora enable Theora encoding via libtheora [no] + --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libutvideo enable Ut Video encoding and decoding via libutvideo [no] --enable-libv4l2 enable libv4l2/v4l-utils [no] --enable-libvo-aacenc enable AAC encoding via libvo-aacenc [no] @@ -1101,6 +1102,7 @@ CONFIG_LIST=" libspeex libstagefright_h264 libtheora + libtwolame libutvideo libv4l2 libvo_aacenc @@ -1676,6 +1678,7 @@ libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" libstagefright_h264_decoder_deps="libstagefright_h264" libtheora_encoder_deps="libtheora" +libtwolame_encoder_deps="libtwolame" libvo_aacenc_encoder_deps="libvo_aacenc" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" libvorbis_decoder_deps="libvorbis" @@ -3440,6 +3443,7 @@ enabled libstagefright_h264 && require_cpp libstagefright_h264 "binder/ProcessS media/stagefright/MediaBufferGroup.h media/stagefright/MediaDebug.h media/stagefright/MediaDefs.h media/stagefright/OMXClient.h media/stagefright/OMXCodec.h" android::OMXClient -lstagefright -lmedia -lutils -lbinder -lgnustl_static enabled libtheora && require libtheora theora/theoraenc.h th_info_init -ltheoraenc -ltheoradec -logg +enabled libtwolame && require libtwolame twolame.h twolame_init -ltwolame enabled libutvideo && require_cpp utvideo "stdint.h stdlib.h utvideo/utvideo.h utvideo/Codec.h" 'CCodec*' -lutvideo -lstdc++ enabled libv4l2 && require_pkg_config libv4l2 libv4l2.h v4l2_ioctl enabled libvo_aacenc && require libvo_aacenc vo-aacenc/voAAC.h voGetAACEncAPI -lvo-aacenc @@ -3825,6 +3829,7 @@ echo "libschroedinger enabled ${libschroedinger-no}" echo "libspeex enabled ${libspeex-no}" echo "libstagefright-h264 enabled ${libstagefright_h264-no}" echo "libtheora enabled ${libtheora-no}" +echo "libtwolame enabled ${libtwolame-no}" echo "libutvideo enabled ${libutvideo-no}" echo "libv4l2 enabled ${libv4l2-no}" echo "libvo-aacenc support ${libvo_aacenc-no}" diff --git a/doc/general.texi b/doc/general.texi index d7369ec611..2773f1a334 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -79,6 +79,14 @@ Go to @url{http://lame.sourceforge.net/} and follow the instructions for installing the library. Then pass @code{--enable-libmp3lame} to configure to enable it. +@section TwoLAME + +FFmpeg can make use of the TwoLAME library for MP2 encoding. + +Go to @url{http://www.twolame.org/} and follow the +instructions for installing the library. +Then pass @code{--enable-libtwolame} to configure to enable it. + @section libvpx FFmpeg can make use of the libvpx library for VP8 encoding. @@ -797,6 +805,7 @@ following image formats are supported: @tab Only versions 3.97-3.99 are supported. @item MP1 (MPEG audio layer 1) @tab @tab IX @item MP2 (MPEG audio layer 2) @tab IX @tab IX + @tab libtwolame can be used alternatively for encoding. @item MP3 (MPEG audio layer 3) @tab E @tab IX @tab encoding supported through external library LAME, ADU MP3 and MP3onMP4 also supported @item MPEG-4 Audio Lossless Coding (ALS) @tab @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 9241c522f2..1cd44d42d7 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -697,6 +697,7 @@ OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o audio_frame_queue.o OBJS-$(CONFIG_LIBSTAGEFRIGHT_H264_DECODER)+= libstagefright.o OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o +OBJS-$(CONFIG_LIBTWOLAME_ENCODER) += libtwolame.o OBJS-$(CONFIG_LIBUTVIDEO_DECODER) += libutvideodec.o OBJS-$(CONFIG_LIBUTVIDEO_ENCODER) += libutvideoenc.o OBJS-$(CONFIG_LIBVO_AACENC_ENCODER) += libvo-aacenc.o mpeg4audio.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index c4c2587ea9..8305bc278e 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -434,6 +434,7 @@ void avcodec_register_all(void) REGISTER_ENCDEC (LIBSPEEX, libspeex); REGISTER_DECODER (LIBSTAGEFRIGHT_H264, libstagefright_h264); REGISTER_ENCODER (LIBTHEORA, libtheora); + REGISTER_ENCODER (LIBTWOLAME, libtwolame); REGISTER_ENCDEC (LIBUTVIDEO, libutvideo); REGISTER_ENCODER (LIBVO_AACENC, libvo_aacenc); REGISTER_ENCODER (LIBVO_AMRWBENC, libvo_amrwbenc); diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c new file mode 100644 index 0000000000..72344510fa --- /dev/null +++ b/libavcodec/libtwolame.c @@ -0,0 +1,196 @@ +/* + * Interface to libtwolame for mp2 encoding + * Copyright (c) 2012 Paul B Mahol + * + * 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 libtwolame for mp2 encoding. + */ + +#include + +#include "libavutil/opt.h" +#include "avcodec.h" +#include "internal.h" +#include "mpegaudio.h" + +typedef struct TWOLAMEContext { + AVClass *class; + int mode; + int psymodel; + int energy; + int error_protection; + int copyright; + int original; + + twolame_options *glopts; + int64_t next_pts; +} TWOLAMEContext; + +static av_cold int twolame_encode_close(AVCodecContext *avctx) +{ + TWOLAMEContext *s = avctx->priv_data; + twolame_close(&s->glopts); + return 0; +} + +static av_cold int twolame_encode_init(AVCodecContext *avctx) +{ + TWOLAMEContext *s = avctx->priv_data; + int ret; + + avctx->frame_size = TWOLAME_SAMPLES_PER_FRAME; + + s->glopts = twolame_init(); + if (!s->glopts) + return AVERROR(ENOMEM); + + twolame_set_verbosity(s->glopts, 0); + twolame_set_mode(s->glopts, s->mode); + twolame_set_psymodel(s->glopts, s->psymodel); + twolame_set_energy_levels(s->glopts, s->energy); + twolame_set_error_protection(s->glopts, s->error_protection); + + twolame_set_num_channels(s->glopts, avctx->channels); + twolame_set_in_samplerate(s->glopts, avctx->sample_rate); + twolame_set_out_samplerate(s->glopts, avctx->sample_rate); + if (avctx->flags & CODEC_FLAG_QSCALE || !avctx->bit_rate) { + twolame_set_VBR(s->glopts, TRUE); + twolame_set_VBR_level(s->glopts, avctx->global_quality); + av_log(avctx, AV_LOG_WARNING, "VBR mode is experimental!\n"); + } else { + twolame_set_bitrate(s->glopts, avctx->bit_rate / 1000); + } + + if ((ret = twolame_init_params(s->glopts))) + goto error; + + return 0; +error: + twolame_encode_close(avctx); + return ret; +} + +static int twolame_encode_frame(AVCodecContext *avctx, AVPacket *avpkt, + const AVFrame *frame, int *got_packet_ptr) +{ + TWOLAMEContext *s = avctx->priv_data; + int ret; + + if ((ret = ff_alloc_packet2(avctx, avpkt, MPA_MAX_CODED_FRAME_SIZE))) + return ret; + + if (frame) { + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_FLT: + ret = twolame_encode_buffer_float32_interleaved(s->glopts, + frame->data[0], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + case AV_SAMPLE_FMT_FLTP: + ret = twolame_encode_buffer_float32(s->glopts, + frame->data[0], frame->data[1], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + case AV_SAMPLE_FMT_S16: + ret = twolame_encode_buffer_interleaved(s->glopts, + frame->data[0], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + case AV_SAMPLE_FMT_S16P: + ret = twolame_encode_buffer(s->glopts, + frame->data[0], frame->data[1], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + default: + return AVERROR_BUG; + } + } else { + ret = twolame_encode_flush(s->glopts, avpkt->data, avpkt->size); + } + + if (ret > 0) { + avpkt->duration = ff_samples_to_time_base(avctx, avctx->frame_size); + if (frame) { + if (frame->pts != AV_NOPTS_VALUE) + avpkt->pts = frame->pts; + } else { + avpkt->pts = s->next_pts; + } + if (avpkt->pts != AV_NOPTS_VALUE) + s->next_pts = avpkt->pts + avpkt->duration; + + avpkt->size = ret; + *got_packet_ptr = 1; + return 0; + } + + return ret; +} + +#define OFFSET(x) offsetof(TWOLAMEContext, x) +#define AE AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM +static const AVOption options[] = { + { "mode", "Mpeg Mode", OFFSET(mode), AV_OPT_TYPE_INT, { TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"}, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" }, + { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { TWOLAME_STEREO }, 0, 0, AE, "mode" }, + { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" }, + { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" }, + { "mono", NULL, 0, AV_OPT_TYPE_CONST, { TWOLAME_MONO }, 0, 0, AE, "mode" }, + { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { 3 }, -1, 4, AE}, + { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { 0 }, 0, 1, AE}, + { "error_protection","enable CRC error protection", OFFSET(error_protection), AV_OPT_TYPE_INT, { 0 }, 0, 1, AE}, + { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { 0 }, 0, 1, AE}, + { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { 0 }, 0, 1, AE}, + { NULL }, +}; + +static const AVClass libtwolame_class = { + .class_name = "libtwolame encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +AVCodec ff_libtwolame_encoder = { + .name = "libtwolame", + .type = AVMEDIA_TYPE_AUDIO, + .id = CODEC_ID_MP3, + .priv_data_size = sizeof(TWOLAMEContext), + .init = twolame_encode_init, + .encode2 = twolame_encode_frame, + .close = twolame_encode_close, + .capabilities = CODEC_CAP_DELAY, + .sample_fmts = (const enum AVSampleFormat[]) { AV_SAMPLE_FMT_FLT, + AV_SAMPLE_FMT_FLTP, + AV_SAMPLE_FMT_S16, + AV_SAMPLE_FMT_S16P, + AV_SAMPLE_FMT_NONE }, + .channel_layouts = (const uint64_t[]) { AV_CH_LAYOUT_MONO, + AV_CH_LAYOUT_STEREO, + 0 }, + .supported_samplerates = (const int[]){ 16000, 22050, 24000, 32000, 44100, 48000, 0 }, + .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"), + .priv_class = &libtwolame_class, +};