TuttleOFX  1
main.cpp
Go to the documentation of this file.
00001 #include "commandLine.hpp"
00002 #include "global.hpp"
00003 #include "nodeDummy.hpp"
00004 
00005 #include <sam/common/node.hpp>
00006 #include <sam/common/node_io.hpp>
00007 #include <sam/common/options.hpp>
00008 #include <sam/common/utility.hpp>
00009 
00010 #include <tuttle/common/exceptions.hpp>
00011 
00012 #include <tuttle/host/attribute/expression.hpp>
00013 #include <tuttle/host/Graph.hpp>
00014 
00015 #include <boost/program_options.hpp>
00016 #include <boost/regex.hpp>
00017 #include <boost/algorithm/string/split.hpp>
00018 #include <boost/foreach.hpp>
00019 #include <boost/filesystem.hpp>
00020 
00021 #include <detector.hpp>
00022 
00023 
00024 namespace bpo = boost::program_options;
00025 namespace ttl = tuttle::host;
00026 
00027 namespace bfs = boost::filesystem;
00028 
00029 
00030 //namespace logging = boost::log;
00031 
00032 void displayHelp( bpo::options_description &infoOptions, bpo::options_description &confOptions )
00033 {
00034         using namespace sam;
00035         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00036         
00037         TUTTLE_LOG_INFO( std::left << color->_blue << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std );
00038         TUTTLE_LOG_INFO( "" );
00039         TUTTLE_LOG_INFO( color->_blue << "NAME" << color->_std );
00040         TUTTLE_LOG_INFO( color->_green << "\tsam do - A command line to execute a list of OpenFX nodes." << color->_std << std::endl );
00041         TUTTLE_LOG_INFO( "" );
00042         TUTTLE_LOG_INFO( color->_blue << "SYNOPSIS" << color->_std );
00043         TUTTLE_LOG_INFO( "\tsam do [options]... [// node [node-options]... [[param=]value]...]... [// [options]...]" << std::endl );
00044         TUTTLE_LOG_INFO( "" );
00045         TUTTLE_LOG_INFO( color->_blue << "DESCRIPTION" << color->_std );
00046         TUTTLE_LOG_INFO( color->_green << "\tA command line to execute a list of OpenFX nodes." << color->_std );
00047         TUTTLE_LOG_INFO( color->_green << "\tUse the sperarator // to pipe images between nodes." << color->_std << std::endl );
00048         TUTTLE_LOG_INFO( "" );
00049         TUTTLE_LOG_INFO( color->_blue << "EXAMPLES" << color->_std << std::left );
00050         SAM_EXAMPLE_TITLE_COUT( "Plugins options" );
00051         SAM_EXAMPLE_LINE_COUT( "Plugin list: ", "sam do --nodes" );
00052         SAM_EXAMPLE_LINE_COUT( "Plugin help: ", "sam do blur -h" );
00053 
00054         SAM_EXAMPLE_TITLE_COUT( "Generators and viewers" );
00055         SAM_EXAMPLE_LINE_COUT ( "Viewer: ", "sam do reader in.@.dpx // viewer" );
00056         SAM_EXAMPLE_LINE_COUT ( "Print: ", "sam do reader in.@.dpx // print color=full16ansi" );
00057         SAM_EXAMPLE_LINE_COUT ( "Constant generator: ", "sam do constant                // viewer" );
00058         SAM_EXAMPLE_LINE_COUT ( "White constant generator: ", "sam do constant color=1,1,1,1  // viewer" );
00059         SAM_EXAMPLE_LINE_COUT ( "HD constant generator: ", "sam do constant size=1920,1080 // viewer" );
00060         SAM_EXAMPLE_LINE_COUT ( "Checkerboard generator: ", "sam do checkerboard            // viewer" );
00061         SAM_EXAMPLE_LINE_COUT ( "Checkerboard generator: ", "sam do checkerboard width=500  // viewer" );
00062         SAM_EXAMPLE_LINE_COUT ( "Checkerboard generator: ", "sam do checkerboard width=1920 ratio=2.35 // viewer" );
00063         /*
00064          SAM_EXAMPLE_LINE_COUT ( "Colorgradient generator: "  , "sam do colorgradient point0=1190,424 color0=0.246,0.44,0.254,1 \\" );
00065          SAM_EXAMPLE_LINE_COUT ( " "                      , "                     point1=458,726  color1=0.396,0.193,0.444,1 format=HD // viewer" );
00066          */
00067         SAM_EXAMPLE_LINE_COUT ( "Text writing: ", "sam do constant // text text=\"hello\" size=80 // viewer" );
00068 
00069         SAM_EXAMPLE_TITLE_COUT( "Image sequence conversion and creation" );
00070         SAM_EXAMPLE_LINE_COUT ( "Convert Image: ", "sam do reader in.dpx // writer out.jpg" );
00071         SAM_EXAMPLE_LINE_COUT ( "Convert Sequence: ", "sam do reader in.####.dpx // writer out.####.jpg" );
00072         SAM_EXAMPLE_LINE_COUT ( "Select a range: ", "sam do reader in.####.dpx // writer out.####.jpg // --range=10,100" );
00073         SAM_EXAMPLE_LINE_COUT ( "", "r and w are shortcuts for reader and writer" );
00074 
00075         SAM_EXAMPLE_TITLE_COUT( "Geometry processing during conversion" );
00076         SAM_EXAMPLE_LINE_COUT ( "Crop: ", "sam do reader in.####.dpx // crop x1=20 x2=1000 y1=10 y2=300 // writer out.jpg" );
00077         SAM_EXAMPLE_LINE_COUT ( "Fill: ", "sam do reader in.####.dpx // crop y1=10 y2=1060 mode=fill color=0.43,0.67,0.50 // writer out.jpg" );
00078         SAM_EXAMPLE_LINE_COUT ( "Resize: ", "sam do reader in.####.dpx // resize size=1920,1080 // writer out.####.jpg" );
00079         SAM_EXAMPLE_LINE_COUT ( "Upscaling: ", "sam do reader in.####.dpx // resize size=1920,1080 filter=lanczos  // writer out.####.jpg" );
00080         SAM_EXAMPLE_LINE_COUT ( "Downscaling: ", "sam do reader in.####.dpx // resize size=720,576   filter=mitchell // writer out.####.jpg" );
00081 
00082         SAM_EXAMPLE_TITLE_COUT( "Color processing during conversion" );
00083         SAM_EXAMPLE_LINE_COUT ( "Lut :", "sam do reader in.####.dpx // lut lutFile.3dl // writer out.jpg" );
00084         SAM_EXAMPLE_LINE_COUT ( "CTL: ", "sam do reader in.####.dpx // ctl file=ctlCode.ctl // writer out.####.jpg" );
00085         SAM_EXAMPLE_LINE_COUT ( "Gamma: ", "sam do reader in.####.dpx // gamma master=2.2 // writer out.####.jpg" );
00086 
00087         SAM_EXAMPLE_TITLE_COUT( "Image Sequence Numbering" );
00088         SAM_EXAMPLE_LINE_COUT ( "Frames with or without padding: ", "image.@.jpg" );
00089         SAM_EXAMPLE_LINE_COUT ( "Frames 1 to 100 padding 4: ", "image.####.jpg -or- image.@.jpg" );
00090         SAM_EXAMPLE_LINE_COUT ( "Frames 1 to 100 padding 5: ", "image.#####.jpg" );
00091         SAM_EXAMPLE_LINE_COUT ( "Printf style padding 4: ", "image.%04d.jpg" );
00092         SAM_EXAMPLE_LINE_COUT ( "All Frames in Directory: ", "/path/to/directory" );
00093 
00094         SAM_EXAMPLE_TITLE_COUT( "Processing options" );
00095         SAM_EXAMPLE_LINE_COUT ( "Range process: ", "sam do reader in.@.dpx // writer out.@.exr // --range 50,100" );
00096         SAM_EXAMPLE_LINE_COUT ( "Single process: ", "sam do reader in.@.dpx // writer out.@.exr // --range 59" );
00097         SAM_EXAMPLE_LINE_COUT ( "Multiple CPUs: ", "sam do reader in.@.dpx // writer out.@.exr // --nb-cores 4" );
00098         SAM_EXAMPLE_LINE_COUT ( "Continues whatever happens: ", "sam do reader in.@.dpx // writer out.@.exr // --continueOnError" );
00099 
00100         TUTTLE_LOG_INFO( "" );
00101         TUTTLE_LOG_INFO( color->_blue << "DISPLAY OPTIONS (replace the process)" << color->_std );
00102         TUTTLE_LOG_INFO( infoOptions );
00103         TUTTLE_LOG_INFO( color->_blue << "CONFIGURE PROCESS" << color->_std );
00104         TUTTLE_LOG_INFO( confOptions );
00105 
00106 }
00107 
00108 void displayHelp( bpo::options_description &infoOptions, bpo::options_description &confOptions, bpo::options_description &expertOptions )
00109 {
00110         using namespace sam;
00111         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00112         
00113         displayHelp( infoOptions, confOptions );
00114 
00115         TUTTLE_LOG_INFO( color->_blue << "EXPERT OPTIONS" << color->_std );
00116         TUTTLE_LOG_INFO( expertOptions );
00117 }
00118 
00119 void displayNodeHelp( std::string& nodeFullName, ttl::Graph::Node& currentNode, bpo::options_description &infoOptions, bpo::options_description &confOptions )
00120 {
00121         using namespace sam;
00122         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00123         
00124         TUTTLE_LOG_INFO( color->_blue << "TuttleOFX project [" << kUrlTuttleofxProject << "]" << color->_std );
00125         TUTTLE_LOG_INFO( "" );
00126         TUTTLE_LOG_INFO( color->_blue << "NODE" << color->_std );
00127         TUTTLE_LOG_INFO( color->_green << "\tsam do " << nodeFullName << " - OpenFX node." << color->_std );
00128         TUTTLE_LOG_INFO( "" );
00129         TUTTLE_LOG_INFO( color->_blue << "DESCRIPTION" << color->_std );
00130         TUTTLE_LOG_INFO( color->_green << "\tnode type: " << ttl::mapNodeTypeEnumToString( currentNode.getNodeType() ) << color->_std );
00131         // internal node help
00132         if( currentNode.getNodeType() == ttl::INode::eNodeTypeImageEffect )
00133         {
00134                 if( currentNode.asImageEffectNode().getDescriptor().getProperties().hasProperty( kOfxImageEffectPluginPropGrouping ) )
00135                 {
00136                         TUTTLE_LOG_INFO( "\t" << color->_green << currentNode.asImageEffectNode().getPluginGrouping() << color->_std );
00137                 }
00138         }
00139         TUTTLE_LOG_INFO( "" );
00140         if( currentNode.getProperties().hasProperty( kOfxPropPluginDescription ) )
00141         {
00142                 TUTTLE_LOG_INFO( currentNode.getProperties().fetchStringProperty( kOfxPropPluginDescription ).getValue( 0 ) );
00143         }
00144         else
00145         {
00146                 TUTTLE_LOG_INFO( "\tNo description." );
00147         }
00148         TUTTLE_LOG_INFO( "" );
00149         TUTTLE_LOG_INFO( color->_blue << "PARAMETERS" << color->_std );
00150         coutParametersWithDetails( currentNode );
00151         TUTTLE_LOG_INFO( "" );
00152         TUTTLE_LOG_INFO( color->_blue << "CLIPS" << color->_std );
00153         coutClipsWithDetails( currentNode );
00154 
00155         TUTTLE_LOG_INFO( "" );
00156         TUTTLE_LOG_INFO( color->_blue << "DISPLAY OPTIONS (override the process)" << color->_std );
00157         TUTTLE_LOG_INFO( infoOptions );
00158         TUTTLE_LOG_INFO( color->_blue << "CONFIGURE PROCESS" << color->_std );
00159         TUTTLE_LOG_INFO( confOptions );
00160 
00161         TUTTLE_LOG_INFO( "" );
00162 }
00163 
00164 void displayNodeHelp( std::string& nodeFullName, ttl::Graph::Node& currentNode, bpo::options_description &infoOptions, bpo::options_description &confOptions, bpo::options_description &expertOptions )
00165 {
00166         using namespace sam;
00167         boost::shared_ptr<tuttle::common::Color>  color( tuttle::common::Color::get() );
00168         
00169         displayNodeHelp( nodeFullName, currentNode, infoOptions, confOptions );
00170 
00171         TUTTLE_LOG_INFO( color->_blue << "EXPERT OPTIONS" << color->_std );
00172         TUTTLE_LOG_INFO( expertOptions );
00173 }
00174 
00175 int addListOfSequencesInListOfProcess( boost::ptr_vector<sequenceParser::FileObject>& inputList, boost::ptr_vector<sequenceParser::FileObject>& outputList, const std::vector<std::string>& extensions )
00176 {
00177         sam::samdo::Dummy dummy;
00178         std::vector<std::string> exts = dummy.getSupportedExtensions( kOfxImageEffectContextReader );
00179         int count = 0;
00180         
00181         BOOST_FOREACH( sequenceParser::FileObject& fo, inputList )
00182         {
00183                 bool isSupportedExtension = false;
00184                 std::string filename;
00185                 std::string ext;
00186                 if( fo.getMaskType() == sequenceParser::eMaskTypeSequence )
00187                 {
00188                         filename = static_cast<const sequenceParser::Sequence&>(fo).getAbsoluteStandardPattern();
00189                 }
00190                 if( fo.getMaskType() == sequenceParser::eMaskTypeFile )
00191                 {
00192                         filename = static_cast<const sequenceParser::File&>(fo).getAbsoluteFilename();
00193                 }
00194                 ext = bfs::path( filename ).extension().string();
00195                 ext.erase( 0, 1 ); // erase the dot
00196 
00197                 BOOST_FOREACH( std::string& e, exts )
00198                 {
00199                         if( e == ext )
00200                         {
00201                                 if( extensions.size() )
00202                                 {
00203                                         BOOST_FOREACH( const std::string& filterExt, extensions )
00204                                         {
00205                                                 if( filterExt == ext )
00206                                                 {
00207                                                         isSupportedExtension = true;
00208                                                 }
00209                                         }
00210                                 }
00211                                 else
00212                                 {
00213                                         isSupportedExtension = true;
00214                                 }
00215                         }
00216                 }
00217                 if( isSupportedExtension )
00218                 {
00219                         count++;
00220                         outputList.push_back( new_clone( fo ) );
00221                 }
00222         }
00223         return count;
00224 }
00225 
00226 std::string getAbsoluteFilename( const sequenceParser::FileObject& fo )
00227 {
00228         if( fo.getMaskType() == sequenceParser::eMaskTypeSequence )
00229                 return static_cast<const sequenceParser::Sequence&>(fo).getAbsoluteStandardPattern();
00230         if( fo.getMaskType() == sequenceParser::eMaskTypeFile )
00231                 return static_cast<const sequenceParser::File&>(fo).getAbsoluteFilename();
00232         return "";
00233 }
00234 
00235 bool isContextSupported( const ttl::Graph::Node* node , const std::string& context )
00236 {
00237         const ttl::ofx::property::OfxhProperty& prop = node->getProperties().fetchProperty( kOfxImageEffectPropSupportedContexts );
00238         std::vector<std::string> contexts = sam::getStringValues( prop );
00239 
00240         BOOST_FOREACH( std::string c, contexts )
00241         {
00242                 if( c == context )
00243                         return true;
00244         }
00245         return false;
00246 }
00247 
00248 int main( int argc, char** argv )
00249 {
00250         signal(SIGINT, signal_callback_handler);
00251 
00252         using namespace tuttle::common;
00253         using namespace sam;
00254         using namespace sam::samdo;
00255         boost::shared_ptr<formatters::Formatter> formatter( formatters::Formatter::get() );
00256         boost::shared_ptr<Color>                 color( Color::get() );
00257 
00258         try
00259         {
00260                 bool continueOnError = false;
00261                 bool stopOnMissingFile = false;
00262                 bool disableProcess = false;
00263                 bool forceIdentityNodesProcess = false;
00264                 bool script = false;
00265                 std::vector<std::string> cl_options;
00266                 std::vector<std::vector<std::string> > cl_commands;
00267 
00268                 formatter->init_logging();
00269                 
00270                 decomposeCommandLine( argc, argv, cl_options, cl_commands );
00271 
00272                 // create the graph
00273                 ttl::Graph graph;
00274                 std::vector<ttl::Graph::Node*> nodes;
00275                 nodes.reserve( 50 );
00276                 
00277                 std::vector<ttl::Graph::Node*> facticesNodes;
00278                 
00279                 ttl::ComputeOptions options;
00280                 std::vector<std::ssize_t> range;
00281                 std::vector<double> renderscale;
00282                 std::size_t step;
00283                 
00284                 std::vector<std::string> idNames; // list of id setted in the command line
00285                 
00286                 // plugins loading
00287                 ttl::core().preload();
00288                 const std::vector<ttl::ofx::imageEffect::OfxhImageEffectPlugin*>& allNodes = ttl::core().getImageEffectPluginCache().getPlugins();
00289 
00290                 // Analyze each part of the command line
00291                 {
00292                         // Analyze sam do flags
00293                         try
00294                         {
00295                                 // Declare the supported options.
00296                                 bpo::options_description infoOptions;
00297                                 infoOptions.add_options()
00298                                         ( kHelpOptionString,    kHelpOptionMessage )
00299                                         ( kVersionOptionString, kVersionOptionMessage )
00300                                         ( kNodesOptionString,   kNodesOptionMessage )
00301                                         ( kColorOptionString,   kColorOptionMessage )
00302                                         ( kScriptOptionString,  kScriptOptionMessage )
00303                                         ( kBriefOptionString,   kBriefOptionMessage )
00304                                         ( kExpertOptionString,  kExpertOptionMessage );
00305                                 bpo::options_description confOptions;
00306                                 confOptions.add_options()
00307                                         ( kContinueOnErrorOptionString,   bpo::value<bool>(), kContinueOnErrorOptionMessage )
00308                                         ( kStopOnMissingFileOptionString, bpo::value<bool>(), kStopOnMissingFileOptionMessage )
00309                                         ( kDisableProcessOptionString,    kDisableProcessOptionMessage )
00310                                         ( kForceIdentityNodesProcessOptionString, kForceIdentityNodesProcessOptionMessage )
00311                                         ( kRangeOptionString,       bpo::value<std::string>(),  kRangeOptionMessage )
00312                                         ( kFirstImageOptionString,  bpo::value<int>(),          kFirstImageOptionMessage )
00313                                         ( kLastImageOptionString,   bpo::value<int>(),          kLastImageOptionMessage )
00314                                         ( kRenderScaleOptionString, bpo::value<std::string >(), kRenderScaleOptionMessage )
00315                                         ( kVerboseOptionString,     bpo::value<int>()->default_value( 2 ), kVerboseOptionMessage )
00316                                         ( kQuietOptionString,       kQuietOptionMessage )
00317                                         ( kNbCoresOptionString,     bpo::value<std::size_t>(), kNbCoresOptionMessage );
00318 
00319                                 // describe hidden options
00320                                 bpo::options_description hidden;
00321                                 hidden.add_options()
00322                                         ( kEnableColorOptionString, bpo::value<std::string > (), kEnableColorOptionMessage )
00323                                         // params for auto-completion
00324                                         ( kNodesListOptionString, kNodesListOptionMessage );
00325 
00326                                 bpo::options_description all_options;
00327                                 all_options.add( infoOptions ).add( confOptions ).add( hidden );
00328 
00329                                 bpo::variables_map samdo_vm;
00330                                 bpo::store( bpo::command_line_parser( cl_options ).options( all_options ).run(), samdo_vm );
00331                                 if( const char* env_do_options = std::getenv( "SAM_DO_OPTIONS" ) )
00332                                 {
00333                                         const std::vector<std::string> vecOptions = bpo::split_unix( env_do_options, " " );
00334                                         bpo::store( bpo::command_line_parser( vecOptions ).options( all_options ).run(), samdo_vm );
00335                                 }
00336                                 if( const char* env_do_options = std::getenv( "SAM_OPTIONS" ) )
00337                                 {
00338                                         const std::vector<std::string> vecOptions = bpo::split_unix( env_do_options, " " );
00339                                         bpo::store( bpo::command_line_parser( vecOptions ).options( all_options ).run(), samdo_vm );
00340                                 }
00341 
00342                                 bpo::notify( samdo_vm );
00343 
00344                                 if( samdo_vm.count( kScriptOptionLongName ) )
00345                                 {
00346                                         // disable color, disable directory printing and set relative path by default
00347                                         script = true;
00348                                 }
00349                                 
00350                                 if( samdo_vm.count(kColorOptionLongName) && !script )
00351                                 {
00352                                         color->enable();
00353                                 }
00354                                 
00355                                 if( samdo_vm.count(kEnableColorOptionLongName) && !script )
00356                                 {
00357                                         const std::string str = samdo_vm[kEnableColorOptionLongName].as<std::string>();
00358                                         if( string_to_boolean( str ) )
00359                                         {
00360                                                 color->enable();
00361                                         }
00362                                         else
00363                                         {
00364                                                 color->disable();
00365                                         }
00366                                 }
00367                                 
00368                                 switch( samdo_vm[ kVerboseOptionLongName ].as< int >() )
00369                                 {
00370                                         case 0 :  formatter->setLogLevel( boost::log::trivial::trace   ); break;
00371                                         case 1 :  formatter->setLogLevel( boost::log::trivial::debug   ); break;
00372                                         case 2 :  formatter->setLogLevel( boost::log::trivial::info    ); break;
00373                                         case 3 :  formatter->setLogLevel( boost::log::trivial::warning ); break;
00374                                         case 4 :  formatter->setLogLevel( boost::log::trivial::error   ); break;
00375                                         case 5 :  formatter->setLogLevel( boost::log::trivial::fatal   ); break;
00376                                         default : formatter->setLogLevel( boost::log::trivial::warning ); break;
00377                                 }
00378                                 
00379                                 if( samdo_vm.count( kQuietOptionLongName ) )
00380                                 {
00381                                         formatter->setLogLevel( boost::log::trivial::fatal );
00382                                 }
00383                                 
00384                                 if( samdo_vm.count( kDisableProcessOptionLongName ) )
00385                                 {
00386                                         disableProcess = true;
00387                                         formatter->setLogLevel( boost::log::trivial::trace );
00388                                 }
00389 
00390                                 // Display options //
00391                                 
00392                                 if( samdo_vm.count( kHelpOptionLongName ) )
00393                                 {
00394                                         displayHelp( infoOptions, confOptions );
00395                                         exit( 0 );
00396                                 }
00397 
00398                                 if( samdo_vm.count( kExpertOptionLongName ) )
00399                                 {
00400                                         displayHelp( infoOptions, confOptions, hidden );
00401                                         exit( 0 );
00402                                 }
00403 
00404                                 if( samdo_vm.count( kBriefOptionLongName ) )
00405                                 {
00406                                         TUTTLE_LOG_INFO( color->_green << "A command line to execute a list of OpenFX nodes" << color->_std );
00407                                         return 0;
00408                                 }
00409 
00410                                 if( samdo_vm.count( kVersionOptionLongName ) )
00411                                 {
00412                                         TUTTLE_LOG_INFO( "TuttleOFX Host - version " << TUTTLE_HOST_VERSION_STR );
00413                                         exit( 0 );
00414                                 }
00415 
00416                                 // Missing operand check //
00417                                 
00418                                 // If it's not the last display option
00419                                 // and if there is no command argument
00420                                 // an argument is missing.
00421                                 if( !( samdo_vm.count( kNodesOptionLongName ) || samdo_vm.count( kNodesListOptionLongName ) ) &&
00422                                     cl_commands.size() == 0 )
00423                                 {
00424                                         // No display option and no sub-command to execute
00425                                         TUTTLE_LOG_ERROR( "sam do: missing operand." );
00426                                         //displayHelp( infoOptions, confOptions );
00427                                         exit( 255 );
00428                                 }
00429                                 
00430                                 
00431                                 // start to analyse and execute all sub-commands //
00432                                 
00433                                 const std::string logFilename = ( ttl::core().getPreferences().getTuttleHomePath() / "sam-do.log" ).string();
00434                                 std::ofstream logFile( logFilename.c_str() );
00435                                 std::streambuf* strm_buffer = std::cerr.rdbuf(); // save cerr's output buffer
00436                                 std::cerr.rdbuf( logFile.rdbuf() ); // redirect output into the file
00437                                 
00438                                 if( samdo_vm.count( kNodesOptionLongName ) || samdo_vm.count( kNodesListOptionLongName ) )
00439                                 {
00440                                         TUTTLE_LOG_INFO( color->_blue << "NODES" << color->_std );
00441                                         std::vector<std::string> pluginNames;
00442                                         
00443                                         Dummy dummy;
00444                                         dummy.addDummyNodeInList( pluginNames );
00445 
00446                                         BOOST_FOREACH( const ttl::ofx::imageEffect::OfxhImageEffectPlugin* node, allNodes )
00447                                         {
00448                                                 std::string plugName = node->getRawIdentifier();
00449                                                 boost::algorithm::replace_first( plugName, "tuttle.", "" );
00450                                                 pluginNames.push_back( plugName );
00451                                         }
00452                                         std::sort( pluginNames.begin(), pluginNames.end() );
00453 
00454                                         const std::string indent = samdo_vm.count( kNodesOptionLongName ) ? "\t" : "";
00455 
00456                                         BOOST_FOREACH( const std::string& pluginName, pluginNames )
00457                                         {
00458                                                 TUTTLE_LOG_INFO( indent << pluginName );
00459                                         }
00460                                         exit( 0 );
00461                                 }
00462 
00463                                 {
00464                                         if( samdo_vm.count( kRangeOptionLongName ) && ( samdo_vm.count( kFirstImageOptionLongName ) || samdo_vm.count( kLastImageOptionLongName ) ) )
00465                                         {
00466                                                 TUTTLE_LOG_ERROR( color->_red << "sam do: could not use " << kRangeOptionLongName << "and " << kFirstImageOptionLongName << " or " << kLastImageOptionLongName << " option." << color->_std << std::endl );
00467                                                 exit( 255 );
00468                                         }
00469                                         
00470                                         if( samdo_vm.count( kFirstImageOptionLongName ) )
00471                                         {
00472                                                 int startFrame = samdo_vm[kFirstImageOptionLongName     ].as< int > ();
00473                                                 options.setBegin( startFrame );
00474                                         }
00475                                         if( samdo_vm.count( kLastImageOptionLongName ) )
00476                                         {
00477                                                 int stopFrame  = samdo_vm[kLastImageOptionLongName].as< int > ();
00478                                                 options.setEnd( stopFrame );
00479                                         }
00480                                         if( samdo_vm.count( kRangeOptionLongName ) )
00481                                         {
00482                                                 const std::string rangeStr = samdo_vm[kRangeOptionLongName].as< std::string > ();
00483                                                 std::vector<std::string> rangeVStr = boost::program_options::split_unix( rangeStr, " ," );
00484                                                 range.reserve( rangeVStr.size() );
00485                                                 TUTTLE_TLOG( TUTTLE_TRACE, rangeVStr.size() );
00486 
00487                                                 BOOST_FOREACH( const std::string& rStr, rangeVStr )
00488                                                 {
00489                                                         range.push_back( tuttle::host::attribute::extractValueFromExpression<std::ssize_t > ( rStr ) );
00490                                                 }
00491                                         }
00492                                         if( range.size() == 1 )
00493                                         {
00494                                                 range.push_back( range[0] );
00495                                         }
00496                                         if( range.size() >= 3 )
00497                                                 step = range[2];
00498                                         else
00499                                                 step = 1;
00500                                 }
00501                                 {
00502                                         if( samdo_vm.count( kRenderScaleOptionLongName ) )
00503                                         {
00504                                                 const std::string renderscaleStr = samdo_vm[kRenderScaleOptionLongName].as<std::string > ();
00505                                                 std::vector<std::string> renderscaleVStr = boost::program_options::split_unix( renderscaleStr, " ," );
00506                                                 renderscale.reserve( renderscaleVStr.size() );
00507                                                 TUTTLE_TLOG( TUTTLE_TRACE, renderscaleVStr.size() );
00508 
00509                                                 BOOST_FOREACH( const std::string& rStr, renderscaleVStr )
00510                                                 {
00511                                                         renderscale.push_back( tuttle::host::attribute::extractValueFromExpression<double>( rStr ) );
00512                                                 }
00513                                         }
00514                                         if( renderscale.size() == 1 )
00515                                         {
00516                                                 renderscale.push_back( renderscale[0] );
00517                                         }
00518                                 }
00519                                 std::cerr.rdbuf( strm_buffer ); // restore old output buffer
00520                                 if( samdo_vm.count( kContinueOnErrorOptionLongName ) )
00521                                 {
00522                                         continueOnError = samdo_vm[kContinueOnErrorOptionLongName].as< bool > ();
00523                                 }
00524                                 if( samdo_vm.count( kStopOnMissingFileOptionLongName ) )
00525                                 {
00526                                         stopOnMissingFile = samdo_vm[kStopOnMissingFileOptionLongName].as< bool > ();
00527                                 }
00528 
00529                                 forceIdentityNodesProcess = samdo_vm.count( kForceIdentityNodesProcessOptionLongName );
00530                         }
00531                         catch( const boost::program_options::error& e )
00532                         {
00533                                 TUTTLE_LOG_ERROR( "sam do: command line error: " << e.what() );
00534                                 exit( 254 );
00535                         }
00536                         catch( ... )
00537                         {
00538                                 TUTTLE_LOG_ERROR( "sam do: error: " << boost::current_exception_diagnostic_information() );
00539                                 exit( 254 );
00540                         }
00541 
00542                         /// @todo Set all sam do options for rendering
00543 
00544                         // Analyse options for each node
00545                         {
00546                                 // Declare the supported options.
00547                                 bpo::options_description infoOptions;
00548                                 infoOptions.add_options()
00549                                         ( kHelpOptionString,    kHelpOptionMessage )
00550                                         ( kVersionOptionString, kVersionOptionMessage )
00551                                         ( kExpertOptionString,  kExpertOptionMessage );
00552                                 bpo::options_description confOptions;
00553                                 confOptions.add_options()
00554                                         ( kVerboseOptionString, kVerboseOptionMessage )
00555                                         ( kIdOptionString, bpo::value<std::string > (), kIdOptionMessage )
00556                                         ( kNbCoresOptionString, bpo::value<std::size_t > (), kNbCoresOptionMessage );
00557                                 // describe openFX options
00558                                 bpo::options_description openfxOptions;
00559                                 openfxOptions.add_options()
00560                                         ( kAttributesOptionString,  kAttributesOptionMessage )
00561                                         ( kPropertiesOptionString,  kPropertiesOptionMessage )
00562                                         ( kClipsOptionString,       kClipsOptionMessage )
00563                                         ( kClipOptionString,        bpo::value<std::string > (), kClipOptionMessage )
00564                                         ( kParametersOptionString,  kParametersOptionMessage )
00565                                         ( kParamInfosOptionString,  bpo::value<std::string > (), kParamInfosOptionMessage )
00566                                         ( kParamValuesOptionString, bpo::value<std::vector<std::string> >(), kParamValuesOptionMessage )
00567                                         // for auto completion
00568                                         ( kParametersReduxOptionString, kParametersReduxOptionMessage )
00569                                         ( kParamTypeOptionString,       bpo::value<std::string > (),     kParamTypeOptionMessage )
00570                                         ( kParamPossibleValuesOptionString, bpo::value<std::string > (), kParamPossibleValuesOptionMessage )
00571                                         ( kParamDefaultOptionString,    bpo::value<std::string > (),     kParamDefaultOptionMessage )
00572                                         ( kParamGroupOptionString,      kParamGroupOptionMessage );
00573 
00574                                 // define default options
00575                                 bpo::positional_options_description param_values;
00576                                 param_values.add( kParamValuesOptionLongName, -1 );
00577 
00578                                 bpo::options_description all_options;
00579                                 all_options.add( infoOptions ).add( confOptions ).add( openfxOptions );
00580 
00581                                 BOOST_FOREACH( const std::vector<std::string>& command, cl_commands )
00582                                 {
00583 
00584                                         std::string userNodeName = command[0];
00585                                         std::string nodeFullName = userNodeName;
00586                                         std::vector<std::string> nodeArgs;
00587                                         
00588                                         boost::algorithm::to_lower( userNodeName );
00589                                         std::copy( command.begin() + 1, command.end(), std::back_inserter( nodeArgs ) );
00590 
00591                                         try
00592                                         {
00593                                                 Dummy dummy;
00594                                                 if( dummy.isDummyNode( userNodeName ) )
00595                                                 {
00596                                                         nodeFullName = "tuttle.dummy";
00597                                                 }
00598                                                 nodeFullName = retrieveNodeFullname( nodeFullName );
00599 
00600                                                 // parse the command line, and put the result in node_vm
00601                                                 bpo::variables_map node_vm;
00602                                                 bpo::store( bpo::command_line_parser( nodeArgs ).options( all_options ).positional( param_values ).run(), node_vm );
00603                                                 if( const char* env_ptr = std::getenv( "SAM_DO_NODE_OPTIONS" ) )
00604                                                 {
00605                                                         std::vector<std::string> envOptions;
00606                                                         std::string env( env_ptr );
00607                                                         envOptions.push_back( env );
00608                                                         bpo::store( bpo::command_line_parser( envOptions ).options( all_options ).run(), node_vm );
00609                                                 }
00610                                                 {
00611                                                         std::string envVarName;
00612                                                         envVarName += "SAM_DO_";
00613                                                         envVarName += boost::algorithm::replace_all_copy( nodeFullName, ".", "_" );
00614                                                         envVarName += "_OPTIONS";
00615                                                         if( const char* env_ptr = std::getenv( envVarName.c_str() ) )
00616                                                         {
00617                                                                 std::vector<std::string> envOptions;
00618                                                                 std::string env( env_ptr );
00619                                                                 envOptions.push_back( env );
00620                                                                 bpo::store( bpo::command_line_parser( envOptions ).options( all_options ).run(), node_vm );
00621                                                         }
00622                                                 }
00623 
00624                                                 bpo::notify( node_vm );
00625                                                 //TUTTLE_LOG_TRACE( "[" << nodeFullName << "]" );
00626 
00627                                                 // Check priority flags:
00628                                                 // If one flag to display informations is used in command line,
00629                                                 // it replaces all the process.
00630                                                 // --help,h --version,v --verbose,V --params --clips --props
00631 
00632                                                 ttl::Graph::Node& currentNode = graph.createNode( nodeFullName );
00633                                                 //if( dummy.isDummyNode( userNodeName ) )
00634 
00635                                                 if( node_vm.count( kHelpOptionLongName ) )
00636                                                 {
00637                                                         if( dummy.isDummyNode( userNodeName ) )
00638                                                                 dummy.displayHelp( userNodeName );
00639                                                         else
00640                                                                 displayNodeHelp( nodeFullName, currentNode, infoOptions, confOptions );
00641                                                         exit( 0 );
00642                                                 }
00643                                                 if( node_vm.count( kExpertOptionString ) )
00644                                                 {
00645                                                         if( dummy.isDummyNode( userNodeName ) )
00646                                                                 dummy.displayExpertHelp( userNodeName );
00647                                                         else
00648                                                                 displayNodeHelp( nodeFullName, currentNode, infoOptions, confOptions, openfxOptions );
00649                                                         exit( 0 );
00650                                                 }
00651 
00652                                                 if( node_vm.count( kVersionOptionLongName ) )
00653                                                 {
00654                                                         TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00655                                                         TUTTLE_LOG_INFO( "Version " << currentNode.getVersionStr() );
00656                                                         TUTTLE_LOG_INFO( "" );
00657                                                         exit( 0 );
00658                                                 }
00659                                                 if( node_vm.count( kAttributesOptionLongName ) )
00660                                                 {
00661                                                         TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00662                                                         TUTTLE_LOG_INFO( "" );
00663                                                         TUTTLE_LOG_INFO( color->_blue << "ATTRIBUTES" << color->_std );
00664                                                         TUTTLE_LOG_INFO( "" );
00665                                                         TUTTLE_LOG_INFO( color->_blue << "- CLIPS" << color->_std );
00666                                                         coutClipsWithDetails( currentNode );
00667                                                         TUTTLE_LOG_INFO( "" );
00668                                                         TUTTLE_LOG_INFO( color->_blue << "- PARAMETERS" << color->_std );
00669                                                         coutParametersWithDetails( currentNode );
00670                                                         TUTTLE_LOG_INFO( "" );
00671                                                         exit( 0 );
00672                                                 }
00673                                                 if( node_vm.count( kPropertiesOptionLongName ) )
00674                                                 {
00675                                                         if( !script )
00676                                                         {
00677                                                                 TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00678                                                                 TUTTLE_LOG_INFO( "" );
00679                                                                 TUTTLE_LOG_INFO( color->_blue << "PROPERTIES" << color->_std );
00680                                                         }
00681                                                         coutProperties( currentNode );
00682                                                         if( !script )
00683                                                                 TUTTLE_LOG_INFO( "" );
00684                                                         exit( 0 );
00685                                                 }
00686                                                 if( node_vm.count( kClipsOptionLongName ) )
00687                                                 {
00688                                                         if( !script )
00689                                                         {
00690                                                                 TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00691                                                                 TUTTLE_LOG_INFO( "" );
00692                                                                 TUTTLE_LOG_INFO( color->_blue << "CLIPS" << color->_std );
00693                                                         }
00694                                                         coutClips( currentNode );
00695                                                         if( !script )
00696                                                                 TUTTLE_LOG_INFO( "" );
00697                                                         exit( 0 );
00698                                                 }
00699                                                 if( node_vm.count( kClipOptionLongName ) )
00700                                                 {
00701                                                         const std::string clipName = node_vm["clip"].as<std::string>();
00702                                                         ttl::attribute::ClipImage& clip = currentNode.getClip(clipName);
00703                                                         
00704                                                         //const String& prop = fetchStringProperty( kOfxImageEffectPropSupportedPixelDepths );
00705                                                         //std::vector<std::string>& bitDepths     = prop.getValues();
00706                                                         
00707                                                         /*std::vector<std::string> bitDepths = clip.getSupportedBitDepth();
00708                                                         BOOST_FOREACH( std::string& s, bitDepths )
00709                                                         {
00710                                                                 s = s.substr( 11 ); // remove 'OfxBitDepth'
00711                                                         }*/
00712                                                         
00713                                                         std::vector<std::string> components = clip.getSupportedComponents();
00714                                                         BOOST_FOREACH( std::string& s, components )
00715                                                         {
00716                                                                 s = s.substr( 17 ); // remove 'OfxImageComponent'
00717                                                         }
00718                                                         
00719                                                         if( !script )
00720                                                         {
00721                                                                 TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00722                                                                 TUTTLE_LOG_INFO( "" );
00723 
00724                                                                 TUTTLE_LOG_INFO( color->_blue << "CLIP: " << color->_green << clipName << color->_std );
00725                                                                 //TUTTLE_LOG_INFO( "supported bit depth: " << boost::algorithm::join( bitDepths, ", " ) );
00726                                                                 TUTTLE_LOG_INFO( "supported components: " << boost::algorithm::join( components, ", " ) );
00727                                                                 TUTTLE_LOG_INFO( "pixel aspect ratio: "   << clip.getPixelAspectRatio() );
00728                                                                 TUTTLE_LOG_INFO( "number of components: " << clip.getNbComponents() );
00729                                                                 TUTTLE_LOG_INFO( "" );
00730                                                         }
00731                                                         else
00732                                                         {
00733                                                                 //TUTTLE_LOG_INFO( boost::algorithm::join( bitDepths, ", " ));
00734                                                                 TUTTLE_LOG_INFO( boost::algorithm::join( components, ", " ) );
00735                                                                 TUTTLE_LOG_INFO( clip.getPixelAspectRatio() );
00736                                                                 TUTTLE_LOG_INFO( clip.getNbComponents());
00737                                                         }
00738                                                         
00739                                                         exit( 0 );
00740                                                 }
00741                                                 if( node_vm.count( kParametersOptionLongName ) )
00742                                                 {
00743                                                         if( !script )
00744                                                         {
00745                                                                 TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00746                                                                 TUTTLE_LOG_INFO( "" );
00747                                                                 TUTTLE_LOG_INFO( color->_blue << "PARAMETERS" << color->_std );
00748                                                                 TUTTLE_LOG_INFO( "" );
00749                                                                 coutParametersWithDetails( currentNode );
00750                                                                 exit( 0 );
00751                                                         }
00752                                                         else
00753                                                         {
00754                                                                 coutParameters( currentNode );
00755                                                                 exit( 0 );
00756                                                         }
00757                                                 }
00758                                                 if( node_vm.count( kParametersReduxOptionLongName ) )
00759                                                 {
00760                                                         coutParameters( currentNode );
00761                                                         exit( 0 );
00762                                                 }
00763                                                 if( node_vm.count( kParamInfosOptionLongName ) )
00764                                                 {
00765                                                         const std::string attributeName = node_vm[kParamInfosOptionLongName].as<std::string > ();
00766                                                         TUTTLE_LOG_INFO( "\tsam do " << nodeFullName );
00767                                                         TUTTLE_LOG_INFO( color->_blue << "PARAM: " << color->_green << attributeName << color->_std );
00768                                                         ttl::ofx::attribute::OfxhParam& param = currentNode.getParamByScriptName( attributeName );
00769                                                         TUTTLE_LOG_INFO( "" );
00770                                                         TUTTLE_LOG_INFO( "\t" << color->_red << ( param.getSecret() ? "SECRET -- " : "" ) << param.getScriptName() << ": " << param.getParamTypeName() << " x" << param.getSize() << color->_std );
00771                                                         TUTTLE_LOG_INFO( "" );
00772                                                         const std::string& hint = param.getHint();
00773                                                         if( hint.size() )
00774                                                         {
00775                                                                 TUTTLE_LOG_INFO( "\t" << hint );
00776                                                         }
00777                                                         TUTTLE_LOG_INFO( "" );
00778                                                         exit( 0 );
00779                                                 }
00780 
00781                                                 if( node_vm.count( kParamTypeOptionLongName ) )
00782                                                 {
00783                                                         const std::string attributeName = node_vm[kParamTypeOptionLongName].as<std::string > ();
00784                                                         ttl::ofx::attribute::OfxhParam& param = currentNode.getParamByScriptName( attributeName );
00785                                                         TUTTLE_LOG_INFO( param.getParamTypeName() );
00786                                                         exit( 0 );
00787                                                 }
00788 
00789                                                 if( node_vm.count( kParamPossibleValuesOptionLongName ) )
00790                                                 {
00791                                                         const std::string attributeName = node_vm[kParamPossibleValuesOptionLongName].as<std::string > ();
00792                                                         ttl::ofx::attribute::OfxhParam& param = currentNode.getParamByScriptName( attributeName );
00793                                                         coutParameterValues( std::cout, param );
00794                                                         exit( 0 );
00795                                                 }
00796                                                 if( node_vm.count( kParamDefaultOptionLongName ) )
00797                                                 {
00798                                                         const std::string attributeName = node_vm[kParamDefaultOptionLongName].as<std::string > ();
00799                                                         ttl::ofx::attribute::OfxhParam& param = currentNode.getParamByScriptName( attributeName );
00800                                                         TUTTLE_LOG_INFO( getFormattedStringValue( param.getProperties().fetchProperty( kOfxParamPropDefault ) ) );
00801                                                         exit( 0 );
00802                                                 }
00803                                                 if( node_vm.count( kParamGroupOptionLongName ) )
00804                                                 {
00805                                                         if( currentNode.getNodeType() == ttl::INode::eNodeTypeImageEffect )
00806                                                         {
00807                                                                 if( currentNode.asImageEffectNode().getDescriptor().getProperties().hasProperty( kOfxImageEffectPluginPropGrouping ) )
00808                                                                 {
00809                                                                         TUTTLE_LOG_INFO( currentNode.asImageEffectNode().getPluginGrouping() );
00810                                                                 }
00811                                                         }
00812                                                         exit( 0 );
00813                                                 }
00814 
00815                                                 if( node_vm.count( kIdOptionLongName ) )
00816                                                 {
00817                                                         const std::string nodeId = node_vm[kIdOptionLongName].as<std::string > ();
00818                                                         idNames.push_back( nodeId );
00819                                                         graph.renameNode( currentNode, nodeId );
00820                                                 }
00821                                                 
00822                                                 // Analyse attributes: parameters / clips
00823                                                 typedef std::pair<ttl::ofx::attribute::OfxhClipImage*, std::string> ClipAndConnection;
00824                                                 std::vector<ClipAndConnection> clipsToConnect;
00825 
00826                                                 if( node_vm.count( kParamValuesOptionLongName ) )
00827                                                 {
00828                                                         const std::vector<std::string> params = node_vm[kParamValuesOptionLongName].as<std::vector<std::string> >();
00829                                                         bool orderedParams = true;
00830                                                         setParametersForNode( params, currentNode, clipsToConnect, dummy.isDummyNode( userNodeName ), orderedParams );
00831                                                 }
00832                                                 
00833                                                 // if it's a dummy, keeping parameters in node
00834                                                 if( dummy.isDummyNode( userNodeName ) )
00835                                                 {
00836                                                         currentNode.getParamByScriptName( "originalnode" ).setValue( command.at(0) );
00837                                                         currentNode.getParamByScriptName( "expression" ).setValue( boost::algorithm::join( nodeArgs, " " ) );
00838                                                         facticesNodes.push_back( &currentNode );
00839                                                 }
00840 
00841                                                 // connect current node to previous node(s)
00842                                                 connectClips( nodes, clipsToConnect, currentNode, graph, idNames );
00843                                                 
00844                                                 nodes.push_back( &currentNode );
00845                                         }
00846                                         catch( boost::program_options::error& e )
00847                                         {
00848                                                 TUTTLE_LOG_ERROR( "[sam do] " << nodeFullName );
00849 #ifdef TUTTLE_PRODUCTION
00850                                                 TUTTLE_LOG_ERROR( "Error: " << e.what() );
00851 #else
00852                                                 TUTTLE_LOG_ERROR( "Debug: " << boost::current_exception_diagnostic_information() );
00853 #endif
00854                                                 exit( 254 );
00855                                         }
00856                                         catch( tuttle::exception::Common& e )
00857                                         {
00858                                                 TUTTLE_LOG_ERROR( "[sam do] " << nodeFullName );
00859 #ifdef TUTTLE_PRODUCTION
00860                                                 TUTTLE_LOG_ERROR( "Error: " << *boost::get_error_info<tuttle::exception::user > ( e ) );
00861 #else
00862                                                 TUTTLE_LOG_ERROR( "Debug: " << boost::current_exception_diagnostic_information() );
00863                                                 TUTTLE_LOG_ERROR( "Backtrace: " << boost::trace( e ) );
00864 #endif
00865                                                 exit( 254 );
00866                                         }
00867                                         catch( ... )
00868                                         {
00869                                                 TUTTLE_LOG_ERROR( "[sam do] " << nodeFullName );
00870                                                 TUTTLE_LOG_ERROR( "Unknown error." );
00871                                                 TUTTLE_LOG_ERROR( "\n" );
00872                                                 TUTTLE_LOG_ERROR( "Debug: " << boost::current_exception_diagnostic_information() );
00873                                                 exit( 254 );
00874                                         }
00875                                 }
00876                         }
00877                 }
00878 
00879                 // print graph in trace level
00880                 TUTTLE_LOG_TRACE( color->_blue << "********** graph composition **********" << color->_std );
00881                 BOOST_FOREACH( const std::vector<std::string>& node, cl_commands )
00882                 {
00883                         TUTTLE_LOG_TRACE( "[" << node[0] << "]" );
00884                         for( std::size_t i = 1; i < node.size(); ++i )
00885                         {
00886                                 const std::string& s = node[i];
00887                                 TUTTLE_LOG_TRACE( ( ( s[0] == '-' ) ? "" : "* " ) << s );
00888                         }
00889                 }
00890                 TUTTLE_LOG_TRACE( color->_blue << "***************************************" << color->_std );
00891                 
00892                 
00893                 if( nodes.size() == 0 )
00894                         // nothing to do!
00895                         exit( 255 );
00896 
00897                 // Setup compute options
00898                 if( range.size() >= 2 )
00899                 {
00900                         options.addTimeRange( range[0], range[1], step );
00901                 }
00902                 
00903                 if( renderscale.size() == 2 )
00904                 {
00905                         options.setRenderScale( renderscale[0], renderscale[1] );
00906                 }
00907                 options.setContinueOnError( continueOnError );
00908                 options.setContinueOnMissingFile( !stopOnMissingFile );
00909                 options.setForceIdentityNodesProcess( forceIdentityNodesProcess );
00910                 
00911                 size_t numberOfLoop = std::numeric_limits<size_t>::max();
00912                 boost::ptr_vector< boost::ptr_vector< sequenceParser::FileObject > > listOfSequencesPerReaderNode;
00913                 std::vector< std::string > listOfSequencesPerWriterNode;
00914                 bool writerHaveExtensionInParameter = false;
00915                 
00916                 if( facticesNodes.size() )
00917                 {
00918                         // create a detector from the sequence parsing library
00919                         
00920                         sequenceParser::EMaskType    researchMask    = sequenceParser::eMaskTypeSequence | sequenceParser::eMaskTypeFile ;
00921                         sequenceParser::EMaskOptions descriptionMask = sequenceParser::eMaskOptionsAbsolutePath | sequenceParser::eMaskOptionsRecursive;
00922                         
00923                         std::vector<std::string> filters;
00924                         
00925                         Dummy dummy;
00926                         
00927                         BOOST_FOREACH( ttl::Graph::Node* n, facticesNodes )
00928                         {
00929                                 std::string name = n->getParamByScriptName( "originalnode" ).getStringValue();
00930                                 dummy.getFullName( name );
00931                                 
00932                                 // get base paths from dummy parameters
00933                                 std::string command = n->getParam("expression").getStringValue();
00934                                 std::vector<std::string> paths;
00935                                 const std::vector<std::string> nodeArgs = bpo::split_unix( command, " " );
00936                                 dummy.getPathsFromCommandLine( paths, nodeArgs );
00937                                 
00938                                 if( dummy.isDummyReaderNode( name ) )
00939                                 {
00940                                         std::vector<std::string> extensions;
00941                                         dummy.getExtensionsFromCommandLine( extensions, nodeArgs );
00942                                         
00943                                         boost::ptr_vector<sequenceParser::FileObject> listOfSequencesForThisNode;
00944                                         
00945                                         // browse all paths in parameters
00946                                         BOOST_FOREACH( std::string& inputPath, paths )
00947                                         {
00948                                                 size_t count = 0;
00949                                                 TUTTLE_LOG_TRACE( "[sam-do] " <<n->getName() << " browse: " << inputPath );
00950                                         
00951                                                 // get filenames adn sequences
00952                                                 boost::ptr_vector<sequenceParser::FileObject> listOfSequences = sequenceParser::fileObjectInDirectory( inputPath, filters, researchMask, descriptionMask );
00953                                                 count += addListOfSequencesInListOfProcess( listOfSequences, listOfSequencesForThisNode, extensions );
00954                                         
00955                                                 bfs::path p( inputPath );
00956                                                 if( ! p.extension().string().size() )
00957                                                 {
00958                                                         for ( bfs::recursive_directory_iterator end, dir( inputPath ); dir != end; ++dir )
00959                                                         {
00960                                                                 if( bfs::is_directory( *dir ) )
00961                                                                 {
00962                                                                         bfs::path currentPath = (bfs::path)*dir;
00963                                                                         boost::ptr_vector<sequenceParser::FileObject> listOfSequences = sequenceParser::fileObjectInDirectory( currentPath.string(), filters, researchMask, descriptionMask );
00964                                                                         count += addListOfSequencesInListOfProcess( listOfSequences, listOfSequencesForThisNode, extensions );
00965                                                                 }
00966                                                         }
00967                                                 }
00968                                         }
00969                                         // found the minimum number of sequence in each dummy reader
00970                                         numberOfLoop = std::min( numberOfLoop, listOfSequencesForThisNode.size() );
00971                                         
00972                                         listOfSequencesPerReaderNode.push_back( new_clone( listOfSequencesForThisNode ) );
00973                                 }
00974                                 if( dummy.isDummyWriterNode( name ) )
00975                                 {
00976                                         // in case of dummy writer, only add the first path, else throw an exception
00977                                         if( paths.size() > 1 )
00978                                                 BOOST_THROW_EXCEPTION( tuttle::exception::Value()
00979                                                                                            << tuttle::exception::user() + "unable to set mutli path in writer." );
00980                                         
00981                                         if( paths.size() )
00982                                         {
00983                                                 listOfSequencesPerWriterNode.push_back( paths.at(0) ); // push only the first path
00984                                                 bfs::path p( paths.at(0) );
00985                                                 if( p.extension().string().size() )
00986                                                         writerHaveExtensionInParameter = true;
00987                                         }
00988                                         else
00989                                                 listOfSequencesPerWriterNode.push_back( "" );
00990                                 }
00991                         }
00992                         
00993                         
00994                 }
00995                 
00996                 // if graph not have dummy reader
00997                 // or no dummy node, process only 1 graph
00998                 if( ! listOfSequencesPerReaderNode.size() ||
00999                         ! facticesNodes.size() ||
01000                         ( ( listOfSequencesPerReaderNode.size() || listOfSequencesPerWriterNode.size() ) && !numberOfLoop ) )
01001                 {
01002                         numberOfLoop = 1;
01003                 }
01004                 
01005                 // check if the graph haave real readers or writers
01006                 // and get filenames list
01007                 std::vector<std::string> filenames;
01008                 bool haveReader = false;
01009                 bool haveWriter = false;
01010                 BOOST_FOREACH( ttl::Graph::Node* n, nodes )
01011                 {
01012                         if( isContextSupported( n, kOfxImageEffectContextReader ) )
01013                         {
01014                                 filenames.push_back( n->getParamByScriptName( "filename" ).getStringValue() );
01015                                 haveReader = true;
01016                         }
01017                         if( isContextSupported( n, kOfxImageEffectContextWriter ) )
01018                         {
01019                                 haveWriter = true;
01020                         }
01021                 }
01022                 
01023                 TUTTLE_LOG_TRACE( "[sam-do] number of loop: " << numberOfLoop );
01024                 TUTTLE_LOG_TRACE( "[sam-do] writer have extension: " << writerHaveExtensionInParameter );
01025                 TUTTLE_LOG_TRACE( "[sam-do] graph have reader : " << haveReader );
01026                 TUTTLE_LOG_TRACE( "[sam-do] graph have writer : " << haveWriter );
01027                 TUTTLE_LOG_TRACE( "[sam-do] number of sequence per reader : " << listOfSequencesPerReaderNode.size() );
01028                 TUTTLE_LOG_TRACE( "[sam-do] number of sequence per writer : " << listOfSequencesPerWriterNode.size() );
01029                 
01030                 if( ( writerHaveExtensionInParameter || haveWriter || haveReader ) && numberOfLoop > 1 )
01031                 {
01032                         BOOST_THROW_EXCEPTION( tuttle::exception::Value()
01033                                                                    << tuttle::exception::user() + "several sequences can’t be transformed into a single sequence or a movie for the moment." );
01034                 }
01035                 
01036                 // Execute the graph
01037 
01038                 Dummy dummy;
01039                 
01040                 for( size_t loop = 0; loop < numberOfLoop; ++loop )
01041                 {
01042                         TUTTLE_LOG_TRACE( "[sam-do] " << color->_red << "graph processing " << loop << color->_std );
01043                         
01044                         // copy graph and node for each iteration
01045                         ttl::Graph graphTmp( graph );
01046                         std::vector<ttl::Graph::Node*> nodesTmp = nodes;
01047                         
01048                         bool processGraph = true;
01049                         size_t countDummyReader = 0;
01050                         size_t countDummyWriter = 0;
01051                         
01052                         
01053                         // replace each dummy node per real reader or writer node on graph
01054                         for( size_t nNode = 0; nNode < facticesNodes.size(); ++nNode )
01055                         {
01056                                 ttl::Graph::Node* readerToReplace = facticesNodes.at( nNode );
01057                         
01058                                 std::string filename;
01059                         
01060                                 std::string name = readerToReplace->getParamByScriptName( "originalnode" ).getStringValue();
01061                                 dummy.getFullName( name );
01062                         
01063                                 // get sequence name (or filename)
01064                                 if( dummy.isDummyReaderNode( name ) )
01065                                 {
01066                                         std::string baseSrcPath = readerToReplace->getParam("expression").getStringValue();
01067                                         bfs::path refPath( baseSrcPath );
01068                                         
01069                                         if( refPath.extension().string().size() )
01070                                         {
01071                                                 // if writer have an extension in the parameter, keep this filename
01072                                                 filename = baseSrcPath;
01073                                         }
01074                                         else
01075                                         {
01076                                                 sequenceParser::FileObject& fo = listOfSequencesPerReaderNode.at( countDummyReader ).at( loop );
01077                                                 filename = getAbsoluteFilename( fo );
01078                                                 countDummyReader++;
01079                                         }
01080                                         TUTTLE_TLOG_VAR( TUTTLE_TRACE, filename );
01081                                 }
01082                                 else // writer dummy
01083                                 {
01084                                         std::string baseDstPath = readerToReplace->getParam("expression").getStringValue();
01085                                         bfs::path refPath( baseDstPath );
01086                                         
01087                                         if( refPath.extension().string().size() )
01088                                         {
01089                                                 // if writer have an extension in the parameter, keep this filename
01090                                                 filename = baseDstPath;
01091                                         }
01092                                         else
01093                                         {
01094                                                 // need to combine filename:
01095                                                 // get root from dummy writer, and add sequence pattern from reader
01096                                                 
01097                                                 std::string baseSrcPath;
01098                                                 if( ! listOfSequencesPerReaderNode.size() )
01099                                                 {
01100                                                         if( ! filenames.size() )
01101                                                                 BOOST_THROW_EXCEPTION( tuttle::exception::Value()
01102                                                                                                            << tuttle::exception::user() + "no pattern was found to set the output filename." );
01103                                                         baseSrcPath = filenames.at(0);
01104                                                 }
01105                                                 else
01106                                                 {
01107                                                         baseSrcPath = facticesNodes.at(0)->getParam("expression").getStringValue();
01108                                                 }
01109                                                 std::vector<std::string> srcPaths;
01110                                                 const std::vector<std::string> srcNodeArgs = bpo::split_unix( baseSrcPath, " " );
01111                                                 dummy.getPathsFromCommandLine( srcPaths, srcNodeArgs );
01112                                                 
01113                                                 std::vector<std::string> extensions;
01114                                                 const std::vector<std::string> dstNodeArgs = bpo::split_unix( baseDstPath, " " );
01115                                                 
01116                                                 dummy.getExtensionsFromCommandLine( extensions, dstNodeArgs );
01117                                                 if( extensions.size() > 1 )
01118                                                         BOOST_THROW_EXCEPTION( tuttle::exception::Value()
01119                                                                                                    << tuttle::exception::user() + "many ext parameter are specified." );
01120                                                 
01121                                                 if( ! listOfSequencesPerReaderNode.size() )
01122                                                 {
01123                                                         filename = bfs::path(baseSrcPath).filename().string();
01124                                                 }
01125                                                 else
01126                                                 {
01127                                                         if( listOfSequencesPerReaderNode.size() && numberOfLoop == 1 )
01128                                                         {
01129                                                                 filename = readerToReplace->getParamByScriptName( "expression" ).getStringValue();
01130                                                         }
01131                                                         else
01132                                                         {
01133                                                                 sequenceParser::FileObject& fo = listOfSequencesPerReaderNode.at( 0 ).at( loop );
01134                                                                 filename = getAbsoluteFilename( fo );
01135                                                         }
01136                                                         
01137                                                         bfs::path filepath( baseSrcPath );
01138                                                         if( filepath.extension().string().size() )
01139                                                         {
01140                                                                 filename = filepath.filename().string();
01141                                                         }
01142                                                         else
01143                                                         {
01144                                                                 filename.erase( 0, srcPaths.at(0).length() );
01145                                                         }
01146                                                 }
01147                                                 TUTTLE_TLOG_VAR3( TUTTLE_TRACE, baseSrcPath, filename, srcPaths.at(0) );
01148                                                 // change extension if necessary
01149                                                 std::string ext;
01150                                                 if( extensions.size() > 0 )
01151                                                 {
01152                                                         bool isSupportedExtension = false;
01153                                                         ext = extensions.at(0);
01154                                                         std::vector<std::string> exts = dummy.getSupportedExtensions( kOfxImageEffectContextWriter );
01155                                                         
01156                                                         BOOST_FOREACH( std::string& e, exts )
01157                                                         {
01158                                                                 if( e == ext )
01159                                                                 {
01160                                                                         isSupportedExtension = true;
01161                                                                 }
01162                                                         }
01163                                                         if( !isSupportedExtension )
01164                                                                 BOOST_THROW_EXCEPTION( tuttle::exception::Value()
01165                                                                                                            << tuttle::exception::user() + "unknown extension." );
01166                                                 }
01167                                                 
01168                                                 bfs::path path = listOfSequencesPerWriterNode.at( countDummyWriter );
01169                                                 path /= filename;
01170                                                 
01171                                                 if( ext.length() )
01172                                                         path.replace_extension( ext );
01173                                                 
01174                                                 filename = path.string();
01175                                         }
01176                                         
01177                                         countDummyWriter++;
01178                                 }
01179                                 
01180                                 
01181                                 // replace dummy node with the correct reader or writer node
01182                                 std::vector<std::string> args = bpo::split_unix( filename, " " );
01183                                 dummy.foundAssociateDummyNode( name, allNodes, args );
01184 
01185                                 TUTTLE_LOG_TRACE( readerToReplace->getName() << " => " << name << " : " << args.at(0) );
01186                                 
01187                                 ttl::Graph::Node& currentNode = graphTmp.createNode( name );
01188                                 
01189                                 graphTmp.replaceNodeConnections( *readerToReplace, currentNode );
01190                                 
01191                                 // Analyse attributes: parameters / clips
01192                                 typedef std::pair<ttl::ofx::attribute::OfxhClipImage*, std::string> ClipAndConnection;
01193                                 std::vector<ClipAndConnection> clipsToConnect;
01194 
01195                                 bool orderedParams = true;
01196                                 setParametersForNode( args, currentNode, clipsToConnect, false, orderedParams );
01197                                 
01198                                 if( isContextSupported( &currentNode, kOfxImageEffectContextReader ) )
01199                                 {
01200                                         nodesTmp.insert( nodesTmp.begin(), &currentNode );
01201                                 }
01202                                 else
01203                                         nodesTmp.push_back( &currentNode );
01204                         }
01205                         if( processGraph )
01206                         {
01207                                 TUTTLE_LOG_TRACE( "[sam-do] graph processing" );
01208                                 if( !disableProcess )
01209                                         graphTmp.compute( *nodesTmp.back(), options );
01210                         }
01211                 }
01212                 
01213                 
01214         }
01215         catch( const tuttle::exception::Common& e )
01216         {
01217 #ifdef TUTTLE_PRODUCTION
01218                 TUTTLE_LOG_ERROR( "[sam-do] Error: " << *boost::get_error_info<tuttle::exception::user > ( e ) );
01219 #else
01220                 TUTTLE_LOG_ERROR( "[sam-do] Debug: " << boost::current_exception_diagnostic_information() );
01221                 TUTTLE_LOG_ERROR( "[sam-do] Backtrace: " << boost::trace( e ));
01222 #endif
01223                 exit( 254 );
01224         }
01225         catch( const boost::program_options::error& e )
01226         {
01227                 TUTTLE_LOG_ERROR( "[sam-do] Error: " << e.what());
01228                 exit( 254 );
01229         }
01230         catch( ... )
01231         {
01232                 TUTTLE_LOG_ERROR( "[sam-do] Error" );
01233 #ifndef TUTTLE_PRODUCTION
01234                 TUTTLE_LOG_ERROR( boost::current_exception_diagnostic_information() );
01235 #endif
01236                 exit( 254 );
01237         }
01238         return 0;
01239 }
01240