当用户拥有两个或以上不同设备录制的同一事件视频/音频,并希望将它们同步或合并时使用。
wjs-syncing-multim. 使用音频交叉对调来计算同一事件的每次多源记录的单个时间抵消,并在每个原版旁边发出一台.sync.json侧车. 原件是一项面向实际任务的技能。它将相关步骤、工具调用和结果整理方式集中到统一流程中,帮助使用者更快完成目标并减少重复操作。
实际使用前应先确认任务范围、数据来源、运行环境、必要权限和关键参数,再依据技能说明逐步执行;若输入条件不完整,应先补齐信息或采用保守配置,避免因错误假设导致结果偏离需求。
执行过程中需要关注工具调用是否成功、接口或依赖是否可用、输出格式是否符合预期,并对异常提示、缺失字段和边界情况进行处理;涉及批量任务时,还应保存进度,避免中断后重复操作。
针对同一事件的多源录制素材,利用音频互相关(audio cross-correlation)计算每个素材相对于参考时间线的单一时间偏移量,并在各原始文件旁生成对应的 .sync.json 侧车文件(sidecar)。原始文件绝不会被修改、复制或重新编码。 下游工具通过 -itsoffset 参数在消费(consume)阶段动态应用该偏移量。
该能力早期版本通过裁剪 + 重编码生成 *_synced.MOV 文件,将偏移“烘焙”进文件中。我们已移除该行为:
_synced.MOV 文件生成耗时超 10 分钟;而生成侧车文件仅需数秒。autoedit.py、NLE 导入、ffmpeg 单行命令)均可读取侧车文件并自行应用偏移量。无工具专属格式锁定风险。原始 PCM 波形互相关在两支麦克风增益/房间响应差异较大时(即副机位几乎总是如此),会产生弱峰值与错误匹配。对数能量包络(log-energy envelope)能有效捕捉对话与音乐的动态特征,这些特征无论频率响应如何,两支麦克风均能共同捕获。切勿跳过包络提取步骤 —— 这正是本能力在低信噪比(low SNR)下保持鲁棒性的根本原因。
filtfilt 方式零相位滤波 —— 用于消除缓慢漂移与增益偏置。delta(t) = slope·t + intercept 进行线性拟合,可识别真实时钟漂移(典型值为 5–50 ppm)。最终采用中点规范偏移量(slope · midpoint + intercept),使残差围绕零对称分布。overlap = [max(0, delta), min(ref_dur, delta + src_dur)]。.sync.json 侧车文件:置于每个非参考输入文件旁。无任何文件被复制、裁剪或重编码。参考输入也生成侧车文件(其中 delta_seconds: 0),以便下游代码统一处理所有输入。scripts/sync.py 是本能力的具体实现。注意:当前脚本仍会同时输出 _synced.MOV 文件,但该路径已被弃用;侧车文件是唯一权威输出。
.sync.json)每个原始输入对应一个侧车文件,与其同目录存放。纯 JSON 格式,文件内不含注释 —— 下方字段说明即为权威定义。
{
"_about": "Sync metadata for cam_b.MOV. Apply via ffmpeg -itsoffset. See wjs-syncing-multicam SKILL.md for full schema.",
"schema_version": 1,
"source": "cam_b.MOV",
"reference": "cam_a.MOV",
"delta_seconds": 12.345,
"drift_slope": 1.8e-5,
"overlap_in_reference": [12.345, 4512.180],
"overlap_in_source": [0.000, 4499.835],
"verification": {
"median_residual_ms": 4.2,
"residual_spread_ms": 11.8,
"probe_count": 24
}
}
| 字段 | 类型 | 含义 |
|---|---|---|
_about |
字符串 | 面向人类的一行简要说明,含回指本 SKILL.md 的链接。始终存在。 |
schema_version |
整数 | 该 Schema 发生破坏性变更时递增。当前版本:1。 |
source |
字符串 | 本侧车文件所描述的原始文件名,路径相对于侧车文件所在目录。永不指向重编码后的文件。 |
reference |
字符串 | 本时间线所对齐的输入文件。参考输入自身的侧车文件亦在此字段中列出自身。 |
delta_seconds |
浮点数 | 本 source 的 t=0 在参考时间线中的对应时刻(单位:秒)。若为正值,表示本素材起始时间晚于参考素材;传给 ffmpeg 时应写作 -itsoffset 。 可为负值(例如某台摄像机提前开机,本素材早于参考素材开始)。 |
drift_slope |
浮点数 | 线性时钟漂移斜率(无量纲,典型值 ~10⁻⁵)。0.0 表示未检测到可观测漂移。下游仅在需音画同步 / 长时唇形同步(lip-sync)时,对本素材单独应用 atempo = 1 + drift_slope;对于镜头剪辑(camera-cut editing),可忽略此字段。 |
overlap_in_reference |
[start, end](单位:秒) |
源素材与参考素材在参考时间线中共同覆盖的时间窗口。可用于裁剪输出,使其严格限定在双方均有效的时间范围内。 |
overlap_in_source |
[start, end](单位:秒) |
同一时间窗口在源素材本地时间线中的表达。overlap_in_reference[0] - delta_seconds = overlap_in_source[0]。 |
verification |
对象 | verify.py 的运行结果,用于驱动“同步是否收敛?”判断门限。median_residual_ms 应为几毫秒;若 residual_spread_ms 大于交付帧率(delivery fps)下的单帧时长,则表明需要但未启用漂移校正。 |
-itsoffset 是 ffmpeg 的 per-input 参数,且必须置于 -i 之前。务必始终从侧车文件中读取 delta_seconds:
# 将 cam_b 对齐至 cam_a 的时间线播放
ffmpeg -itsoffset $(jq -r .delta_seconds cam_b.MOV.sync.json) -i cam_b.MOV
-i cam_a.MOV
-filter_complex "[0:v][1:v]hstack" out.mp4
# 裁剪至双方共同覆盖的时间窗口(参数来自 cam_b.MOV.sync.json)
ffmpeg -ss -i cam_b.MOV -t ...
对于 wjs-editing-multicam,其 autoedit.py 中的 EDL 构建器会自动加载所有 .sync.json 文件;你无需手动拼接这些命令行参数。
常见情况:主摄像机覆盖 75 分钟,而 Riverside / 手机 / 领夹麦录音设备仅覆盖中间 30 分钟。scripts/sync_partial.py REF.MOV NEW.mp4 执行以下操作:
t=0 在参考时间线中的位置(delta_seconds 可能很大,例如 1842.5)。overlap_in_reference 明确告知消费者该输入的有效覆盖时段;超出此窗口的部分,回退至主摄像机素材。--audio-only 标志仅用于向下游提示该源无视频流 —— 当前已无编码环节可跳过。
对于镜头剪辑(camera-cut editing,最常见情形),一小时内 ±25 ms 的残差低于人眼可感知阈值 —— 此时可设 drift_slope: 0.0,仅使用中点 delta_seconds。
对于需音画同步 / 长时唇形同步(>30 分钟且 verification.residual_spread_ms > 40)的情形,下游需对源素材应用 atempo = 1 + drift_slope。源文件本身仍不作修改 —— atempo 滤镜仅在消费时运行。
scripts/verify.py REF.MOV SRC.MOV SRC.sync.json 会依据侧车文件中记录的 delta_seconds,对两个原始文件(对源素材应用 -itsoffset)重新提取音频,并再次执行多段探测互相关。结果将写回侧车文件的 verification 字段中。
通过标准:median_residual_ms < 15 且 residual_spread_ms < 交付帧率(delivery fps)下单帧时长。失败则需启用漂移校正后重试。
-itsoffset 在音频与视频上的语义不同 —— 为确保同步正确性,它必须是该输入的第一个参数。ffmpeg -i src -itsoffset X 错误;ffmpeg -itsoffset X -i src 正确。source / reference 的路径必须相对于侧车文件所在目录,而非下游进程的工作目录。请以 Path(sidecar).parent 为基准解析 source 与 reference。drift_slope “烘焙”进侧车文件的 delta_seconds 字段中。 二者分属独立字段自有其意义 —— 简单消费者可忽略漂移,音画同步消费者可主动应用;混合二者将丢失关键信息。相关专题
热门下载
相关下载
精品课程
共39课时 | 5.4万人学习
共101课时 | 21万人学习
共39课时 | 4.8万人学习