mcpField
N
narrate-video

narrate-video

github.com/feiskyer创意与媒体15181 次安装28 周前更新
代码仓库

关于 narrate-video

这项 Skill 为视频添加定时旁白,涵盖场景分析、脚本编写、语音生成与同步检查,适合需要让旁白贴合画面内容的创作者。

主要功能

  1. 01分析场景与时间点
  2. 02编写分段定时旁白
  3. 03使用 Azure 或 Gemini 生成语音
  4. 04将旁白与视频合并
  5. 05检查音量、静音间隔与同步

适用场景

  1. 01为产品演示视频添加旁白
  2. 02根据场景时间调整草稿脚本
  3. 03生成指定语言的配音

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/feiskyer/video-skills --skill narrate-video

安装后在 Claude Code 中输入/narrate-video确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

references/
gemini-tts.md
voices.md
scripts/
check_env.py
narration_script_template.py

详细介绍

视频旁白

为视频添加专业配音。分析视频,撰写或润色带时间标记的脚本,通过 Azure TTS 或 Gemini 3.1 Flash TTS 生成语音并进行合并,制作出音画同步的配音视频。

输入:$ARGUMENTS

其他资源


阶段 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 或 gemini
  • VOICE_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: 包装格式

评论

支持 Markdown