OStreamAudioEncoder.cpp

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) Massimo Cora' 2006 <maxcvs@email.it>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU Library General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00017  */
00018  
00019 
00020 #include <string.h>
00021 #include <stdlib.h>
00022 #include "OStreamAudioEncoder.hh"
00023 
00024 
00025 OStreamAudioEncoder::OStreamAudioEncoder( unsigned int io_buf_size, ostream_encoding_type encoding_type,
00026                                                                                  int num_channels /* = 2 */ ) :
00027                                                                         _internal_buffer_size( io_buf_size ),
00028                                                                         _encoding_type( encoding_type ),
00029                                                                         _num_channels( num_channels )
00030 {
00031         _initialized = false;
00032         if ( io_buf_size <= 1 ) {
00033                 DEBUG_PRINT ("io_buf_size is wrong\n.");
00034                 return;
00035         }
00036         
00037         // allocate the internal buffer
00038         _internal_buffer = new unsigned char[_internal_buffer_size];
00039 
00040         _ready_to_encode_frame = NULL;
00041         if ( encoder_initialize () == true ) {
00042                 _initialized = true;
00043         }
00044 }
00045 
00046 OStreamAudioEncoder::~OStreamAudioEncoder ()
00047 {
00048         if ( _internal_buffer )
00049                 delete _internal_buffer;
00050 
00051         if ( _ready_to_encode_frame )
00052                 free( _ready_to_encode_frame );
00053 
00054         free_pcm_buffer ();
00055         av_close_input_file( _out_fmt_context );
00056 // FIXME
00057 // etc
00058 //              avcodec_close(c);
00059 //              av_free(c);
00060 
00061 }
00062 
00063 
00064 
00065 bool OStreamAudioEncoder::open_codec( AVStream *stream )
00066 {
00067     AVCodec *codec;
00068     AVCodecContext *codec_context;
00069 
00070     codec_context = stream->codec;
00071 
00072     // NB: codec = AVCodec
00073     codec = avcodec_find_encoder( codec_context->codec_id );
00074     if ( !codec ) {
00075         DEBUG_PRINT ("codec not found\n");
00076                 return false;
00077     }
00078 
00079     // lets open the codec
00080     if ( avcodec_open( codec_context, codec ) < 0 ) {
00081                 return false;
00082     }
00083         
00084         return true;
00085 }
00086 
00087 
00088 AVStream* OStreamAudioEncoder::create_audio_stream( AVFormatContext *io_fmt_context, int codec_id )
00089 {
00090     AVCodecContext *codec_context;
00091     AVStream *stream;
00092 
00093         // create a new stream given AVFormatContext [which in this case is set to
00094         // output]
00095         // With this call it's allocated also c = st->codec, the codec_context
00096     stream = av_new_stream( io_fmt_context, 0 );
00097     if ( !stream ) {
00098         DEBUG_PRINT ("Could not alloc stream\n");
00099                 return NULL;
00100     }
00101 
00102     // AVCodecContext is a member of AVStream!
00103     // now we'll setup the parameters of AVCodecContext
00104     codec_context = stream->codec;
00105     codec_context->codec_id = (CodecID)codec_id;
00106     codec_context->codec_type = CODEC_TYPE_AUDIO;
00107 
00108     codec_context->bit_rate = 64000;
00109     codec_context->sample_rate = 44100;
00110     codec_context->channels = _num_channels;
00111 
00112     return stream;
00113 }
00114 
00115 bool OStreamAudioEncoder::encoder_initialize ()
00116 {
00117         char *encoding_str;
00118         // register all codecs
00119         av_register_all();
00120 
00121         
00122         // initialize a circular bufffer. This will contain pcm_s16le data.
00123         if ( init_pcm_buffer( 2 * MAX_AUDIO_PACKET_SIZE ) == false )
00124                 return false;
00125         
00126         
00127         switch ( _encoding_type ) {
00128                 case OSTREAM_ENCODING_MP3:
00129                         encoding_str = "mp3";
00130                         _out_fmt = guess_format ( encoding_str, NULL, NULL);
00131 
00132                         if( !_out_fmt ) {
00133                                 DEBUG_PRINT( "Could not find suitable output format.\n");
00134                                 return false;
00135                         }
00136                         break;
00137 
00138                 default:
00139                         DEBUG_PRINT ("could not find known OSTREAM_ENCODING type.\n" );
00140                         break;
00141         }
00142 
00143         _out_fmt_context = av_alloc_format_context ();
00144         if( !_out_fmt_context ) {
00145                 DEBUG_PRINT( "Memory error.\n" );
00146                 return false;
00147         }
00148 
00149         // set output format of AVFormatContext
00150         _out_fmt_context->oformat = _out_fmt;
00151 
00152         // check if we had a correct video_codec 
00153     if ( _out_fmt->audio_codec == CODEC_ID_NONE ) {
00154         DEBUG_PRINT( "CODEC_ID_NONE\n" );
00155                 return false;
00156         }
00157 
00158         // add the stream
00159         if(!( _audio_stream = create_audio_stream( _out_fmt_context, _out_fmt->audio_codec ) )) {
00160                 DEBUG_PRINT( "error in adding stream\n" );
00161                 return false;
00162         }
00163 
00164     // set the output parameters (must be done even if no parameters)
00165     if ( av_set_parameters( _out_fmt_context, NULL ) < 0 ) {
00166         DEBUG_PRINT( "Invalid output format parameters\n" );
00167         return false;
00168     }
00169 
00170         // open codec associated with current video_stream
00171         if ( !open_codec( _audio_stream ) ) {
00172         DEBUG_PRINT( "could not open codec\n" );                
00173                 return false;
00174         }
00175 
00176         // set the frame size
00177         _frame_size = _audio_stream->codec->frame_size;
00178         
00179         // and the encoded size
00180         _encoded_frame_size = _frame_size * 2 * _num_channels;  
00181         _ready_to_encode_frame = (unsigned char*) calloc( _encoded_frame_size, sizeof(unsigned char) );
00182         
00183         return true;
00184 }
00185 
00186 const unsigned char* OStreamAudioEncoder::encode_audio_frame( unsigned char* in_pcm_buffer, 
00187                                                                                                                          int in_pcm_buffer_size, int *out_size )
00188 {
00189     AVCodecContext *codec_context;      
00190 
00191         *out_size = 0;
00192         
00193         if ( in_pcm_buffer  == NULL )
00194                 return NULL;
00195         
00196         if ( !_initialized ) {
00197                 DEBUG_PRINT( "initializing class failed.\n" );
00198                 return NULL;
00199         }
00200 
00201         // we need to add the pcm_data to the _pcm_internal_buffer. We will then read back 
00202         // a good _frame_size frame of data. Infact we can encode only on right data size,
00203         // otherwise we will have broken encoded audio data. Three days to discover this... -_-
00204         write_pcm_buffer ( in_pcm_buffer, in_pcm_buffer_size );
00205 
00206         if ( _ready_to_encode_frame == NULL )  {
00207                 DEBUG_PRINT( "_ready_to_encode_frame == NULL\n");
00208                 return NULL;
00209         }
00210         
00211         // ok, read back a _encoded_frame_size frame
00212         read_pcm_buffer( _ready_to_encode_frame, _encoded_frame_size );
00213 
00214         if( in_pcm_buffer_size > _internal_buffer_size ) {
00215                 DEBUG_PRINT( "in_buffer_size too big\n" );
00216                 return NULL;
00217         }
00218         
00219         codec_context = _audio_stream->codec;
00220                 
00221         *out_size = avcodec_encode_audio( codec_context, _internal_buffer, in_pcm_buffer_size, (short*)_ready_to_encode_frame );
00222         
00223         return _internal_buffer;
00224 }
00225 
00226 
00227 
00228 bool OStreamAudioEncoder::init_pcm_buffer ( int size )
00229 {
00230     _pcm_internal_buffer = (unsigned char*)calloc( size, sizeof(unsigned char) );
00231     
00232         if (!_pcm_internal_buffer)
00233         return false;
00234         
00235     _pcm_end_ptr =  _pcm_internal_buffer + size;
00236     _pcm_write_ptr = _pcm_read_ptr = _pcm_internal_buffer;
00237         
00238     return true;                
00239 }
00240 
00241 void OStreamAudioEncoder::free_pcm_buffer ()
00242 {
00243         if ( _pcm_internal_buffer != NULL )
00244                 free( _pcm_internal_buffer );
00245 }
00246 
00247 int OStreamAudioEncoder::read_pcm_buffer( unsigned char *buf, int buf_size )
00248 {
00249     int len;
00250     int size = _pcm_write_ptr - _pcm_read_ptr;
00251     if (size < 0)
00252         size += _pcm_end_ptr - _pcm_internal_buffer;
00253 
00254     if (size < buf_size)
00255         return -1;
00256         
00257     while (buf_size > 0) {
00258         len = ( _pcm_end_ptr - _pcm_read_ptr ) > ( buf_size ) ? 
00259                         ( buf_size ) : ( _pcm_end_ptr - _pcm_read_ptr );
00260                 
00261         memcpy( buf, _pcm_read_ptr, len );
00262         buf += len;
00263         _pcm_read_ptr += len;
00264                 
00265         if ( _pcm_read_ptr >= _pcm_end_ptr )
00266             _pcm_read_ptr = _pcm_internal_buffer;
00267                 
00268         buf_size -= len;
00269     }
00270         
00271     return 0;
00272 }
00273 
00274 
00275 void OStreamAudioEncoder::write_pcm_buffer( const unsigned char *buf, int size )
00276 {
00277     int len;
00278 
00279     while (size > 0) {
00280         len = ( _pcm_end_ptr - _pcm_write_ptr ) > ( size ) ? 
00281                         ( size ) : ( _pcm_end_ptr - _pcm_write_ptr );
00282 
00283         memcpy( _pcm_write_ptr, buf, len );
00284         _pcm_write_ptr += len;
00285                 
00286         if ( _pcm_write_ptr >= _pcm_end_ptr )
00287             _pcm_write_ptr = _pcm_internal_buffer;
00288         buf += len;
00289         size -= len;
00290     }
00291 }
00292 

Generated on Tue Dec 26 10:32:38 2006 for Omnimeeting by  doxygen 1.4.7