TuttleOFX  1
ProcessVisitors.hpp
Go to the documentation of this file.
00001 #ifndef _TUTTLE_HOST_PROCESSVISITORS_HPP_
00002 #define _TUTTLE_HOST_PROCESSVISITORS_HPP_
00003 
00004 #include "ProcessVertexData.hpp"
00005 
00006 #include <tuttle/host/memory/MemoryCache.hpp>
00007 
00008 #include <boost/graph/properties.hpp>
00009 #include <boost/graph/visitors.hpp>
00010 #include <boost/graph/depth_first_search.hpp>
00011 #include <boost/graph/breadth_first_search.hpp>
00012 #include <boost/foreach.hpp>
00013 #include <boost/date_time/posix_time/posix_time.hpp>
00014 #include <boost/unordered_map.hpp>
00015 
00016 #include <iostream>
00017 #include <fstream>
00018 #include <vector>
00019 
00020 namespace tuttle {
00021 namespace host {
00022 namespace graph {
00023 
00024 template<class TGraph>
00025 inline void connectClips( TGraph& graph )
00026 {
00027         BOOST_FOREACH( typename TGraph::edge_descriptor ed, graph.getEdges() )
00028         {
00029                 typename TGraph::Edge& edge           = graph.instance( ed );
00030                 typename TGraph::Vertex& vertexOutput = graph.targetInstance( ed );
00031                 typename TGraph::Vertex& vertexInput  = graph.sourceInstance( ed );
00032 
00033                 TUTTLE_TLOG( TUTTLE_TRACE, "[Connect Clips] " << edge );
00034                 TUTTLE_TLOG( TUTTLE_TRACE, "[Connect Clips] " << vertexOutput << " -> " << vertexInput );
00035                 //TUTTLE_TLOG_VAR( TUTTLE_TRACE, edge.getInAttrName() );
00036                 
00037                 if( ! vertexOutput.isFake() && ! vertexInput.isFake() )
00038                 {
00039                         INode& outputNode = vertexOutput.getProcessNode();
00040                         INode& inputNode = vertexInput.getProcessNode();
00041                         inputNode.connect( outputNode, inputNode.getAttribute( edge.getInAttrName() ) );
00042                 }
00043         }
00044 }
00045 
00046 
00047 namespace visitor {
00048 
00049 
00050 
00051 template<class TGraph>
00052 class Setup1 : public boost::default_dfs_visitor
00053 {
00054 public:
00055         typedef typename TGraph::GraphContainer GraphContainer;
00056         typedef typename TGraph::Vertex Vertex;
00057 
00058         Setup1( TGraph& graph )
00059                 : _graph( graph )
00060         {}
00061 
00062         template<class VertexDescriptor, class Graph>
00063         void finish_vertex( VertexDescriptor v, Graph& g )
00064         {
00065                 Vertex& vertex = _graph.instance( v );
00066 
00067                 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 1] finish vertex " << vertex );
00068                 if( vertex.isFake() )
00069                         return;
00070 
00071                 vertex.getProcessNode().setup1();
00072         }
00073 
00074 private:
00075         TGraph& _graph;
00076 };
00077 
00078 template<class TGraph>
00079 class Setup2 : public boost::default_dfs_visitor
00080 {
00081 public:
00082         typedef typename TGraph::GraphContainer GraphContainer;
00083         typedef typename TGraph::Vertex Vertex;
00084 
00085         Setup2( TGraph& graph )
00086                 : _graph( graph )
00087         {}
00088 
00089         template<class VertexDescriptor, class Graph>
00090         void discover_vertex( VertexDescriptor v, Graph& g )
00091         {
00092                 Vertex& vertex = _graph.instance( v );
00093 
00094                 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 2] discover vertex " << vertex );
00095                 if( vertex.isFake() )
00096                         return;
00097 
00098                 vertex.getProcessNode().setup2_reverse();
00099         }
00100 
00101 private:
00102         TGraph& _graph;
00103 };
00104 
00105 
00106 template<class TGraph>
00107 class Setup3 : public boost::default_dfs_visitor
00108 {
00109 public:
00110         typedef typename TGraph::GraphContainer GraphContainer;
00111         typedef typename TGraph::Vertex Vertex;
00112 
00113         Setup3( TGraph& graph )
00114                 : _graph( graph )
00115         {}
00116         template<class VertexDescriptor, class Graph>
00117         void finish_vertex( VertexDescriptor v, Graph& g )
00118         {
00119                 Vertex& vertex = _graph.instance( v );
00120 
00121                 TUTTLE_TLOG( TUTTLE_TRACE, "[Setup 3] finish vertex " << vertex );
00122                 if( vertex.isFake() )
00123                         return;
00124 
00125                 vertex.getProcessNode().setup3();
00126         }
00127 
00128 private:
00129         TGraph& _graph;
00130 };
00131 
00132 template<class TGraph>
00133 class TimeDomain : public boost::default_dfs_visitor
00134 {
00135 public:
00136         typedef typename TGraph::GraphContainer GraphContainer;
00137         typedef typename TGraph::Vertex Vertex;
00138 
00139         TimeDomain( TGraph& graph )
00140                 : _graph( graph )
00141         {}
00142 
00143         template<class VertexDescriptor, class Graph>
00144         void finish_vertex( VertexDescriptor vd, Graph& g )
00145         {
00146                 Vertex& vertex = _graph.instance( vd );
00147 
00148                 TUTTLE_TLOG( TUTTLE_TRACE, "[Time Domain] finish vertex " << vertex );
00149                 if( vertex.isFake() )
00150                         return;
00151 
00152                 vertex.getProcessData()._timeDomain = vertex.getProcessNode().computeTimeDomain();
00153                 TUTTLE_TLOG( TUTTLE_TRACE, "[Time Domain] min: " << vertex.getProcessData()._timeDomain.min << ", max: " << vertex.getProcessData()._timeDomain.max );
00154         }
00155 
00156 private:
00157         TGraph& _graph;
00158 };
00159 
00160 template<class TGraph>
00161 class ComputeHashAtTime : public boost::default_dfs_visitor
00162 {
00163 public:
00164         typedef typename TGraph::GraphContainer GraphContainer;
00165         typedef typename TGraph::Vertex Vertex;
00166         typedef typename TGraph::Edge Edge;
00167         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00168         typedef typename TGraph::edge_descriptor edge_descriptor;
00169         typedef typename TGraph::Vertex::Key VertexKey;
00170 
00171         ComputeHashAtTime( TGraph& graph, NodeHashContainer& outNodesHash, const OfxTime time )
00172                 : _graph( graph )
00173                 , _outNodesHash( outNodesHash )
00174                 , _time( time )
00175         {
00176                 //TUTTLE_TLOG( TUTTLE_TRACE, "[ComputeHashAtTime] constructor" );
00177         }
00178 
00179         template<class VertexDescriptor, class Graph>
00180         void finish_vertex( VertexDescriptor vd, Graph& g )
00181         {
00182                 Vertex& vertex = _graph.instance( vd );
00183                 TUTTLE_TLOG( TUTTLE_TRACE, "[Compute Hash At Time] finish vertex " << vertex );
00184 
00185                 if( vertex.isFake() )
00186                         return;
00187 
00188                 const std::size_t localHash = vertex.getProcessNode().getLocalHashAtTime(_time);
00189 
00190                 typedef std::map<VertexKey, std::size_t> InputsHash;
00191                 InputsHash inputsGlobalHash;
00192                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) )
00193                 {
00194                         const Edge& edge = _graph.instance( ed );
00195                         vertex_descriptor inputVertexDesc = _graph.target( ed );
00196                         Vertex& inputVertex = _graph.instance( inputVertexDesc );
00197                         
00198                         const std::size_t inputGlobalHash = _outNodesHash.getHash(inputVertex.getKey());
00199                         // Key is: (clipName, time)
00200                         VertexKey k( edge.getInAttrName(), edge.getOutTime() );
00201                         inputsGlobalHash[k] = inputGlobalHash;
00202                 }
00203                 // inputGlobalHashes is put into a map to be ordered by clip name
00204                 // the clipName is unique for each time used
00205                 std::size_t seed = localHash;
00206                 BOOST_FOREACH( const typename InputsHash::value_type& inputGlobalHash, inputsGlobalHash )
00207                 {
00208                         //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, inputGlobalHash.first, inputGlobalHash.second );
00209                         boost::hash_combine( seed, inputGlobalHash.first.getName() ); // name of the input clip connected
00210                         boost::hash_combine( seed, inputGlobalHash.second );
00211                 }
00212                 _outNodesHash.addHash( vertex.getKey(), seed );
00213                 //TUTTLE_TLOG_VAR( TUTTLE_TRACE, localHash );
00214                 //TUTTLE_TLOG_VAR2( TUTTLE_TRACE, vertex.getKey(), seed );
00215         }
00216 
00217 private:
00218         TGraph& _graph;
00219         NodeHashContainer& _outNodesHash;
00220         OfxTime _time;
00221 };
00222 
00223 
00224 /**
00225  * @brief Create a new version of a graph with nodes deployed over time.
00226  *
00227  * Compute kOfxImageEffectActionGetFramesNeeded for each node if kOfxImageEffectPropTemporalClipAccess is true.
00228  */
00229 template<class TGraph>
00230 class DeployTime : public boost::default_dfs_visitor
00231 {
00232 public:
00233         typedef typename TGraph::GraphContainer GraphContainer;
00234         typedef typename TGraph::Vertex Vertex;
00235         typedef typename TGraph::Edge Edge;
00236         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00237         typedef typename TGraph::edge_descriptor edge_descriptor;
00238 
00239         DeployTime( TGraph& graph, const OfxTime time )
00240                 : _graph( graph )
00241                 , _time( time )
00242         {
00243                 // clear all time informations before to fill with new values
00244                 BOOST_FOREACH( const vertex_descriptor vd, graph.getVertices() )
00245                 {
00246                         Vertex& v = graph.instance( vd );
00247                         v.clearTimeInfo();
00248                 }
00249                 BOOST_FOREACH( const edge_descriptor ed, graph.getEdges() )
00250                 {
00251                         Edge& e = graph.instance( ed );
00252                         e.clearTimeInfo();
00253                 }
00254         }
00255 
00256         template<class VertexDescriptor, class Graph>
00257         void discover_vertex( VertexDescriptor v, Graph& g )
00258         {
00259                 Vertex& vertex = _graph.instance( v );
00260                 
00261                 TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] " << vertex );
00262                 if( vertex.isFake() )
00263                 {
00264                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) )
00265                         {
00266                                 Edge& e = _graph.instance( ed );
00267                                 e._timesNeeded[_time].insert( _time );
00268                                 //TUTTLE_TLOG( TUTTLE_TRACE, "--- insert edge: " << _time );
00269                         }
00270                         vertex._data._times.insert( _time );
00271                         return;
00272                 }
00273 
00274                 // merge times nedded for all out edges
00275                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( v ) )
00276                 {
00277                         const Edge& edge = _graph.instance( ed );
00278                         //TUTTLE_TLOG( TUTTLE_TRACE, "-- outEdge: " << edge );
00279                         BOOST_FOREACH( const typename Edge::TimeMap::value_type& timesNeeded, edge._timesNeeded )
00280                         {
00281                                 vertex._data._times.insert( timesNeeded.second.begin(), timesNeeded.second.end() );
00282 //                              std::cout << "--- insert vertex: ";
00283 //                              std::copy( (*timesNeeded).second.begin(),
00284 //                                         (*timesNeeded).second.end(),
00285 //                                                 std::ostream_iterator<OfxTime>(std::cout, ",") );
00286 //                              std::cout << std::endl;
00287                         }
00288                 }
00289                 
00290                 // Set all times needed on each input edges
00291                 BOOST_FOREACH( const OfxTime t, vertex._data._times )
00292                 {
00293                         TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] time: " << boost::lexical_cast< std::string >(t) );
00294                         INode::ClipTimesSetMap mapInputsTimes = vertex.getProcessNode().getTimesNeeded( t );
00295 //                      BOOST_FOREACH( const INode::InputsTimeMap::value_type& v, mapInputsTimes )
00296 //                      {
00297 //                              TUTTLE_TLOG_VAR( TUTTLE_TRACE, v.first );
00298 //                      }
00299                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) )
00300                         {
00301                                 Edge& edge = _graph.instance( ed );
00302 //                              TUTTLE_TLOG( TUTTLE_INFO, "-- inEdge "<<t<<": " << edge );
00303 //                              const Vertex& input = _graph.targetInstance( ed );
00304 //                              TUTTLE_TLOG_VAR( TUTTLE_TRACE, input.getName() );
00305 //                              std::cout << "--- insert edges: ";
00306 //                              std::copy( mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].begin(),
00307 //                                         mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].end(),
00308 //                                                 std::ostream_iterator<OfxTime>(std::cout, ",") );
00309                                 edge._timesNeeded[t] = mapInputsTimes[edge.getInAttrName()];
00310                         }
00311                 }
00312         }
00313 
00314 private:
00315         TGraph& _graph;
00316         OfxTime _time;
00317 };
00318 
00319 template<class TGraph>
00320 struct IdentityNodeConnection
00321 {
00322         typedef typename TGraph::GraphContainer GraphContainer;
00323         typedef typename TGraph::Vertex Vertex;
00324         typedef typename Vertex::Key VertexKey;
00325         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00326         typedef typename TGraph::Edge Edge;
00327         typedef typename TGraph::edge_descriptor edge_descriptor;
00328         
00329         VertexKey _identityVertex; ///< the identity node to remove
00330         struct InputClipConnection
00331         {
00332                 VertexKey _srcNode;
00333                 std::string _inputClip;
00334         };
00335         struct OutputClipConnection
00336         {
00337                 VertexKey _dstNode;
00338                 std::string _dstNodeClip;
00339         };
00340         InputClipConnection _input;
00341         std::vector< OutputClipConnection > _outputs;
00342 };
00343 
00344 /**
00345  * @warning in progress...
00346  */
00347 template<class TGraph>
00348 class RemoveIdentityNodes : public boost::default_dfs_visitor
00349 {
00350 public:
00351         typedef typename TGraph::GraphContainer GraphContainer;
00352         typedef typename TGraph::Vertex Vertex;
00353         typedef typename Vertex::Key VertexKey;
00354         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00355         typedef typename TGraph::Edge Edge;
00356         typedef typename TGraph::edge_descriptor edge_descriptor;
00357 
00358 public:
00359         RemoveIdentityNodes( TGraph& graph, std::vector<IdentityNodeConnection<TGraph> >& toRemove )
00360                 : _graph( graph )
00361                 , _toRemove( toRemove )
00362         {}
00363         
00364         template<class VertexDescriptor, class Graph>
00365         void finish_vertex( VertexDescriptor vd, Graph& g )
00366         {
00367                 Vertex& vertex = _graph.instance( vd );
00368 
00369                 TUTTLE_TLOG( TUTTLE_TRACE, "[Remove identity nodes] finish vertex " << vertex );
00370                 if( vertex.isFake() )
00371                         return;
00372 
00373                 std::string inputClip;
00374                 OfxTime atTime;
00375                 if( vertex.getProcessNode().isIdentity( vertex.getProcessDataAtTime(), inputClip, atTime ) )
00376                 {
00377                         try
00378                         {
00379                                 if( inputClip.size() == 0 )
00380                                 {
00381                                         BOOST_THROW_EXCEPTION( exception::Logic()
00382                                                 << exception::dev() + "There is an error in the plugin: The plugin declares to be identity but don't give the name of the input clip to use." );
00383                                 }
00384                                 IdentityNodeConnection<TGraph> reconnect;
00385                                 reconnect._identityVertex = _graph.instance(vd).getKey();
00386                                 reconnect._input._inputClip = inputClip;
00387                                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) )
00388                                 {
00389                                         const Edge& e = _graph.instance( ed );
00390                                         if( ( e.getInAttrName() == inputClip ) &&
00391                                             ( e.getOutTime() == atTime )
00392                                           )
00393                                         {
00394                                                 vertex_descriptor in = _graph.target( ed );
00395                                                 reconnect._input._srcNode = _graph.instance(in).getKey();
00396                                         }
00397                                 }
00398                                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( vd ) )
00399                                 {
00400                                         const Edge& e = _graph.instance( ed );
00401                                         vertex_descriptor out = _graph.source( ed );
00402                                         typename IdentityNodeConnection<TGraph>::OutputClipConnection c;
00403                                         c._dstNode = _graph.instance(out).getKey();
00404                                         c._dstNodeClip = e.getInAttrName();
00405                                         reconnect._outputs.push_back(c);
00406                                 }
00407                                 TUTTLE_TLOG( TUTTLE_TRACE, "isIdentity => " << vertex.getName() << " - " << inputClip << " at time " << atTime );
00408                                 _toRemove.push_back( reconnect );
00409                                 TUTTLE_TLOG_VAR( TUTTLE_TRACE, _toRemove.size() );
00410                         }
00411                         catch( boost::exception& e )
00412                         {
00413                                 e << exception::user() + "A node is declared identity without given a valid input clip ("+quotes(inputClip)+", "+atTime+ ")."
00414                                   << exception::nodeName( vertex.getName() )
00415                                   << exception::time( vertex.getProcessDataAtTime()._time );
00416                                 throw;
00417                         }
00418                 }
00419         }
00420 
00421 private:
00422         TGraph& _graph;
00423         std::vector<IdentityNodeConnection<TGraph> >& _toRemove;
00424         
00425 };
00426 
00427 /**
00428  * @brief Unconnect identity nodes and re-connect neightbors nodes
00429  *
00430  * ////////////////////////////////////////////////////////////////////////////////
00431  * //        Output at time 5
00432  * //          |
00433  * //        Retime time -2 <-- identity node declare to use Merge at time 3
00434  * //          |
00435  * //        Merge at time 3 <-- identity node declare to use ReadA at time 3
00436  * //        /    \
00437  * //      /        \
00438  * //    /            \
00439  * // ReadA time 3   ReadB time 3
00440  * //
00441  * ////////////////////////////////////////////////////////////////////////////////
00442  * // After removing identity nodes:
00443  * //
00444  * // Output at time 5
00445  * //   |
00446  * // ReadA time 3
00447  * //
00448  * // Retime time -2 <-- leave unconnected  
00449  * // Merge at time 3 <-- leave unconnected  
00450  * // ReadB time 3 <-- leave unconnected
00451  * ////////////////////////////////////////////////////////////////////////////////
00452  */
00453 template<class TGraph>
00454 void removeIdentityNodes( TGraph& graph, const std::vector<IdentityNodeConnection<TGraph> >& nodesToRemove )
00455 {
00456 //      TUTTLE_IF_DEBUG(
00457 //              TUTTLE_LOG_VAR( TUTTLE_TRACE, toRemove.size() );
00458 //              BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, toRemove )
00459 //              {
00460 //                      TUTTLE_LOG( TUTTLE_TRACE, connection._identityVertex );
00461 //                      TUTTLE_LOG( TUTTLE_TRACE, "IN: "
00462 //                              << connection._identityVertex << "::" << connection._input._inputClip
00463 //                              << " <<-- "
00464 //                              << connection._input._srcNode << "::" kOfxOutputAttributeName );
00465 //                      
00466 //                      BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs )
00467 //                      {
00468 //                              TUTTLE_LOG( TUTTLE_TRACE, "OUT: "
00469 //                                      << connection._identityVertex << "::" kOfxOutputAttributeName
00470 //                                      << " -->> "
00471 //                                      << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip );
00472 //                      }
00473 //              }
00474 //      );
00475 //      TUTTLE_LOG( TUTTLE_TRACE, "-- removeIdentityNodes --" );
00476         typedef typename TGraph::Vertex Vertex;
00477         typedef typename Vertex::Key VertexKey;
00478         
00479         typedef boost::unordered_map<VertexKey, const IdentityNodeConnection<TGraph>*> IdentityMap;
00480         IdentityMap identityNodes;
00481         
00482         BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove )
00483         {
00484                 identityNodes[connection._identityVertex] = &connection;
00485         }
00486         
00487         BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove )
00488         {
00489                 TUTTLE_TLOG( TUTTLE_TRACE, boost::lexical_cast<std::string>(connection._identityVertex) );
00490                 TUTTLE_TLOG( TUTTLE_TRACE, "IN: "
00491                         << boost::lexical_cast<std::string>(connection._identityVertex) << "::" << boost::lexical_cast<std::string>(connection._input._inputClip)
00492                         << " <<-- "
00493                         << boost::lexical_cast<std::string>(connection._input._srcNode) << "::" kOfxOutputAttributeName );
00494                 const typename TGraph::VertexKey* searchIn = &( connection._input._srcNode );
00495                 {
00496                         // search a non-identity node to replace the connection
00497                         typename IdentityMap::const_iterator it = identityNodes.find( *searchIn );
00498                         typename IdentityMap::const_iterator itEnd = identityNodes.end();
00499                         while( it != itEnd )
00500                         {
00501                                 searchIn = &( it->second->_input._srcNode );
00502                                 it = identityNodes.find( *searchIn );
00503                         }
00504                 }
00505                 const typename TGraph::VertexKey& in = *searchIn;
00506                 const typename TGraph::vertex_descriptor descIn  = graph.getVertexDescriptor( in );
00507                 
00508                 // replace all input/output connections of the identity node by one edge
00509                 BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs )
00510                 {
00511                         //TUTTLE_LOG( TUTTLE_TRACE, "OUT: "
00512                         //      << connection._identityVertex << "::" kOfxOutputAttributeName
00513                         //      << " -->> "
00514                         //      << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip );
00515                         const typename TGraph::VertexKey& out = outputClipConnection._dstNode;
00516                         const std::string inAttr = outputClipConnection._dstNodeClip;
00517 
00518                         const typename TGraph::vertex_descriptor descOut = graph.getVertexDescriptor( out );
00519 
00520                         const typename TGraph::Edge e( in, out, inAttr );
00521                         graph.addEdge( descOut, descIn, e );
00522                 }
00523                 // Warning: We don't remove the vertex itself to not invalidate vertex_descriptors but only remove edges.
00524 //              graph.removeVertex( graph.getVertexDescriptor(connection._identityVertex) );
00525                 // remove all node connections
00526                 graph.clearVertex( graph.getVertexDescriptor(connection._identityVertex) );
00527         }
00528 }
00529 
00530 template<class TGraph>
00531 class PreProcess1 : public boost::default_dfs_visitor
00532 {
00533 public:
00534         typedef typename TGraph::GraphContainer GraphContainer;
00535         typedef typename TGraph::Vertex Vertex;
00536 
00537         PreProcess1( TGraph& graph )
00538                 : _graph( graph )
00539         {}
00540 
00541         template<class VertexDescriptor, class Graph>
00542         void finish_vertex( VertexDescriptor v, Graph& g )
00543         {
00544                 Vertex& vertex = _graph.instance( v );
00545 
00546                 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 1] finish vertex " << vertex );
00547                 if( vertex.isFake() )
00548                         return;
00549 
00550                 //TUTTLE_TLOG( TUTTLE_TRACE, vertex.getProcessDataAtTime()._time );
00551                 vertex.getProcessNode().preProcess1( vertex.getProcessDataAtTime() );
00552         }
00553 
00554 private:
00555         TGraph& _graph;
00556 };
00557 
00558 template<class TGraph>
00559 class PreProcess2 : public boost::default_dfs_visitor
00560 {
00561 public:
00562         typedef typename TGraph::GraphContainer GraphContainer;
00563         typedef typename TGraph::Vertex Vertex;
00564 
00565         PreProcess2( TGraph& graph )
00566                 : _graph( graph )
00567         {}
00568 
00569         template<class VertexDescriptor, class Graph>
00570         void discover_vertex( VertexDescriptor v, Graph& g )
00571         {
00572                 Vertex& vertex = _graph.instance( v );
00573 
00574                 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 2] discover vertex " << vertex );
00575                 if( vertex.isFake() )
00576                         return;
00577 
00578                 vertex.getProcessNode().preProcess2_reverse( vertex.getProcessDataAtTime() );
00579         }
00580 
00581 private:
00582         TGraph& _graph;
00583 };
00584 
00585 template<class TGraph>
00586 class OptimizeGraph : public boost::default_dfs_visitor
00587 {
00588 public:
00589         typedef typename TGraph::GraphContainer GraphContainer;
00590         typedef typename TGraph::Vertex Vertex;
00591         typedef typename TGraph::Edge Edge;
00592         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00593         typedef typename TGraph::edge_descriptor edge_descriptor;
00594         typedef typename TGraph::in_edge_iterator in_edge_iterator;
00595         typedef typename TGraph::out_edge_iterator out_edge_iterator;
00596 
00597         OptimizeGraph( TGraph& graph )
00598                 : _graph( graph )
00599         {
00600         }
00601 
00602         template <class VertexDescriptor, class Graph>
00603         void finish_vertex( VertexDescriptor v, const Graph& g )
00604         {
00605                 using namespace boost;
00606                 using namespace boost::graph;
00607                 Vertex& vertex = _graph.instance( v );
00608 
00609                 ProcessVertexAtTimeData& procOptions = vertex.getProcessDataAtTime();
00610                 if( !vertex.isFake() )
00611                 {
00612                         // compute local infos, need to be a real node !
00613                         vertex.getProcessNode().preProcess_infos( vertex.getProcessDataAtTime(), procOptions._time, procOptions._localInfos );
00614                 }
00615 
00616                 // compute global infos for inputs
00617 
00618                 // direct dependencies (originally the node inputs)
00619                 BOOST_FOREACH( const edge_descriptor& oe, out_edges( v, _graph.getGraph() ) )
00620                 {
00621 //                      Edge& outEdge = _graph.instance(*oe);
00622                         Vertex& outVertex = _graph.targetInstance( oe );
00623                         procOptions._inputsInfos += outVertex.getProcessDataAtTime()._localInfos;
00624                         procOptions._globalInfos += outVertex.getProcessDataAtTime()._globalInfos;
00625                 }
00626                 procOptions._globalInfos += procOptions._localInfos;
00627 
00628 //              BOOST_FOREACH( const edge_descriptor& ie, in_edges( v, _graph.getGraph() ) )
00629 //              {
00630 //                      Edge& e = _graph.instance( ie );
00631 //              }
00632 
00633 
00634 //              TUTTLE_TLOG( TUTTLE_TRACE, vertex.getName() );
00635 //              TUTTLE_TLOG( TUTTLE_TRACE, procOptions );
00636         }
00637 
00638 private:
00639         TGraph& _graph;
00640 };
00641 
00642 template<class TGraph>
00643 class Process : public boost::default_dfs_visitor
00644 {
00645 public:
00646         typedef typename TGraph::GraphContainer GraphContainer;
00647         typedef typename TGraph::Vertex Vertex;
00648 
00649         Process( TGraph& graph, memory::IMemoryCache& cache )
00650                 : _graph( graph )
00651                 , _cache( cache )
00652                 , _result( NULL )
00653         {
00654         }
00655         
00656         Process( TGraph& graph, memory::IMemoryCache& cache, memory::IMemoryCache& result )
00657                 : _graph( graph )
00658                 , _cache( cache )
00659                 , _result( &result )
00660         {
00661         }
00662         
00663         /**
00664          * Set a MemoryCache object to accumulate output nodes buffers.
00665          */
00666         void setOutputMemoryCache( memory::IMemoryCache& result )
00667         {
00668                 _result = &result;
00669         }
00670 
00671         template<class VertexDescriptor, class Graph>
00672         void finish_vertex( VertexDescriptor v, Graph& g )
00673         {
00674                 Vertex& vertex = _graph.instance( v );
00675                 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] finish_vertex " << vertex );
00676 
00677                 // do nothing on the empty output node
00678                 // it's just a link to final nodes
00679                 if( vertex.isFake() )
00680                         return;
00681 
00682                 // check if abort ?
00683 
00684                 // launch the process
00685                 boost::posix_time::ptime t1(boost::posix_time::microsec_clock::local_time());
00686                 vertex.getProcessNode().process( vertex.getProcessDataAtTime() );
00687                 boost::posix_time::ptime t2(boost::posix_time::microsec_clock::local_time());
00688                 _cumulativeTime += t2 - t1;
00689                 
00690                 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] " << quotes(vertex._name) << " " << vertex._data._time << " took: " << t2 - t1 << " (cumul: " << _cumulativeTime << ")" << vertex );
00691                 
00692                 if( _result && vertex.getProcessDataAtTime()._isFinalNode )
00693                 {
00694                         memory::CACHE_ELEMENT img = _cache.get( vertex._clipName + "." kOfxOutputAttributeName, vertex._data._time );
00695                         if( ! img.get() )
00696                         {
00697                                 BOOST_THROW_EXCEPTION( exception::Logic()
00698                                         << exception::user() + "Output buffer not found in memoryCache at the end of the node process."
00699                                         << exception::nodeName( vertex._name )
00700                                         << exception::time( vertex._data._time ) );
00701                         }
00702                         _result->put( vertex._clipName, vertex._data._time, img );
00703                 }
00704         }
00705 
00706 private:
00707         TGraph& _graph;
00708         memory::IMemoryCache& _cache;
00709         memory::IMemoryCache* _result;
00710         boost::posix_time::time_duration _cumulativeTime;
00711 };
00712 
00713 template<class TGraph>
00714 class PostProcess : public boost::default_dfs_visitor
00715 {
00716 public:
00717         typedef typename TGraph::GraphContainer GraphContainer;
00718         typedef typename TGraph::Vertex Vertex;
00719 
00720         PostProcess( TGraph& graph )
00721                 : _graph( graph )
00722         {}
00723 
00724         template<class VertexDescriptor, class Graph>
00725         void initialize_vertex( VertexDescriptor v, Graph& g )
00726         {
00727                 Vertex& vertex = _graph.instance( v );
00728 
00729                 TUTTLE_TLOG( TUTTLE_TRACE,"[Post-process] initialize_vertex " << vertex );
00730                 if( vertex.isFake() )
00731                         return;
00732         }
00733 
00734         template<class VertexDescriptor, class Graph>
00735         void finish_vertex( VertexDescriptor v, Graph& g )
00736         {
00737                 Vertex& vertex = _graph.instance( v );
00738 
00739                 TUTTLE_TLOG( TUTTLE_TRACE, "[Post-process] finish_vertex " << vertex );
00740                 if( vertex.isFake() )
00741                         return;
00742 
00743                 vertex.getProcessNode().postProcess( vertex.getProcessDataAtTime() );
00744         }
00745 
00746 private:
00747         TGraph& _graph;
00748 };
00749 
00750 }
00751 }
00752 }
00753 }
00754 
00755 #endif
00756