TuttleOFX
1
|
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( ¤tNode ); 00839 } 00840 00841 // connect current node to previous node(s) 00842 connectClips( nodes, clipsToConnect, currentNode, graph, idNames ); 00843 00844 nodes.push_back( ¤tNode ); 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( ¤tNode, kOfxImageEffectContextReader ) ) 01199 { 01200 nodesTmp.insert( nodesTmp.begin(), ¤tNode ); 01201 } 01202 else 01203 nodesTmp.push_back( ¤tNode ); 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