Skip to content

Instantly share code, notes, and snippets.

@eugeneniemand
Last active October 30, 2024 00:42
Show Gist options
  • Select an option

  • Save eugeneniemand/abd6bd5e7e974e7b2b902441bdbc3ff3 to your computer and use it in GitHub Desktop.

Select an option

Save eugeneniemand/abd6bd5e7e974e7b2b902441bdbc3ff3 to your computer and use it in GitHub Desktop.
Davinci Resolve Freeze Frame and Extend Script

Caution

This script is freshly created, and I haven’t fully tested it myself in real editing scenarios yet. Use at your own discretion—I’m not responsible for any unexpected results!

🎬 DaVinci Freeze Frame Magic 🎉

Splitting a clip, freezing the last frame, and extending it manually can be super time-consuming, especially if you’re an online course author recording demos and voiceovers. If you’re like me, you probably have to do this dozens of times in each editing session. To save time, I created a script using some of DaVinci’s API (found here) and pyautogui keyboard shortcuts to automate the process!

🎥Demo

FreezeFrame.mp4

Warning

Currently, this script is Windows-only. I haven’t considered Mac compatibility.

Important

Make sure the keyboard shortcuts in the script match your setup!

🚀 Getting Started

  1. Install pyautogui globally on your machine.
  2. Copy the script FreezeFrame.py to your scripts folder, by default located at:
    C:\ProgramData\Blackmagic Design\DaVinci Resolve\Fusion\Scripts\Edit\
  3. Assign a keyboard shortcut—I use Shift+Alt+F for quick access.

Note

You can adjust the extension duration (in seconds or frames) or remove it altogether for full flexibility.

🎉 🍾 That’s it! Enjoy smoother editing and more time saved!

import pyautogui # Import pyautogui to simulate keystrokes and mouse actions
# Get the current project and timeline from DaVinci Resolve
project = resolve.GetProjectManager().GetCurrentProject()
timeline = project.GetCurrentTimeline()
# Get the timeline frame rate as an integer
frame_rate = int(project.GetSetting("timelineFrameRate"))
# Function to get the clip currently under the playhead
def get_clip_under_playhead():
# Convert the current playhead position from timecode to frame count
playhead_position = timecode_to_frames(timeline.GetCurrentTimecode(), frame_rate)
# Retrieve all clips in the first video track
clips = timeline.GetItemListInTrack("video", 1) # assuming video track 1
# Iterate through clips to find one that includes the playhead position
for clip in clips:
if clip.GetStart() <= playhead_position <= clip.GetEnd():
return clip # Return the clip found under the playhead
return None # Return None if no clip is found under the playhead
# Function to convert a timecode string (HH:MM:SS:FF) to an integer frame count
def timecode_to_frames(timecode, frame_rate):
hh, mm, ss, ff = map(int, timecode.split(":"))
# Calculate total frames based on hours, minutes, seconds, and frames
total_frames = (hh * 3600 + mm * 60 + ss) * frame_rate + ff
return total_frames
# Function to convert a frame count back into a timecode string (HH:MM:SS:FF)
def frames_to_timecode(frames, frame_rate):
hours = frames // (3600 * frame_rate)
minutes = (frames % (3600 * frame_rate)) // (60 * frame_rate)
seconds = (frames % (60 * frame_rate)) // frame_rate
frames_remaining = frames % frame_rate
# Format the timecode with zero-padded values
return f"{int(hours):02}:{int(minutes):02}:{int(seconds):02}:{int(frames_remaining):02}"
# Function to convert seconds to frames
def seconds_to_frames(seconds, frame_rate):
return int(seconds * frame_rate)
# Extend the freeze frame by a specified duration (in seconds or frames)
def extend_freeze_frame(clip, duration_frames=None, duration_seconds=None):
# Calculate frame rate and duration in frames
if duration_seconds is not None:
duration_frames = seconds_to_frames(duration_seconds, frame_rate)
# Calculate and set new end frame
current_end = clip.GetEnd()
new_end_frame = current_end + duration_frames
# Select the nearest edit point
timeline.SetCurrentTimecode(frames_to_timecode(current_end, frame_rate))
pyautogui.press('v')
# Move the playhead to the new postion
timeline.SetCurrentTimecode(frames_to_timecode(new_end_frame, frame_rate))
# Extend Edit
pyautogui.press('e')
# Main Execution
clip = get_clip_under_playhead()
if clip:
# Move the playhead to just before the last frame of the clip
print(clip.GetName())
end_frame = clip.GetEnd()
timeline.SetCurrentTimecode(frames_to_timecode(end_frame - (frame_rate / 2), frame_rate))
# Trigger keyboard shortcut for splitting the clip at the playhead
pyautogui.hotkey('ctrl', '\\')
# Select next clip
pyautogui.hotkey('ctrl', 'right')
# Move the playhead to the second last frame of the clip
timeline.SetCurrentTimecode(frames_to_timecode(end_frame - 1, frame_rate))
# Apply a freeze frame by pressing Shift + R
pyautogui.hotkey('shift', 'R')
new_clip = get_clip_under_playhead()
new_clip.SetClipColor("Orange")
extend_freeze_frame(new_clip,duration_seconds=1)
print("Freeze Frame applied at the last frame of the clip.")
else:
print("No clip found under the playhead.") # Message if no clip is detected at the playhead
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment