From 718907cd881a0b593264aed059c0e00da13f9e15 Mon Sep 17 00:00:00 2001 From: Paul B Mahol Date: Wed, 1 Aug 2012 16:33:34 +0000 Subject: [PATCH] libtwolame MP2 encoding support Signed-off-by: Vittorio Giovara --- Changelog | 1 + configure | 4 + doc/general.texi | 11 +- libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/libtwolame.c | 226 ++++++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 4 +- 7 files changed, 245 insertions(+), 3 deletions(-) create mode 100644 libavcodec/libtwolame.c diff --git a/Changelog b/Changelog index b3ab301179..53805659bc 100644 --- a/Changelog +++ b/Changelog @@ -17,6 +17,7 @@ version : - LucasArts SMUSH SANM video decoder - LucasArts SMUSH VIMA audio decoder (ADPCM) - LucasArts SMUSH demuxer +- MP2 encoding via TwoLAME version 10: diff --git a/configure b/configure index 4d005f1bbc..3c49d9c8b6 100755 --- a/configure +++ b/configure @@ -197,6 +197,7 @@ External library support: --enable-libschroedinger enable Dirac de/encoding via libschroedinger [no] --enable-libspeex enable Speex de/encoding via libspeex [no] --enable-libtheora enable Theora encoding via libtheora [no] + --enable-libtwolame enable MP2 encoding via libtwolame [no] --enable-libvo-aacenc enable AAC encoding via libvo-aacenc [no] --enable-libvo-amrwbenc enable AMR-WB encoding via libvo-amrwbenc [no] --enable-libvorbis enable Vorbis encoding via libvorbis [no] @@ -1141,6 +1142,7 @@ EXTERNAL_LIBRARY_LIST=" libschroedinger libspeex libtheora + libtwolame libvo_aacenc libvo_amrwbenc libvorbis @@ -1947,6 +1949,7 @@ libspeex_decoder_deps="libspeex" libspeex_encoder_deps="libspeex" libspeex_encoder_select="audio_frame_queue" libtheora_encoder_deps="libtheora" +libtwolame_encoder_deps="libtwolame" libvo_aacenc_encoder_deps="libvo_aacenc" libvo_aacenc_encoder_select="audio_frame_queue" libvo_amrwbenc_encoder_deps="libvo_amrwbenc" @@ -4038,6 +4041,7 @@ enabled librtmp && require_pkg_config librtmp librtmp/rtmp.h RTMP_Sock 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 libtwolame && require libtwolame twolame.h twolame_init -ltwolame enabled libvo_aacenc && require libvo_aacenc vo-aacenc/voAAC.h voGetAACEncAPI -lvo-aacenc enabled libvo_amrwbenc && require libvo_amrwbenc vo-amrwbenc/enc_if.h E_IF_init -lvo-amrwbenc enabled libvorbis && require libvorbis vorbis/vorbisenc.h vorbis_info_init -lvorbisenc -lvorbis -logg diff --git a/doc/general.texi b/doc/general.texi index f1287cf8d9..2612eb140e 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -71,6 +71,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 + +Libav 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 Libav can make use of the libvpx library for VP8 encoding. @@ -834,7 +842,8 @@ following image formats are supported: @item Monkey's Audio @tab @tab X @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 +@item MP2 (MPEG audio layer 2) @tab IE @tab IX + @tab encoding supported also through external library TwoLAME @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 42819fdabf..5bd9778f0f 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -603,6 +603,7 @@ OBJS-$(CONFIG_LIBSCHROEDINGER_ENCODER) += libschroedingerenc.o \ OBJS-$(CONFIG_LIBSPEEX_DECODER) += libspeexdec.o OBJS-$(CONFIG_LIBSPEEX_ENCODER) += libspeexenc.o OBJS-$(CONFIG_LIBTHEORA_ENCODER) += libtheoraenc.o +OBJS-$(CONFIG_LIBTWOLAME_ENCODER) += libtwolame.o OBJS-$(CONFIG_LIBVO_AACENC_ENCODER) += libvo-aacenc.o mpeg4audio.o OBJS-$(CONFIG_LIBVO_AMRWBENC_ENCODER) += libvo-amrwbenc.o OBJS-$(CONFIG_LIBVORBIS_ENCODER) += libvorbis.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b734db3dc8..47bbef56df 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -236,6 +236,7 @@ void avcodec_register_all(void) REGISTER_DECODER(SVQ3, svq3); REGISTER_ENCDEC (TARGA, targa); REGISTER_DECODER(THEORA, theora); + REGISTER_ENCODER(LIBTWOLAME, libtwolame); REGISTER_DECODER(THP, thp); REGISTER_DECODER(TIERTEXSEQVIDEO, tiertexseqvideo); REGISTER_ENCDEC (TIFF, tiff); diff --git a/libavcodec/libtwolame.c b/libavcodec/libtwolame.c new file mode 100644 index 0000000000..d8d73b3bcc --- /dev/null +++ b/libavcodec/libtwolame.c @@ -0,0 +1,226 @@ +/* + * Interface to libtwolame for mp2 encoding + * Copyright (c) 2012 Paul B Mahol + * + * 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 + */ + +/** + * @file + * Interface to libtwolame for mp2 encoding. + */ + +#include + +#include "libavutil/common.h" +#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; + int verbosity; + + 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; + avctx->delay = 512 - 32 + 1; + + s->glopts = twolame_init(); + if (!s->glopts) + return AVERROR(ENOMEM); + + twolame_set_verbosity(s->glopts, s->verbosity); + 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_copyright(s->glopts, s->copyright); + twolame_set_original(s->glopts, s->original); + + 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 / (float) FF_QP2LAMBDA); + av_log(avctx, AV_LOG_WARNING, + "VBR in MP2 is a hack, use another codec that supports it.\n"); + } else { + twolame_set_bitrate(s->glopts, avctx->bit_rate / 1000); + } + + ret = twolame_init_params(s->glopts); + if (ret) { + twolame_encode_close(avctx); + return AVERROR_UNKNOWN; + } + + return 0; +} + +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_packet(avpkt, MPA_MAX_CODED_FRAME_SIZE)) < 0) + return ret; + + if (frame) { + switch (avctx->sample_fmt) { + case AV_SAMPLE_FMT_FLT: + ret = twolame_encode_buffer_float32_interleaved(s->glopts, + (const float *)frame->data[0], + frame->nb_samples, + avpkt->data, + avpkt->size); + break; + case AV_SAMPLE_FMT_FLTP: + ret = twolame_encode_buffer_float32(s->glopts, + (const float *)frame->data[0], + (const float *)frame->data[1], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + case AV_SAMPLE_FMT_S16: + ret = twolame_encode_buffer_interleaved(s->glopts, + (const short int *)frame->data[0], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + case AV_SAMPLE_FMT_S16P: + ret = twolame_encode_buffer(s->glopts, + (const short int *)frame->data[0], + (const short int *)frame->data[1], + frame->nb_samples, + avpkt->data, avpkt->size); + break; + default: + av_log(avctx, AV_LOG_ERROR, + "Unsupported sample format %d.\n", avctx->sample_fmt); + return AVERROR_BUG; + } + } else { + ret = twolame_encode_flush(s->glopts, avpkt->data, avpkt->size); + } + + if (!ret) // no bytes written + return 0; + if (ret < 0) // twolame error + return AVERROR_UNKNOWN; + + avpkt->duration = ff_samples_to_time_base(avctx, frame->nb_samples); + if (frame) { + if (frame->pts != AV_NOPTS_VALUE) + avpkt->pts = frame->pts - ff_samples_to_time_base(avctx, avctx->delay); + } else { + avpkt->pts = s->next_pts; + } + // this is for setting pts for flushed packet(s). + if (avpkt->pts != AV_NOPTS_VALUE) + s->next_pts = avpkt->pts + avpkt->duration; + + av_shrink_packet(avpkt, ret); + *got_packet_ptr = 1; + return 0; +} + +#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, { .i64 = TWOLAME_AUTO_MODE }, TWOLAME_AUTO_MODE, TWOLAME_MONO, AE, "mode"}, + { "auto", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_AUTO_MODE }, 0, 0, AE, "mode" }, + { "stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_STEREO }, 0, 0, AE, "mode" }, + { "joint_stereo", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_JOINT_STEREO }, 0, 0, AE, "mode" }, + { "dual_channel", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_DUAL_CHANNEL }, 0, 0, AE, "mode" }, + { "mono", NULL, 0, AV_OPT_TYPE_CONST, { .i64 = TWOLAME_MONO }, 0, 0, AE, "mode" }, + { "psymodel", "Psychoacoustic Model", OFFSET(psymodel), AV_OPT_TYPE_INT, { .i64 = 3 }, -1, 4, AE}, + { "energy_levels","enable energy levels", OFFSET(energy), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "error_protection","enable CRC error protection", OFFSET(error_protection), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "copyright", "set MPEG Audio Copyright flag", OFFSET(copyright), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "original", "set MPEG Audio Original flag", OFFSET(original), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 1, AE}, + { "verbosity", "set library optput level (0-10)", OFFSET(verbosity), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 10, AE}, + { NULL }, +}; + +static const AVClass twolame_class = { + .class_name = "libtwolame encoder", + .item_name = av_default_item_name, + .option = options, + .version = LIBAVUTIL_VERSION_INT, +}; + +static const AVCodecDefault twolame_defaults[] = { + { "b", "384000" }, + { "ar", "48000" }, + { NULL }, +}; + +static const int twolame_samplerates[] = { + 16000, 22050, 24000, 32000, 44100, 48000, 0 +}; + +AVCodec ff_libtwolame_encoder = { + .name = "libtwolame", + .long_name = NULL_IF_CONFIG_SMALL("libtwolame MP2 (MPEG audio layer 2)"), + .type = AVMEDIA_TYPE_AUDIO, + .id = AV_CODEC_ID_MP2, + .priv_data_size = sizeof(TWOLAMEContext), + .init = twolame_encode_init, + .encode2 = twolame_encode_frame, + .close = twolame_encode_close, + .capabilities = CODEC_CAP_DELAY, + .defaults = twolame_defaults, + .priv_class = &twolame_class, + .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 = twolame_samplerates, +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index a92213e669..4a8febc536 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -29,8 +29,8 @@ #include "libavutil/version.h" #define LIBAVCODEC_VERSION_MAJOR 55 -#define LIBAVCODEC_VERSION_MINOR 45 -#define LIBAVCODEC_VERSION_MICRO 2 +#define LIBAVCODEC_VERSION_MINOR 46 +#define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ LIBAVCODEC_VERSION_MINOR, \