Esempio n. 1
0
def testClipOrderWithSameInputs():
    """
	The "merge" node has 2 input clips. The order of these input connections
	modify the hash only if these input are different.

	"Merge.A -> Read1" and "Merge.B -> Read2"
	is the same than
	"Merge.A -> Read2" and "Merge.B -> Read1"
	ONLY IF Read1 is the same than Read2
	"""
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 72])
    a_read2 = a_g.createNode("tuttle.checkerboard", size=[50, 72])
    a_merge = a_g.createNode("tuttle.merge")
    a_g.connect(a_read1, a_merge.getClip("A"))
    a_g.connect(a_read2, a_merge.getClip("B"))

    b_g = tuttle.Graph()
    b_read1 = b_g.createNode("tuttle.checkerboard", size=[50, 72])
    b_read2 = b_g.createNode("tuttle.checkerboard", size=[50, 72])
    b_merge = b_g.createNode("tuttle.merge")
    b_g.connect(b_read2, b_merge.getClip("A"))
    b_g.connect(b_read1, b_merge.getClip("B"))

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(aHashMap, time)
    aHash = aHashMap.getHash(a_merge.getName(), time)

    bHashMap = tuttle.NodeHashContainer()
    b_g.computeGlobalHashAtTime(bHashMap, time)
    bHash = bHashMap.getHash(b_merge.getName(), time)

    assert_equal(aHash, bHash)
Esempio n. 2
0
def testSameGraph():
    """
	If we create 2 identical graphs, their hashes should be the same!
	"""
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 50])
    a_read2 = a_g.createNode("tuttle.checkerboard", size=[50, 49])
    a_merge = a_g.createNode("tuttle.merge")
    a_g.connect(a_read1, a_merge.getClip("A"))
    a_g.connect(a_read2, a_merge.getClip("B"))

    b_g = tuttle.Graph()
    b_read1 = b_g.createNode("tuttle.checkerboard", size=[50, 50])
    b_read2 = b_g.createNode("tuttle.checkerboard", size=[50, 49])
    b_merge = b_g.createNode("tuttle.merge")
    b_g.connect(b_read1, b_merge.getClip("A"))
    b_g.connect(b_read2, b_merge.getClip("B"))

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(aHashMap, time)
    aHash = aHashMap.getHash(a_merge.getName(), time)

    bHashMap = tuttle.NodeHashContainer()
    b_g.computeGlobalHashAtTime(bHashMap, time)
    bHash = bHashMap.getHash(b_merge.getName(), time)

    assert_equal(aHash, bHash)
Esempio n. 3
0
def testClipOrder():
    """
	The "merge" node has 2 input clips. The order of these input connections
	should modify the hash.

	"Merge.A -> Read1" and "Merge.B -> Read2"
	is NOT the same than
	"Merge.A -> Read2" and "Merge.B -> Read1"
	"""
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 50])
    a_read2 = a_g.createNode("tuttle.checkerboard", size=[50, 49])
    a_merge = a_g.createNode("tuttle.merge")
    a_g.connect(a_read1, a_merge.getClip("A"))
    a_g.connect(a_read2, a_merge.getClip("B"))

    c_g = tuttle.Graph()
    c_read1 = c_g.createNode("tuttle.checkerboard", size=[50, 50])
    c_read2 = c_g.createNode("tuttle.checkerboard", size=[50, 49])
    c_merge = c_g.createNode("tuttle.merge")
    c_g.connect(c_read2, c_merge.getClip("A"))
    c_g.connect(c_read1, c_merge.getClip("B"))

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(aHashMap, time)
    aHash = aHashMap.getHash(a_merge.getName(), time)

    cHashMap = tuttle.NodeHashContainer()
    c_g.computeGlobalHashAtTime(cHashMap, time)
    cHash = cHashMap.getHash(c_merge.getName(), time)

    assert_not_equal(aHash, cHash)
Esempio n. 4
0
def testNotTheSameClipIsUnconnected():
    """
	A "fade" node with 2 optional input clips should have different hashes
	depending on which input is unconnected.
	"""
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 50])
    a_fade = a_g.createNode("tuttle.fade")
    a_g.connect(a_read1, a_fade.getClip("SourceFrom"))
    # a_fade.getClip("SourceTo") is unconnected

    b_g = tuttle.Graph()
    b_read1 = b_g.createNode("tuttle.checkerboard", size=[50, 50])
    b_fade = b_g.createNode("tuttle.fade")
    b_g.connect(b_read1, b_fade.getClip("SourceTo"))
    # b_fade.getClip("SourceFrom") is unconnected

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(aHashMap, time)
    aHash = aHashMap.getHash(a_fade.getName(), time)

    bHashMap = tuttle.NodeHashContainer()
    b_g.computeGlobalHashAtTime(bHashMap, time)
    bHash = bHashMap.getHash(b_fade.getName(), time)

    assert_not_equal(aHash, bHash)
