resolve-scripting

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Resolve scripting: what actually works (Resolve Studio 21)

Resolve 脚本:真正有效的方法(Resolve Studio 21)

Check the API for the installed version before trusting memory: the scripting docs ship with Resolve, and functions move (some changed between 20 and 21).
在依赖记忆之前,先检查已安装版本对应的 API:脚本文档随 Resolve 一同提供,而且函数会发生变化(有些在 20 和 21 之间发生了变化)。

Golden rules

黄金规则

  • Only add. New timelines (never overwrite: "name v2"), imports into bins, clips on free tracks. Never touch the creator's template or their timelines/media. Never switch/create/close projects.
  • Verify every write by reading it back. Many setters return True and do nothing.
  • Save the project at the end of each step.
  • 只做新增。 新建时间线(绝不覆盖:使用“name v2”),将素材导入 bin,并把片段放在空闲轨道上。绝不触碰创作者的模板或其时间线/媒体。绝不切换、创建或关闭项目。
  • 每次写入后都要回读验证。 许多 setter 返回 True,却什么也没做。
  • 每一步结束后保存项目。

Building the timeline

构建时间线

  • Find bins by name recursively. Import files once (reuse the media pool item if the same path is already imported).
  • Copy the template with
    DuplicateTimeline(name)
    , move it into the timelines bin, then empty every track (unlock locked tracks temporarily). The copy keeps the track FX chain (voice treatment on A1, music treatment on A2) - that's why we copy instead of creating.
  • Frame rate mismatch footage vs template: stop and ask. If they choose the footage rate:
    useCustomSettings=1
    ,
    timelineFrameRate
    ,
    timelinePlaybackFrameRate
    .
  • Custom frame (e.g. 4:3 2880x2160): set
    timelineResolutionWidth/Height
    and the output resolution, then input mismatch behaviour
    scaleToCrop
    ("scale full frame with crop"). The default
    scaleToFit
    letterboxes. Read it back.
  • AppendToTimeline
    :
    endFrame
    is exclusive. For audio-only media, start/end frames count in the clip's own frame rate (a WAV reports 23.976), not the timeline's.
  • Audio duration from timecode: at 23.976, a timecode counts 24 frames per second.
    seconds = ((h*3600+m*60+s)*round(fps) + f) / fps
    . Using 23.976 per second lost 16 frames on an 11-minute music bed.
  • Check after laying: piece count on V1 and A1, each duration, no gaps.
  • 递归查找指定名称的 bin。文件只导入一次(如果同一路径已经导入,则复用媒体池中的项目)。
  • 使用
    DuplicateTimeline(name)
    复制模板,将其移动到 timelines bin,然后清空每条轨道(临时解锁锁定轨道)。副本会保留轨道 FX 链(A1 上的人声处理、A2 上的音乐处理)——因此选择复制而不是新建。
  • **素材与模板的帧率不一致:**停止操作并询问。如果对方选择素材帧率:
    useCustomSettings=1
    、
    timelineFrameRate
    、
    timelinePlaybackFrameRate
    。
  • **自定义画幅(如 4:3 2880x2160):**设置
    timelineResolutionWidth/Height
    和输出分辨率,然后将输入不匹配行为设为
    scaleToCrop
    (“缩放完整画面并裁切”)。默认的
    scaleToFit
    会产生黑边。回读确认。
  • AppendToTimeline
    :
    endFrame
    是排他的(不包含该帧)。对于纯音频媒体,起始/结束帧按片段自身的帧率计算(一个 WAV 报告为 23.976),而不是时间线的帧率。
  • **根据 timecode 计算音频时长:**在 23.976 下,timecode 按每秒 24 帧计数。
    seconds = ((h*3600+m*60+s)*round(fps) + f) / fps
    。如果按每秒 23.976 帧计算,一段 11 分钟的音乐会少 16 帧。
  • 铺设完成后检查:V1 和 A1 上的片段数量、各片段时长,以及是否存在空隙。

Picture

