← Все статьи DaVinci Resolve API
DaVinci Resolve APIПродвинутыйTimeline

Как разрезать клип в DaVinci Resolve через Python

SetCurrentTimecode, поиск клипа под кадром и split через горячую клавишу Resolve

Показываем практический способ разрезания клипа: найти элементы Timeline, которые пересекают нужный кадр, поставить playhead и выполнить штатный split в интерфейсе Resolve.

API

Resolve Scripting API

Язык

Python

Resolve

19–20+

Требуется

Запущенный Resolve

Синтаксис

result = api_method()

Параметры

  • Параметры зависят от конкретного метода Resolve Scripting API и показаны в рабочем примере.

Возвращает

Возвращаемое значение нужно проверять перед следующим шагом автоматизации.

Полный рабочий пример Pythonкод можно использовать как основу скрипта
import os
import subprocess
import sys
import time
from pathlib import Path


def import_resolve_module():
    try:
        import DaVinciResolveScript as dvr
        return dvr
    except ImportError:
        search_paths = [
            os.environ.get("RESOLVE_SCRIPT_API", ""),
            os.environ.get("RESOLVE_MODULES", ""),
            r"C:\\ProgramData\\Blackmagic Design\\DaVinci Resolve\\Support\\Developer\\Scripting\\Modules",
            "/opt/resolve/Developer/Scripting/Modules",
            "/opt/BlackmagicDesign/DaVinciResolve/Developer/Scripting/Modules",
            "/Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules",
            str(Path.home() / "Library/Application Support/Blackmagic Design/DaVinci Resolve/Developer/Scripting/Modules"),
        ]
        for path in search_paths:
            if path and os.path.isdir(path) and path not in sys.path:
                sys.path.append(path)
        import DaVinciResolveScript as dvr
        return dvr


def safe_call(obj, name, *args):
    try:
        fn = getattr(obj, name, None)
        if callable(fn):
            return fn(*args)
    except Exception:
        return None
    return None


def frames_to_tc(frame: int, fps: float) -> str:
    fps_i = max(1, int(round(fps)))
    total = int(round(frame))
    ff = total % fps_i
    seconds = total // fps_i
    hh = seconds // 3600
    mm = (seconds % 3600) // 60
    ss = seconds % 60
    return f"{hh:02d}:{mm:02d}:{ss:02d}:{ff:02d}"


def get_timeline_fps(project, timeline) -> float:
    value = safe_call(timeline, "GetSetting", "timelineFrameRate") or safe_call(project, "GetSetting", "timelineFrameRate")
    try:
        return float(value)
    except Exception:
        return 24.0


def iter_timeline_items(timeline):
    for media_type in ("video", "audio"):
        track_count = int(safe_call(timeline, "GetTrackCount", media_type) or 0)
        for track_index in range(1, track_count + 1):
            for item in safe_call(timeline, "GetItemListInTrack", media_type, track_index) or []:
                yield item


def set_playhead(timeline, frame: int, fps: float) -> bool:
    timecode = frames_to_tc(frame, fps)
    if safe_call(timeline, "SetCurrentTimecode", timecode):
        return True
    if safe_call(timeline, "SetCurrentFrame", int(frame)):
        return True
    return False


