2006-09-10 17:02:42 +03:00
/*
* copyright ( c ) 2002 Mark Hills < mark @ pogo . org . uk >
*
2006-10-07 18:30:46 +03:00
* This file is part of FFmpeg .
*
* FFmpeg is free software ; you can redistribute it and / or
2006-09-10 17:02:42 +03:00
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation ; either
2006-10-07 18:30:46 +03:00
* version 2.1 of the License , or ( at your option ) any later version .
2006-09-10 17:02:42 +03:00
*
2006-10-07 18:30:46 +03:00
* FFmpeg is distributed in the hope that it will be useful ,
2006-09-10 17:02:42 +03:00
* 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
2006-10-07 18:30:46 +03:00
* License along with FFmpeg ; if not , write to the Free Software
2007-07-05 13:40:25 +03:00
* Foundation , Inc . , 51 Franklin Street , Fifth Floor , Boston , MA 02110 - 1301 USA
2006-09-10 17:02:42 +03:00
*/
2003-03-06 13:32:04 +02:00
/**
2010-04-20 17:45:34 +03:00
* @ file
2003-03-06 13:32:04 +02:00
* Ogg Vorbis codec support via libvorbisenc .
* @ author Mark Hills < mark @ pogo . org . uk >
2002-09-01 21:07:56 +03:00
*/
# include <vorbis/vorbisenc.h>
2010-09-29 18:09:38 +03:00
# include "libavutil/opt.h"
2002-09-01 21:07:56 +03:00
# include "avcodec.h"
2007-06-02 04:41:07 +03:00
# include "bytestream.h"
2010-06-27 12:25:05 +03:00
# include "vorbis.h"
2011-07-04 09:44:49 +03:00
# include "libavutil/mathematics.h"
2002-09-01 21:07:56 +03:00
2004-04-04 20:06:30 +03:00
# undef NDEBUG
# include <assert.h>
2004-04-04 17:39:20 +03:00
# define OGGVORBIS_FRAME_SIZE 64
2002-09-01 21:07:56 +03:00
2004-04-04 17:39:20 +03:00
# define BUFFER_SIZE (1024*64)
2002-09-01 21:07:56 +03:00
typedef struct OggVorbisContext {
2010-09-29 18:09:38 +03:00
AVClass * av_class ;
2002-09-01 21:07:56 +03:00
vorbis_info vi ;
vorbis_dsp_state vd ;
vorbis_block vb ;
2004-04-04 17:39:20 +03:00
uint8_t buffer [ BUFFER_SIZE ] ;
int buffer_index ;
2008-10-15 10:29:37 +03:00
int eof ;
2002-11-22 09:27:13 +02:00
/* decoder */
vorbis_comment vc ;
2004-04-04 05:07:15 +03:00
ogg_packet op ;
2010-09-29 18:09:38 +03:00
double iblock ;
2002-09-01 21:07:56 +03:00
} OggVorbisContext ;
2010-09-29 18:09:38 +03:00
static const AVOption options [ ] = {
2011-05-01 01:21:56 +03:00
{ " iblock " , " Sets the impulse block bias " , offsetof ( OggVorbisContext , iblock ) , FF_OPT_TYPE_DOUBLE , { . dbl = 0 } , - 15 , 0 , AV_OPT_FLAG_AUDIO_PARAM | AV_OPT_FLAG_ENCODING_PARAM } ,
2010-09-29 18:09:38 +03:00
{ NULL }
} ;
2010-10-14 10:47:49 +03:00
static const AVClass class = { " libvorbis " , av_default_item_name , options , LIBAVUTIL_VERSION_INT } ;
2002-09-01 21:07:56 +03:00
2009-02-22 15:48:55 +02:00
static av_cold int oggvorbis_init_encoder ( vorbis_info * vi , AVCodecContext * avccontext ) {
2010-09-29 18:09:38 +03:00
OggVorbisContext * context = avccontext - > priv_data ;
2006-01-21 19:09:23 +02:00
double cfreq ;
2002-12-21 17:54:21 +02:00
2005-09-02 14:08:49 +03:00
if ( avccontext - > flags & CODEC_FLAG_QSCALE ) {
2006-01-21 19:09:23 +02:00
/* variable bitrate */
if ( vorbis_encode_setup_vbr ( vi , avccontext - > channels ,
2005-09-02 14:08:49 +03:00
avccontext - > sample_rate ,
2009-02-10 00:11:28 +02:00
avccontext - > global_quality / ( float ) FF_QP2LAMBDA / 10.0 ) )
2006-01-21 19:09:23 +02:00
return - 1 ;
} else {
2010-06-05 01:40:31 +03:00
int minrate = avccontext - > rc_min_rate > 0 ? avccontext - > rc_min_rate : - 1 ;
int maxrate = avccontext - > rc_min_rate > 0 ? avccontext - > rc_max_rate : - 1 ;
2006-01-21 19:09:23 +02:00
/* constant bitrate */
if ( vorbis_encode_setup_managed ( vi , avccontext - > channels ,
2010-06-05 01:40:31 +03:00
avccontext - > sample_rate , minrate , avccontext - > bit_rate , maxrate ) )
2006-01-21 19:09:23 +02:00
return - 1 ;
2010-06-05 01:40:40 +03:00
/* variable bitrate by estimate, disable slow rate management */
if ( minrate = = - 1 & & maxrate = = - 1 )
if ( vorbis_encode_ctl ( vi , OV_ECTL_RATEMANAGE2_SET , NULL ) )
return - 1 ;
2006-01-21 19:09:23 +02:00
}
2002-12-21 17:54:21 +02:00
2006-01-21 19:09:23 +02:00
/* cutoff frequency */
if ( avccontext - > cutoff > 0 ) {
cfreq = avccontext - > cutoff / 1000.0 ;
if ( vorbis_encode_ctl ( vi , OV_ECTL_LOWPASS_SET , & cfreq ) )
return - 1 ;
}
2002-09-01 21:07:56 +03:00
2010-09-29 18:09:38 +03:00
if ( context - > iblock ) {
vorbis_encode_ctl ( vi , OV_ECTL_IBLOCK_SET , & context - > iblock ) ;
}
2011-04-15 12:48:03 +03:00
if ( avccontext - > channels = = 3 & &
avccontext - > channel_layout ! = ( AV_CH_LAYOUT_STEREO | AV_CH_FRONT_CENTER ) | |
avccontext - > channels = = 4 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_2_2 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_QUAD | |
avccontext - > channels = = 5 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_5POINT0 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_5POINT0_BACK | |
avccontext - > channels = = 6 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_5POINT1 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_5POINT1_BACK | |
avccontext - > channels = = 7 & &
avccontext - > channel_layout ! = ( AV_CH_LAYOUT_5POINT1 | AV_CH_BACK_CENTER ) | |
avccontext - > channels = = 8 & &
avccontext - > channel_layout ! = AV_CH_LAYOUT_7POINT1 ) {
if ( avccontext - > channel_layout ) {
char name [ 32 ] ;
av_get_channel_layout_string ( name , sizeof ( name ) , avccontext - > channels ,
avccontext - > channel_layout ) ;
av_log ( avccontext , AV_LOG_ERROR , " %s not supported by Vorbis: "
" output stream will have incorrect "
" channel layout. \n " , name ) ;
} else {
av_log ( avccontext , AV_LOG_WARNING , " No channel layout specified. The encoder "
" will use Vorbis channel layout for "
" %d channels. \n " , avccontext - > channels ) ;
}
}
2006-01-21 19:09:23 +02:00
return vorbis_encode_setup_init ( vi ) ;
2002-09-01 21:07:56 +03:00
}
2010-07-21 00:54:46 +03:00
/* How many bytes are needed for a buffer of length 'l' */
static int xiph_len ( int l ) { return ( 1 + l / 255 + l ) ; }
2008-03-21 05:11:20 +02:00
static av_cold int oggvorbis_encode_init ( AVCodecContext * avccontext ) {
2002-09-01 21:07:56 +03:00
OggVorbisContext * context = avccontext - > priv_data ;
2004-04-04 18:19:20 +03:00
ogg_packet header , header_comm , header_code ;
uint8_t * p ;
2010-07-21 00:54:46 +03:00
unsigned int offset ;
2002-09-01 21:07:56 +03:00
vorbis_info_init ( & context - > vi ) ;
if ( oggvorbis_init_encoder ( & context - > vi , avccontext ) < 0 ) {
2009-07-01 09:48:27 +03:00
av_log ( avccontext , AV_LOG_ERROR , " oggvorbis_encode_init: init_encoder failed \n " ) ;
2005-12-22 03:10:11 +02:00
return - 1 ;
2002-09-01 21:07:56 +03:00
}
vorbis_analysis_init ( & context - > vd , & context - > vi ) ;
vorbis_block_init ( & context - > vd , & context - > vb ) ;
2004-04-04 18:19:20 +03:00
vorbis_comment_init ( & context - > vc ) ;
vorbis_comment_add_tag ( & context - > vc , " encoder " , LIBAVCODEC_IDENT ) ;
vorbis_analysis_headerout ( & context - > vd , & context - > vc , & header ,
& header_comm , & header_code ) ;
2005-12-17 20:14:38 +02:00
2010-07-21 00:54:46 +03:00
avccontext - > extradata_size =
1 + xiph_len ( header . bytes ) + xiph_len ( header_comm . bytes ) +
header_code . bytes ;
p = avccontext - > extradata =
av_malloc ( avccontext - > extradata_size + FF_INPUT_BUFFER_PADDING_SIZE ) ;
2005-05-13 21:10:23 +03:00
p [ 0 ] = 2 ;
offset = 1 ;
offset + = av_xiphlacing ( & p [ offset ] , header . bytes ) ;
offset + = av_xiphlacing ( & p [ offset ] , header_comm . bytes ) ;
memcpy ( & p [ offset ] , header . packet , header . bytes ) ;
offset + = header . bytes ;
memcpy ( & p [ offset ] , header_comm . packet , header_comm . bytes ) ;
offset + = header_comm . bytes ;
memcpy ( & p [ offset ] , header_code . packet , header_code . bytes ) ;
offset + = header_code . bytes ;
2010-07-21 00:54:46 +03:00
assert ( offset = = avccontext - > extradata_size ) ;
2005-12-17 20:14:38 +02:00
2004-04-04 18:19:20 +03:00
/* vorbis_block_clear(&context->vb);
vorbis_dsp_clear ( & context - > vd ) ;
vorbis_info_clear ( & context - > vi ) ; */
vorbis_comment_clear ( & context - > vc ) ;
2005-12-17 20:14:38 +02:00
2002-09-01 21:07:56 +03:00
avccontext - > frame_size = OGGVORBIS_FRAME_SIZE ;
2005-12-17 20:14:38 +02:00
2002-12-09 14:03:43 +02:00
avccontext - > coded_frame = avcodec_alloc_frame ( ) ;
avccontext - > coded_frame - > key_frame = 1 ;
2005-12-17 20:14:38 +02:00
2002-09-01 21:07:56 +03:00
return 0 ;
}
2002-11-22 09:27:13 +02:00
static int oggvorbis_encode_frame ( AVCodecContext * avccontext ,
2005-12-22 03:10:11 +02:00
unsigned char * packets ,
int buf_size , void * data )
2002-09-01 21:07:56 +03:00
{
OggVorbisContext * context = avccontext - > priv_data ;
ogg_packet op ;
2004-12-18 18:20:42 +02:00
signed short * audio = data ;
2008-10-15 10:29:37 +03:00
int l ;
if ( data ) {
2010-07-11 09:40:05 +03:00
const int samples = avccontext - > frame_size ;
2008-10-15 10:29:37 +03:00
float * * buffer ;
2010-06-27 12:25:05 +03:00
int c , channels = context - > vi . channels ;
2002-09-01 21:07:56 +03:00
2008-10-15 10:31:06 +03:00
buffer = vorbis_analysis_buffer ( & context - > vd , samples ) ;
2010-06-27 12:25:05 +03:00
for ( c = 0 ; c < channels ; c + + ) {
int co = ( channels > 8 ) ? c :
ff_vorbis_encoding_channel_layout_offsets [ channels - 1 ] [ c ] ;
2008-10-15 10:31:06 +03:00
for ( l = 0 ; l < samples ; l + + )
2010-06-27 12:25:05 +03:00
buffer [ c ] [ l ] = audio [ l * channels + co ] / 32768.f ;
2005-12-22 03:10:11 +02:00
}
2008-10-15 10:31:06 +03:00
vorbis_analysis_wrote ( & context - > vd , samples ) ;
2008-10-15 10:29:37 +03:00
} else {
if ( ! context - > eof )
vorbis_analysis_wrote ( & context - > vd , 0 ) ;
context - > eof = 1 ;
}
2002-09-01 21:07:56 +03:00
while ( vorbis_analysis_blockout ( & context - > vd , & context - > vb ) = = 1 ) {
2005-12-22 03:10:11 +02:00
vorbis_analysis ( & context - > vb , NULL ) ;
vorbis_bitrate_addblock ( & context - > vb ) ;
2002-09-01 21:07:56 +03:00
2005-12-22 03:10:11 +02:00
while ( vorbis_bitrate_flushpacket ( & context - > vd , & op ) ) {
2007-02-21 12:15:08 +02:00
/* i'd love to say the following line is a hack, but sadly it's
* not , apparently the end of stream decision is in libogg . */
2010-06-22 09:53:06 +03:00
if ( op . bytes = = 1 & & op . e_o_s )
2004-06-23 00:14:01 +03:00
continue ;
2010-07-11 09:59:21 +03:00
if ( context - > buffer_index + sizeof ( ogg_packet ) + op . bytes > BUFFER_SIZE ) {
av_log ( avccontext , AV_LOG_ERROR , " libvorbis: buffer overflow. " ) ;
return - 1 ;
}
2004-04-04 17:39:20 +03:00
memcpy ( context - > buffer + context - > buffer_index , & op , sizeof ( ogg_packet ) ) ;
context - > buffer_index + = sizeof ( ogg_packet ) ;
memcpy ( context - > buffer + context - > buffer_index , op . packet , op . bytes ) ;
context - > buffer_index + = op . bytes ;
// av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes);
2005-12-22 03:10:11 +02:00
}
2002-09-01 21:07:56 +03:00
}
2004-04-04 20:06:30 +03:00
l = 0 ;
2004-04-04 17:39:20 +03:00
if ( context - > buffer_index ) {
2004-04-04 18:19:20 +03:00
ogg_packet * op2 = ( ogg_packet * ) context - > buffer ;
2004-04-04 17:39:20 +03:00
op2 - > packet = context - > buffer + sizeof ( ogg_packet ) ;
2004-04-04 20:06:30 +03:00
2004-06-23 00:14:01 +03:00
l = op2 - > bytes ;
2005-09-04 12:03:01 +03:00
avccontext - > coded_frame - > pts = av_rescale_q ( op2 - > granulepos , ( AVRational ) { 1 , avccontext - > sample_rate } , avccontext - > time_base ) ;
2005-09-04 12:04:52 +03:00
//FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate
2004-04-04 20:06:30 +03:00
2010-07-11 09:59:21 +03:00
if ( l > buf_size ) {
av_log ( avccontext , AV_LOG_ERROR , " libvorbis: buffer overflow. " ) ;
return - 1 ;
}
2004-06-23 00:14:01 +03:00
memcpy ( packets , op2 - > packet , l ) ;
context - > buffer_index - = l + sizeof ( ogg_packet ) ;
2010-06-16 22:03:54 +03:00
memmove ( context - > buffer , context - > buffer + l + sizeof ( ogg_packet ) , context - > buffer_index ) ;
2004-04-04 17:39:20 +03:00
// av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l);
}
2004-04-04 20:06:30 +03:00
return l ;
2002-09-01 21:07:56 +03:00
}
2008-03-21 05:11:20 +02:00
static av_cold int oggvorbis_encode_close ( AVCodecContext * avccontext ) {
2002-09-01 21:07:56 +03:00
OggVorbisContext * context = avccontext - > priv_data ;
/* ogg_packet op ; */
2005-12-17 20:14:38 +02:00
2002-09-01 21:07:56 +03:00
vorbis_analysis_wrote ( & context - > vd , 0 ) ; /* notify vorbisenc this is EOF */
vorbis_block_clear ( & context - > vb ) ;
vorbis_dsp_clear ( & context - > vd ) ;
vorbis_info_clear ( & context - > vi ) ;
2002-12-09 14:03:43 +02:00
av_freep ( & avccontext - > coded_frame ) ;
2004-04-04 18:19:20 +03:00
av_freep ( & avccontext - > extradata ) ;
2005-12-17 20:14:38 +02:00
2002-09-01 21:07:56 +03:00
return 0 ;
}
2011-01-25 23:40:11 +02:00
AVCodec ff_libvorbis_encoder = {
2011-09-23 22:11:15 +03:00
. name = " libvorbis " ,
. type = AVMEDIA_TYPE_AUDIO ,
. id = CODEC_ID_VORBIS ,
. priv_data_size = sizeof ( OggVorbisContext ) ,
. init = oggvorbis_encode_init ,
. encode = oggvorbis_encode_frame ,
. close = oggvorbis_encode_close ,
. capabilities = CODEC_CAP_DELAY ,
. sample_fmts = ( const enum AVSampleFormat [ ] ) { AV_SAMPLE_FMT_S16 , AV_SAMPLE_FMT_NONE } ,
. long_name = NULL_IF_CONFIG_SMALL ( " libvorbis Vorbis " ) ,
. priv_class = & class ,
} ;