画面

  • Zoom:
    item.SetProperty("ZoomX", z)
    and
    "ZoomY"
    (centre anchored). Works in 21.
  • Grades:
    Timeline.ApplyGradeFromDRX
    fails in 21. Use each item's graph:
    item.GetNodeGraph().ApplyGradeFromDRX(path, 0)
    . It occasionally fails on one piece and works on a retry: try twice, then count graded pieces (node count) and report.
  • Never put a log look on non-log footage. Read the profile from the camera's sidecar XML, not from luma guesses.
  • SetClipColor("Green")
    on B-roll pieces.
  • 缩放:
    item.SetProperty("ZoomX", z)
    和
    "ZoomY"
    (以中心点为锚点)。在 21 中有效。
  • 调色:
    Timeline.ApplyGradeFromDRX
    在 21 中无效。改用每个片段的 graph:
    item.GetNodeGraph().ApplyGradeFromDRX(path, 0)
    。它偶尔会在某个片段上失败,但重试后又会成功:尝试两次,然后统计已调色片段的数量(节点数)并报告。
  • 切勿对非 Log 素材套用 Log 风格。从相机的 sidecar XML 中读取 profile,而不是根据亮度猜测。
  • 为 B-roll 片段调用
    SetClipColor("Green")
    。

Audio

音频

  • Normalize:
    Timeline.NormalizeAudioLevel(items, {normalizationMode, targetLevel, targetLoudness, setLevelMode})
    with
    resolve.NORMALIZE_AUDIO_SET_LEVEL_INDEPENDENT
    . See
    voice-and-audio
    for values.
  • Per clip:
    AudioVolume
    (dB),
    SetVoiceIsolationState({"isEnabled": True, "amount": 50})
    , Dialogue Leveler properties. EQ is not scriptable; Fairlight presets can be applied if the user saved some.
  • Silent track trap: a template's music track had a track-level AI Music Remixer switched on (and a Stereo Width insert). Anything placed on that track rendered as silence while the same file played on another track. The API can't read or toggle it; it's in the Edit page → select the track header → Inspector → Audio. If music is silent, check that first.
  • **标准化:**使用
    Timeline.NormalizeAudioLevel(items, {normalizationMode, targetLevel, targetLoudness, setLevelMode})
    ,并配合
    resolve.NORMALIZE_AUDIO_SET_LEVEL_INDEPENDENT
    。具体数值参见
    voice-and-audio
    。
  • 逐片段设置:
    AudioVolume
    (dB)、
    SetVoiceIsolationState({"isEnabled": True, "amount": 50})
    、Dialogue Leveler 属性。EQ 无法通过脚本设置;如果用户保存了一些 Fairlight 预设,则可以应用。
  • **静音轨道陷阱:**模板的音乐轨道启用了轨道级 AI Music Remixer(并带有 Stereo Width 插入效果)。放到该轨道上的内容渲染出来却是静音,而同一文件放在其他轨道上则正常。API 无法读取或切换它;需要在 Edit 页面 → 选择轨道头 → Inspector → Audio 中设置。如果音乐没有声音,首先检查这一点。

Diagnosing audio the reliable way

可靠诊断音频的方法

When "there's no sound", don't guess. Render a few seconds of audio from Resolve and compare it with the source file:
  • Project render:
    SetCurrentRenderFormatAndCodec("mov", "ProRes422LT")
    ,
    SetRenderSettings({SelectAllFrames: False, MarkIn, MarkOut, TargetDir, CustomName, ExportVideo: False, ExportAudio: True, AudioCodec: "lpcm"})
    ,
    AddRenderJob()
    .
  • From an external script, rendering only starts with
    StartRendering([job], False)
    (isInteractiveMode False). Other forms return False and the job stays "Ready".
  • Render into a folder without spaces (a path with spaces left the job unstarted).
  • Wait on
    GetRenderJobStatus(job)
    until "Complete", not on
    IsRenderingInProgress()
    (it can be False before rendering begins).
  • Correlate the rendered audio with the source (mono, 8 kHz, best lag): ~0.9 = present, ~0.0 = missing. Least-squares gain tells how much of an SFX is in the mix.
  • Restore the Deliver settings afterwards (format, whole timeline, video+audio on, output folder): your test changes the creator's export settings.
  • AddRenderJob
    jumps to the Deliver page;
    SetTrackEnable
    only works on the Edit page (on other pages it returns True and does nothing). Go back with
    OpenPage("edit")
    .
  • Timeline export (
    Timeline.Export(path, EXPORT_DRT)
    ) is a zip of XML with per-track fields; deeper mixer state is a compressed binary. Useful for diffing a working vs broken track.
