@ -49,6 +49,7 @@
typedef struct OggVorbisContext {
AVClass * av_class ; /**< class for AVOptions */
AVFrame frame ;
vorbis_info vi ; /**< vorbis_info used during init */
vorbis_dsp_state vd ; /**< DSP state used for analysis */
vorbis_block vb ; /**< vorbis_block used for analysis */
@ -390,3 +391,170 @@ AVCodec ff_libvorbis_encoder = {
. priv_class = & class ,
. defaults = defaults ,
} ;
static int oggvorbis_decode_init ( AVCodecContext * avccontext ) {
OggVorbisContext * context = avccontext - > priv_data ;
uint8_t * p = avccontext - > extradata ;
int i , hsizes [ 3 ] ;
unsigned char * headers [ 3 ] , * extradata = avccontext - > extradata ;
vorbis_info_init ( & context - > vi ) ;
vorbis_comment_init ( & context - > vc ) ;
if ( ! avccontext - > extradata_size | | ! p ) {
av_log ( avccontext , AV_LOG_ERROR , " vorbis extradata absent \n " ) ;
return - 1 ;
}
if ( p [ 0 ] = = 0 & & p [ 1 ] = = 30 ) {
for ( i = 0 ; i < 3 ; i + + ) {
hsizes [ i ] = bytestream_get_be16 ( & p ) ;
headers [ i ] = p ;
p + = hsizes [ i ] ;
}
} else if ( * p = = 2 ) {
unsigned int offset = 1 ;
p + + ;
for ( i = 0 ; i < 2 ; i + + ) {
hsizes [ i ] = 0 ;
while ( ( * p = = 0xFF ) & & ( offset < avccontext - > extradata_size ) ) {
hsizes [ i ] + = 0xFF ;
offset + + ;
p + + ;
}
if ( offset > = avccontext - > extradata_size - 1 ) {
av_log ( avccontext , AV_LOG_ERROR ,
" vorbis header sizes damaged \n " ) ;
return - 1 ;
}
hsizes [ i ] + = * p ;
offset + + ;
p + + ;
}
hsizes [ 2 ] = avccontext - > extradata_size - hsizes [ 0 ] - hsizes [ 1 ] - offset ;
#if 0
av_log ( avccontext , AV_LOG_DEBUG ,
" vorbis header sizes: %d, %d, %d, / extradata_len is %d \n " ,
hsizes [ 0 ] , hsizes [ 1 ] , hsizes [ 2 ] , avccontext - > extradata_size ) ;
# endif
headers [ 0 ] = extradata + offset ;
headers [ 1 ] = extradata + offset + hsizes [ 0 ] ;
headers [ 2 ] = extradata + offset + hsizes [ 0 ] + hsizes [ 1 ] ;
} else {
av_log ( avccontext , AV_LOG_ERROR ,
" vorbis initial header len is wrong: %d \n " , * p ) ;
return - 1 ;
}
for ( i = 0 ; i < 3 ; i + + ) {
context - > op . b_o_s = i = = 0 ;
context - > op . bytes = hsizes [ i ] ;
context - > op . packet = headers [ i ] ;
if ( vorbis_synthesis_headerin ( & context - > vi , & context - > vc , & context - > op ) < 0 ) {
av_log ( avccontext , AV_LOG_ERROR , " %d. vorbis header damaged \n " , i + 1 ) ;
return - 1 ;
}
}
avccontext - > channels = context - > vi . channels ;
avccontext - > sample_rate = context - > vi . rate ;
avccontext - > time_base = ( AVRational ) { 1 , avccontext - > sample_rate } ;
vorbis_synthesis_init ( & context - > vd , & context - > vi ) ;
vorbis_block_init ( & context - > vd , & context - > vb ) ;
return 0 ;
}
static inline int conv ( int samples , float * * pcm , char * buf , int channels ) {
int i , j ;
ogg_int16_t * ptr , * data = ( ogg_int16_t * ) buf ;
float * mono ;
for ( i = 0 ; i < channels ; i + + ) {
ptr = & data [ i ] ;
mono = pcm [ i ] ;
for ( j = 0 ; j < samples ; j + + ) {
* ptr = av_clip_int16 ( mono [ j ] * 32767.f ) ;
ptr + = channels ;
}
}
return 0 ;
}
static int oggvorbis_decode_frame ( AVCodecContext * avccontext , void * data ,
int * got_frame_ptr , AVPacket * avpkt )
{
OggVorbisContext * context = avccontext - > priv_data ;
float * * pcm ;
ogg_packet * op = & context - > op ;
int samples , total_samples , total_bytes ;
int ret ;
int16_t * output ;
if ( ! avpkt - > size ) {
//FIXME flush
return 0 ;
}
context - > frame . nb_samples = 8192 * 4 ;
if ( ( ret = avccontext - > get_buffer ( avccontext , & context - > frame ) ) < 0 ) {
av_log ( avccontext , AV_LOG_ERROR , " get_buffer() failed \n " ) ;
return ret ;
}
output = ( int16_t * ) context - > frame . data [ 0 ] ;
op - > packet = avpkt - > data ;
op - > bytes = avpkt - > size ;
// av_log(avccontext, AV_LOG_DEBUG, "%d %d %d %"PRId64" %"PRId64" %d %d\n", op->bytes, op->b_o_s, op->e_o_s, op->granulepos, op->packetno, buf_size, context->vi.rate);
/* for(i=0; i<op->bytes; i++)
av_log ( avccontext , AV_LOG_DEBUG , " %02X " , op - > packet [ i ] ) ;
av_log ( avccontext , AV_LOG_DEBUG , " \n " ) ; */
if ( vorbis_synthesis ( & context - > vb , op ) = = 0 )
vorbis_synthesis_blockin ( & context - > vd , & context - > vb ) ;
total_samples = 0 ;
total_bytes = 0 ;
while ( ( samples = vorbis_synthesis_pcmout ( & context - > vd , & pcm ) ) > 0 ) {
conv ( samples , pcm , ( char * ) output + total_bytes , context - > vi . channels ) ;
total_bytes + = samples * 2 * context - > vi . channels ;
total_samples + = samples ;
vorbis_synthesis_read ( & context - > vd , samples ) ;
}
context - > frame . nb_samples = total_samples ;
* got_frame_ptr = 1 ;
* ( AVFrame * ) data = context - > frame ;
return avpkt - > size ;
}
static int oggvorbis_decode_close ( AVCodecContext * avccontext ) {
OggVorbisContext * context = avccontext - > priv_data ;
vorbis_info_clear ( & context - > vi ) ;
vorbis_comment_clear ( & context - > vc ) ;
return 0 ;
}
AVCodec ff_libvorbis_decoder = {
. name = " libvorbis " ,
. type = AVMEDIA_TYPE_AUDIO ,
. id = CODEC_ID_VORBIS ,
. priv_data_size = sizeof ( OggVorbisContext ) ,
. init = oggvorbis_decode_init ,
. decode = oggvorbis_decode_frame ,
. close = oggvorbis_decode_close ,
. capabilities = CODEC_CAP_DELAY ,
} ;