def focus_resolve_window() -> bool:
    if sys.platform.startswith("win"):
        command = "$ws=New-Object -ComObject WScript.Shell; $null=$ws.AppActivate('DaVinci Resolve')"
        subprocess.call(["powershell", "-NoProfile", "-Command", command], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        time.sleep(0.2)
        return True

    if sys.platform.startswith("linux"):
        for needle in ("DaVinci Resolve", "resolve", "Blackmagic Design"):
            for args in (("--name", needle), ("--class", needle)):
                try:
                    output = subprocess.check_output(["xdotool", "search", *args], text=True).strip()
                    ids = [line for line in output.splitlines() if line.strip()]
                    if ids:
                        subprocess.call(["xdotool", "windowactivate", "--sync", ids[-1]], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
                        time.sleep(0.2)
                        return True
                except Exception:
                    pass
        raise RuntimeError("Окно DaVinci Resolve не найдено")

    return True


def send_split_hotkey() -> bool:
    focus_resolve_window()
    if sys.platform.startswith("win"):
        try:
            import pyautogui
            pyautogui.hotkey("ctrl", "b")
        except Exception:
            command = "Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.SendKeys]::SendWait('^b')"
            subprocess.call(["powershell", "-NoProfile", "-Command", command], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        time.sleep(0.15)
        return True

    if sys.platform.startswith("linux"):
        subprocess.call(["xdotool", "key", "ctrl+b"], stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
        time.sleep(0.15)
        return True

    raise RuntimeError("Split hotkey не реализован для этой платформы")


def split_at_frame(timeline, fps: float, frame: int) -> bool:
    touching = []
    for item in iter_timeline_items(timeline):
        start = safe_call(item, "GetStart")
        end = safe_call(item, "GetEnd")
        if start is not None and end is not None and int(start) < frame < int(end):
            touching.append(item)

    if not touching:
        return True
    if not set_playhead(timeline, frame, fps):
        return False
    return send_split_hotkey()


dvr = import_resolve_module()
resolve = dvr.scriptapp("Resolve")
project = resolve.GetProjectManager().GetCurrentProject()
timeline = project.GetCurrentTimeline()
fps = get_timeline_fps(project, timeline)

if not split_at_frame(timeline, fps, frame=240):
    raise RuntimeError("Не удалось разрезать клип")

print("Split completed")

Документация

Что делает пример

DaVinci Resolve Scripting API не во всех версиях дает прямой метод SplitClip. Поэтому практический bridge-подход использует доступный API для установки playhead, а сам разрез выполняет штатной командой интерфейса через Ctrl+B.

Почему сначала ищем клип под кадром

Если в заданном кадре нет клипа, split не нужен. Проверка диапазона защищает Timeline от лишних действий и позволяет спокойно запускать скрипт на списке кадров.

Ограничения подхода

Этот пример зависит от фокуса окна Resolve и системной отправки hotkey. На Linux нужен xdotool, на Windows используется pyautogui или PowerShell SendKeys.

Разбор примера

1

Подключение к Resolve

Пример начинает работу с подключения к запущенному DaVinci Resolve через официальный Python-модуль.

2

Проверка проекта

Перед вызовами Media Pool, Timeline или Render Queue код проверяет наличие открытого проекта.

3

Вызов метода API

Основной блок выполняет задачу статьи: как разрезать клип в davinci resolve через python.

4

Проверка результата

После вызова API результат проверяется, чтобы скрипт не продолжал работу с пустым объектом или не созданной задачей.

Особенности Resolve API

  • Перед массовой нарезкой сделайте копию Timeline.
  • На Linux установите xdotool, если используете этот способ.
  • Горячая клавиша должна соответствовать команде Split Clip в Resolve.
  • Это практический способ из автоматизации, а не отдельный официальный метод SplitClip.

Частые ошибки

Resolve API недоступен

Причина: Приложение не запущено или Python не видит DaVinciResolveScript.

Решение: Запустите Resolve и проверьте путь к Developer/Scripting/Modules.

Метод вернул None или False

Причина: В Resolve нет нужного проекта, Timeline, клипов, preset или доступа к папке.

Решение: Проверьте входные данные и добавьте явную проверку результата после каждого важного вызова API.

Скрипт работает только на одной машине

Причина: Пути к файлам или папкам Resolve зашиты под конкретную систему.

Решение: Вынесите пути в переменные и добавьте стандартные пути Windows, Linux и macOS.

Следующий шаг

Следующий шаг зависит от задачи: импорт медиа, создание Timeline или запуск рендера.

Связанные статьи API