Esempio n. 5
0
def testNotValidGraphRaise():
    """
	To compute the hash we need to run setupAtTime first (we need to know if
	the node isFrameVaying, etc.).
	"setupAtTime()" raises if the graph is not valid, like a non optional clip
	is unconnected. And there is no sense to compute the hash of a node which
	is not valid.
	
	@todo: The computeGlobalHashAtTime should not throw, and it should compute
	the hash of all valid nodes.
	"""
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 50])
    a_read2 = a_g.createNode("tuttle.checkerboard", size=[50, 49])
    a_merge = a_g.createNode("tuttle.merge")
    a_g.connect(a_read1, a_merge.getClip("A"))

    b_g = tuttle.Graph()
    b_read1 = b_g.createNode("tuttle.checkerboard", size=[50, 50])
    b_read2 = b_g.createNode("tuttle.checkerboard", size=[50, 49])
    b_merge = b_g.createNode("tuttle.merge")
    b_g.connect(b_read2, b_merge.getClip("B"))

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    assert_raises(Exception, a_g.computeGlobalHashAtTime, aHashMap, time)

    bHashMap = tuttle.NodeHashContainer()
    assert_raises(Exception, b_g.computeGlobalHashAtTime, bHashMap, time)
Esempio n. 6
0
    def retrieveImage(self, frame, frameChanged):
        """
            Computes the node at the frame indicated if the frame has changed (if the time has changed).
        """
        buttleData = ButtleDataSingleton().get()
        #Get the name of the currentNode of the viewer
        node = buttleData.getCurrentViewerNodeName()
        #Get the gloabl hashCode of the node
        if node is not None:
            hashMap = tuttle.NodeHashContainer()
            buttleData.getGraph().getGraphTuttle().computeGlobalHashAtTime(
                hashMap, frame)
            node_hashCode = hashMap.getHash(node, frame)
        #Get the map
        mapNodeToImage = buttleData.getMapNodeNameToComputedImage()

        try:
            self.setNodeError("")
            for key in mapNodeToImage.keys():
                #If the image is already calculated
                if node_hashCode == key and frameChanged is False:
                    #print "**************************Image already calculated**********************"
                    return mapNodeToImage.get(node_hashCode)
            #If it is not
            #print "**************************Image is not already calculated**********************"
            return self.computeNode(node, frame)
        except Exception as e:
            logging.debug("Can't display node : " + node)
            self.setNodeError(str(e))
            raise
Esempio n. 7
0
def testIdentityNode():
    a_g = tuttle.Graph()
    a_read1 = a_g.createNode("tuttle.checkerboard", size=[50, 50])
    a_timeshift = a_g.createNode("tuttle.timeshift", offset=3)
    a_invert = a_g.createNode("tuttle.invert")
    a_g.connect([a_read1, a_timeshift, a_invert])

    time = 0.0

    aHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(aHashMap, time)
    aHash = aHashMap.getHash(a_invert.getName(), time)

    # The Timshift node itself is an identity node,
    # and it only modify the timing of nodes.
    # So if the input doesn't change over time, it doesn't modify the hash
    a_timeshift.getParam("offset").setValue(0)

    bHashMap = tuttle.NodeHashContainer()
    a_g.computeGlobalHashAtTime(bHashMap, time)
    bHash = bHashMap.getHash(a_invert.getName(), time)

    assert_equal(aHash, bHash)
Esempio n. 8
0
    def computeNode(self, node, frame):
        """
            Computes the node (displayed in the viewer) at the frame indicated.
        """
        buttleData = ButtleDataSingleton().get()
        graphTuttle = buttleData.getGraph().getGraphTuttle()

        #Get the output where we save the result
        self._tuttleImageCache = tuttle.MemoryCache()

        if buttleData.getVideoIsPlaying():  # if a video is playing
            processGraph = buttleData.getProcessGraph()
            processGraph.setupAtTime(frame)
            processGraph.processAtTime(self._tuttleImageCache, frame)
        else:  # if it's an image only
            processOptions = tuttle.ComputeOptions(int(frame))
            processGraph = tuttle.ProcessGraph(processOptions, graphTuttle,
                                               [node])
            processGraph.setup()
            timeRange = tuttle.TimeRange(frame, frame,
                                         1)  # buttleData.getTimeRange()
            processGraph.beginSequence(timeRange)
            processGraph.setupAtTime(frame)
            processGraph.processAtTime(self._tuttleImageCache, frame)
            processGraph.endSequence()

        self._computedImage = self._tuttleImageCache.get(0)

        #Add the computedImage to the map
        hashMap = tuttle.NodeHashContainer()
        graphTuttle.computeGlobalHashAtTime(hashMap, frame)
        hasCode = hashMap.getHash(node, frame)
        #Max 15 computedImages saved in memory
        if hasCode not in buttleData._mapNodeNameToComputedImage.keys(
        ) and len(buttleData._mapNodeNameToComputedImage) < 15:
            buttleData._mapNodeNameToComputedImage.update(
                {hasCode: self._computedImage})
        elif hasCode not in buttleData._mapNodeNameToComputedImage.keys(
        ) and len(buttleData._mapNodeNameToComputedImage) >= 15:
            #Delete a computed image from the memory (random)
            buttleData._mapNodeNameToComputedImage.popitem()
            buttleData._mapNodeNameToComputedImage.update(
                {hasCode: self._computedImage})

        return self._computedImage
