动态排版影片转 DaVinci Resolve
将动态排版影片的 spec.js 转换为 Resolve 时间线,其中每个镜头都是一个独立的片段并带有自己的 Fusion 合成:真实的 Text+ 和 Text3D、关键帧摄像机、相同的节拍时序。编辑器随后可以在 Fusion 页面中打开任意镜头,重新输入单词、修剪或替换音乐。
这是使用 Resolve 工具进行的重建,并非像素级匹配。请说明与原始内容的变更(setup 以 notes 列表形式返回),并报告给用户。
开始之前
- Resolve Studio 正在运行并已打开一个项目。使用
get_resolve_status检查,并调用一次get_whats_new(因为 Resolve 服务器会要求)。 - 电影文件夹中包含
spec.js和引擎文件,并在其中执行了npm install playwright。 - Resolve 外部使用安装了 Pillow 的 Python 来测量版式。ffmpeg 已加入 PATH。
询问用户
在构建之前,从对话中确定以下内容:
- 哪个项目。 时间线将添加到已打开的项目中。告知用户当前是哪个项目。切换项目可能会导致未保存的工作丢失,因此如果是错误项目,请让用户自行切换。
- 时间线名称。 默认为
<标题> (Fusion)。查看现有时间线,选择一个未被占用的名称。切勿重复使用或替换本会话中未由你构建的时间线。 - 字体。 Text+ 只能看到已安装的字体,而影片中通常使用的 Archivo 字体通常未安装。如果项目显示了品牌字体,则使用该字体。调用
fonts_available(resolve, 'Lato', 'Inter')进行检查;未经询问不要安装字体。粗体重磅最清晰:Black、Heavy、ExtraBold。 - 音频。 可以是现有时间线的音乐编辑(
audio_from_timeline)、文件(audio_from_file)或不需要。如果某个时间线已包含此影片及其音乐,优先提供该选项,因为这样可以保留用户的编辑。
步骤
下面的 SKILL 指本技能的文件夹,F 指电影文件夹。每个 Resolve 步骤都通过 run_script_unsafe 执行,单次调用限时 60 秒,并以以下代码开头:
SKILL = r'<本技能文件夹>'; F = r'<电影文件夹>'
exec(open(SKILL + r'\scripts\resolve_build.py', encoding='utf-8').read())
1. 导出 spec(在 shell 中执行):
node "<SKILL>/scripts/export_film.mjs" "<F>"
写入 <F>/resolve/film.json 并将 Logo 导出为透明 PNG,同时打印它找到的块。
2. 创建时间线:
result = setup(resolve, project, F, '我的影片 (Fusion)', 'Lato', 'Black', 'Inter', 'Medium')
最后两个字体用于小号文字和模拟 UI。它会创建时间线、一个 Kinetic Films / <标题> 素材箱和一个黑色占位片段,并返回镜头数量和 notes。时间线尺寸和帧率来自项目,因此在 60 fps 下制作的影片可以放置在 30 fps 的时间线上。仅在 1920x1080、60 fps 下验证过,因此其他格式需仔细检查。
3. 测量版式(在 shell 中使用安装了 Pillow 的 Python 执行):
python "<SKILL>/scripts/measure_fonts.py" "<F>" Lato Black
如果不执行此步骤,文字将使用估计宽度,可能无法很好地填充画面。如果报告找不到字体文件,请继续并仔细检查画面布局。
4. 构建。 重复直到 done 为真;它会从中断处继续:
result = build_batch(project, F, 40)
然后添加 HUD(仅当影片包含 HUD 时)、音频和场景标记:
result = dict(hud=add_hud(project, F), audio=audio_from_timeline(project, F, '音乐编辑'), markers=add_markers(project, F))
HUD 是一个 Fusion 片段,位于整个影片的轨道 2 上。编辑器可以禁用该片段以将其移除。
5. 检查帧画面。 在 Resolve 21.2 或更高版本上,此步骤会从时间线直接导出每个镜头中间位置的标注画面,无需渲染,也不会更改渲染设置,几秒钟即可完成。这些画面会保存到 <F>/resolve/review/。检查是否有黑帧、文字是否在画面范围内、开场文字是否清晰、图片是否覆盖整个画面。在渲染之前修复任何问题。frame_grid(project, F, seconds=[4.2, 9.35]) 可在选定时刻(例如转场末尾)以全尺寸导出画面。
result = frame_grid(project, F)
这些帧画面与相同帧的渲染结果匹配(已在 21.2 上验证)。在旧版不支持 ExportThumbnails 的 Resolve 上会抛出错误,因此改为通过渲染结果来判断。
6. 渲染并测量运动。
result = start_render(project, F, 'my_film') # 有 GPU H.264 编码器时优先使用
# 后续调用:result = wait_render(project, result_job_id, 50)
在强大 GPU 上,30 秒的 1080p60 渲染预计需要 2 到 4 分钟。之后仅使用 remove_job 移除你自己的任务。渲染队列中可能包含用户的其他任务。start_render 会修改项目的渲染设置,请告知用户。
运动只能从视频中测量。如果安装了 scenario-kinetic-film 的脚本,则在渲染结果上运行 holds.py 和 dyn.py。目标:静止帧不超过 40%,结束卡片前无超过 0.6 秒的停顿,中位运动值不低于 2.5。报告数值,包括未达标的部分。
如需修改内容,请修复后使用 setup(..., replace=True) 重新构建(仅限本技能构建的时间线),然后重复步骤 4 到 6。对于仅修改少数镜头的情况,使用 rebuild_shots(project, F, [8.2, 13]) 替换指定时间(秒)或镜头索引处的合成,其余保持不变。如果影片的文字发生了变化,请重新执行步骤 3。
7. 完成。 除非用户要求,否则让用户自行保存;保存也会提交他们打开的其他未保存编辑。报告时间线名称、notes、渲染时间和审查数据。提醒占位片段必须保留在其素材箱中,否则镜头可能显示为离线。
禁止事项及原因
以下每项都需要花费大量时间才能发现。详细信息请参阅 references/fusion-traps.md;在修改 fusion_lib.py 或遇到问题时请先阅读该文件。
- 不要在构建过程中锁定合成。 这会导致片段渲染为黑帧。仅在创建 Loader 时锁定(如
Shot.loader所做);否则设置 Loader 的片段会打开模态文件选择器,阻断所有脚本操作。 - 不要使用
ExportCurrentFrameAsStill进行预览。 它会超越 Fusion 并返回黑帧或过时画面。frame_grid使用Timeline.ExportFrame和ExportThumbnails,是可靠的,但仅适用于当前时间线:未打开过的时间线会在报告成功的同时导出黑帧。 - 不要叠加运动模糊。 文字自身运动和摄像机运动同时做模糊会使工作量倍增。仅对摄像机做模糊,且仅在快速移动时。
- 不要认为更快的编码器总能解决缓慢的渲染。 Fusion 帧生成通常是瓶颈。在更改设置前请先进行测量。
参考
- references/block-map.md:14 种块各自如何转换以及哪些内容被近似处理。如果影片使用了 Graph、Counters、Progress、Chain、Prompt、Notes 或 Rewind,或者用户询问镜头还原度,请阅读此文件。
- references/fusion-traps.md:通过实践发现的 API 行为,以及如何恢复卡死的 Resolve。