From: Gildas Bazin Date: Thu, 29 Jul 2004 18:15:38 +0000 (+0000) Subject: * modules/codec/toolame.c: MPEG-1/2 layer II audio encoder using libtoolame (http... X-Git-Tag: 0.8.0~796 X-Git-Url: https://git.sesse.net/?a=commitdiff_plain;h=bb8c0315c2271eceb6f8f6f467b3b2a013a0b5d3;p=vlc * modules/codec/toolame.c: MPEG-1/2 layer II audio encoder using libtoolame (http://users.tpg.com.au/adslblvi/). Patch from Christophe Massiot. --- diff --git a/configure.ac b/configure.ac index 295aa95b20..e7f9947b6b 100644 --- a/configure.ac +++ b/configure.ac @@ -441,7 +441,7 @@ AC_CHECK_LIB(m,cos,[ VLC_ADD_LDFLAGS([adjust distort a52tofloat32 dtstofloat32],[-lm]) ]) AC_CHECK_LIB(m,pow,[ - VLC_ADD_LDFLAGS([ffmpeg stream_out_transcode stream_out_transrate i420_rgb faad equalizer vlc],[-lm]) + VLC_ADD_LDFLAGS([ffmpeg stream_out_transcode stream_out_transrate i420_rgb faad toolame equalizer vlc],[-lm]) ]) AC_CHECK_LIB(m,sqrt,[ VLC_ADD_LDFLAGS([headphone_channel_mixer normvol],[-lm]) @@ -1959,6 +1959,50 @@ then fi fi +dnl +dnl toolame encoder plugin +dnl +AC_ARG_ENABLE(toolame, +[ --enable-toolame toolame codec (default disabled)]) +if test "${enable_toolame}" = "yes" +then + AC_ARG_WITH(toolame-tree, + [ --with-toolame-tree=PATH toolame tree for static linking]) + if test -n "${with_toolame_tree}" + then + AC_MSG_CHECKING(for libtoolame.a in ${with_toolame_tree}) + real_toolame_tree="`cd ${with_toolame_tree} 2>/dev/null && pwd`" + if test -z "${real_toolame_tree}" + then + dnl The given directory can't be found + AC_MSG_RESULT(no) + AC_MSG_ERROR([cannot cd to ${with_toolame_tree}]) + fi + if test -f "${real_toolame_tree}/libtoolame/libtoolame.a" + then + dnl Use a custom toolame + AC_MSG_RESULT(${real_toolame_tree}/libtoolame/libtoolame.a) + VLC_ADD_BUILTINS([toolame]) + VLC_ADD_LDFLAGS([toolame],[${real_faad_tree}/libtoolame/libtoolame.a]) + VLC_ADD_CPPFLAGS([toolame],[-I${real_toolame_tree}/libtoolame]) + else + dnl The given libtoolame wasn't built + AC_MSG_RESULT(no) + AC_MSG_ERROR([cannot find ${real_toolame_tree}/libtoolame/libtoolame.a, make sure you compiled libtoolame in ${with_toolame_tree}]) + fi + else + CPPFLAGS="${CPPFLAGS_save} ${CPPFLAGS_toolame}" + LDFLAGS="${LDFLAGS_save} ${LDFLAGS_toolame}" + AC_CHECK_HEADERS(toolame.h, , + [ AC_MSG_ERROR([Cannot find development header for libtoolame...]) ]) + AC_CHECK_LIB(toolame, toolame_init, [ + VLC_ADD_PLUGINS([toolame]) + VLC_ADD_LDFLAGS([toolame],[-ltoolame]) ], + [ AC_MSG_ERROR([Cannot find libtoolame library...]) ]) + LDFLAGS="${LDFLAGS_save}" + CPPFLAGS="${CPPFLAGS_save}" + fi +fi dnl dnl dnl dnl xvid decoder plugin diff --git a/modules/codec/Modules.am b/modules/codec/Modules.am index 27eb7485a0..8a220689e6 100644 --- a/modules/codec/Modules.am +++ b/modules/codec/Modules.am @@ -22,3 +22,4 @@ SOURCES_faad = faad.c SOURCES_dvbsub = dvbsub.c SOURCES_mash = mash.cpp SOURCES_x264 = x264.c +SOURCES_toolame = toolame.c diff --git a/modules/codec/toolame.c b/modules/codec/toolame.c new file mode 100644 index 0000000000..ece228354e --- /dev/null +++ b/modules/codec/toolame.c @@ -0,0 +1,264 @@ +/***************************************************************************** + * toolame.c: libtoolame encoder (MPEG-1/2 layer II) module + * (using libtoolame from http://users.tpg.com.au/adslblvi/) + ***************************************************************************** + * Copyright (C) 2004 VideoLAN + * $Id$ + * + * Authors: Christophe Massiot + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. + *****************************************************************************/ + +/***************************************************************************** + * Preamble + *****************************************************************************/ +#include +#include +#include +#include + +#include + +#define MPEG_FRAME_SIZE 1152 +#define MAX_CODED_FRAME_SIZE 1792 + +/**************************************************************************** + * Local prototypes + ****************************************************************************/ +static int OpenEncoder ( vlc_object_t * ); +static void CloseEncoder ( vlc_object_t * ); +static block_t *Encode ( encoder_t *, aout_buffer_t * ); + +/***************************************************************************** + * Module descriptor + *****************************************************************************/ +#define ENC_CFG_PREFIX "sout-toolame-" + +#define ENC_QUALITY_TEXT N_("Encoding quality") +#define ENC_QUALITY_LONGTEXT N_( \ + "Allows you to specify a quality between 0.0 (high) and 50.0 (low), " \ + "instead of specifying a particular bitrate. " \ + "This will produce a VBR stream." ) +#define ENC_MODE_TEXT N_("Stereo mode") +#define ENC_MODE_LONGTEXT N_( \ + "[0=stereo, 1=dual-mono, 2=joint-stereo]" ) +#define ENC_VBR_TEXT N_("VBR mode") +#define ENC_VBR_LONGTEXT N_( \ + "By default the encoding is CBR." ) + +vlc_module_begin(); + set_description( _("libtoolame audio encoder") ); + set_capability( "encoder", 200 ); + set_callbacks( OpenEncoder, CloseEncoder ); + + add_float( ENC_CFG_PREFIX "quality", 0.0, NULL, ENC_QUALITY_TEXT, + ENC_QUALITY_LONGTEXT, VLC_FALSE ); + add_integer( ENC_CFG_PREFIX "mode", 0, NULL, ENC_MODE_TEXT, + ENC_MODE_LONGTEXT, VLC_FALSE ); + add_bool( ENC_CFG_PREFIX "vbr", 0, NULL, ENC_VBR_TEXT, + ENC_VBR_LONGTEXT, VLC_FALSE ); +vlc_module_end(); + +static const char *ppsz_enc_options[] = { + "quality", "mode", "vbr", NULL +}; + +/***************************************************************************** + * encoder_sys_t : toolame encoder descriptor + *****************************************************************************/ +struct encoder_sys_t +{ + /* + * Input properties + */ + int16_t p_left[MPEG_FRAME_SIZE]; + int16_t p_right[MPEG_FRAME_SIZE]; + int i_nb_samples; + audio_date_t pts; + + /* + * libtoolame properties + */ + toolame_options *p_toolame; + unsigned char p_out_buffer[MAX_CODED_FRAME_SIZE]; +}; + +/***************************************************************************** + * OpenEncoder: probe the encoder and return score + *****************************************************************************/ +static int OpenEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys; + vlc_value_t val; + + if ( (p_enc->fmt_out.i_codec != VLC_FOURCC('m','p','g','a') && + !p_enc->b_force) + || p_enc->fmt_in.audio.i_channels > 2 ) + { + return VLC_EGENERIC; + } + + /* Allocate the memory needed to store the decoder's structure */ + if( ( p_sys = (encoder_sys_t *)malloc(sizeof(encoder_sys_t)) ) == NULL ) + { + msg_Err( p_enc, "out of memory" ); + return VLC_EGENERIC; + } + p_enc->p_sys = p_sys; + + p_enc->pf_header = NULL; + p_enc->pf_encode_audio = Encode; + p_enc->fmt_in.i_codec = AOUT_FMT_S16_NE; + p_enc->fmt_out.i_codec = VLC_FOURCC('m','p','g','a'); + + sout_ParseCfg( p_enc, ENC_CFG_PREFIX, ppsz_enc_options, p_enc->p_cfg ); + + p_sys->p_toolame = toolame_init(); + + /* Set options */ + toolame_setSampleFreq( p_sys->p_toolame, p_enc->fmt_out.audio.i_rate ); + + var_Get( p_enc, ENC_CFG_PREFIX "vbr", &val ); + if ( val.b_bool ) + { + FLOAT i_quality; + var_Get( p_enc, ENC_CFG_PREFIX "quality", &val ); + i_quality = val.i_int; + if ( i_quality > 50.0 ) i_quality = 50.0; + if ( i_quality < 0.0 ) i_quality = 0.0; + toolame_setVBR( p_sys->p_toolame, 1 ); + toolame_setVBRLevel( p_sys->p_toolame, i_quality ); + } + else + { + toolame_setBitrate( p_sys->p_toolame, p_enc->fmt_out.i_bitrate / 1000 ); + } + + if ( p_enc->fmt_in.audio.i_channels == 1 ) + { + toolame_setMode( p_sys->p_toolame, MPG_MD_MONO ); + } + else + { + var_Get( p_enc, ENC_CFG_PREFIX "mode", &val ); + switch ( val.i_int ) + { + case 1: + toolame_setMode( p_sys->p_toolame, MPG_MD_DUAL_CHANNEL ); + break; + case 2: + toolame_setMode( p_sys->p_toolame, MPG_MD_JOINT_STEREO ); + break; + case 0: + default: + toolame_setMode( p_sys->p_toolame, MPG_MD_STEREO ); + break; + } + } + + if ( toolame_init_params( p_sys->p_toolame ) ) + { + msg_Err( p_enc, "toolame initialization failed" ); + return -VLC_EGENERIC; + } + + p_sys->i_nb_samples = 0; + aout_DateInit( &p_sys->pts, p_enc->fmt_out.audio.i_rate ); + + return VLC_SUCCESS; +} + +/**************************************************************************** + * Encode: the whole thing + **************************************************************************** + * This function spits out MPEG packets. + ****************************************************************************/ +static void Uninterleave( encoder_t *p_enc, int16_t *p_in, int i_nb_samples ) +{ + int16_t *p_left = p_enc->p_sys->p_left + p_enc->p_sys->i_nb_samples; + int16_t *p_right = p_enc->p_sys->p_right + p_enc->p_sys->i_nb_samples; + + while ( i_nb_samples > 0 ) + { + *p_left++ = *p_in++; + *p_right++ = *p_in++; + i_nb_samples--; + } +} + +static block_t *Encode( encoder_t *p_enc, aout_buffer_t *p_aout_buf ) +{ + encoder_sys_t *p_sys = p_enc->p_sys; + int16_t *p_buffer = (int16_t *)p_aout_buf->p_buffer; + int i_nb_samples = p_aout_buf->i_nb_samples; + block_t *p_chain = NULL; + mtime_t i_computed_pts = p_aout_buf->start_date - + (mtime_t)1000000 * (mtime_t)p_sys->i_nb_samples / + (mtime_t)p_enc->fmt_in.audio.i_rate; + + if ( aout_DateGet( &p_sys->pts ) - i_computed_pts > 10000 || + aout_DateGet( &p_sys->pts ) - i_computed_pts < -10000 ) + { + msg_Dbg( p_enc, "resetting audio date" ); + aout_DateSet( &p_sys->pts, i_computed_pts ); + } + + while ( p_sys->i_nb_samples + i_nb_samples >= MPEG_FRAME_SIZE ) + { + int i_used; + block_t *p_block; + + Uninterleave( p_enc, p_buffer, MPEG_FRAME_SIZE - p_sys->i_nb_samples ); + i_nb_samples -= MPEG_FRAME_SIZE - p_sys->i_nb_samples; + p_buffer += (MPEG_FRAME_SIZE - p_sys->i_nb_samples) * 2; + + toolame_encode_buffer( p_sys->p_toolame, p_sys->p_left, + p_sys->p_right, MPEG_FRAME_SIZE, + p_sys->p_out_buffer, MAX_CODED_FRAME_SIZE, + &i_used ); + p_sys->i_nb_samples = 0; + p_block = block_New( p_enc, i_used ); + p_enc->p_vlc->pf_memcpy( p_block->p_buffer, p_sys->p_out_buffer, + i_used ); + p_block->i_length = (mtime_t)1000000 * + (mtime_t)MPEG_FRAME_SIZE / (mtime_t)p_enc->fmt_in.audio.i_rate; + p_block->i_dts = p_block->i_pts = aout_DateGet( &p_sys->pts ); + aout_DateIncrement( &p_sys->pts, MPEG_FRAME_SIZE ); + block_ChainAppend( &p_chain, p_block ); + } + + if ( i_nb_samples ) + { + Uninterleave( p_enc, p_buffer, i_nb_samples ); + p_sys->i_nb_samples += i_nb_samples; + } + + return p_chain; +} + +/***************************************************************************** + * CloseEncoder: toolame encoder destruction + *****************************************************************************/ +static void CloseEncoder( vlc_object_t *p_this ) +{ + encoder_t *p_enc = (encoder_t *)p_this; + encoder_sys_t *p_sys = p_enc->p_sys; + + toolame_deinit( p_sys->p_toolame ); + + free( p_sys ); +}