当“没有声音”时,不要靠猜。渲染几秒音频,并将结果与源文件进行比较:
  • 项目渲染:
    SetCurrentRenderFormatAndCodec("mov", "ProRes422LT")
    、
    SetRenderSettings({SelectAllFrames: False, MarkIn, MarkOut, TargetDir, CustomName, ExportVideo: False, ExportAudio: True, AudioCodec: "lpcm"})
    、
    AddRenderJob()
    。
  • **在外部脚本中,只有使用
    StartRendering([job], False)
    (
    isInteractiveMode
    为 False)才会真正开始渲染。**其他形式会返回 False,任务仍停留在“Ready”。
  • 渲染到不含空格的文件夹(路径中包含空格会导致任务无法启动)。
  • 等待
    GetRenderJobStatus(job)
    返回“Complete”,不要依赖
    IsRenderingInProgress()
    (渲染开始前它也可能为 False)。
  • 将渲染音频与源文件做相关性分析(单声道、8 kHz、最佳偏移):约 0.9 表示存在,约 0.0 表示缺失。最小二乘增益可以反映混音中包含多少 SFX。
  • 之后恢复 Deliver 设置(格式、整条时间线、视频和音频均开启、输出文件夹):测试操作会更改创作者的导出设置。
  • AddRenderJob
    会跳转到 Deliver 页面;
    SetTrackEnable
    仅在 Edit 页面上有效(在其他页面上会返回 True,却什么也没做)。使用
    OpenPage("edit")
    返回。
  • 时间线导出(
    Timeline.Export(path, EXPORT_DRT)
    )是一个包含逐轨道字段的 XML 压缩包;更深的混音器状态则存储为压缩二进制数据。适合对比正常轨道与故障轨道。

Subtitles

字幕

  • MediaPool.AppendToTimeline
    with an imported .srt ignores recordFrame and appends the subtitles after the end of the timeline. Passing start/end frames for it crashed Resolve 21.1.
  • Use File > Import > Subtitle in the UI (the creator clicks it, or computer-use). It places the first cue at the playhead and shifts the rest relative to it, so make the SRT's first cue start at 00:00:00,000, or everything lands early.
  • Subtitle track style can't be set by script; read it from a DRT export if you need to record it.
  • 对已导入的 .srt 使用
    MediaPool.AppendToTimeline
    时,会忽略
    recordFrame
    ,并将字幕追加到时间线末尾。传入起始/结束帧会导致 Resolve 21.1 崩溃。
  • 在 UI 中使用 File > Import > Subtitle(由创作者点击,或使用 computer-use)。它会将第一条字幕放在播放头位置,并以该位置为基准移动其余字幕,因此应确保 SRT 的第一条字幕从 00:00:00,000 开始,否则所有字幕都会提前出现。
  • 无法通过脚本设置字幕轨道样式;如果需要记录该样式,可以从 DRT 导出中读取。

Overlays and media cache

叠加素材与媒体缓存

  • Re-rendered files with the same name can keep playing stale cached frames: give each new render a new name (
    -v2
    ) and replace the clip.
  • Place overlays on the first free unlocked track from V2 up; never on V1.
  • 重新渲染的文件如果使用相同名称,可能持续播放缓存中的旧帧:为每次新渲染使用新名称(
    -v2
    ),然后替换片段。
  • 将叠加素材放到从 V2 向上找到的第一条空闲且未锁定的轨道上;绝不要放在 V1 上。

Reading the timeline the creator edited

读取创作者编辑后的时间线

Before music, captions or graphics, map the timeline as it is now: walk V1 items (name, start, left offset) to find where each kept word and each B-roll landed. They trim and delete things; follow their version.
在处理音乐、字幕或图形之前,先按当前状态梳理时间线:遍历 V1 片段(名称、起点、左侧偏移),确定每个保留的词和每个 B-roll 的实际落点。他们会裁剪和删除内容;以他们的版本为准。