OStreamVideoEncoder.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 "OStreamVideoEncoder.hh"
00021 
00022 
00023 OStreamVideoEncoder::OStreamVideoEncoder( unsigned int io_buf_size, ostream_encoding_type encoding_type,
00024                                                                                   int video_width, int video_height, 
00025                                                                                   int fps /* = 25 */,
00026                                                                                   PixelFormat opencv_pix_fmt /*= PIX_FMT_BGR24*/) : 
00027                                                                         _internal_buffer_size( io_buf_size ),
00028                                                                         _encoding_type( encoding_type ),
00029                                                                         _video_width( video_width ), 
00030                                                                         _video_height( video_height ),
00031                                                                         _fps( fps ),
00032                                                                         _opencv_pix_fmt( opencv_pix_fmt )
00033 {
00034         _initialized = false;
00035         if ( io_buf_size <= 1 ) {
00036                 DEBUG_PRINT ("io_buf_size is wrong\n.");
00037                 return;
00038         }
00039         
00040         // allocate the internal buffer
00041         _internal_buffer = new unsigned char[_internal_buffer_size];
00042         
00043         if ( encoder_initialize () == true ) {;
00044                 _initialized = true;
00045         }
00046 }
00047 
00048 OStreamVideoEncoder::~OStreamVideoEncoder()
00049 {
00050         // FIXME: destroy
00051         if ( _internal_buffer )
00052                 delete _internal_buffer;
00053 
00054 // etc
00055 //              avcodec_close(c);
00056 //              av_free(c);
00057         
00058 }
00059 
00060 bool OStreamVideoEncoder::open_codec( AVStream *stream )
00061 {
00062     AVCodec *codec;
00063     AVCodecContext *codec_context;
00064 
00065     codec_context = stream->codec;
00066 
00067     // NB: codec = AVCodec
00068     codec = avcodec_find_encoder( codec_context->codec_id );
00069     if ( !codec ) {
00070         DEBUG_PRINT ("codec not found\n");
00071                 return false;
00072     }
00073 
00074     // lets open the codec
00075     if ( avcodec_open( codec_context, codec ) < 0 ) {
00076                 return false;
00077     }
00078         
00079         return true;
00080 }
00081 
00082 AVFrame* OStreamVideoEncoder::create_avframe( int pixel_format )
00083 {
00084     AVFrame *frame;
00085     unsigned char *picture_buf;
00086     int pic_size;
00087     
00088     frame = avcodec_alloc_frame ();
00089     if ( !frame )
00090         return NULL;
00091         
00092     pic_size = avpicture_get_size( pixel_format, _video_width, _video_height );
00093     picture_buf = (unsigned char*)calloc( pic_size, sizeof(unsigned char) );
00094     
00095         if ( !picture_buf ) {
00096         av_free( frame );
00097         return NULL;
00098     }
00099         
00100         // lets fill picture with the picture_buf just created
00101     avpicture_fill((AVPicture *)frame, picture_buf, pixel_format, _video_width, _video_height );
00102     return frame;
00103 }
00104 
00105 
00106 AVStream* OStreamVideoEncoder::create_video_stream( AVFormatContext *io_fmt_context, int codec_id )
00107 {
00108     AVCodecContext *codec_context;
00109     AVStream *stream;
00110 
00111         // create a new stream given AVFormatContext [which in this case is set to
00112         // output]
00113         // With this call it's allocated also c = st->codec, the codec_context
00114     stream = av_new_stream( io_fmt_context, 0 );
00115     if ( !stream ) {
00116         DEBUG_PRINT ("Could not alloc stream\n");
00117                 return NULL;
00118     }
00119     
00120     // AVCodecContext is a member of AVStream!
00121     // now we'll setup the parameters of AVCodecContext
00122     codec_context = stream->codec;
00123     codec_context->codec_id = (CodecID)codec_id;
00124     codec_context->codec_type = CODEC_TYPE_VIDEO;
00125 
00126     // sample parameters
00127     codec_context->bit_rate = 400000;
00128         
00129     codec_context->width = _video_width;
00130     codec_context->height = _video_height;
00131     codec_context->time_base.den = _fps;
00132     codec_context->time_base.num = 1;
00133         
00134         // intra frame sending every twelve frames
00135     codec_context->gop_size = 12; 
00136 
00137         switch ( _encoding_type ) {
00138         case OSTREAM_ENCODING_MJPEG:
00139                         codec_context->pix_fmt = PIX_FMT_YUVJ420P; 
00140                         break;
00141                 
00142                 case OSTREAM_ENCODING_H263P:
00143                     codec_context->pix_fmt = PIX_FMT_YUV420P; 
00144                         break;
00145                 
00146                 default:
00147                         codec_context->pix_fmt = PIX_FMT_YUVJ420P;
00148                         break;
00149         }
00150 
00151     return stream;
00152 }
00153 
00154 bool OStreamVideoEncoder::encoder_initialize () 
00155 {
00156         char *encoding_str;
00157         // register all codecs
00158         av_register_all();
00159         
00160         switch ( _encoding_type ) {
00161                 case OSTREAM_ENCODING_MJPEG:
00162                         encoding_str = "mjpeg";
00163                         _out_fmt = guess_format ( encoding_str, NULL, NULL);
00164                 
00165                         if( !_out_fmt ) {
00166                                 DEBUG_PRINT( "Could not find suitable output format.\n");
00167                                 return false;
00168                         }
00169                 
00170                         break;
00171                 
00172                 case OSTREAM_ENCODING_H263P:
00173                         encoding_str ="h263";
00174                         _out_fmt = guess_format ( encoding_str, NULL, NULL);
00175                 
00176                         if( !_out_fmt ) {
00177                                 DEBUG_PRINT( "Could not find suitable output format.\n");
00178                                 return false;
00179                         }
00180 
00181                         // specify the sub-codec we want to use. Without this we won't be able
00182                         // to stream H263P not use 640x480 videos
00183                         _out_fmt->video_codec = CODEC_ID_H263P;
00184                 
00185                         break;
00186                 
00187                 default:
00188                         DEBUG_PRINT ("could not find known OSTREAM_ENCODING type.\n" );
00189                         break;
00190         }
00191 
00192         _out_fmt_context = av_alloc_format_context ();
00193         if( !_out_fmt_context ) {
00194                 DEBUG_PRINT( "Memory error.\n" );
00195                 return false;
00196         }
00197         
00198         // set output format of AVFormatContext
00199         _out_fmt_context->oformat = _out_fmt;
00200 
00201         // check if we had a correct video_codec 
00202     if ( _out_fmt->video_codec == CODEC_ID_NONE ) {
00203         DEBUG_PRINT( "CODEC_ID_NONE\n" );
00204                 return false;
00205         }
00206         
00207         // add the stream
00208         if(!( _video_stream = create_video_stream( _out_fmt_context, _out_fmt->video_codec ) )) {
00209                 DEBUG_PRINT( "error in adding stream\n" );
00210                 return false;
00211         }
00212 
00213     // set the output parameters (must be done even if no parameters)
00214     if ( av_set_parameters( _out_fmt_context, NULL ) < 0 ) {
00215         DEBUG_PRINT( "Invalid output format parameters\n" );
00216         return false;
00217     }
00218 
00219         // open codec associated with current video_stream
00220         if ( !open_codec( _video_stream ) ) {
00221         DEBUG_PRINT( "could not open codec\n" );                
00222                 return false;
00223         }
00224                 
00225         // we should now create the frame on which we can store the converted bytes
00226         // ready to be encoded
00227     _ready_to_encode_frame = create_avframe( _video_stream->codec->pix_fmt );
00228     if ( !_ready_to_encode_frame ) {
00229         DEBUG_PRINT( "Could not allocate encoded_frame\n" );
00230                 return false;
00231     }
00232 
00233         // we'll receive IplImage(s). This _opencv_frame will be converted to a stream-compatible
00234         // AVFrame [see up _ready_to_encode_frame]
00235         _opencv_frame = create_avframe( _opencv_pix_fmt );
00236     if ( !_opencv_frame ) {
00237                 DEBUG_PRINT( "Could not allocate opencv frame\n");
00238                 return false;
00239         }
00240         
00241         return true;
00242 }
00243  
00244 
00245 const unsigned char* OStreamVideoEncoder::encode_video_frame( IplImage *image, int *out_size )
00246 {
00247     AVCodecContext *codec_context;
00248         *out_size = 0;
00249         
00250         if ( image == NULL )
00251                 return NULL;
00252         
00253         if ( !_initialized ) {
00254                 DEBUG_PRINT( "initializing class failed.\n" );
00255                 return NULL;
00256         }
00257 
00258         if( image->imageSize > _internal_buffer_size ) {
00259                 DEBUG_PRINT( "image_size too big.\n" );
00260                 return NULL;
00261         }
00262         
00263         codec_context = _video_stream->codec;
00264 
00265         // this is an hack. We just assign the pointer image->imageData to
00266         // _opencv_frame->data[0] without using a memcpy. This should speed the things up.
00267         _opencv_frame->data[0] = (uint8_t*)image->imageData;
00268         
00269         /*/
00270         int img_convert(AVPicture *dst, int dst_pix_fmt,
00271                     const AVPicture *src, int pix_fmt,
00272                         int width, int height);
00273         /*/    
00274     img_convert( (AVPicture *)_ready_to_encode_frame, codec_context->pix_fmt, 
00275                                 (AVPicture *)_opencv_frame, _opencv_pix_fmt, codec_context->width, 
00276                                 codec_context->height );
00277         /*/
00278         int avcodec_encode_video(AVCodecContext *avctx, uint8_t *buf, int buf_size,
00279                                 const AVFrame *pict);
00280         /*/
00281     // encode the image
00282     *out_size = avcodec_encode_video( codec_context, _internal_buffer, _internal_buffer_size, 
00283                                                                          _ready_to_encode_frame );
00284 
00285         return _internal_buffer;
00286 }
00287 

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