4
$\begingroup$

Suppose we have an image strip in VSE and it has 2 keyframes for its opacity. How can I edit the values of each one of them via python?

$\endgroup$

3 Answers 3

8
$\begingroup$

Import the bpy module to access Blender's data.

import bpy

Context Method

If you just created the keyframes and are simply scripting in the text editor, you can look up the objects by context. You need to be certain that the strip has two keyframes and is selected (active) in the sequencer.

Get the active scene by context.

scene = bpy.context.scene

Get the active sequencer strip by context.

strip = scene.sequence_editor.active_strip

Lookup the fcurve connected to the data_path of the active strip with it's name and property. (Look at batFINGER's answer on how to construct the data_path more elegantly with strip.path_from_id("blend_alpha").)

data_path = 'sequence_editor.sequences_all["' + strip.name + '"].blend_alpha'
fcrv = scene.animation_data.action.fcurves.find(data_path)

Assign some values to the keyframe_points stored in the fcurve.

for i, y in [[0, 0.0], [1, 1.0]]:
    fcrv.keyframe_points[i].co.y = y
    fcrv.keyframe_points[i].handle_left.y = y
    fcrv.keyframe_points[i].handle_right.y = y

Force the sequencer to refresh.

bpy.ops.sequencer.refresh_all()

Data Method

If are trying to use this functionality from an addon or are unsure wether an active strip is selected or even if keyframes are present at all, you have to validate the data.

View code snippet from github.

Encapsulate the functionality in a method, which can be aborted, if a precondition is missing. The required parameters are:

  • the scene's name

  • the sequencer strip's name

  • the values which are used to overwrite the existing keyframes values

    def modify_strip_keyframes(scene_name, strip_name, keyframe_values = [1.0, 0.0]):

Get the scene by name, but return if it doesn't exist.

    scene = bpy.data.scenes.get(scene_name)
    if scene == None:
        print("Scene not found.")
        return

Verify that there is animation_data and a sequence_editor. If there are no keyframes or no strips, these items will be None. (Calling properties of None will crash the script.)

    if (scene.animation_data == None or scene.sequence_editor == None):
        print("No strips with keyframes.")
        return
    

Get the strip by name and get the fcurve associated with it's blend_alpha (the opacity) property.

    strip = scene.sequence_editor.sequences.get(strip_name)
    if strip == None:
        print("Strip not found.")
        return
    
    data_path = 'sequence_editor.sequences_all["' + strip_name + '"].blend_alpha'
    fcrv = scene.animation_data.action.fcurves.find(data_path)
    
    if fcrv == None:
        print("No opacity keyframes found.")
        return

Verify that there are as many keyframe_points on the fcurve, as values have been supplied. Then loop over the points and assign the new values to the keyframe_point coordinates co.

    if len(fcrv.keyframe_points) != len(keyframe_values):
        print("The strip has " + str(len(fcrv.keyframe_points)) +
            " keys, but " + str(len(keyframe_values)) + " values were supplied.")
        return
    
    for i in range(len(fcrv.keyframe_points)):
        key = fcrv.keyframe_points[i]
        key.co.y = keyframe_values[i]
        key.handle_left.y = keyframe_values[i]
        key.handle_right.y = keyframe_values[i]
        key.handle_left.x = key.co.x
        key.handle_right.x = key.co.x
    

To execute the function, call it and refresh the sequencer to visualize the change.

modify_strip_keyframes("Scene", "cat", keyframe_values = [1, 0.5])
bpy.ops.sequencer.refresh_all()
$\endgroup$
3
  • 1
    $\begingroup$ Very comprehensive If I had have seen this before answering wouldn't have bothered. Path from ID gives some point of diff. $\endgroup$
    – batFINGER
    Commented Aug 19, 2020 at 10:20
  • 1
    $\begingroup$ I didn't know path_from_id. I will give a reference to your answer. $\endgroup$
    – Leander
    Commented Aug 19, 2020 at 10:24
  • $\begingroup$ You opened my horizons, thank you! $\endgroup$
    – user18359
    Commented Aug 19, 2020 at 10:52
6
$\begingroup$

Find the fcurve based on its datapath

The suggestion of toggling into graph editor and looking at the visible fcurves, will be dependent on graph editor settings.

Instead create the datapath that is keyframed and search for it in the action fcurves.

VSE strip animations belong to the scene object.

Script below

  • gets the active strip

  • finds the path of the active strip from its ID object, the scene, an example for active movie strip named "Foo"

     'sequence_editor.sequences_all["Foo"].blend_alpha'
    
  • Searches for it within the scene actions fcurve collection

Note: Many or all of the properties above could have value None including the sequence editor the active strip, the animation data and the action. Would need to test for each.

import bpy
from bpy import context

scene = context.scene
seq = scene.sequence_editor
active_strip = seq.active_strip
datapath = active_strip.path_from_id("blend_alpha")
action = scene.animation_data.action

fc = action.fcurves.find(datapath)
$\endgroup$
1
$\begingroup$
#Assuming you are at VSE with your strip selected
context.area.type = 'GRAPH_EDITOR'
for fcurve in context.visible_fcurves:
    for keyframe in fcurve.keyframe_points:
        #Do w/e you want with the keyframe
        pass
#We switch back to VSE
context.area.type = 'SEQUENCE_EDITOR'

My misconception was that Graph > Keyframes. While the reality is Graph > FCurves > Keyframes.

$\endgroup$

You must log in to answer this question.