TuttleOFX  1
AVWriterPlugin.cpp
Go to the documentation of this file.
00001 #include "AVWriterPlugin.hpp"
00002 #include "AVWriterProcess.hpp"
00003 #include "AVWriterDefinitions.hpp"
00004 
00005 #include <libav/LibAVPreset.hpp>
00006 #include <libav/LibAVFormatPreset.hpp>
00007 #include <libav/LibAVVideoPreset.hpp>
00008 #include <libav/LibAVAudioPreset.hpp>
00009 #include <libav/LibAVVideoWriter.hpp>
00010 #include <libav/LibAVOptions.hpp>
00011 
00012 #include <boost/gil/gil_all.hpp>
00013 #include <boost/foreach.hpp>
00014 
00015 #include <cctype>
00016 
00017 namespace tuttle {
00018 namespace plugin {
00019 namespace av {
00020 namespace writer {
00021 
00022 void AVWriterPlugin::disableAVOptionsForCodecOrFormat( const std::vector<AVPrivOption>& avPrivOpts, const std::string& codec )
00023 {
00024         std::vector<OFX::GroupParam*> groups;
00025 
00026         BOOST_FOREACH( AVPrivOption opt, avPrivOpts )
00027         {
00028                 if( opt.o.unit && opt.o.type == AV_OPT_TYPE_FLAGS )
00029                 {
00030                         std::string name = "g_";
00031                         name += opt.class_name;
00032                         name += "_";
00033                         name += opt.o.unit;
00034                         
00035                         OFX::GroupParam* curOpt = fetchGroupParam( name );
00036                         curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00037                         
00038                         groups.push_back( curOpt );
00039                         continue;
00040                 }
00041                 if( opt.o.unit && opt.o.type == AV_OPT_TYPE_INT )
00042                 {
00043                         std::string name = opt.class_name;
00044                         name += "_";
00045                         name += opt.o.name;
00046                         
00047                         OFX::ChoiceParam* curOpt = fetchChoiceParam( name );
00048                         curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00049                         continue;
00050                 }
00051                 
00052                 std::string name = opt.class_name;
00053                 name += "_";
00054                 name += opt.o.name;
00055                 
00056                 switch( opt.o.type )
00057                 {
00058                         case AV_OPT_TYPE_FLAGS:
00059                         {
00060                                 OFX::BooleanParam* curOpt = fetchBooleanParam( name );
00061                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00062                                 break;
00063                         }
00064                         case AV_OPT_TYPE_INT:
00065                         case AV_OPT_TYPE_INT64:
00066                         {
00067                                 OFX::IntParam* curOpt = fetchIntParam( name );
00068                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00069                                 break;
00070                         }
00071                         case AV_OPT_TYPE_DOUBLE:
00072                         case AV_OPT_TYPE_FLOAT:
00073                         {
00074                                 OFX::DoubleParam* curOpt = fetchDoubleParam( name );
00075                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00076                                 break;
00077                         }
00078                         case AV_OPT_TYPE_STRING:
00079                         {
00080                                 OFX::StringParam* curOpt = fetchStringParam( name );
00081                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00082                                 break;
00083                         }
00084                         case AV_OPT_TYPE_RATIONAL:
00085                         {
00086                                 OFX::Int2DParam* curOpt = fetchInt2DParam( name );
00087                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00088                                 break;
00089                         }
00090                         case AV_OPT_TYPE_BINARY:
00091                         {
00092                                 OFX::StringParam* curOpt = fetchStringParam( name );
00093                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00094                                 break;
00095                         }
00096                         case AV_OPT_TYPE_CONST:
00097                         {
00098                                 break;
00099                         }
00100                         default:
00101                         {
00102                                 TUTTLE_LOG_WARNING( "AudioVideo: undefined type for " << opt.o.name );
00103                         }
00104                 }
00105         }
00106         
00107         BOOST_FOREACH( AVPrivOption opt, avPrivOpts )
00108         {
00109                 switch( opt.o.type )
00110                 {
00111                         case AV_OPT_TYPE_CONST:
00112                         {
00113                                 BOOST_FOREACH( OFX::GroupParam* g, groups )
00114                                 {
00115                                         std::string name = "g_";
00116                                         name += opt.class_name;
00117                                         name += "_";
00118                                         name += opt.o.unit;
00119                                         if( name == g->getName() )
00120                                         {
00121                                                 std::string name = "flags_";
00122                                                 name += opt.class_name;
00123                                                 name += "_";
00124                                                 name += opt.o.name;
00125                                                 
00126                                                 OFX::BooleanParam* curOpt = fetchBooleanParam( name );
00127                                                 curOpt->setIsSecretAndDisabled( !( opt.class_name == codec ) );
00128                                                 break;
00129                                         }
00130                                 }
00131                                 break;
00132                         }
00133                         default:
00134                         {
00135                                 break;
00136                         }
00137                 }
00138         }
00139 }
00140 
00141 void AVWriterPlugin::updatePixelFormat( const std::string& videoCodecName )
00142 {
00143         AVCodec* _videoCodec = avcodec_find_encoder_by_name( videoCodecName.c_str() );
00144         
00145         _paramVideoPixelFormat->resetOptions();
00146         if( _videoCodec->pix_fmts == 0 )
00147         {
00148                 for( int pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++ )
00149                 {
00150                         const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[pix_fmt];
00151                         if(!pix_desc->name)
00152                                 continue;
00153                         _paramVideoPixelFormat->appendOption( pix_desc->name );
00154                 }
00155                 return;
00156         }
00157         
00158         int i = 0;
00159         while( _videoCodec->pix_fmts[i] != -1 )
00160         {
00161                 const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[ _videoCodec->pix_fmts[i] ];
00162                 _paramVideoPixelFormat->appendOption( pix_desc->name );
00163                 i++;
00164         }
00165 }
00166 
00167 AVWriterPlugin::AVWriterPlugin( OfxImageEffectHandle handle )
00168         : AVOptionPlugin( handle )
00169         , _initWriter ( false )
00170 {
00171         // We want to render a sequence
00172         setSequentialRender( true );
00173 
00174         _paramFormat     = AVOptionPlugin::fetchChoiceParam( kParamFormat );
00175         _paramVideoCodec = fetchChoiceParam( kParamVideoCodec );
00176         _paramAudioCodec = fetchChoiceParam( kParamAudioCodec );
00177         
00178         _paramMainPreset       = fetchChoiceParam( kParamMainPreset );
00179         _paramFormatPreset     = fetchChoiceParam( kParamFormatPreset );
00180         _paramVideoCodecPreset = fetchChoiceParam( kParamVideoPreset );
00181         _paramAudioCodecPreset = fetchChoiceParam( kParamAudioPreset );
00182         
00183         _paramUseCustomFps     = fetchBooleanParam( kParamUseCustomFps );
00184         _paramCustomFps        = fetchDoubleParam( kParamCustomFps );
00185         
00186         _paramVideoPixelFormat = fetchChoiceParam( kParamVideoCodecPixelFmt );
00187         
00188         std::string formatName = _writer.getFormatsShort( ).at(_paramFormat->getValue() );
00189         disableAVOptionsForCodecOrFormat( _writer.getFormatPrivOpts(), formatName );
00190         
00191         std::string videoCodecName = _writer.getVideoCodecsShort( ).at(_paramVideoCodec->getValue() );
00192         disableAVOptionsForCodecOrFormat( _writer.getVideoCodecPrivOpts(), videoCodecName );
00193         
00194         updatePixelFormat( videoCodecName );
00195         
00196         std::string audioCodecName = _writer.getAudioCodecsShort( ).at(_paramAudioCodec->getValue() );
00197         disableAVOptionsForCodecOrFormat( _writer.getAudioCodecPrivOpts(), audioCodecName );
00198 }
00199 
00200 AVProcessParams AVWriterPlugin::getProcessParams()
00201 {
00202         AVProcessParams params;
00203 
00204         params._filepath = _paramFilepath->getValue();
00205         params._format = _paramFormat->getValue();
00206         params._videoCodec                     = _paramVideoCodec        ->getValue();
00207         params._audioCodec                     = _paramAudioCodec        ->getValue();
00208         params._videoPixelFormat               = static_cast<PixelFormat>( _paramVideoPixelFormat->getValue() );
00209         
00210         _writer.setVideoCodec( params._videoCodec );
00211 
00212         return params;
00213 }
00214 
00215 void AVWriterPlugin::changedParam( const OFX::InstanceChangedArgs& args, const std::string& paramName )
00216 {
00217         WriterPlugin::changedParam( args, paramName );
00218         
00219         if( paramName == kParamFormat )
00220         {
00221                 std::string formatName = _writer.getFormatsShort( ).at(_paramFormat->getValue() );
00222                 disableAVOptionsForCodecOrFormat( _writer.getFormatPrivOpts(), formatName );
00223         }
00224         if( paramName == kParamVideoCodec )
00225         {
00226                 std::string videoCodecName = _writer.getVideoCodecsShort( ).at(_paramVideoCodec->getValue() );
00227                 disableAVOptionsForCodecOrFormat( _writer.getVideoCodecPrivOpts(), videoCodecName );
00228                 updatePixelFormat( videoCodecName );
00229         }
00230         if( paramName == kParamAudioCodec )
00231         {
00232                 std::string codecName = _writer.getAudioCodecsShort( ).at(_paramAudioCodec->getValue() );
00233                 disableAVOptionsForCodecOrFormat( _writer.getAudioCodecPrivOpts(), codecName );
00234         }
00235         
00236         if( paramName == kParamMainPreset )
00237         {
00238                 //TUTTLE_LOG_TRACE( "preset change " << _paramMainPreset->getValue() );
00239                 if( _paramMainPreset->getValue() == 0 )
00240                         return;
00241                 
00242                 std::vector<std::string> idList;
00243                 std::vector<std::string> idLabelList;
00244                 LibAVPreset::getPresetList( idList, idLabelList );
00245                 
00246                 LibAVPreset p( idList.at( _paramMainPreset->getValue() - 1 ) );
00247                 
00248                 std::vector<std::string> idFormatList;
00249                 LibAVFormatPreset::getPresetList( idFormatList );
00250 
00251                 std::vector<std::string> idVideoList;
00252                 LibAVVideoPreset::getPresetList( idVideoList );
00253                 
00254                 std::vector<std::string> idAudioList;
00255                 LibAVAudioPreset::getPresetList( idAudioList);
00256                 
00257                 int formatIndex = 0;
00258                 int videoIndex  = 0;
00259                 int audioIndex  = 0;
00260                 for( unsigned int id = 0; id < idFormatList.size(); id++ )
00261                 {
00262                         if( idFormatList.at( id ) == p.getFormatID() )
00263                         {
00264                                 formatIndex = id + 1;
00265                                 break;
00266                         }
00267                 }
00268                 
00269                 for( unsigned int id = 0; id < idVideoList.size(); id++ )
00270                 {
00271                         if( idVideoList.at( id ) == p.getVideoID() )
00272                         {
00273                                 videoIndex = id + 1;
00274                                 break;
00275                         }
00276                 }
00277                 
00278                 
00279                 for( unsigned int id = 0; id < idAudioList.size(); id++ )
00280                 {
00281                         if( idAudioList.at( id ) == p.getAudioID() )
00282                         {
00283                                 audioIndex = id + 1;
00284                                 break;
00285                         }
00286                 }
00287                 /*
00288                 TUTTLE_LOG_INFO( "set format at " << formatIndex );
00289                 TUTTLE_LOG_INFO( "set video at " << formatIndex );
00290                 TUTTLE_LOG_INFO( "set audio at " << formatIndex );*/
00291                 
00292                 _paramFormatPreset->setValue( formatIndex );
00293                 _paramVideoCodecPreset->setValue( videoIndex );
00294                 _paramAudioCodecPreset->setValue( audioIndex );
00295         }
00296         
00297         if( paramName == kParamFormatPreset )
00298         {
00299                 //TUTTLE_LOG_INFO( "preset change " << _paramFormatPreset->getValue() );
00300                 if( _paramFormatPreset->getValue() == 0 )
00301                         return;
00302                 std::vector<std::string> idFormatList;
00303                 LibAVFormatPreset::getPresetList( idFormatList );
00304                 
00305                 LibAVFormatPreset p( idFormatList.at( _paramFormatPreset->getValue() - 1 ) );
00306                 setParameters( p.getParameters() );
00307         }
00308         
00309         if( paramName == kParamVideoPreset )
00310         {
00311                 if( _paramVideoCodecPreset->getValue() == 0 )
00312                         return;
00313                 std::vector<std::string> idVideoList;
00314                 LibAVVideoPreset::getPresetList( idVideoList );
00315                 
00316                 LibAVVideoPreset p( idVideoList.at( _paramVideoCodecPreset->getValue() - 1 ) );
00317                 setParameters( p.getParameters() );
00318         }
00319         
00320         if( paramName == kParamAudioPreset )
00321         {
00322                 if( _paramAudioCodecPreset->getValue() == 0 )
00323                         return;
00324                 std::vector<std::string> idAudioList;
00325                 LibAVAudioPreset::getPresetList( idAudioList);
00326                 
00327                 LibAVAudioPreset p( idAudioList.at( _paramAudioCodecPreset->getValue() - 1 ) );
00328                 setParameters( p.getParameters() );
00329         }
00330 }
00331 
00332 void AVWriterPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences )
00333 {
00334         // Need to be computed at each frame
00335         clipPreferences.setOutputFrameVarying( true );
00336 }
00337 
00338 bool AVWriterPlugin::isIdentity( const OFX::RenderArguments& args, OFX::Clip*& identityClip, OfxTime& identityTime )
00339 {
00340         return WriterPlugin::isIdentity( args, identityClip, identityTime );
00341 }
00342 
00343 void AVWriterPlugin::beginSequenceRender( const OFX::BeginSequenceRenderArguments& args )
00344 {
00345         _initWriter = false;
00346         WriterPlugin::beginSequenceRender( args );
00347         
00348         AVProcessParams params = getProcessParams();
00349         
00350         //TUTTLE_LOG_VAR( TUTTLE_WARNING, _clipSrc->getFrameRate() );
00351         
00352         _writer.setFilename    ( params._filepath );
00353         _writer.setFormat      ( params._format );
00354         _writer.setVideoCodec  ( params._videoCodec );
00355         if( _paramUseCustomFps->getValue() )
00356         {
00357                 _writer.setFps( _paramCustomFps->getValue() );
00358         }
00359         else
00360         {
00361                 _writer.setFps( _clipSrc->getFrameRate() );
00362         }
00363         _writer.setAspectRatio ( _clipSrc->getPixelAspectRatio() );
00364         _writer.setPixelFormat ( params._videoPixelFormat );
00365 }
00366 
00367 /**
00368  * @brief The overridden render function
00369  * @param[in]   args     Rendering parameters
00370  */
00371 void AVWriterPlugin::render( const OFX::RenderArguments& args )
00372 {
00373         WriterPlugin::render( args );
00374         
00375         //OfxRangeD range = args.frameRange;
00376         const OfxRectI bounds = _clipSrc->getPixelRod( args.time, args.renderScale );
00377         _writer.setWidth ( bounds.x2 - bounds.x1 );
00378         _writer.setHeight( bounds.y2 - bounds.y1 );
00379         
00380         if( !_initWriter )
00381         {
00382                 _writer.start( );
00383         
00384                 // set Format parameters
00385                 AVFormatContext* avFormatContext;
00386                 avFormatContext = avformat_alloc_context();
00387                 setParameters( _writer, eAVParamFormat, (void*)avFormatContext, AV_OPT_FLAG_ENCODING_PARAM, 0 );
00388                 
00389                 std::string formatName = _writer.getFormatsShort( ).at(_paramFormat->getValue() );
00390                 setParameters( _writer, eAVParamFormat, _writer.getFormatPrivOpts(), formatName );
00391                 
00392                 // set Video Codec parameters
00393                 AVCodecContext* avCodecContext;
00394                 
00395         #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 53, 8, 0 )
00396                 avCodecContext = avcodec_alloc_context();
00397                 // deprecated in the same version
00398                 //avCodecContext = avcodec_alloc_context2( AVMEDIA_TYPE_UNKNOWN );
00399         #else
00400                 AVCodec* avCodec = NULL;
00401                 avCodecContext = avcodec_alloc_context3( avCodec );
00402         #endif
00403                 setParameters( _writer, eAVParamVideo, (void*)avCodecContext, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM, 0 );
00404                 
00405                 std::string codecName = _writer.getVideoCodecsShort( ).at(_paramVideoCodec->getValue() );
00406                 setParameters( _writer, eAVParamVideo, _writer.getVideoCodecPrivOpts(), codecName );
00407                 
00408                 // set Audio Codec parameters
00409                 //codecName = _writer.getAudioCodecsShort( ).at(_paramAudioCodec->getValue() );
00410                 //setParameters( _writer, eAVParamAudio, _writer.getAudioCodecPrivOpts(), codecName );
00411                 
00412                 _writer.finishInit();
00413                 
00414                 _initWriter = true;
00415         }
00416         
00417         doGilRender<AVWriterProcess>( *this, args );
00418 }
00419 
00420 void AVWriterPlugin::endSequenceRender( const OFX::EndSequenceRenderArguments& args )
00421 {
00422         _writer.finish();
00423         _initWriter = false;
00424 }
00425 
00426 }
00427 }
00428 }
00429 }