4

I'm trying to edit videos for my dance group. What I'd like to be able to do is have an overlay that I can set the B.P.M (beats per minute) and I can display a simple metronome + counter over the video.

I notice that there is a text effect in the VSE

enter image description here

Is there any way to hook a callback based on the frame count that can change the text as the video progresses? This might be able to get me what I need.

Progress

I've discovered that I can do

import bpy

def my_handler(scene):
    print("Frame Change", scene.frame_current)

bpy.app.handlers.frame_change_pre.append(my_handler)

and the current frame count is output to the console. Now I would need to calculate and inject some text into the VSE

First real attempt

import bpy

def my_handler(scene):
    print("Frame Change", scene.frame_current)
    ob = bpy.data.objects['TimeCode']
    ob['Text']=scene.frame_current


bpy.app.handlers.frame_change_pre.append(my_handler)

where I have a text effect added to the VSE and defined as

enter image description here

but I get console errors as

File "C:\Users\bradp\OneDrive\Video\NewStyle C\choreo1.blend\Counter", line 7, in my_handler KeyError: 'bpy_prop_collection[key]: key "TimeCode" not found'

bradgonesurfing
  • 173
  • 1
  • 7

4 Answers4

5

You can use Animation Nodes to do this very easily:

Node Tree

You can do all sort of editing like:

Node Tree 2

The Frame Rate input is hidden by default, show it like this:

Node Tree 3

Omar Emara
  • 22,639
  • 5
  • 55
  • 103
3

The following script displays the frame count as an overlay

import bpy


def my_handler(scene):
    print("Frame Change", scene.frame_current)
    bpy.data.scenes['Scene'].sequence_editor.sequences_all["TimeCode"].text=str(scene.frame_current)


bpy.app.handlers.frame_change_pre.append(my_handler)

The path to the data object was retrieved from the tooltip

enter image description here

bradgonesurfing
  • 173
  • 1
  • 7
  • Nice. Could expand this for a generic case for any strip in scene named "TimeCode". .Would need to check seq = scene.sequence_editor is not None, and seq.sequences_all.get("TimeCode") is not None. – batFINGER Oct 29 '17 at 16:11
  • Actually this does't work as it only works in manual mode. When I create a rendering the script is not called. No idea why. – bradgonesurfing Oct 29 '17 at 16:53
  • lol, see what you mean. Does appear to work in render (still) image. Suggest adding a text object to scene and using frame change handler to animate its body. – batFINGER Oct 29 '17 at 17:22
  • 1
    The reason this script does not work during rendering is you also need to add it as a render_pre handler. See my answer for a little elaboration. – Scott McPeak Feb 05 '20 at 07:26
2

Expanding and slightly correcting the answer by bradgonesurfing, you can do this without any addons. First, create the text strip in the Video Sequence Editor and give it a name like "Timer". Now, create a Python script similar to this:

# TimerScript.py
# Arrange to update a VSE text strip to show elapsed time.

# Put this file next to your .blend file, open it in the Blender
# Text Editor view, and use "Text -> Run Script" to run it.  It
# will be active for the duration of the Blender editing session.

import bpy

scene = bpy.context.scene
obj = scene.sequence_editor.sequences_all['Timer']
fps = scene.render.fps

def recalculate_text(scene):
    # Number of frames since the start of the text strip.
    frames = scene.frame_current - obj.frame_start

    # Divide to get hours, minutes, seconds, and hundredths of a second.
    seconds_float = frames / fps
    seconds = int(seconds_float)
    hundredths = int((seconds_float - seconds) * 100)
    minutes = int(seconds / 60)
    seconds -= minutes * 60
    hours = int(minutes / 60)
    minutes -= hours * 60

    # Combine as a string.
    time_string = "{:d}:{:02d}:{:02d}.{:02d}".format(
        hours, minutes, seconds, hundredths)

    # Update the text object.    
    #print('Recalc: ' + time_string)
    obj.text = time_string

# This is used when moving between frames during editing.
bpy.app.handlers.frame_change_pre.clear()
bpy.app.handlers.frame_change_pre.append(recalculate_text)

# This is used during animation rendering.
bpy.app.handlers.render_pre.clear()
bpy.app.handlers.render_pre.append(recalculate_text)

Open the script in the Blender Text Editor (you can create it there in the first place) and run it via "Text → Run Script".

The slightly tricky bit, and the correction to Brad's answer, is you need to install this both as a pre-frame handler and a pre-render handler. If you only set it as pre-frame, then the update will not happen when rendering animations!

Scott McPeak
  • 136
  • 1
0

I know nothing about scripting. Try to answer it with the manual way. From my understaning, it is about rendering a sequence of numbers and clamp it into one minute.


If anything fancy is not needed. Frame counter can be generated from Metadata.

Properties > Render > Metadata > Stamp Output

Render Frame count in frame

  • Setup a empty Scene and set End Frame = BPM
  • Render the empty scene with Metadata ON and Transparent.
  • Overlay the clip to the dancing video, Transform the clip to one minute long with Speed Control. and Loop it over.

For video looping, please refer to:

How do you make a movie loop in the sequencer?

MA Jacob
  • 115
  • 11