Esempio n. 9
0
def testUnusedNodes():
    """
	It should not have any impact, if there are invalid but
	unused nodes in the graph.
	Nodes could be invalid if they have unconnected mandatory clips.

	And the other hand, if you ask to compute those invalid nodes,
	it should raise an exception.
	"""

    g = tuttle.Graph()
    read1 = g.createNode("tuttle.checkerboard",
                         size=[20, 137]).asImageEffectNode()
    read2 = g.createNode("tuttle.checkerboard",
                         size=[234, 357]).asImageEffectNode()
    merge = g.createNode("tuttle.merge", rod="union").asImageEffectNode()

    # Unconnected but unused nodes should not impede the computation
    pushpixel_unused = g.createNode("tuttle.pushpixel").asImageEffectNode()
    invert_unused = g.createNode("tuttle.invert").asImageEffectNode()

    g.connect(read1, merge.getClip("A"))
    g.connect(read2, merge.getClip("B"))

    hashMap = tuttle.NodeHashContainer()
    g.computeGlobalHashAtTime(hashMap, 0, [merge])

    ## TODO: Should not raise, even if there are invalid nodes.
    # g.computeGlobalHashAtTime(hashMap, 0)

    outputCache = tuttle.MemoryCache()
    g.compute(outputCache, merge)

    # Trying to compute all nodes should raise an error
    # on unconnected filters (invert and pushpixel).
    assert_raises(Exception, g.compute, outputCache)
Esempio n. 10
0
def convertScenePatterns(scene):
    '''
    Replace PATTERNS with real filepaths.
    :param scene: dict with nodes, params and connections.
    :return: (scene, outputFilepaths)
    '''
    outputScene = copy.deepcopy(scene)
    # Preload general plugins to use getBestReader/getBestWriter.
    tuttle.core().getPluginCache().addDirectoryToPath(globalOfxPluginPath)
    tuttle.core().preload(False)
    logging.debug("outputScene: " + str(outputScene))

    outputResources = []
    for node in outputScene['nodes']:

        if 'plugin' in node and node['plugin'] is not 'reader':
            logging.debug("Retrieve bundleId from plugin: " +
                          str(node['plugin']))
            resp = requests.get(catalogRootUri + "/bundle/" + node['plugin'] +
                                '/bundle')
            if resp.status_code == 404:
                logging.warning("Cannont retrieve bundleId for plugin: " +
                                str(node['plugin']))
            else:
                respJson = resp.json()
                node["bundleId"] = respJson['bundleId']
                logging.debug("bundleId: " + str(respJson['bundleId']))

        for parameter in node['parameters']:
            logging.warning('param: %s %s', parameter['id'],
                            parameter['value'])
            if isinstance(parameter['value'], (str, unicode)):

                if 'plugin' not in node and '{RESOURCES_DIR}' in parameter[
                        'value']:
                    parameter['value'] = parameter['value'].replace(
                        '{RESOURCES_DIR}', config.resourcesPath)
                    node['plugin'] = tuttle.getBestReader(
                        str(parameter['value']))

                if 'plugin' not in node and '{UNIQUE_OUTPUT_FILE}' in parameter[
                        'value']:
                    node['plugin'] = tuttle.getBestWriter(
                        str(parameter['value']))

    # Declare Bundles paths to TuttleOFX
    bundleIds = []
    for node in outputScene['nodes']:
        if 'bundleId' in node:
            bundleIds.append(node['bundleId'])
        else:
            logging.error("No bundle defined for node: " + str(node))
    bundlePaths = [
        os.path.join(pluginsStorage, str(bundleId)) for bundleId in bundleIds
    ]
    logging.debug("bundlePaths: " + str(bundlePaths))
    configLocalPluginPath(bundlePaths)

    logging.debug("outputScene after conversion: " + str(outputScene))

    # Create a Tuttle Graph to generate the UID for each node
    tuttleGraphTmp = loadGraph(outputScene)
    # logging.warning("tuttleGraphTemp" + str(tuttleGraphTmp))
    # logging.warning("outputScene" + str(outputScene))
    nodesHashMap = tuttle.NodeHashContainer()
    tuttleGraphTmp.computeGlobalHashAtTime(nodesHashMap, 0.0)

    for node in outputScene['nodes']:
        for parameter in node['parameters']:
            logging.warning('param: %s %s', parameter['id'],
                            parameter['value'])
            if isinstance(parameter['value'], (str, unicode)):

                if '{UNIQUE_OUTPUT_FILE}' in parameter['value']:
                    prefix, suffix = parameter['value'].split(
                        '{UNIQUE_OUTPUT_FILE}')
                    nodeHash = str(nodesHashMap.getHash(node['name'], 0.0))
                    node['hash'] = nodeHash
                    filename = nodeHash + suffix
                    filepath = os.path.join(config.renderDirectory,
                                            cache.cachePathFromFile(filename))
                    outputResources.append(filename)
                    parameter['value'] = filepath

    return (outputScene, outputResources)