关于 wjs-segmenting-video
wjs-segmenting-video 是将长视频与现有 SRT 切分为适合目标平台的独立短片的技能,供需要人工判断主题边界的视频工作流使用。它采用精确时间重编码切片,并输出裁剪片段、逐段 SRT 和帧图,供后续叠加处理。
主要功能
- 01依据 SRT 人工判断主题边界
- 02按指定时间精确切片
- 03检查并按需调整画面方向
- 04生成逐段 SRT 与中点帧
- 05将原始片段交给后期技能
适用场景
- 01从长视频挑选可独立观看的片段
- 02为短视频平台准备不同方向的片段
- 03切片后交给 wjs-overlaying-video 添加字幕和封面
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ jianshuo/ claude-skills --skill wjs-segmenting-video安装后在 Claude Code 中输入/wjs-segmenting-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/example_segments.jsonplatform_sizes.mdsegments_schema.jsonscripts/burn_subs.pycompose_cover.pymake_cover.pyprepend_intro.pysegment.py详细介绍
wjs-segmenting-video
将长视频和 SRT 切分为多个独立短片,每个短片都适配目标平台。此技能在切分和裁切后即结束——它会将原始短片交给 /wjs-overlaying-video,用于制作封面、字幕、插图、CTA 和最终渲染。
适用场景
- 有现成 SRT 转录文本的长视频(≥10 分钟)。
- 目标是制作独立短片(每个短片无需上下文也能看懂)。
- 用户会(或你会)在
/wjs-overlaying-video中单独进行后期制作。
不适用场景
- 单主题剪辑 → 直接使用
ffmpeg -ss A -to B。 - 尚无转录文本 → 先运行
/wjs-transcribing-audio(如果片段需要使用非源语言,再运行/wjs-translating-subtitles)。 - 多机位剪辑 → 使用
/wjs-editing-multicam。 - 在单个主题内进行多次剪切的集锦 → 这是剪辑,不是切分。
此技能是什么——不是什么
| 是 | 不是 |
|---|---|
| 由你(Agent)阅读完整 SRT 并确定主题边界 | 运行 NLP 主题建模、静音检测或“爆款时刻”评分的脚本。主题边界属于语义范畴;Descript、OpusClip、Riverside Magic Clips 等同类工具都会因自动化处理而判断错误。 |
segment.py 负责切分;/wjs-reframing-video 负责调整方向 | 端到端的“魔法”流水线 |
| 默认采用精准定位切分(重新编码)——片段严格从指定时间戳开始 | 流复制切分(会产生最多一个 GOP 时长的关键帧对齐偏移) |
| 交付裁切后的原始短片 + 每个短片对应的 SRT | 烧录字幕、封面、片头、CTA(这些由 /wjs-overlaying-video 处理) |
工作流
long video + SRT
↓ (agent reads SRT, decides topics — judgment, not parsing)
segments.json
↓ segment.py --reencode (accurate seek; clip starts exactly at requested t)
clip_NN.mp4 + frame_NN.jpg
↓ ASK: target platform orientation match source?
↓ /wjs-reframing-video on each clip (if 16:9 → 9:16, etc.)
↓ re-extract frames from cropped clips
clip_NN.mp4 (now in target orientation) + clip_NN.zh-CN.burn.srt
↓
HAND OFF → /wjs-overlaying-video
(does covers + captions + illustrations + CTA + final render)
第 1 步——阅读 SRT,编写 segments.json
不要把主题识别交给脚本。 对每个候选片段,判断:
- 是否完整自洽? 初次观看的观众无需先前上下文也必须能看懂。
- 是否围绕单一主题? 一个核心问题或见解;如果说话者在片段中途转向新话题,那就是两个片段。
- 时长是否适合平台? 视频号为 60–180 秒,抖音和 Shorts 为 30–60 秒。短于 30 秒会让人觉得内容被截断;长于 4 分钟则会降低留存率。
- 是否有引入和收尾? 以主张、问题或生动画面开场;以要点总结收尾。绝不能在句子中间结束。
- 对齐到 SRT 字幕条目边界——绝不能从单词中间切开。
10 分钟的视频源通常可以剪出 3–6 个高质量片段。删掉平淡的中间内容。质量胜过数量。
架构(完整规范见 references/segments_schema.json,示例见 references/example_segments.json):
{
"source_video": "input.mp4",
"source_srt": "input.zh-CN.srt",
"platform": "wechat_channels",
"segments": [{
"id": 1, "slug": "intent-not-code",
"title": "AI 时代不是写代码\n而是写意图",
"summary": "Two-sentence pitch — what's the insight, what's at stake.",
"start": "00:00:43.460", "end": "00:02:35.220",
"cover_prompt": "Visual concept for gpt-image-2 (style anchor, not literal scene)"
}]
}
slug = kebab-case 英文(用于文件名)。title 使用 \n 换行,最多 2 行,每行 8–12 个汉字。cover_prompt 由下游 /wjs-overlaying-video 的封面生成步骤使用——请在此处填写,以便叠加技能直接读取,无需再次询问。
第 2 步——精准定位切分
python3 ~/.claude/skills/wjs-segmenting-video/scripts/segment.py \
--segments segments.json --out output/ --reencode
--reencode 是默认推荐模式。它通过
ffmpeg -ss N -i src -c:v libx264 -c:a aac 切分,使输出严格从指定时间戳开始。使用 CPU 时,每个片段约需 30 秒。它还会为每个片段提取一帧中点画面,保存到 output/frame_NN_slug.jpg。
为什么默认使用 --reencode 而不是流复制:
通过 ffmpeg -ss N -c copy 进行流复制时,会定位到 N 之前最近的关键帧(无法重新编码)。因此,输出的 t=0 会映射到源视频的 t=keyframe,片段会在所需语音前播放一小段“前导”内容。从主 SRT 中按边界 N 切出的字幕会恰好提前于音频一个 GOP 时长——听众会感觉“字幕比声音快”。
实际使用 GOP=2s 的 H.264 视频源时,每个片段都会偏移 0.6–1.5 秒。这看起来像是下游的同步问题;实际上是上游切分时机有误。
流复制变体(仅当你能控制源编码时)
如果源视频已使用 -force_key_frames 在每个
请求的剪辑边界重新编码,流复制是准确的。工作流:
# Build the comma-separated keyframe list from segments.json
KF=$(python3 -c "import json; s=json.load(open('segments.json'))
ts=[]
for seg in s['segments']:
ts += [seg['start'], seg['end']]
print(','.join(ts))")
# Re-encode master once, forcing keyframes at all segment boundaries
ffmpeg -i master.mp4 \
-c:v libx264 -preset medium -crf 18 \
-force_key_frames "$KF" \
-c:a copy master_kf.mp4
# Now stream-copy cuts land exactly:
python3 segment.py --segments segments.json --source master_kf.mp4 --out output/
仅在反复调整片段边界时使用此方法(你会多次重新剪切
同一个源视频)。对于一次性处理,--reencode 更简单,
而且同样准确。
诊断已剪切片段中的关键帧对齐问题
ffprobe -v error -select_streams v:0 -read_intervals "$((N-2))%$((N+5))" \
-show_entries packet=pts_time,flags -of csv=p=0 master.mp4 | grep "K_"
类似 360.023,K__ 362.023,K__ 的输出 → GOP=2s。在
361.000 处使用 -c copy 剪切,实际会从 360.023 开始,字幕会比音频
提前 0.977s。补救方法是为每个片段添加 SRT 偏移调整
(请求的起始时间 − 最近的前置关键帧),并应用到每条字幕的
开始/结束时间;但根本的解决方法是使用 --reencode 重新剪切。
第 3 步 — 检查方向(继续前先询问)
将源视频的宽高比与目标平台进行比较:
| 平台 | 原生方向 | 宽高比 |
|---|---|---|
| 视频号 (WeChat Channels) | 竖屏 | 9:16 |
| 抖音 / TikTok / Reels | 竖屏 | 9:16 |
| 小红书 (Xiaohongshu video) | 竖屏 | 9:16 |
| YouTube Shorts | 竖屏 | 9:16 |
| YouTube(普通版) | 横屏 | 16:9 |
| B站 (Bilibili) | 横屏 | 16:9 |
使用 ffprobe 检查:
ffprobe -v error -select_streams v:0 \
-show_entries stream=width,height -of csv=p=0 clip_01_*.mp4
如果源视频的宽高比已符合平台要求 → 跳过此步骤。
如果不符合 → 转换前询问用户。示例措辞:
源视频是横屏 (1920×1080),平台 视频号 需要竖屏 (9:16)。是否对每段 调用
/wjs-reframing-video转成竖屏?(crop 会用 MediaPipe 跟踪正在说话 的人的脸,保持说话人始终在画面中)
绝不要悄悄跳过检查——直到上传时才发现横屏片段需要转成竖屏, 会令人非常沮丧,而这正是此技能要避免的问题。
调用 /wjs-reframing-video
裁剪脚本需要在 Python 3.12 虚拟环境中安装 mediapipe + opencv + numpy(mediapipe 不提供适用于 3.14+ 的 wheel)。一次性设置:
uv venv --python 3.12 /tmp/_crop_venv
/tmp/_crop_venv/bin/python -m pip install mediapipe opencv-python numpy
逐片段调用:
for n in 01 02 03 04 05; do
slug=$(ls clip_${n}_*.mp4 | grep -v -E "_intro|_burned|_vert" | head -1 | sed -E "s/clip_${n}_(.+)\.mp4/\1/")
/tmp/_crop_venv/bin/python ~/.claude/skills/wjs-reframing-video/scripts/crop.py \
"clip_${n}_${slug}.mp4" \
--out "clip_${n}_${slug}_vert.mp4" \
--target portrait \
--bitrate 8M # 视频号 caps at 10Mbps
done
裁剪后,将裁剪版本替换为规范名称,以便后续流水线能够找到它们:
mkdir -p _horizontal_archive
for n in 01 02 03 04 05; do
base=$(ls clip_${n}_*_vert.mp4 | sed -E "s/_vert\.mp4$//")
mv "${base}.mp4" "_horizontal_archive/"
mv "${base}_vert.mp4" "${base}.mp4"
# Re-extract midpoint frame:
mid=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "${base}.mp4" | awk '{print $1/2}')
slug=$(echo "$base" | sed -E "s/^clip_${n}_//")
ffmpeg -hide_banner -loglevel error -ss "$mid" -i "${base}.mp4" \
-frames:v 1 -q:v 3 "frame_${n}_${slug}.jpg" -y
done
合理性检查:裁剪日志中的人脸出现在画面内的检测率可能偏低(例如 face#0: 9.6s on screen (9%)),这是因为说话人坐在距离摄像机约 2 m 以外的位置。数值偏低没问题——活动说话人滞后机制加上回退到最大人脸,仍能生成居中效果良好的裁剪结果。但**0 face observations / (no face / fallback): 100% 不行**:没有任何关键点时,裁剪会回退到画面中心;在双人访谈布景中,中心落在说话人之间的背景上(壁炉 / 植物),而不是任何人身上。遇到这种情况时,放弃 MediaPipe 裁剪,改为根据说话人的已知画面位置进行确定性固定裁剪——参见
/wjs-reframing-video →“零检测回退”。提交前务必进行视觉验证:提取一帧中间帧,确认说话人位于画面中央。
第 4 步 — 按片段切分 SRT
python3 ~/.claude/skills/wjs-segmenting-video/scripts/burn_subs.py \
--segments segments.json --out output/ --no-burn
--no-burn 标志会生成逐片段 SRT(clip_NN_slug.zh-CN.burn.srt),
时间戳已调整为从 0 开始——这正是
/wjs-overlaying-video 字幕所需的输入(其合成会从 t=cover_duration 开始正文,
而不是使用主时钟)。
尽管脚本名称 burn_subs.py 沿用了旧称,但在 --no-burn 模式下,此步骤不会
将像素烧录到画面中——它只是一个 SRT 切分器。(烧录像素的模式供旧版“路径 A”工作流使用,但现已弃用,推荐改用
/wjs-overlaying-video 的 HTML/CSS 字幕渲染。)
交接包 — 交付给 /wjs-overlaying-video 的内容
完成第 1–4 步后,准确交付以下各片段的产物:
output/
clip_NN_slug.mp4 # raw cropped clip (target orientation, no subs, no cover)
clip_NN_slug.zh-CN.burn.srt # per-clip SRT, timestamps shifted to start at 0
frame_NN_slug.jpg # midpoint frame (cover reference)
segments.json # for slug/title/summary/cover_prompt metadata
接着调用 /wjs-overlaying-video 添加封面、字幕、插图、
CTA,并为每个片段生成可直接上传的 MP4。叠加技能会为每个片段生成一个最终合成视频,并通过一次编码完成渲染(不会连续多次重新编码)。
快速参考
| 任务 | 命令 |
|---|---|
| 剪辑片段(精确,默认) | segment.py --segments S.json --out output/ --reencode |
| 探测源视频宽高比 | ffprobe -v error -select_streams v:0 -show_entries stream=width,height -of csv=p=0 IN.mp4 |
| 转换方向(先询问) | 按每个片段调用 /wjs-reframing-video |
| 切分每个片段的 SRT | burn_subs.py --segments S.json --out output/ --no-burn |
| 诊断关键帧位置 | ffprobe -v error -select_streams v:0 -read_intervals A%B -show_entries packet=pts_time,flags -of csv=p=0 src.mp4 | grep K_ |
常见错误
- 在句子中间剪切 — 始终对齐到 SRT 字幕条目的边界。
- 试图用完 100% 的视频内容 — 从 10 分钟视频中剪出 3–6 个优质片段很正常。无聊的中段直接删掉。
- 让大模型撰写标题 — 标题需要判断,而非概括。传给 make_cover 之前,请先审核并重写。
- 未使用
--force_key_frames预处理就进行流复制 — 可能导致片段中的音频最多比字幕提前 1 GOP。除非源视频经过专门处理,否则请使用--reencode(默认)。 - 跳过方向检查 — 横屏播客发到视频号,到上传时才发现方向不对,这种情况本可避免。请先探测宽高比,并在裁剪前询问用户。
- 在此技能中烧录字幕 / 生成封面 — 这些工作已移至
/wjs-overlaying-video。此技能在步骤 4 后结束。
与其他技能集成
/wjs-transcribing-audio— 如果缺少源 SRT,请先生成。为准确设置字幕条目时间,优先使用逐词 Whisper 输出(或 Volcano/豆包 ASR 输出)。如果需要翻译片段,请接着调用/wjs-translating-subtitles。/wjs-reframing-video— 当源视频方向与目标平台不匹配时,在步骤 3 调用。基于人脸跟踪的主动说话者跟随可让说话者始终处于画面内。/wjs-editing-multicam— 如果源视频为多机位,请先渲染同步后的单个 MP4,再进行片段剪辑。/wjs-overlaying-video— 步骤 4 之后所有工作的默认下游技能。封面、字幕、插图、CTA 和最终渲染都在此完成。请勿在此技能中添加后期制作工作。
文件与参考资料
scripts/segment.py— 精确定位 + 流复制剪辑scripts/burn_subs.py— SRT 切分工具(--no-burn模式);旧版 libass 烧录模式已弃用,改用/wjs-overlaying-videoreferences/segments_schema.json— segments.json 的 JSON Schemareferences/example_segments.json— 完整示例