TuttleOFX  1
nodeDummy.cpp
Go to the documentation of this file.
00001 #include <tuttle/common/utils/global.hpp>
00002 #include <tuttle/common/exceptions.hpp>
00003 #include <tuttle/host/Core.hpp>
00004 #include <tuttle/host/ofx/OfxhImageEffectPlugin.hpp>
00005 
00006 #include <boost/algorithm/string/join.hpp>
00007 #include <boost/foreach.hpp>
00008 #include <boost/filesystem.hpp>
00009 #include <boost/algorithm/string.hpp>
00010 
00011 #include <iostream>
00012 #include <cstring>
00013 #include <algorithm>
00014 
00015 #include "nodeDummy.hpp"
00016 
00017 namespace sam {
00018 namespace samdo {
00019 
00020 bool Dummy::isDummyReaderNode( const std::string& nodeName )
00021 {
00022         return ( ( nodeName == READER_DUMMY_FULLNAME ) || ( nodeName == READER_DUMMY_NAME ) || ( nodeName == READER_DUMMY_SHORTNAME ) );
00023 }
00024 
00025 bool Dummy::isDummyWriterNode( const std::string& nodeName )
00026 {
00027         return ( ( nodeName == WRITER_DUMMY_FULLNAME ) || ( nodeName == WRITER_DUMMY_NAME ) || ( nodeName == WRITER_DUMMY_SHORTNAME ) );
00028 }
00029 
00030 bool Dummy::isDummyNode( const std::string& nodeName )
00031 {
00032         return ( isDummyReaderNode( nodeName ) || isDummyWriterNode( nodeName ) );
00033 }
00034 
00035 void Dummy::getFullName( std::string& inputNode )
00036 {
00037         if( isDummyReaderNode( inputNode ) )
00038         {
00039                 inputNode = READER_DUMMY_NAME;
00040                 return;
00041         }
00042         if( isDummyWriterNode( inputNode ) )
00043         {
00044                 inputNode = WRITER_DUMMY_NAME;
00045                 return;
00046         }
00047 }
00048 
00049 bpo::options_description Dummy::getInfoOptions()
00050 {
00051         bpo::options_description infoOptions;
00052         infoOptions.add_options()
00053                 ( kHelpOptionString, kHelpOptionMessage )
00054                 ( kVersionOptionString, kVersionOptionMessage )
00055                 ( kExpertOptionString, kExpertOptionMessage )
00056                 ( kPluginsOptionString, kPluginsOptionMessage )
00057                 ( kFormatOptionString, kFormatOptionMessage );
00058         return infoOptions;
00059 }
00060 
00061 bpo::options_description Dummy::getConfOptions()
00062 {
00063         bpo::options_description confOptions;
00064         confOptions.add_options()
00065                 ( kVerboseOptionString, kVerboseOptionMessage )
00066                 ( kIdOptionString, bpo::value<std::string > (), kIdOptionMessage )
00067                 ( kNbCoresOptionString, bpo::value<std::size_t > (), kNbCoresOptionMessage );
00068         return confOptions;
00069 }
00070 
00071 bpo::options_description Dummy::getOpenFXOptions()
00072 {
00073         bpo::options_description openFXOptions;
00074         openFXOptions.add_options()
00075                 ( kAttributesOptionString, kAttributesOptionMessage )
00076                 ( kPropertiesOptionString, kPropertiesOptionMessage )
00077                 ( kClipsOptionString, kClipsOptionMessage )
00078                 ( kClipOptionString, bpo::value<std::string > (), kClipOptionMessage )
00079                 ( kParametersOptionString, kParametersOptionMessage )
00080                 ( kParamInfosOptionString, bpo::value<std::string > (), kParamInfosOptionMessage )
00081                 ( kParamValuesOptionString, bpo::value<std::vector<std::string> >(), kParamValuesOptionMessage )
00082                 // for auto completion
00083                 ( kParametersReduxOptionString, kParametersReduxOptionMessage )
00084                 ( kParamTypeOptionString, bpo::value<std::string > (), kParamTypeOptionMessage )
00085                 ( kParamPossibleValuesOptionString, bpo::value<std::string > (), kParamPossibleValuesOptionMessage )
00086                 ( kParamDefaultOptionString, bpo::value<std::string > (), kParamDefaultOptionMessage )
00087                 ( kParamGroupOptionString, kParamGroupOptionMessage );
00088         return openFXOptions;
00089 }
00090 
00091 void Dummy::getCommandLineParameters( bpo::variables_map& node_vm, const std::vector<std::string>& nodeArgs )
00092 {
00093         // Declare the supported options.
00094         bpo::options_description infoOptions = getInfoOptions();
00095         bpo::options_description confOptions = getConfOptions();
00096         // describe openFX options
00097         bpo::options_description openfxOptions = getOpenFXOptions();
00098 
00099         bpo::positional_options_description param_values;
00100         param_values.add( kParamValuesOptionLongName, -1 );
00101         
00102         bpo::options_description all_options;
00103         all_options.add( infoOptions ).add( confOptions ).add( openfxOptions );
00104         
00105         bpo::store( bpo::command_line_parser( nodeArgs ).options( all_options ).positional( param_values ).run(), node_vm );
00106 }
00107 
00108 void Dummy::getParametersFromCommandLine( std::vector<std::string>& parameters, const std::vector<std::string>& nodeArgs )
00109 {
00110         bpo::variables_map node_vm;
00111         getCommandLineParameters( node_vm, nodeArgs );
00112         
00113         if( node_vm.count( kParamValuesOptionLongName ) )
00114         {
00115                 parameters = node_vm[kParamValuesOptionLongName].as< std::vector< std::string> > ();
00116         }
00117 }
00118 
00119 void Dummy::getPathsFromCommandLine( std::vector<std::string>& paths, const std::vector<std::string>& nodeArgs )
00120 {
00121         getParametersFromCommandLine( paths, nodeArgs );
00122         
00123         std::vector<std::string>::iterator it = paths.begin();
00124         for( ; it < paths.end(); it++ )
00125         {
00126                 if( (*it).find("=") != std::string::npos )
00127                 {
00128                         paths.erase( it );
00129                         it--;
00130                 }
00131         }
00132         if( paths.size() == 0 )
00133         {
00134                 paths.push_back( "./" );
00135         }
00136 }
00137 
00138 void Dummy::getExtensionsFromCommandLine( std::vector<std::string>& extensions, const std::vector<std::string>& nodeArgs )
00139 {
00140         getParametersFromCommandLine( extensions, nodeArgs );
00141         
00142         std::vector<std::string>::iterator it = extensions.begin();
00143         for( ; it < extensions.end(); it++ )
00144         {
00145                 if( std::strncmp( (*it).c_str() , "ext=" , 4 ) != 0 )
00146                 {
00147                         extensions.erase( it );
00148                         it--;
00149                 }
00150                 else
00151                 {
00152                         *it = (*it).erase( 0, 4 ); // erase ext=
00153                 }
00154         }
00155 }
00156 
00157 void Dummy::addDummyNodeInList( std::vector<std::string>& list )
00158 {
00159         list.push_back( READER_DUMMY_NAME );
00160         list.push_back( WRITER_DUMMY_NAME );
00161 }
00162 
00163 void Dummy::addFullNameDummyNodeInList( std::vector<std::string>& list )
00164 {
00165         list.push_back( READER_DUMMY_FULLNAME );
00166         list.push_back( WRITER_DUMMY_FULLNAME );
00167 }
00168 
00169 void Dummy::addShortNameDummyNodeInList( std::vector<std::string>& list )
00170 {
00171         list.push_back( READER_DUMMY_SHORTNAME );
00172         list.push_back( WRITER_DUMMY_SHORTNAME );
00173 }
00174 
00175 std::vector<std::string> Dummy::getAllSupportedNodes( const std::string& context )
00176 {
00177         const NodeList& nodeList = ttl::core().getImageEffectPluginCache().getPlugins();
00178         std::vector<std::string> listOfPlugins;
00179         
00180         BOOST_FOREACH( ttl::ofx::imageEffect::OfxhImageEffectPlugin* node, nodeList )
00181         {
00182                 try
00183                 {
00184                         const std::string pluginName = node->getRawIdentifier();
00185                         node->loadAndDescribeActions();
00186                         if( node->supportsContext( context ) )
00187                         {
00188                                 listOfPlugins.push_back( pluginName );
00189                         }
00190                 }
00191                 catch(...)
00192                 {
00193                         /// @todo Create a list of loading errors?
00194                 }
00195         }
00196         
00197         // sort results
00198         std::sort( listOfPlugins.begin(), listOfPlugins.end() );
00199         return listOfPlugins;
00200 }
00201 
00202 std::vector<std::string> Dummy::getSupportedExtensions( const std::string& context )
00203 {
00204         const NodeList& nodeList = ttl::core().getImageEffectPluginCache().getPlugins();
00205         std::vector<std::string> listOfExtensions;
00206         
00207         BOOST_FOREACH( ttl::ofx::imageEffect::OfxhImageEffectPlugin* node, nodeList )
00208         {
00209                 try
00210                 {
00211                         node->loadAndDescribeActions();
00212                         if( node->supportsContext( context ) )
00213                         {
00214                                 //TUTTLE_LOG_INFO( pluginName );
00215                                 if( node->getDescriptorInContext( context ).getProperties().hasProperty( kTuttleOfxImageEffectPropSupportedExtensions ) )
00216                                 {
00217                                         const tuttle::host::ofx::property::OfxhProperty& prop = node->getDescriptorInContext( context ).getProperties().fetchProperty( kTuttleOfxImageEffectPropSupportedExtensions );
00218         
00219                                         for( std::size_t n = 0; n < prop.getDimension(); ++n )
00220                                         {
00221                                                 listOfExtensions.push_back( prop.getStringValue( n ) );
00222                                         }
00223                                 }
00224                         }
00225                 }
00226                 catch(...)
00227                 {}
00228         }
00229         
00230         // sort results
00231         std::sort( listOfExtensions.begin(), listOfExtensions.end() );
00232         
00233         // delete similar extension
00234         listOfExtensions.erase( std::unique( listOfExtensions.begin(), listOfExtensions.end() ), listOfExtensions.end() );
00235         
00236         return listOfExtensions;
00237 }
00238 
00239 void Dummy::printAllSupportedNodes( const std::string& context )
00240 {
00241         BOOST_FOREACH( const std::string& pluginName, getAllSupportedNodes( context ) )
00242         {
00243                 TUTTLE_LOG_INFO( pluginName );
00244         }
00245 }
00246 
00247 void Dummy::printAllSupportedExtensions( const std::string& context )
00248 {
00249         TUTTLE_LOG_INFO( boost::algorithm::join( getSupportedExtensions( context ), "," ) );
00250 }
00251 
00252 void Dummy::displayHelp( const std::string& nodeFullName )
00253 {
00254         using namespace sam;
00255         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00256         
00257         TUTTLE_LOG_INFO( color->_blue << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std );
00258         TUTTLE_LOG_INFO( "" );
00259         TUTTLE_LOG_INFO( color->_blue << "NODE" << color->_std );
00260         TUTTLE_LOG_INFO( color->_green << "\tsam do " << nodeFullName << " - OpenFX node." << color->_std );
00261         TUTTLE_LOG_INFO( "" );
00262         TUTTLE_LOG_INFO( color->_blue << "DESCRIPTION" << color->_std );
00263         TUTTLE_LOG_INFO( color->_green << "\tnode type: dummy (specific to TuttleOFX)" << color->_std );
00264         // internal node help
00265         TUTTLE_LOG_INFO( "" );
00266         TUTTLE_LOG_INFO( "Dummy reader call specific reader detected by the extension of the sequence name." );
00267         TUTTLE_LOG_INFO( "" );
00268         TUTTLE_LOG_INFO( color->_blue << "ASSOCIATED PLUGINS" << color->_std );
00269         if( isDummyReaderNode( nodeFullName ) )
00270                 printAllSupportedNodes( kOfxImageEffectContextReader );
00271         if( isDummyWriterNode( nodeFullName ) )
00272                 printAllSupportedNodes( kOfxImageEffectContextWriter );
00273         TUTTLE_LOG_INFO( "" );
00274         TUTTLE_LOG_INFO( color->_blue << "SUPPORTED FORMATS" << color->_std );
00275         if( isDummyReaderNode( nodeFullName ) )
00276                 printAllSupportedExtensions( kOfxImageEffectContextReader );
00277         if( isDummyWriterNode( nodeFullName ) )
00278                 printAllSupportedExtensions( kOfxImageEffectContextWriter );
00279         TUTTLE_LOG_INFO( "" );
00280         TUTTLE_LOG_INFO( color->_blue << "PARAMETERS" << color->_std );
00281         TUTTLE_LOG_INFO( color->_green << "\t" << std::left << std::setw( 25 ) << "ext" << ": " << color->_std << " String\n\t  select extension from supported format list.");
00282         TUTTLE_LOG_INFO( "" );
00283         //TUTTLE_LOG_INFO( color->_blue << "CLIPS" << color->_std );
00284         //coutClipsWithDetails( currentNode );
00285 
00286         TUTTLE_LOG_INFO( "" );
00287         TUTTLE_LOG_INFO( color->_blue << "DISPLAY OPTIONS (override the process)" << color->_std );
00288         TUTTLE_LOG_INFO( getInfoOptions() );
00289         TUTTLE_LOG_INFO( color->_blue << "CONFIGURE PROCESS" << color->_std );
00290         TUTTLE_LOG_INFO( getConfOptions() );
00291 
00292         TUTTLE_LOG_INFO( "" );
00293 }
00294 
00295 void Dummy::displayExpertHelp( const std::string& nodeFullName )
00296 {
00297         using namespace sam;
00298         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00299         
00300         displayHelp( nodeFullName );
00301 
00302         TUTTLE_LOG_INFO( color->_blue << "EXPERT OPTIONS" << color->_std );
00303         TUTTLE_LOG_INFO( getOpenFXOptions() );
00304 }
00305 
00306 void Dummy::foundAssociateSpecificDummyNode( std::string& inputNode, const std::string& dummyNodeName, const NodeList& nodeList, const std::vector<std::string>& nodeArgs )
00307 {
00308         if( std::strcmp( inputNode.c_str(), dummyNodeName.c_str() ) )
00309                 return;
00310         
00311         bpo::variables_map node_vm;
00312         getCommandLineParameters( node_vm, nodeArgs );
00313         
00314         if( node_vm.count( kHelpOptionLongName ) )
00315         {
00316                 displayHelp( dummyNodeName );
00317                 exit( 0 );
00318         }
00319         if( node_vm.count( kExpertOptionLongName ) )
00320         {
00321                 displayExpertHelp( dummyNodeName );
00322                 exit( 0 );
00323         }
00324         if( node_vm.count( kPluginsOptionLongName ) )
00325         {
00326                 if( isDummyReaderNode( dummyNodeName ) )
00327                         printAllSupportedNodes( kOfxImageEffectContextReader );
00328                 if( isDummyWriterNode( dummyNodeName ) )
00329                         printAllSupportedNodes( kOfxImageEffectContextWriter );
00330                 exit( 0 );
00331         }
00332         
00333         if( node_vm.count( kFormatOptionLongName ) )
00334         {
00335                 if( isDummyReaderNode( dummyNodeName ) )
00336                         printAllSupportedExtensions( kOfxImageEffectContextReader );
00337                 if( isDummyWriterNode( dummyNodeName ) )
00338                         printAllSupportedExtensions( kOfxImageEffectContextWriter );
00339                 exit( 0 );
00340         }
00341         
00342         if( node_vm.count( kVersionOptionLongName ) )
00343         {
00344                 TUTTLE_LOG_INFO( "\tsam do " << dummyNodeName );
00345                 TUTTLE_LOG_INFO( "Version 1.0" );
00346                 TUTTLE_LOG_INFO( "" );
00347                 exit( 0 );
00348         }
00349 
00350         if( nodeArgs.size() == 0 )
00351         {
00352                 if( isDummyWriterNode( dummyNodeName ) )
00353                 {
00354                         inputNode = "tuttle.dummy";
00355                         return;
00356                 }
00357                 
00358                 BOOST_THROW_EXCEPTION( tuttle::exception::Value()
00359                                                            << tuttle::exception::user() + "specify and input name (file or sequence)." );
00360         }
00361         
00362         std::vector<std::string> paths;
00363         bool needRecursiveProcess = false;
00364         if( kParamValuesOptionLongName )
00365         {
00366                 paths = node_vm[kParamValuesOptionLongName].as< std::vector< std::string> > ();
00367                 BOOST_FOREACH( const std::string& basePath, paths )
00368                 {
00369                         //TUTTLE_LOG_VAR( TUTTLE_TRACE, basePath );
00370                         boost::filesystem::path p( basePath );
00371                         std::string inputExtension = p.extension().string();
00372                         boost::algorithm::to_lower( inputExtension );
00373                         if( inputExtension.size() )
00374                         {
00375                                 break;
00376                         }
00377                         else
00378                         {
00379                                 needRecursiveProcess = true;
00380                         }
00381                 }
00382         }
00383         else
00384         {
00385                 paths.push_back( "./" );
00386         }
00387 
00388         if( needRecursiveProcess )
00389         {
00390                 TUTTLE_LOG_INFO("recursive");
00391                 inputNode = "tuttle.dummy";
00392                 return;
00393         }
00394         
00395         boost::filesystem::path p( paths.at(0) );
00396         std::string inputExtension = p.extension().string();
00397         inputExtension = inputExtension.substr( 1 ); // remove '.' at begining
00398         unsigned int numberOfSupportedExtension = std::numeric_limits<unsigned int>::max();
00399         BOOST_FOREACH( ttl::ofx::imageEffect::OfxhImageEffectPlugin* node, nodeList )
00400         {
00401                 const std::string pluginName = node->getRawIdentifier();
00402                 if( boost::algorithm::find_first( pluginName, dummyNodeName ) )
00403                 {
00404                         tuttle::host::ofx::imageEffect::OfxhImageEffectPlugin* plugin = tuttle::host::core().getImageEffectPluginById( pluginName );
00405                         plugin->loadAndDescribeActions();
00406                         const tuttle::host::ofx::imageEffect::OfxhImageEffectPlugin::ContextSet contexts = plugin->getContexts();
00407                         const tuttle::host::ofx::property::OfxhSet& properties = plugin->getDescriptorInContext( *contexts.begin() ).getProperties();
00408                         if( properties.hasProperty( kTuttleOfxImageEffectPropSupportedExtensions ) )
00409                         {
00410                                 const tuttle::host::ofx::property::OfxhProperty& prop = properties.fetchProperty( kTuttleOfxImageEffectPropSupportedExtensions );
00411 
00412                                 for( std::size_t n = 0; n < prop.getDimension(); ++n )
00413                                 {
00414                                         //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, prop.getStringValue( n ), inputExtension );
00415                                         if( prop.getStringValue( n ) == inputExtension )
00416                                         {
00417                                                 //TUTTLE_TLOG( TUTTLE_TRACE, pluginName << " [" << prop.getDimension() << "] can read " << prop.getStringValue( n ) );
00418                                                 if( prop.getDimension() < numberOfSupportedExtension )
00419                                                 {
00420                                                         // Arbitrary solution...
00421                                                         // If we found multiple plugins that support the requested format,
00422                                                         // we select the plugin which supports the lowest number of formats.
00423                                                         // So by defaut, we select specialized plugin before
00424                                                         // plugin using generic libraries with all formats.
00425                                                         numberOfSupportedExtension = prop.getDimension();
00426                                                         inputNode = pluginName;
00427                                                 }
00428                                         }
00429                                 }
00430                         }
00431                 }
00432         }
00433         if( numberOfSupportedExtension == std::numeric_limits<unsigned int>::max() )
00434         {
00435                 BOOST_THROW_EXCEPTION( tuttle::exception::Value()
00436                                                            << tuttle::exception::user() + "Unsupported extension \"" + inputExtension + "\"." );
00437         }
00438         TUTTLE_LOG_WARNING( "Replace " << dummyNodeName << " with: " << inputNode );
00439 }
00440 
00441 void Dummy::foundAssociateDummyNode( std::string& inputNode, const std::vector<ttl::ofx::imageEffect::OfxhImageEffectPlugin*>& nodeList, const std::vector<std::string>& nodeArgs )
00442 {
00443         getFullName( inputNode );
00444         foundAssociateSpecificDummyNode( inputNode, READER_DUMMY_NAME, nodeList, nodeArgs );
00445         foundAssociateSpecificDummyNode( inputNode, WRITER_DUMMY_NAME, nodeList, nodeArgs );
00446 }
00447 
00448 }
00449 }