TuttleOFX  1
TuttleOFX/libraries/tuttle/src/tuttle/host/graph/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 
00262 
00263                 TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] " << vertex );
00264                 if( vertex.isFake() )
00265                 {
00266                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) )
00267                         {
00268                                 Edge& e = _graph.instance( ed );
00269                                 e._timesNeeded[_time].insert( _time );
00270                                 //TUTTLE_TLOG( TUTTLE_TRACE, "--- insert edge: " << _time );
00271                         }
00272                         vertex._data._times.insert( _time );
00273                         return;
00274                 }
00275 
00276                 // merge times nedded for all out edges
00277                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( v ) )
00278                 {
00279                         const Edge& edge = _graph.instance( ed );
00280                         //TUTTLE_TLOG( TUTTLE_TRACE, "-- outEdge: " << edge );
00281                         BOOST_FOREACH( const typename Edge::TimeMap::value_type& timesNeeded, edge._timesNeeded )
00282                         {
00283                                 vertex._data._times.insert( timesNeeded.second.begin(), timesNeeded.second.end() );
00284 //                              std::cout << "--- insert vertex: ";
00285 //                              std::copy( (*timesNeeded).second.begin(),
00286 //                                         (*timesNeeded).second.end(),
00287 //                                                 std::ostream_iterator<OfxTime>(std::cout, ",") );
00288 //                              std::cout << std::endl;
00289                         }
00290                 }
00291                 
00292                 // Set all times needed on each input edges
00293                 BOOST_FOREACH( const OfxTime t, vertex._data._times )
00294                 {
00295                         TUTTLE_TLOG( TUTTLE_TRACE, "[Deploy Time] time: " << boost::lexical_cast< std::string >(t) );
00296                         INode::ClipTimesSetMap mapInputsTimes = vertex.getProcessNode().getTimesNeeded( t );
00297 //                      BOOST_FOREACH( const INode::InputsTimeMap::value_type& v, mapInputsTimes )
00298 //                      {
00299 //                              TUTTLE_TLOG_VAR( TUTTLE_TRACE, v.first );
00300 //                      }
00301                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( v ) )
00302                         {
00303                                 Edge& edge = _graph.instance( ed );
00304 //                              TUTTLE_TLOG( TUTTLE_INFO, "-- inEdge "<<t<<": " << edge );
00305 //                              const Vertex& input = _graph.targetInstance( ed );
00306 //                              TUTTLE_TLOG_VAR( TUTTLE_TRACE, input.getName() );
00307 //                              std::cout << "--- insert edges: ";
00308 //                              std::copy( mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].begin(),
00309 //                                         mapInputsTimes[input.getName()+"." kOfxOutputAttributeName].end(),
00310 //                                                 std::ostream_iterator<OfxTime>(std::cout, ",") );
00311                                 edge._timesNeeded[t] = mapInputsTimes[edge.getInAttrName()];
00312                         }
00313                 }
00314         }
00315 
00316 private:
00317         TGraph& _graph;
00318         OfxTime _time;
00319 };
00320 
00321 template<class TGraph>
00322 struct IdentityNodeConnection
00323 {
00324         typedef typename TGraph::GraphContainer GraphContainer;
00325         typedef typename TGraph::Vertex Vertex;
00326         typedef typename Vertex::Key VertexKey;
00327         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00328         typedef typename TGraph::Edge Edge;
00329         typedef typename TGraph::edge_descriptor edge_descriptor;
00330         
00331         VertexKey _identityVertex; ///< the identity node to remove
00332         struct InputClipConnection
00333         {
00334                 VertexKey _srcNode;
00335                 std::string _inputClip;
00336         };
00337         struct OutputClipConnection
00338         {
00339                 VertexKey _dstNode;
00340                 std::string _dstNodeClip;
00341         };
00342         InputClipConnection _input;
00343         std::vector< OutputClipConnection > _outputs;
00344 };
00345 
00346 /**
00347  * @warning in progress...
00348  */
00349 template<class TGraph>
00350 class RemoveIdentityNodes : public boost::default_dfs_visitor
00351 {
00352 public:
00353         typedef typename TGraph::GraphContainer GraphContainer;
00354         typedef typename TGraph::Vertex Vertex;
00355         typedef typename Vertex::Key VertexKey;
00356         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00357         typedef typename TGraph::Edge Edge;
00358         typedef typename TGraph::edge_descriptor edge_descriptor;
00359 
00360 public:
00361         RemoveIdentityNodes( TGraph& graph, std::vector<IdentityNodeConnection<TGraph> >& toRemove )
00362                 : _graph( graph )
00363                 , _toRemove( toRemove )
00364         {}
00365         
00366         template<class VertexDescriptor, class Graph>
00367         void finish_vertex( VertexDescriptor vd, Graph& g )
00368         {
00369                 Vertex& vertex = _graph.instance( vd );
00370 
00371                 TUTTLE_TLOG( TUTTLE_TRACE, "[Remove identity nodes] finish vertex " << vertex );
00372                 if( vertex.isFake() )
00373                         return;
00374 
00375                 std::string inputClip;
00376                 OfxTime atTime;
00377                 if( vertex.getProcessNode().isIdentity( vertex.getProcessDataAtTime(), inputClip, atTime ) )
00378                 {
00379                         try
00380                         {
00381                                 IdentityNodeConnection<TGraph> reconnect;
00382                                 reconnect._identityVertex = vertex.getKey();
00383                                 reconnect._input._inputClip = inputClip;
00384                                 
00385                                 if( ! inputClip.empty() )
00386                                 {
00387                                         // The inputClip should not be empty in the OpenFX standard,
00388                                         // but it's used in TuttleOFX to disable the process of the node
00389                                         // and all the graph branch behind.
00390                                         
00391                                         bool clipFound = false;
00392                                         bool clipFoundAtTime = false;
00393                                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) )
00394                                         {
00395                                                 const Edge& e = _graph.instance( ed );
00396                                                 if( e.getInAttrName() == inputClip )
00397                                                 {
00398                                                         clipFound = true;
00399                                                         if( e.getOutTime() == atTime )
00400                                                         {
00401                                                                 clipFoundAtTime = true;
00402                                                                 vertex_descriptor in = _graph.target( ed );
00403                                                                 reconnect._input._srcNode = _graph.instance(in).getKey();
00404                                                         }
00405                                                 }
00406                                         }
00407                                         if( ! clipFound )
00408                                         {
00409                                                 std::stringstream existingClips;
00410                                                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) )
00411                                                 {
00412                                                         const Edge& e = _graph.instance( ed );
00413                                                         existingClips << e.getInAttrName() << ", ";
00414                                                 }
00415                                                 BOOST_THROW_EXCEPTION( exception::Bug()
00416                                                                 << exception::dev() + "Plugin declares itself as identity, but gives a non existing input clip. "
00417                                                                         "(node: " + vertex.getName() + ", input clip:" + inputClip + ", existing clips: (" + existingClips.str() + "))"
00418                                                                 );
00419                                         }
00420                                         if( ! clipFoundAtTime )
00421                                         {
00422                                                 std::stringstream framesNeeded;
00423                                                 BOOST_FOREACH( const edge_descriptor& ed, _graph.getOutEdges( vd ) )
00424                                                 {
00425                                                         const Edge& e = _graph.instance( ed );
00426                                                         if( e.getInAttrName() == inputClip )
00427                                                         {
00428                                                                 framesNeeded << e.getOutTime() << ", ";
00429                                                         }
00430                                                 }
00431                                                 BOOST_THROW_EXCEPTION( exception::Bug()
00432                                                                 << exception::dev() + "Plugin declares itself as identity, but gives a time on the input clip different from declared framesNeeded. "
00433                                                                         "(node: " + vertex.getName() + ", input clip:" + inputClip + ", time:" + atTime + ", framesNeeded:(" + framesNeeded.str() + "))"
00434                                                                 );
00435                                         }
00436                                         
00437                                         BOOST_FOREACH( const edge_descriptor& ed, _graph.getInEdges( vd ) )
00438                                         {
00439                                                 const Edge& e = _graph.instance( ed );
00440                                                 vertex_descriptor out = _graph.source( ed );
00441                                                 typename IdentityNodeConnection<TGraph>::OutputClipConnection c;
00442                                                 c._dstNode = _graph.instance(out).getKey();
00443                                                 c._dstNodeClip = e.getInAttrName();
00444                                                 reconnect._outputs.push_back(c);
00445                                         }
00446                                 }
00447                                 TUTTLE_TLOG( TUTTLE_TRACE, "isIdentity => " << vertex.getName() << " - " << inputClip << " at time " << atTime );
00448                                 _toRemove.push_back( reconnect );
00449                                 TUTTLE_TLOG_VAR( TUTTLE_TRACE, _toRemove.size() );
00450                         }
00451                         catch( boost::exception& e )
00452                         {
00453                                 e << exception::user() + "Error on the node " + quotes(vertex.getName()) + ". It fails to declare itself as an identity node."
00454                                   << exception::nodeName( vertex.getName() )
00455                                   << exception::time( vertex.getProcessDataAtTime()._time );
00456                                 throw;
00457                         }
00458                 }
00459         }
00460 
00461 private:
00462         TGraph& _graph;
00463         std::vector<IdentityNodeConnection<TGraph> >& _toRemove;
00464         
00465 };
00466 
00467 /**
00468  * @brief Unconnect identity nodes and re-connect neightbors nodes
00469  *
00470  * ////////////////////////////////////////////////////////////////////////////////
00471  * //        Output at time 5
00472  * //          |
00473  * //        Retime time -2 <-- identity node declare to use Merge at time 3
00474  * //          |
00475  * //        Merge at time 3 <-- identity node declare to use ReadA at time 3
00476  * //        /    \
00477  * //      /        \
00478  * //    /            \
00479  * // ReadA time 3   ReadB time 3
00480  * //
00481  * ////////////////////////////////////////////////////////////////////////////////
00482  * // After removing identity nodes:
00483  * //
00484  * // Output at time 5
00485  * //   |
00486  * // ReadA time 3
00487  * //
00488  * // Retime time -2 <-- leave unconnected  
00489  * // Merge at time 3 <-- leave unconnected  
00490  * // ReadB time 3 <-- leave unconnected
00491  * ////////////////////////////////////////////////////////////////////////////////
00492  */
00493 template<class TGraph>
00494 void removeIdentityNodes( TGraph& graph, const std::vector<IdentityNodeConnection<TGraph> >& nodesToRemove )
00495 {
00496 //      TUTTLE_IF_DEBUG(
00497 //              TUTTLE_LOG_VAR( TUTTLE_TRACE, toRemove.size() );
00498 //              BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, toRemove )
00499 //              {
00500 //                      TUTTLE_LOG( TUTTLE_TRACE, connection._identityVertex );
00501 //                      TUTTLE_LOG( TUTTLE_TRACE, "IN: "
00502 //                              << connection._identityVertex << "::" << connection._input._inputClip
00503 //                              << " <<-- "
00504 //                              << connection._input._srcNode << "::" kOfxOutputAttributeName );
00505 //                      
00506 //                      BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs )
00507 //                      {
00508 //                              TUTTLE_LOG( TUTTLE_TRACE, "OUT: "
00509 //                                      << connection._identityVertex << "::" kOfxOutputAttributeName
00510 //                                      << " -->> "
00511 //                                      << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip );
00512 //                      }
00513 //              }
00514 //      );
00515 //      TUTTLE_LOG( TUTTLE_TRACE, "-- removeIdentityNodes --" );
00516         typedef typename TGraph::Vertex Vertex;
00517         typedef typename Vertex::Key VertexKey;
00518         
00519         typedef boost::unordered_map<VertexKey, const IdentityNodeConnection<TGraph>*> IdentityMap;
00520         IdentityMap identityNodes;
00521         
00522         BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove )
00523         {
00524                 identityNodes[connection._identityVertex] = &connection;
00525         }
00526         
00527         bool disabledBranch = false;
00528         BOOST_FOREACH( const IdentityNodeConnection<TGraph>& connection, nodesToRemove )
00529         {
00530                 if( connection._input._inputClip.empty() )
00531                 {
00532                         // The input clip is empty, this not in the OpenFX standard.
00533                         // In Tuttle, it means that the branch is disabled.
00534                         disabledBranch = true;
00535                 }
00536                 else
00537                 {
00538                         // Create new connections if the input clip name is not empty
00539                         TUTTLE_TLOG_TRACE( boost::lexical_cast<std::string>(connection._identityVertex) );
00540                         TUTTLE_TLOG_TRACE( "IN: "
00541                                 << boost::lexical_cast<std::string>(connection._identityVertex) << "::" << boost::lexical_cast<std::string>(connection._input._inputClip)
00542                                 << " <<-- "
00543                                 << boost::lexical_cast<std::string>(connection._input._srcNode) << "::" kOfxOutputAttributeName );
00544                         const typename TGraph::VertexKey* searchIn = &( connection._input._srcNode );
00545                         {
00546                                 // search a non-identity node to replace the connection
00547                                 typename IdentityMap::const_iterator it = identityNodes.find( *searchIn );
00548                                 typename IdentityMap::const_iterator itEnd = identityNodes.end();
00549                                 while( it != itEnd )
00550                                 {
00551                                         searchIn = &( it->second->_input._srcNode );
00552                                         it = identityNodes.find( *searchIn );
00553                                 }
00554                         }
00555                         const typename TGraph::VertexKey& in = *searchIn;
00556                         const typename TGraph::vertex_descriptor descIn  = graph.getVertexDescriptor( in );
00557 
00558                         // replace all input/output connections of the identity node by one edge
00559                         BOOST_FOREACH( const typename IdentityNodeConnection<TGraph>::OutputClipConnection& outputClipConnection, connection._outputs )
00560                         {
00561                                 //TUTTLE_TLOG_TRACE( "OUT: "
00562                                 //      << connection._identityVertex << "::" kOfxOutputAttributeName
00563                                 //      << " -->> "
00564                                 //      << outputClipConnection._dstNode << "::" << outputClipConnection._dstNodeClip );
00565                                 const typename TGraph::VertexKey& out = outputClipConnection._dstNode;
00566                                 const std::string inAttr = outputClipConnection._dstNodeClip;
00567 
00568                                 const typename TGraph::vertex_descriptor descOut = graph.getVertexDescriptor( out );
00569 
00570                                 const typename TGraph::Edge e( in, out, inAttr );
00571                                 graph.addEdge( descOut, descIn, e );
00572                         }
00573                 }
00574                 // Warning: We don't remove the vertex itself to not invalidate vertex_descriptors but only remove edges.
00575 //              graph.removeVertex( graph.getVertexDescriptor(connection._identityVertex) );
00576                 // remove all node connections
00577                 graph.clearVertex( graph.getVertexDescriptor(connection._identityVertex) );
00578         }
00579         
00580         if( disabledBranch )
00581         {
00582                 // @todo: Remove connections of all vertices not connected to the output.
00583                 // These unconnected branches have been created by identity nodes without source clip.
00584         }
00585 }
00586 
00587 template<class TGraph>
00588 class PreProcess1 : public boost::default_dfs_visitor
00589 {
00590 public:
00591         typedef typename TGraph::GraphContainer GraphContainer;
00592         typedef typename TGraph::Vertex Vertex;
00593 
00594         PreProcess1( TGraph& graph )
00595                 : _graph( graph )
00596         {}
00597 
00598         template<class VertexDescriptor, class Graph>
00599         void finish_vertex( VertexDescriptor v, Graph& g )
00600         {
00601                 Vertex& vertex = _graph.instance( v );
00602 
00603                 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 1] finish vertex " << vertex );
00604                 if( vertex.isFake() )
00605                         return;
00606 
00607                 //TUTTLE_TLOG( TUTTLE_TRACE, vertex.getProcessDataAtTime()._time );
00608                 vertex.getProcessNode().preProcess1( vertex.getProcessDataAtTime() );
00609         }
00610 
00611 private:
00612         TGraph& _graph;
00613 };
00614 
00615 template<class TGraph>
00616 class PreProcess2 : public boost::default_dfs_visitor
00617 {
00618 public:
00619         typedef typename TGraph::GraphContainer GraphContainer;
00620         typedef typename TGraph::Vertex Vertex;
00621 
00622         PreProcess2( TGraph& graph )
00623                 : _graph( graph )
00624         {}
00625 
00626         template<class VertexDescriptor, class Graph>
00627         void discover_vertex( VertexDescriptor v, Graph& g )
00628         {
00629                 Vertex& vertex = _graph.instance( v );
00630 
00631                 TUTTLE_TLOG( TUTTLE_TRACE, "[Preprocess 2] discover vertex " << vertex );
00632                 if( vertex.isFake() )
00633                         return;
00634 
00635                 vertex.getProcessNode().preProcess2_reverse( vertex.getProcessDataAtTime() );
00636         }
00637 
00638 private:
00639         TGraph& _graph;
00640 };
00641 
00642 template<class TGraph>
00643 class OptimizeGraph : public boost::default_dfs_visitor
00644 {
00645 public:
00646         typedef typename TGraph::GraphContainer GraphContainer;
00647         typedef typename TGraph::Vertex Vertex;
00648         typedef typename TGraph::Edge Edge;
00649         typedef typename TGraph::vertex_descriptor vertex_descriptor;
00650         typedef typename TGraph::edge_descriptor edge_descriptor;
00651         typedef typename TGraph::in_edge_iterator in_edge_iterator;
00652         typedef typename TGraph::out_edge_iterator out_edge_iterator;
00653 
00654         OptimizeGraph( TGraph& graph )
00655                 : _graph( graph )
00656         {
00657         }
00658 
00659         template <class VertexDescriptor, class Graph>
00660         void finish_vertex( VertexDescriptor v, const Graph& g )
00661         {
00662                 using namespace boost;
00663                 using namespace boost::graph;
00664                 Vertex& vertex = _graph.instance( v );
00665 
00666                 ProcessVertexAtTimeData& procOptions = vertex.getProcessDataAtTime();
00667                 if( !vertex.isFake() )
00668                 {
00669                         // compute local infos, need to be a real node !
00670                         vertex.getProcessNode().preProcess_infos( vertex.getProcessDataAtTime(), procOptions._time, procOptions._localInfos );
00671                 }
00672 
00673                 // compute global infos for inputs
00674 
00675                 // direct dependencies (originally the node inputs)
00676                 BOOST_FOREACH( const edge_descriptor& oe, out_edges( v, _graph.getGraph() ) )
00677                 {
00678 //                      Edge& outEdge = _graph.instance(*oe);
00679                         Vertex& outVertex = _graph.targetInstance( oe );
00680                         procOptions._inputsInfos += outVertex.getProcessDataAtTime()._localInfos;
00681                         procOptions._globalInfos += outVertex.getProcessDataAtTime()._globalInfos;
00682                 }
00683                 procOptions._globalInfos += procOptions._localInfos;
00684 
00685 //              BOOST_FOREACH( const edge_descriptor& ie, in_edges( v, _graph.getGraph() ) )
00686 //              {
00687 //                      Edge& e = _graph.instance( ie );
00688 //              }
00689 
00690 
00691 //              TUTTLE_TLOG( TUTTLE_TRACE, vertex.getName() );
00692 //              TUTTLE_TLOG( TUTTLE_TRACE, procOptions );
00693         }
00694 
00695 private:
00696         TGraph& _graph;
00697 };
00698 
00699 template<class TGraph>
00700 class Process : public boost::default_dfs_visitor
00701 {
00702 public:
00703         typedef typename TGraph::GraphContainer GraphContainer;
00704         typedef typename TGraph::Vertex Vertex;
00705 
00706         Process( TGraph& graph, memory::IMemoryCache& cache )
00707                 : _graph( graph )
00708                 , _cache( cache )
00709                 , _result( NULL )
00710         {
00711         }
00712         
00713         Process( TGraph& graph, memory::IMemoryCache& cache, memory::IMemoryCache& result )
00714                 : _graph( graph )
00715                 , _cache( cache )
00716                 , _result( &result )
00717         {
00718         }
00719         
00720         /**
00721          * Set a MemoryCache object to accumulate output nodes buffers.
00722          */
00723         void setOutputMemoryCache( memory::IMemoryCache& result )
00724         {
00725                 _result = &result;
00726         }
00727 
00728         template<class VertexDescriptor, class Graph>
00729         void finish_vertex( VertexDescriptor v, Graph& g )
00730         {
00731                 Vertex& vertex = _graph.instance( v );
00732                 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] finish_vertex " << vertex );
00733 
00734                 // do nothing on the empty output node
00735                 // it's just a link to final nodes
00736                 if( vertex.isFake() )
00737                         return;
00738 
00739                 // check if abort ?
00740 
00741                 // launch the process
00742                 boost::posix_time::ptime t1(boost::posix_time::microsec_clock::local_time());
00743                 vertex.getProcessNode().process( vertex.getProcessDataAtTime() );
00744                 boost::posix_time::ptime t2(boost::posix_time::microsec_clock::local_time());
00745                 _cumulativeTime += t2 - t1;
00746                 
00747                 TUTTLE_TLOG( TUTTLE_TRACE, "[Process] " << quotes(vertex._name) << " " << vertex._data._time << " took: " << t2 - t1 << " (cumul: " << _cumulativeTime << ")" << vertex );
00748                 
00749                 if( _result && vertex.getProcessDataAtTime()._isFinalNode )
00750                 {
00751                         memory::CACHE_ELEMENT img = _cache.get( vertex._clipName + "." kOfxOutputAttributeName, vertex._data._time );
00752                         if( ! img.get() )
00753                         {
00754                                 BOOST_THROW_EXCEPTION( exception::Logic()
00755                                         << exception::user() + "Output buffer not found in memoryCache at the end of the node process."
00756                                         << exception::dev() + vertex._clipName + "." kOfxOutputAttributeName + " at time " + vertex._data._time
00757                                         << exception::nodeName( vertex._name )
00758                                         << exception::time( vertex._data._time ) );
00759                         }
00760                         _result->put( vertex._clipName, vertex._data._time, img );
00761                 }
00762         }
00763 
00764 private:
00765         TGraph& _graph;
00766         memory::IMemoryCache& _cache;
00767         memory::IMemoryCache* _result;
00768         boost::posix_time::time_duration _cumulativeTime;
00769 };
00770 
00771 template<class TGraph>
00772 class PostProcess : public boost::default_dfs_visitor
00773 {
00774 public:
00775         typedef typename TGraph::GraphContainer GraphContainer;
00776         typedef typename TGraph::Vertex Vertex;
00777 
00778         PostProcess( TGraph& graph )
00779                 : _graph( graph )
00780         {}
00781 
00782         template<class VertexDescriptor, class Graph>
00783         void initialize_vertex( VertexDescriptor v, Graph& g )
00784         {
00785                 Vertex& vertex = _graph.instance( v );
00786 
00787                 TUTTLE_TLOG( TUTTLE_TRACE,"[Post-process] initialize_vertex " << vertex );
00788                 if( vertex.isFake() )
00789                         return;
00790         }
00791 
00792         template<class VertexDescriptor, class Graph>
00793         void finish_vertex( VertexDescriptor v, Graph& g )
00794         {
00795                 Vertex& vertex = _graph.instance( v );
00796 
00797                 TUTTLE_TLOG( TUTTLE_TRACE, "[Post-process] finish_vertex " << vertex );
00798                 if( vertex.isFake() )
00799                         return;
00800 
00801                 vertex.getProcessNode().postProcess( vertex.getProcessDataAtTime() );
00802         }
00803 
00804 private:
00805         TGraph& _graph;
00806 };
00807 
00808 
00809 template<class TGraph>
00810 class BeforeRenderCallbackVisitor : public boost::default_dfs_visitor
00811 {
00812 public:
00813         typedef typename TGraph::Vertex Vertex;
00814     BeforeRenderCallbackVisitor( TGraph& graph )
00815         : _graph( graph )
00816     {}
00817 
00818     template<class VertexDescriptor, class Graph>
00819     void finish_vertex( VertexDescriptor v, Graph& g )
00820     {
00821         Vertex& vertex = _graph.instance( v );
00822                 if( !vertex.isFake() )
00823                 {
00824             vertex.getProcessNode().beforeRenderCallback( vertex.getProcessNode(), vertex.getProcessDataAtTime() );
00825         }
00826     }
00827 
00828 private:
00829         TGraph& _graph;
00830 };
00831 
00832 
00833 }
00834 }
00835 }
00836 }
00837 
00838 #endif
00839