TuttleOFX
1
|
00001 #include "AVWriterPluginFactory.hpp" 00002 #include "AVWriterPlugin.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/LibAVOptionsFactory.hpp> 00011 00012 00013 #include <tuttle/plugin/context/WriterPluginFactory.hpp> 00014 00015 #include <boost/algorithm/string/join.hpp> 00016 #include <boost/algorithm/string/split.hpp> 00017 #include <boost/algorithm/string/classification.hpp> 00018 00019 #include <string> 00020 #include <vector> 00021 00022 namespace tuttle { 00023 namespace plugin { 00024 namespace av { 00025 namespace writer { 00026 00027 /** 00028 * @brief Function called to describe the plugin main features. 00029 * @param[in, out] desc Effect descriptor 00030 */ 00031 void AVWriterPluginFactory::describe( OFX::ImageEffectDescriptor& desc ) 00032 { 00033 desc.setLabels( 00034 "TuttleAVWriter", 00035 "AVWriter", 00036 "Audio Video writer" ); 00037 desc.setPluginGrouping( "tuttle/image/io" ); 00038 00039 std::vector<std::string> supportedExtensions; 00040 { 00041 AVOutputFormat* oFormat = av_oformat_next( NULL ); 00042 while( oFormat != NULL ) 00043 { 00044 if( oFormat->extensions != NULL ) 00045 { 00046 using namespace boost::algorithm; 00047 const std::string extStr( oFormat->extensions ); 00048 std::vector<std::string> exts; 00049 split( exts, extStr, is_any_of(",") ); 00050 00051 // remove empty extensions... 00052 for( std::vector<std::string>::iterator it = exts.begin(); it != exts.end(); ) 00053 { 00054 if( it->size() == 0 ) 00055 it = exts.erase( it ); 00056 else 00057 ++it; 00058 } 00059 supportedExtensions.insert( supportedExtensions.end(), exts.begin(), exts.end() ); 00060 } 00061 oFormat = av_oformat_next( oFormat ); 00062 } 00063 } 00064 00065 desc.setDescription( "Video writer based on LibAV library\n\n" 00066 "Supported extensions: \n" + 00067 boost::algorithm::join( supportedExtensions, ", " ) 00068 ); 00069 00070 // add the supported contexts 00071 desc.addSupportedContext( OFX::eContextWriter ); 00072 desc.addSupportedContext( OFX::eContextGeneral ); 00073 00074 // add supported pixel depths 00075 desc.addSupportedBitDepth( OFX::eBitDepthUByte ); 00076 desc.addSupportedBitDepth( OFX::eBitDepthUShort ); 00077 desc.addSupportedBitDepth( OFX::eBitDepthFloat ); 00078 00079 // add supported extensions 00080 desc.addSupportedExtensions( supportedExtensions ); 00081 00082 // plugin flags 00083 desc.setRenderThreadSafety( OFX::eRenderInstanceSafe ); 00084 desc.setHostFrameThreading( false ); 00085 desc.setSupportsMultiResolution( false ); 00086 desc.setSupportsMultipleClipDepths( true ); 00087 desc.setSupportsTiles( kSupportTiles ); 00088 } 00089 00090 /** 00091 * @brief Function called to describe the plugin controls and features. 00092 * @param[in, out] desc Effect descriptor 00093 * @param[in] context Application context 00094 */ 00095 void AVWriterPluginFactory::describeInContext( OFX::ImageEffectDescriptor& desc, 00096 OFX::EContext context ) 00097 { 00098 LibAVVideoWriter writer; 00099 00100 OFX::ClipDescriptor* srcClip = desc.defineClip( kOfxImageEffectSimpleSourceClipName ); 00101 00102 srcClip->addSupportedComponent( OFX::ePixelComponentRGBA ); 00103 srcClip->addSupportedComponent( OFX::ePixelComponentRGB ); 00104 srcClip->addSupportedComponent( OFX::ePixelComponentAlpha ); 00105 srcClip->setSupportsTiles( kSupportTiles ); 00106 00107 // Create the mandated output clip 00108 OFX::ClipDescriptor* dstClip = desc.defineClip( kOfxImageEffectOutputClipName ); 00109 dstClip->addSupportedComponent( OFX::ePixelComponentRGBA ); 00110 dstClip->addSupportedComponent( OFX::ePixelComponentRGB ); 00111 dstClip->addSupportedComponent( OFX::ePixelComponentAlpha ); 00112 dstClip->setSupportsTiles( kSupportTiles ); 00113 00114 // Controls 00115 describeWriterParamsInContext( desc, context ); 00116 OFX::ChoiceParamDescriptor* bitDepth = static_cast<OFX::ChoiceParamDescriptor*>( desc.getParamDescriptor( kTuttlePluginBitDepth ) ); 00117 bitDepth->appendOption( kTuttlePluginBitDepth8 ); 00118 /// @todo: 16 bits 00119 bitDepth->setDefault( eTuttlePluginBitDepth8 ); 00120 bitDepth->setEnabled( false ); 00121 00122 OFX::BooleanParamDescriptor* premult = static_cast<OFX::BooleanParamDescriptor*>( desc.getParamDescriptor( kParamPremultiplied ) ); 00123 premult->setDefault( true ); 00124 00125 /// MAIN PRESET SELECTOR 00126 OFX::ChoiceParamDescriptor* mainPreset = desc.defineChoiceParam( kParamMainPreset ); 00127 mainPreset->setLabel( "Main Preset" ); 00128 mainPreset->appendOption( "custom", "Customized configuration" ); 00129 00130 std::vector<std::string> idList; 00131 std::vector<std::string> idLabelList; 00132 LibAVPreset::getPresetList( idList, idLabelList ); 00133 for( unsigned int it = 0; it < idList.size(); ++it ) 00134 { 00135 mainPreset->appendOption( idList.at( it ), idLabelList.at( it ) ); 00136 } 00137 00138 // Groups 00139 OFX::GroupParamDescriptor* formatGroup = desc.defineGroupParam( kParamFormatGroup ); 00140 OFX::GroupParamDescriptor* videoGroup = desc.defineGroupParam( kParamVideoGroup ); 00141 OFX::GroupParamDescriptor* audioGroup = desc.defineGroupParam( kParamAudioGroup ); 00142 OFX::GroupParamDescriptor* metaGroup = desc.defineGroupParam( kParamMetaGroup ); 00143 00144 formatGroup->setLabel( "Format" ); 00145 videoGroup->setLabel( "Video" ); 00146 audioGroup->setLabel( "Audio" ); 00147 metaGroup->setLabel( "Metadata" ); 00148 00149 formatGroup->setAsTab( ); 00150 videoGroup->setAsTab( ); 00151 audioGroup->setAsTab( ); 00152 metaGroup->setAsTab( ); 00153 00154 /// FORMAT PARAMETERS 00155 /// format preset 00156 OFX::ChoiceParamDescriptor* formatPreset = desc.defineChoiceParam( kParamFormatPreset ); 00157 formatPreset->setLabel( "Format Preset" ); 00158 formatPreset->appendOption( "custom", "Customized configuration" ); 00159 std::vector<std::string> idFormatList; 00160 std::vector<std::string> idFormatLabelList; 00161 LibAVFormatPreset::getPresetList( idFormatList, idFormatLabelList ); 00162 for( unsigned int it = 0; it < idFormatList.size(); ++it ) 00163 { 00164 formatPreset->appendOption( idFormatList.at( it ), idFormatLabelList.at( it ) ); 00165 } 00166 formatPreset->setParent( formatGroup ); 00167 00168 /// format list 00169 int default_format = 0; 00170 OFX::ChoiceParamDescriptor* format = desc.defineChoiceParam( kParamFormat ); 00171 for( std::vector<std::string>::const_iterator itShort = writer.getFormatsShort().begin(), 00172 itLong = writer.getFormatsLong().begin(), 00173 itEnd = writer.getFormatsShort().end(); 00174 itShort != itEnd; 00175 ++itShort, 00176 ++itLong ) 00177 { 00178 format->appendOption( *itShort, *itLong ); 00179 if( (*itShort) == "mp4" ) 00180 default_format = format->getNOptions() - 1; 00181 } 00182 format->setCacheInvalidation( OFX::eCacheInvalidateValueAll ); 00183 format->setDefault( default_format ); 00184 format->setParent( formatGroup ); 00185 00186 AVFormatContext* avFormatContext; 00187 avFormatContext = avformat_alloc_context(); 00188 addOptionsFromAVOption( desc, formatGroup, (void*)avFormatContext, AV_OPT_FLAG_ENCODING_PARAM, 0 ); 00189 avformat_free_context( avFormatContext ); 00190 00191 /// format parameters 00192 OFX::GroupParamDescriptor* formatDetailledGroup = desc.defineGroupParam( kParamFormatDetailledGroup ); 00193 formatDetailledGroup->setLabel( "Detailled" ); 00194 formatDetailledGroup->setAsTab( ); 00195 formatDetailledGroup->setParent( formatGroup ); 00196 00197 addOptionsFromAVOption( desc, formatDetailledGroup, writer.getFormatPrivOpts() ); 00198 00199 // fps parameters 00200 OFX::BooleanParamDescriptor* useCustomFps = desc.defineBooleanParam( kParamUseCustomFps ); 00201 useCustomFps->setLabel( "Override Fps" ); 00202 useCustomFps->setDefault( false ); 00203 useCustomFps->setHint( "Override the input Fps (Frames Per Second) with a custom Fps value." ); 00204 00205 OFX::DoubleParamDescriptor* customFps = desc.defineDoubleParam( kParamCustomFps ); 00206 customFps->setLabel( "Custom Fps" ); 00207 customFps->setDefault( 1.0 ); 00208 customFps->setHint( "Choose a custom value to override the Fps (Frames Per Second)." ); 00209 00210 /// VIDEO PARAMETERS 00211 /// video codec preset 00212 OFX::ChoiceParamDescriptor* videoPreset = desc.defineChoiceParam( kParamVideoPreset ); 00213 videoPreset->setLabel( "Video Preset" ); 00214 videoPreset->appendOption( "custom", "Customized configuration" ); 00215 00216 std::vector<std::string> idVideoList; 00217 std::vector<std::string> idVideoLabelList; 00218 LibAVVideoPreset::getPresetList( idVideoList, idVideoLabelList ); 00219 for( unsigned int it = 0; it < idVideoList.size(); ++it ) 00220 { 00221 videoPreset->appendOption( idVideoList.at( it ), idVideoLabelList.at( it ) ); 00222 } 00223 videoPreset->setParent( videoGroup ); 00224 00225 /// video codec list 00226 int default_codec = 0; 00227 OFX::ChoiceParamDescriptor* videoCodec = desc.defineChoiceParam( kParamVideoCodec ); 00228 for( std::vector<std::string>::const_iterator itShort = writer.getVideoCodecsShort().begin(), 00229 itLong = writer.getVideoCodecsLong().begin(), 00230 itEnd = writer.getVideoCodecsShort().end(); 00231 itShort != itEnd; 00232 ++itShort, 00233 ++itLong ) 00234 { 00235 videoCodec->appendOption( *itShort, *itLong ); 00236 if( (*itShort) == "mpeg4" ) 00237 default_codec = videoCodec->getNOptions() - 1; 00238 } 00239 videoCodec->setCacheInvalidation( OFX::eCacheInvalidateValueAll ); 00240 videoCodec->setDefault( default_codec ); 00241 videoCodec->setParent( videoGroup ); 00242 00243 /// video codec parameters 00244 OFX::ChoiceParamDescriptor* videoCodecPixelFmt = desc.defineChoiceParam( kParamVideoCodecPixelFmt ); 00245 videoCodecPixelFmt->setLabel( kParamVideoCodecPixelFmt ); 00246 videoCodecPixelFmt->setLabel( "Select the output video pixel type." ); 00247 00248 for( int pix_fmt = 0; pix_fmt < PIX_FMT_NB; pix_fmt++ ) 00249 { 00250 const AVPixFmtDescriptor *pix_desc = &av_pix_fmt_descriptors[pix_fmt]; 00251 if(!pix_desc->name) 00252 continue; 00253 videoCodecPixelFmt->appendOption( pix_desc->name ); 00254 } 00255 videoCodecPixelFmt->setParent( videoGroup ); 00256 00257 AVCodecContext* avCodecContext; 00258 #if LIBAVCODEC_VERSION_INT < AV_VERSION_INT( 53, 8, 0 ) 00259 avCodecContext = avcodec_alloc_context(); 00260 // deprecated in the same version 00261 //avCodecContext = avcodec_alloc_context2( AVMEDIA_TYPE_UNKNOWN ); 00262 #else 00263 AVCodec* avCodec = NULL; 00264 avCodecContext = avcodec_alloc_context3( avCodec ); 00265 #endif 00266 00267 addOptionsFromAVOption( desc, videoGroup, (void*)avCodecContext, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_VIDEO_PARAM, 0 ); 00268 00269 OFX::GroupParamDescriptor* videoDetailledGroup = desc.defineGroupParam( kParamVideoDetailledGroup ); 00270 videoDetailledGroup->setLabel( "Detailled" ); 00271 videoDetailledGroup->setAsTab( ); 00272 videoDetailledGroup->setParent( videoGroup ); 00273 00274 addOptionsFromAVOption( desc, videoDetailledGroup, writer.getVideoCodecPrivOpts() ); 00275 00276 /// AUDIO PARAMETERS 00277 /// audio codec preset 00278 OFX::ChoiceParamDescriptor* audioPreset = desc.defineChoiceParam( kParamAudioPreset ); 00279 audioPreset->setLabel( "Audio Preset" ); 00280 audioPreset->appendOption( "custom", "Customized configuration" ); 00281 00282 std::vector<std::string> idAudioList; 00283 std::vector<std::string> idAudioLabelList; 00284 LibAVAudioPreset::getPresetList( idAudioList, idAudioLabelList ); 00285 for( unsigned int it = 0; it < idAudioList.size(); ++it ) 00286 { 00287 audioPreset->appendOption( idAudioList.at( it ), idAudioLabelList.at( it ) ); 00288 } 00289 audioPreset->setParent( audioGroup ); 00290 00291 /// audio codec list 00292 int default_audio_codec = 0; 00293 OFX::ChoiceParamDescriptor* audioCodec = desc.defineChoiceParam( kParamAudioCodec ); 00294 for( std::vector<std::string>::const_iterator itShort = writer.getAudioCodecsShort().begin(), 00295 itLong = writer.getAudioCodecsLong().begin(), 00296 itEnd = writer.getAudioCodecsShort().end(); 00297 itShort != itEnd; 00298 ++itShort, 00299 ++itLong ) 00300 { 00301 audioCodec->appendOption( *itShort, *itLong ); 00302 if( (*itShort) == "pcm_s24be" ) 00303 default_audio_codec = audioCodec->getNOptions() - 1; 00304 } 00305 audioCodec->setCacheInvalidation( OFX::eCacheInvalidateValueAll ); 00306 audioCodec->setDefault( default_audio_codec ); 00307 audioCodec->setParent( audioGroup ); 00308 00309 /// audio codec parameters 00310 addOptionsFromAVOption( desc, audioGroup, (void*)avCodecContext, AV_OPT_FLAG_ENCODING_PARAM | AV_OPT_FLAG_AUDIO_PARAM, AV_OPT_FLAG_VIDEO_PARAM ); 00311 00312 OFX::GroupParamDescriptor* audioDetailledGroup = desc.defineGroupParam( kParamAudioDetailledGroup ); 00313 audioDetailledGroup->setLabel( "Detailled" ); 00314 audioDetailledGroup->setAsTab( ); 00315 audioDetailledGroup->setParent( audioGroup ); 00316 00317 addOptionsFromAVOption( desc, audioDetailledGroup, writer.getAudioCodecPrivOpts() ); 00318 00319 av_free( avCodecContext ); 00320 00321 /// METADATA PARAMETERS 00322 OFX::GroupParamDescriptor* metaDetailledGroup = desc.defineGroupParam( kParamMetaDetailledGroup ); 00323 metaDetailledGroup->setLabel( "Detailled" ); 00324 metaDetailledGroup->setAsTab( ); 00325 metaDetailledGroup->setParent( metaGroup ); 00326 } 00327 00328 /** 00329 * @brief Function called to create a plugin effect instance 00330 * @param[in] handle effect handle 00331 * @param[in] context Application context 00332 * @return plugin instance 00333 */ 00334 OFX::ImageEffect* AVWriterPluginFactory::createInstance( OfxImageEffectHandle handle, 00335 OFX::EContext context ) 00336 { 00337 return new AVWriterPlugin( handle ); 00338 } 00339 00340 } 00341 } 00342 } 00343 }