关于 narrate-video
这项 Skill 为视频添加定时旁白,涵盖场景分析、脚本编写、语音生成与同步检查,适合需要让旁白贴合画面内容的创作者。
主要功能
- 01分析场景与时间点
- 02编写分段定时旁白
- 03使用 Azure 或 Gemini 生成语音
- 04将旁白与视频合并
- 05检查音量、静音间隔与同步
适用场景
- 01为产品演示视频添加旁白
- 02根据场景时间调整草稿脚本
- 03生成指定语言的配音
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ feiskyer/ video-skills --skill narrate-video安装后在 Claude Code 中输入/narrate-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/gemini-tts.mdvoices.mdscripts/check_env.pynarration_script_template.py详细介绍
视频旁白
为视频添加专业配音。分析视频,撰写或润色带时间标记的脚本,通过 Azure TTS 或 Gemini 3.1 Flash TTS 生成语音并进行合并,制作出音画同步的配音视频。
输入:$ARGUMENTS
其他资源
- 音色表和时长估算:references/voices.md
- Gemini TTS API 和 AI Studio 请求格式:references/gemini-tts.md
- Python 脚本模板:scripts/narration_script_template.py — 复制到视频所在目录,命名为
narration_script.py,并填写占位符
阶段 0:设置
提供方
默认使用 azure,除非用户明确要求使用 Gemini,或已配置 GEMINI_API_KEY。使用 Gemini 时,请遵循 references/gemini-tts.md 中记录的官方 Gemini TTS 请求模式。
语言
询问用户想使用哪种语言。默认使用英语。在 references/voices.md 中查找音色和语速。
环境
# 1. Check provider credentials exist (NEVER read or display their values)
scripts/check_env.py azure
# or
scripts/check_env.py gemini
# 2. Check tool dependencies
command -v ffmpeg && command -v ffprobe && command -v python3
# 3. Check Python dependencies
python3 -c "import dotenv" 2>&1
# 4. Azure only
python3 -c "import azure.cognitiveservices.speech" 2>&1
如果选择 Azure,且缺少 AZURE_SPEECH_KEY 或 AZURE_SPEECH_REGION,请用户将其添加到 ~/.narrate_video.env:
AZURE_SPEECH_KEY=your-key-here
AZURE_SPEECH_REGION=your-region-here
如果选择 Gemini,且缺少 GEMINI_API_KEY,请用户将其添加到 ~/.narrate_video.env:
GEMINI_API_KEY=your-key-here
# Optional override
GEMINI_TTS_MODEL=gemini-3.1-flash-tts-preview
然后停止操作——密钥属于敏感信息,只检查其是否存在,绝不能读取或显示其值。
阶段 1:视频分析
1.1 元数据
ffprobe -v quiet -print_format json -show_format -show_streams <video>
记录视频总时长、分辨率、帧率,以及是否存在音轨。
1.2 场景提取
以 3–4 秒为间隔提取帧,以识别场景转换:
mkdir -p /tmp/narration-frames
for t in $(seq 0 3 <duration>); do
ffmpeg -y -ss $t -i <video> -frames:v 1 -q:v 2 /tmp/narration-frames/frame_${t}s.jpg 2>/dev/null
done
查看这些帧(使用 Read 工具查看图像)。记录每次场景转换的准确时间戳。如果时间点不明确,以 1–2 秒为间隔提取更多帧,以确定准确时刻。
1.3 转场图
创建场景转场表,将时间戳与画面内容对应起来:
0s - Opening screen
3s - User starts typing
8s - System begins processing
34s - Response appears
描述屏幕内容的旁白应在内容已经显示后再开始。观众会注意到音频早于画面出现,这会让人感到突兀。画面出现后稍作停顿再开始旁白会更自然,就像主持人正在引导你观看眼前的内容。
阶段 2:撰写脚本
格式
每段旁白都是一个 (start_seconds, text) 元组:
SEGMENTS = [
(0, "Opening narration here."),
(8, "Next segment narration..."),
]
撰写指南
时间安排:各段之间至少留出 1 秒静音,这段间隔能让旁白听起来自然从容,而不是仓促赶场。使用 references/voices.md 中的时长估算来判断文本是否合适:英语按每秒 2.5 个单词计算,再取估算字数的 80% 作为安全上限。
连贯性:各段之间应衔接自然。使用过渡词(“And”“Now”“So”)会有所帮助,但要注意变化,连续三次使用 “And now” 会显得机械。
根据输入调整:如果用户提供了草稿,应根据场景分析校准时间戳,删减超出时间窗口的文本,并润色语言,但要保留用户的意图和要点。如果没有草稿,则根据画面内容为每个场景撰写旁白。
Gemini 提示词规范:如果使用 Gemini,请将风格说明与口播稿分开。脚本模板已在文本外添加安全的 TRANSCRIPT: 前缀,因为 Gemini 3.1 Flash TTS 有时会把元数据读出来,或拒绝含糊的提示词。
生成前检查
生成音频前,确认每段旁白都能在时长内说完:
window = next_segment_start - this_segment_start
max_words = window * words_per_second * 0.8
如果某段太长,现在就缩短文本——删减字词远比重新生成音频省时省力。
阶段 3:生成脚本
将 scripts/narration_script_template.py 复制到视频目录,并命名为 narration_script.py。填写:
TTS_PROVIDER,值为azure或geminiVOICE_NAME,从对应服务提供商的表格中选择INPUT_VIDEO和OUTPUT_VIDEO(仅限相对路径)SEGMENTS,内容来自阶段 2
设计说明
这些选择源于对实际生产问题的调试:
amix中的normalize=0:ffmpeg 的amix默认会按输入数量降低音量。有 20 个片段时,输出音量会变成原来的 1/20——几乎听不见。- 丢弃原始音频:即使将原始音频以 5% 的音量混入,也会产生明显的双重人声效果。
- 遇到重叠时中止:如果任一片段的音频延伸到下一片段的开始时间之后,脚本就会停止并报告问题。音频重叠会让效果听起来不正常。
- 跳过已有音频文件:脚本只会为没有现有缓存文件的片段生成音频。Azure 使用
.mp3;Gemini 使用.wav。如果更改了某个片段的文本,请在重新运行前删除对应的seg_XXX.*文件。 - Gemini 重试逻辑:Gemini 3.1 Flash TTS 有时会返回暂时性的
500错误。模板会在失败前自动重试几次。
阶段 4:运行并迭代
python3 narration_script.py
如果时间报告显示存在重叠(间隔 < 0),请决定是缩短文本,还是将下一片段的开始时间推迟。如果更改了文本,请先删除 narration_segments/ 中对应的缓存音频文件。如果只更改开始时间,则可直接重新运行。
持续迭代,直到所有间隔均不小于 0。
阶段 5:验证
每次成功构建后运行以下三项检查:
音量
ffmpeg -i <output> -ss 0 -t 30 -af "volumedetect" -vn -f null - 2>&1 | grep -E "mean_volume|max_volume"
预期 mean_volume 在 -25 到 -15 dB 之间,max 在 -10 到 0 dB 之间。如果 mean 低于 -40 dB,则表示未应用 normalize=0 修正——请检查滤镜字符串。
静音间隔
ffmpeg -i <output> -af "silencedetect=noise=-30dB:d=0.3" -vn -f null - 2>&1 | grep -E "silence_(start|end)" | head -20
确认片段切换之间有干净的静音。静音边界应与预期的片段结束和开始时间一致。
音画同步
在 5–8 个关键片段的开始时间提取帧并查看:
for t in <timestamps>; do
ffmpeg -y -ss $t -i <output> -frames:v 1 -q:v 2 /tmp/verify_${t}s.jpg 2>/dev/null
done
当该场景的旁白开始时,屏幕上的内容应已显示。
故障排除
| 症状 | 原因 | 修复方法 |
|---|---|---|
| 两个人声同时播放 | 混入了原始音频 | 只映射 [final] 音轨,绝不要映射 0:a |
| 音频几乎听不见 | amix 按输入数量降低了音量 | 在 amix 参数中添加 :normalize=0 |
| 旁白不同步 | 场景时间戳不精确 | 在问题区域附近以 1–2s 的间隔重新提取帧 |
| 片段边界处发生重叠 | 上一个片段持续时间过长 | 缩短该片段的文本,或延后下一片段的开始时间 |
| 文本已更改但音频没有变化 | 旧的缓存音频文件仍然存在 | 删除 narration_segments/seg_XXX.* 并重新运行 |
| 视频结束时音频被截断 | 最后一个片段超出了视频时长 | 缩短片段,使其在视频结束前 3–4s 播完 |
Gemini 返回 500 | 预览模型输出了文本 token,而非音频 | 重新运行;模板已会重试暂时性故障 |
| Gemini 把提示词标签读出声 | 提示词分类器失效,或提示词过于含糊 | 保持转录文本明确,并使用模板的 TRANSCRIPT: 包装格式 |