TuttleOFX  1
LibAVVideoWriter.cpp
Go to the documentation of this file.
00001 #include "LibAVVideoWriter.hpp"
00002 #include "LibAVPreset.hpp"
00003 #include "LibAVFormatPreset.hpp"
00004 
00005 #include <tuttle/plugin/global.hpp>
00006 #include <tuttle/plugin/exceptions.hpp>
00007 
00008 #include <boost/foreach.hpp>
00009 
00010 #include <cstdio>
00011 
00012 
00013 namespace tuttle {
00014 namespace plugin {
00015 namespace av {
00016 
00017 #if LIBAVFORMAT_VERSION_INT < AV_VERSION_INT( 52, 40, 0 )
00018 // compatibility with previous versions of libavformat
00019 #define av_guess_format guess_format
00020 #endif
00021 
00022 #ifdef _MSC_VER
00023 #define snprintf _snprintf
00024 #endif
00025 
00026 static boost::int64_t pts = 0;
00027 
00028 LibAVVideoWriter::LibAVVideoWriter()
00029         : LibAV()
00030         , _avFormatOptions   ( NULL )
00031         , _stream            ( NULL )
00032         , _avVideoOptions    ( NULL )
00033         , _avAudioOptions    ( NULL )
00034         , _sws_context       ( NULL )
00035         , _videoCodec        ( NULL )
00036         , _audioCodec        ( NULL )
00037         , _ofmt              ( NULL )
00038         , _statusCode        ( eWriterStatusIgnoreFinish )
00039         , _filename          ( "" )
00040         , _width             ( 0 )
00041         , _height            ( 0 )
00042         , _aspectRatio       ( 1 )
00043         , _out_pixelFormat   ( PIX_FMT_YUV420P )
00044         , _fps               ( 25.0f )
00045         , _formatName        ( "" )
00046         , _videoCodecName    ( "" )
00047         , _audioCodecName    ( "" )
00048 {
00049         AVOutputFormat* fmt = av_oformat_next( NULL );
00050         
00051         while( fmt )
00052         {
00053                 // add only format with video track
00054                 if( fmt->video_codec != AV_CODEC_ID_NONE )
00055                 {
00056                         if( fmt->long_name )
00057                         {
00058                                 _formatsLongNames.push_back( std::string( fmt->long_name ) + std::string( " (" ) + std::string( fmt->name ) + std::string( ")" ) );
00059                                 _formatsShortNames.push_back( std::string( fmt->name ) );
00060                         }
00061                         if( fmt->priv_class )
00062                         {
00063                                 const AVOption *o = NULL;
00064 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 51, 12, 0 )
00065                                 while( ( o = av_next_option( &fmt->priv_class, o ) ) )
00066 #else
00067                                 while( ( o = av_opt_next( &fmt->priv_class, o ) ) )
00068 #endif
00069                                 {
00070                                         AVPrivOption avprivopt;
00071                                         avprivopt.o = *o;
00072                                         avprivopt.class_name = std::string( fmt->name );
00073                                         _formatPrivOpts.push_back( avprivopt );
00074                                 }
00075                         }
00076                 }
00077                 fmt = av_oformat_next( fmt );
00078         }
00079 
00080         AVCodec* c = NULL;
00081         while( ( c = av_codec_next( c ) ) )
00082         {
00083 #if LIBAVCODEC_VERSION_INT >= AV_VERSION_INT( 53, 34, 0 )
00084                 if( c->encode2 )
00085 #else
00086                 if( c->encode )
00087 #endif
00088                 {
00089                         switch( c->type )
00090                         {
00091                                 case AVMEDIA_TYPE_VIDEO:
00092                                 {
00093                                         if( c->long_name )
00094                                         {
00095                                                 _videoCodecsLongNames.push_back( std::string( c->long_name ) );
00096                                                 _videoCodecsShortNames.push_back( std::string( c->name ) );
00097                                         }
00098                                         if( c->priv_class )
00099                                         {
00100                                                 const AVOption *o = NULL;
00101 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 51, 12, 0 )
00102                                                 while( ( o = av_next_option( &c->priv_class, o ) ) )
00103 #else
00104                                                 while( ( o = av_opt_next( &c->priv_class, o ) ) )
00105 #endif
00106                                                 {
00107                                                         AVPrivOption avprivopt;
00108                                                         avprivopt.o = *o;
00109                                                         avprivopt.class_name = std::string( c->name );
00110                                                         _videoCodecPrivOpts.push_back( avprivopt );
00111                                                 }
00112                                         }
00113                                         break;
00114                                 }
00115                                 case AVMEDIA_TYPE_AUDIO:
00116                                 {
00117                                         if( c->long_name )
00118                                         {
00119                                                 _audioCodecsLongNames.push_back( std::string( c->long_name ) );
00120                                                 _audioCodecsShortNames.push_back( std::string( c->name ) );
00121                                         }
00122                                         if( c->priv_class )
00123                                         {
00124                                                 const AVOption *o = NULL;
00125 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 51, 12, 0 )
00126                                                 while( ( o = av_next_option( &c->priv_class, o ) ) )
00127 #else
00128                                                 while( ( o = av_opt_next( &c->priv_class, o ) ) )
00129 #endif
00130                                                 {
00131                                                         AVPrivOption avprivopt;
00132                                                         avprivopt.o = *o;
00133                                                         avprivopt.class_name = std::string( c->name );
00134                                                         _audioCodecPrivOpts.push_back( avprivopt );
00135                                                 }
00136                                         }
00137                                         break;
00138                                 }
00139                                 default:
00140                                         break;
00141                         }
00142                 }
00143         }
00144 
00145 }
00146 
00147 int LibAVVideoWriter::start( )
00148 {
00149         if( !_avFormatOptions )
00150         {
00151                 _avFormatOptions = avformat_alloc_context();
00152                 _ofmt = NULL;
00153                 
00154                 const char* filename = getFilename().c_str();
00155                 
00156                 if( !_avFormatOptions )
00157                 {
00158                         TUTTLE_LOG_ERROR( "avWriter: format context allocation failed" );
00159                         return false;
00160                 }
00161                 
00162                 if( !_formatName.empty() )
00163                 {
00164                         _ofmt = av_guess_format( _formatName.c_str(), NULL, NULL );
00165                         if (!_ofmt)
00166                         {
00167                                 TUTTLE_LOG_ERROR( "avWriter: Requested output format " << _formatName << " is not a suitable output format" );
00168                                 return false;
00169                         }
00170                 }
00171                 else
00172                 {
00173                         _ofmt = av_guess_format( NULL, filename, NULL );
00174                         if (!_ofmt)
00175                         {
00176                                 TUTTLE_LOG_ERROR( "avWriter: Unable to find a suitable output format for " << filename );
00177                                 return false;
00178                         }
00179                 }
00180                 
00181                 _avFormatOptions->oformat = _ofmt;
00182                 if( _avFormatOptions->oformat->priv_data_size > 0 )
00183                 {
00184                         _avFormatOptions->priv_data = av_mallocz( _avFormatOptions->oformat->priv_data_size );
00185                         if( !_avFormatOptions->priv_data )
00186                         {
00187                                 TUTTLE_LOG_ERROR( "avWriter: format context allocation failed" );
00188                                 return false;
00189                         }
00190                         if( _avFormatOptions->oformat->priv_class )
00191                         {
00192                                 *(const AVClass**)_avFormatOptions->priv_data= _avFormatOptions->oformat->priv_class;
00193                                 av_opt_set_defaults( _avFormatOptions->priv_data );
00194                         }
00195                 }
00196                 else
00197                         _avFormatOptions->priv_data = NULL;
00198                 
00199                 if( filename )
00200                         av_strlcpy( _avFormatOptions->filename, filename, sizeof( _avFormatOptions->filename ) );
00201 
00202                 TUTTLE_LOG_TRACE( "avWriter: " << std::string( _ofmt->name ) << " format selected" );
00203         }
00204 
00205         if( !_stream )
00206         {
00207                 _videoCodec = avcodec_find_encoder_by_name( _videoCodecName.c_str() );
00208                 if (!_videoCodec)
00209                 {
00210                         BOOST_THROW_EXCEPTION( exception::Format()
00211                                 << exception::user( "avWriter: codec not found." ) );
00212                 }
00213                 TUTTLE_LOG_TRACE( "avWriter: " << std::string(_videoCodec->name) << " codec selected" );
00214                 
00215                 _avVideoOptions = avcodec_alloc_context3( _videoCodec );
00216 
00217                 _stream = avformat_new_stream( _avFormatOptions, _videoCodec );
00218                 if( !_stream )
00219                 {
00220                         BOOST_THROW_EXCEPTION( exception::File()
00221                                 << exception::user( "avWriter: out of memory." ) );
00222                 }
00223                 avcodec_get_context_defaults3(_stream->codec, _videoCodec);
00224 
00225 //              TUTTLE_LOG_VAR2( TUTTLE_INFO, _videoCodecName, _videoPresetName );
00226                 
00227                 _stream->codec->width              = getWidth();
00228                 _stream->codec->height             = getHeight();
00229                 _stream->codec->time_base          = av_inv_q( av_d2q( _fps, INT_MAX ) );
00230                 //TUTTLE_LOG_VAR( TUTTLE_INFO,  _fps );
00231                 //TUTTLE_LOG_VAR2( TUTTLE_INFO, _stream->codec->time_base.num, _stream->codec->time_base.den );
00232                 
00233                 _stream->codec->sample_rate        = 48000; ///< samples per second
00234                 _stream->codec->channels           = 0;     ///< number of audio channels
00235         }
00236         return true;
00237 }
00238 
00239 bool LibAVVideoWriter::finishInit()
00240 {
00241         int pixfmt_allowed = 0, k;
00242         if ( _videoCodec->pix_fmts )
00243         {
00244                 for ( k = 0; _videoCodec->pix_fmts[k] != PIX_FMT_NONE; k++ )
00245                 {
00246                         if ( _videoCodec->pix_fmts[k] == _out_pixelFormat )
00247                         {
00248                                 pixfmt_allowed = 1;
00249                                 break;
00250                         }
00251                 }
00252         }
00253         else
00254         {
00255                 // If a codec does not contain a list of supported pixel
00256                 // formats, just assume that _out_PixelFormat is valid
00257                 pixfmt_allowed = 1;
00258         }
00259         
00260         if ( !pixfmt_allowed )
00261         {
00262                 // av_get_pix_fmt_name requires lavu 51.3.0 or higher
00263                 TUTTLE_LOG_ERROR( "avWriter: pixel format " << av_get_pix_fmt_name(_out_pixelFormat) << " not available in codec" );
00264                 _out_pixelFormat = _videoCodec->pix_fmts[0];
00265                 TUTTLE_LOG_ERROR( "avWriter: auto-selecting " << av_get_pix_fmt_name(_out_pixelFormat) );
00266         }
00267         _stream->codec->pix_fmt     = _out_pixelFormat;
00268         
00269         if( !strcmp( _avFormatOptions->oformat->name, "mp4" ) || !strcmp( _avFormatOptions->oformat->name, "mov" ) || !strcmp( _avFormatOptions->oformat->name, "3gp" ) || !strcmp( _avFormatOptions->oformat->name, "flv" ) )
00270                 _stream->codec->flags |= CODEC_FLAG_GLOBAL_HEADER;
00271         
00272         av_dump_format( _avFormatOptions, 0, getFilename().c_str(), 1 );
00273         
00274         if( avcodec_open2( _stream->codec, _videoCodec, NULL ) < 0 )
00275         {
00276                 freeFormat();
00277                 BOOST_THROW_EXCEPTION( exception::Format()
00278                                                            << exception::user( "avWriter: unable to open codec." ) );
00279                 return false;
00280         }
00281         
00282         if( !( _ofmt->flags & AVFMT_NOFILE ) )
00283         {
00284                 if( avio_open2( &_avFormatOptions->pb, getFilename().c_str(),
00285                                                 AVIO_FLAG_WRITE, NULL, NULL ) < 0 )
00286                 {
00287                         freeFormat();
00288                         BOOST_THROW_EXCEPTION( exception::FileNotExist()
00289                                                                    << exception::user( "avWriter: unable to open file." ) );
00290                 }
00291         }
00292         
00293         int error = avformat_write_header( _avFormatOptions, NULL );
00294         if( error )
00295         {
00296                 TUTTLE_LOG_ERROR( libavError_toString( error) );
00297                 BOOST_THROW_EXCEPTION( exception::Format()
00298                                                            << exception::user( "avWriter: unable to write header." ) );
00299         }
00300         return true;
00301 }
00302 
00303 std::string LibAVVideoWriter::getErrorStr( const int errnum ) const
00304 {
00305         static const std::size_t errbuf_size = 2048;
00306         char errbuf[errbuf_size];
00307         av_strerror( errnum, errbuf, errbuf_size );
00308         return std::string( errbuf );
00309 }
00310 
00311 int LibAVVideoWriter::execute( boost::uint8_t* const in_buffer, const int in_width, const int in_height, const PixelFormat in_pixelFormat )
00312 {
00313         _statusCode = eWriterStatusIgnoreFinish;
00314         
00315         _statusCode = eWriterStatusCleanup;
00316         
00317         AVFrame* in_frame = avcodec_alloc_frame();
00318         avcodec_get_frame_defaults( in_frame );
00319         avpicture_fill( (AVPicture*)in_frame, in_buffer, in_pixelFormat, in_width, in_height );
00320 
00321         AVFrame* out_frame = avcodec_alloc_frame();
00322         avcodec_get_frame_defaults( out_frame );
00323         int out_picSize = avpicture_get_size( _out_pixelFormat, getWidth(), getHeight() );
00324         boost::uint8_t* out_buffer = (boost::uint8_t*) av_malloc( out_picSize );
00325         avpicture_fill( (AVPicture*) out_frame, out_buffer, _out_pixelFormat, getWidth(), getHeight() );
00326 
00327         _sws_context = sws_getCachedContext( _sws_context, in_width, in_height, in_pixelFormat, getWidth(), getHeight(), _out_pixelFormat, SWS_BICUBIC, NULL, NULL, NULL );
00328 
00329         TUTTLE_TLOG( TUTTLE_TRACE, "avWriter: input format: " << av_get_pix_fmt_name( in_pixelFormat ) << " -> output format: " << av_get_pix_fmt_name( _out_pixelFormat ) );
00330 
00331         if( !_sws_context )
00332         {
00333                 BOOST_THROW_EXCEPTION( exception::Failed()
00334                         << exception::user() + "libav-conversion failed (" + in_pixelFormat + "->" + _out_pixelFormat + ")." );
00335         }
00336         const int error = sws_scale( _sws_context, in_frame->data, in_frame->linesize, 0, getHeight(), out_frame->data, out_frame->linesize );
00337         if( error < 0 )
00338         {
00339                 BOOST_THROW_EXCEPTION( exception::Failed()
00340                         << exception::user() + "libav-conversion failed (" + in_pixelFormat + "->" + _out_pixelFormat + ")." );
00341         }
00342 
00343         int ret = 0;
00344         if( ( _avFormatOptions->oformat->flags & AVFMT_RAWPICTURE ) &&
00345                 ( _stream->codec->codec->id == AV_CODEC_ID_RAWVIDEO ) )
00346         {
00347                 //TUTTLE_TLOG( TUTTLE_TRACE, "RAW : " << sizeof( AVPicture ) );
00348                 AVPacket pkt;
00349                 av_init_packet( &pkt );
00350                 pkt.data         = (boost::uint8_t*) out_frame;
00351                 pkt.size         = sizeof( AVPicture );
00352                 pkt.pts          = av_rescale_q(out_frame->pts, _stream->codec->time_base, _stream->time_base);
00353                 pkt.stream_index = _stream->index;
00354                 pkt.flags       |= AV_PKT_FLAG_KEY;
00355                 
00356                 ret = av_interleaved_write_frame( _avFormatOptions, &pkt );
00357                 if ( ret < 0 )
00358                 {
00359                         BOOST_THROW_EXCEPTION( exception::File()
00360                                 << exception::user( "avWriter: error writing packet to file" ) );
00361                 }
00362         }
00363         else
00364         {
00365                 AVPacket pkt;
00366                 _hasFrame = 0;
00367                 av_init_packet( &pkt );
00368                 pkt.size = 0;
00369                 pkt.data = NULL;
00370                 pkt.stream_index = _stream->index;
00371 
00372                 if( ( _stream->codec->coded_frame ) &&
00373                     ( _stream->codec->coded_frame->pts != static_cast<boost::int64_t>( AV_NOPTS_VALUE ) ) )
00374                 {
00375                         pkt.pts = av_rescale_q( _stream->codec->coded_frame->pts, _stream->codec->time_base, _stream->time_base );
00376                         TUTTLE_TLOG( TUTTLE_TRACE, "avWriter: Video Frame PTS: " << pkt.pts );
00377                 }
00378                 else
00379                 {
00380                         TUTTLE_TLOG( TUTTLE_TRACE, "avWriter: Video Frame PTS: not set" );
00381                 }
00382                 if( _stream->codec->coded_frame &&
00383                     _stream->codec->coded_frame->key_frame )
00384                 {
00385                         pkt.flags |= AV_PKT_FLAG_KEY;
00386                 }
00387                 
00388                 out_frame->pts = pts;
00389                 out_frame->quality = _stream->codec->global_quality;
00390                 pts += _stream->codec->time_base.num;
00391                 ret = avcodec_encode_video2( _stream->codec, &pkt, out_frame, &_hasFrame );
00392                 if( ret < 0 )
00393                 {
00394                         TUTTLE_LOG_ERROR( "avWriter: error writing packet to file" );
00395                         TUTTLE_LOG_ERROR( getErrorStr(ret) );
00396                         return false;
00397                 }
00398 
00399                 
00400                 if( _hasFrame )
00401                 {
00402                         ret = av_interleaved_write_frame( _avFormatOptions, &pkt );
00403                         if ( ret < 0 )
00404                         {
00405                                 BOOST_THROW_EXCEPTION( exception::File()
00406                                         << exception::user( "avWriter: error writing packet to file" ) );
00407                         }
00408                 }
00409         }
00410 
00411         av_free( out_buffer );
00412         av_free( out_frame );
00413         av_free( in_frame );
00414         // in_buffer not free (function parameter)
00415 
00416         if( ret < 0 )
00417         {
00418                 BOOST_THROW_EXCEPTION( exception::File()
00419                         << exception::user( "avWriter: error writing frame to file." ) );
00420         }
00421 
00422         _statusCode = eWriterStatusSuccess;
00423         return true;
00424 }
00425 
00426 void LibAVVideoWriter::finish()
00427 {
00428         if( _statusCode == eWriterStatusIgnoreFinish )
00429                 return;
00430         
00431         int ret = 0;
00432 
00433         for( _hasFrame = 1; _hasFrame; )
00434         {
00435                 TUTTLE_TLOG( TUTTLE_TRACE, "encode last frames ..." );
00436                 AVPacket pkt;
00437                 av_init_packet( &pkt );
00438                 pkt.size = 0;
00439                 pkt.data = NULL;
00440                 pkt.stream_index = _stream->index;
00441                 
00442                 
00443                 ret = avcodec_encode_video2( _stream->codec, &pkt, NULL, &_hasFrame );
00444                 if( ret < 0 )
00445                 {
00446                         TUTTLE_LOG_ERROR( "avWriter: error writing packet to file" );
00447                         TUTTLE_LOG_ERROR( getErrorStr(ret) );
00448                         break;
00449                 }
00450                 
00451                 if( _hasFrame )
00452                 {
00453                         TUTTLE_LOG_ERROR( "write packet" );
00454                         ret = av_interleaved_write_frame( _avFormatOptions, &pkt );
00455                         if ( ret < 0 )
00456                         {
00457                                 BOOST_THROW_EXCEPTION( exception::File()
00458                                         << exception::user( "avWriter: error writing packet to file" ) );
00459                         }
00460                         av_free_packet( &pkt );
00461                 }
00462         }
00463         
00464         av_write_trailer( _avFormatOptions );
00465         avcodec_close( _stream->codec );
00466         if( !( _avFormatOptions->oformat->flags & AVFMT_NOFILE ) )
00467                 avio_close( _avFormatOptions->pb );
00468         freeFormat();
00469         
00470 }
00471 
00472 void LibAVVideoWriter::freeFormat()
00473 {
00474         avcodec_close( _stream->codec );
00475         for( int i = 0; i < static_cast<int>( _avFormatOptions->nb_streams ); ++i )
00476                 av_freep( &_avFormatOptions->streams[i] );
00477         av_free( _avFormatOptions );
00478         _avFormatOptions = 0;
00479         _stream          = 0;
00480 }
00481 
00482 }
00483 }
00484 }