内容分四块: 1、产品规划产出 —— MCN 短视频整合营销工作台的①段五份(1a 需求/1b 竞品/1c 画像/1d 策略/1e 场景)、②段两份(2a 功能/2b 布局)、③段界面(DESIGN.md 契约与令牌表 + mcn-workbench.html 原型 + 实测/会诊/审查三份 + 23 张闸门截图)。 2、开源竞品调研 —— 5 个内容工作台项目的取证原始件与 1b 系列分析文档。 3、参考资料 —— 竞品视频抽帧 1145 张 + 2 个源视频 + 功能点截图。 4、机制侧 —— 协作脚本与状态台账、工作区记忆日志、抽帧/OCR 脚本。 .gitignore 只排运行时日志、脚本备份副本与一次性探针输出,其余按原样入库。
7.4 KiB
7.4 KiB
视频抽帧与字幕规范(SOP)
抖音等平台视频下载后的抽帧与字幕提取标准流程。基于 2026-08-30 实测(《当队伍里有两只贪吃的猪》70.3s)沉淀。 应用场景:视频理解、画面反推提示词、字幕转录、分镜分析。
⚠️ 核心铁律(任何抽帧/字幕任务执行前必读,违反即漏帧 / 全批失败)
本规范结论必须逐条执行,不是参考建议。历史上已两次因"未按此执行"导致字幕大面积丢失(教训 #006、#010)。执行前请逐项勾选:
- 双因素 + 首尾 + 补帧,缺一不可:① 画面
scene 0.3② 字幕区scene 0.1(漏这条 = 画面静止但字幕换句的帧全丢) ③scene 0.05补漏 ④ 首尾帧 ⑤ >5s 长间隔补中点。 - 字幕区必须 crop 后再 scene 检测,crop 按实际分辨率底部 15%:1080p 横屏
crop=1920:162:0:918;720pcrop=1280:108:0:612;竖屏 720×960crop=720:240:0:720。先抽一帧确认字幕位置再 crop。 - 字幕 OCR 必须逐帧:对每帧字幕区都做 OCR,再按时间滚动去重(相似度 ≥0.80 合并保留最长),禁止只对每个聚类「代表帧」OCR(代表帧模糊/过渡/fade → 整句丢失)。
- CRLF 防护:Python/Windows 生成时间戳列表须
newline='\n',否则行尾带\r→ ffmpeg-ss报 Invalid duration 全批失败。 - 禁
select='eq(t,...)'精确时间匹配抽帧(浮点误差命中率极低),一律用-ss逐点抽。 - 反推 ≠ 规则:禁止从旧产物(
scene_*.txt/frames_combined/kf_*)反推流程当规则;执行以本规范为准,文档缺失先补文档再执行。
一、抽帧策略(双因素 + 首尾 + 补帧,⭐ 权威方案)
核心原则:只抽"有信息量的帧"——画面变化点 + 字幕变化点 + 首尾帧 + 长间隔补帧,避免固定节奏(fps=1)浪费静止帧。
| 因素 | 命令 | 阈值 | 捕捉内容 |
|---|---|---|---|
| ① 画面变化 | select='gt(scene,0.3)' |
0.3 | 镜头切换/画面突变 |
| ② 字幕变化 | crop=W:底1/4:0:Y + select='gt(scene,0.1)' |
0.1 | 字幕换句(含画面静止时) |
| ③ 低阈值补漏 | select='gt(scene,0.05)' |
0.05 | 中等缓变(0.05~0.3 盲区,如 53.93s 案例) |
| ④ 首帧/尾帧 | -ss 0 / -ss DUR-0.3 |
— | 开场/结尾画面(scene 不触发) |
| ⑤ 长间隔强制补帧 | 帧间隔 >5s → 该段中点强制抽 1 帧 | — | 物理兜底,杜绝长盲区(如 8.4s 空隙) |
执行流程:
- 画面 scene 检测(0.3)→ 时间点 A
- 字幕区 scene 检测(0.1)→ 时间点 B
- 低阈值 scene 检测(0.05)→ 时间点 C(补中等缓变盲区,不是可选补救,是标准步骤)
- 合并去重 A∪B∪C → 基础帧集
- 长间隔强制补帧:排序后检查帧间隔,任一 >5s 则在该段中点补 1 帧(物理上无盲区)
- 必加首帧(0s)+ 尾帧(
DUR-0.3或-ss 69.9) - 逐时间点
-ss抽帧(精确时间匹配eq(t,xx)命中率低,勿用)
字幕区裁剪(竖屏 720×960):字幕通常在底部 1/4 → crop=720:240:0:720。横屏或字幕位置不同时按实际调整。
二、抽帧命令模板
FF="/path/ffmpeg.exe"; VIDEO="video.mp4"; mkdir -p frames_combined
# ① 画面变化点
ffmpeg -i "$VIDEO" -vf "select='gt(scene,0.3)',showinfo" -vsync vfr -f null - 2>&1 \
| grep -oE "pts_time:[0-9.]+" | cut -d: -f2 | sort -n -u > scene_03.txt
# ② 字幕变化点(竖屏底部 1/4 区域)
ffmpeg -i "$VIDEO" -vf "crop=720:240:0:720,select='gt(scene,0.1)',showinfo" -vsync vfr -f null - 2>&1 \
| grep -oE "pts_time:[0-9.]+" | cut -d: -f2 | sort -n -u > subtitle_01.txt
# ③ 低阈值复查(scene=0.05,找中等缓变盲区)
ffmpeg -i "$VIDEO" -vf "select='gt(scene,0.05)',showinfo" -vsync vfr -f null - 2>&1 \
| grep -oE "pts_time:[0-9.]+" | cut -d: -f2 | sort -n -u > scene_005.txt
# ④ 合并 + 长间隔强制补帧(间隔 >5s 补中点,物理杜绝盲区)
sort -n -u scene_03.txt subtitle_01.txt scene_005.txt > times.txt
echo "0" >> times.txt # 首帧
DUR=$(ffprobe -v error -show_entries format=duration -of csv=p=0 "$VIDEO")
# 长间隔补帧:遍历排序后时间点,间隔>5s 插入中点
prev=""
for t in $(sort -n -u times.txt); do
if [ -n "$prev" ]; then
gap=$(echo "$t - $prev" | bc)
if [ "$(echo "$gap > 5" | bc)" = "1" ]; then
mid=$(echo "($t + $prev) / 2" | bc)
echo "$mid" >> times.txt
fi
fi
prev="$t"
done
sort -n -u times.txt > times_final.txt
# ⑤ 逐时间点抽帧(尾帧用 DUR-0.3 防超界)
i=0
for t in $(cat times_final.txt); do
[ "$(echo "$t > $DUR" | bc)" = "1" ] && t=$(echo "$DUR - 0.3" | bc)
i=$((i+1))
ffmpeg -y -ss "$t" -i "$VIDEO" -frames:v 1 -q:v 2 "frames_combined/c_$(printf %02d $i)_${t}s.jpg" 2>/dev/null
done
三、帧命名规则
frames_combined/c_XX_时间s.jpg(如c_01_2.233333s.jpg)- 时间戳保留原始精度(scene 检测输出浮点),便于按帧对应视频时刻
四、时间区间划分(每帧代表的时间段)
- 相邻帧中点划分(Voronoi):帧 i 代表
[中点(i-1,i), 中点(i,i+1)] - 首帧从 0 起、尾帧到视频结束(DUR)
- 用于:分镜时间轴、字幕时间线、画面-台词对应
五、字幕提取
- 抖音字幕是烧录在画面上的(非独立字幕轨)→ 从帧画面转录(OCR / 视觉读取)
- 字幕区 scene 检测已保证每个换句时刻都有一帧(含画面静止时)
- 🔴 必须逐帧 OCR 字幕区(见顶部核心铁律第 3 条):对每一帧都做 OCR,再按时间滚动去重,保留最完整版本。禁止只对每个聚类「代表帧」OCR——代表帧一旦模糊/过渡/fade,整句字幕会永久丢失(#010 事故根因)。
- 转录产出:
字幕稿_日期.md,格式 = 时间线表(时间 | 台词 | 帧文件) - 长间隔段(如 8~9s 无变化):该段字幕可能持续同句,读帧确认即可
六、三版抽帧对比(为什么不用固定节奏)
| 方案 | 帧数(70s) | 感知画面 | 感知字幕 | 结论 |
|---|---|---|---|---|
| I 帧 | 12 | ❌ | ❌ | 编码关键帧,漏字幕 |
| fps=1 | 70 | ❌ | ✅ | 固定节奏,浪费 56% |
| 双因素+首尾+补帧 | 31 | ✅ | ✅ | 精准全覆盖,省帧 |
七、常见坑
select='eq(t,2.233333)'精确时间匹配命中率极低(浮点误差)→ 用-ss逐点抽- 尾帧
-ss DUR会超出视频末尾 → 用DUR-0.3或-ss 69.9(70s 视频) - scene=0.05 会产生大量抖动点(相邻 <0.05s)→ 与基础帧集比对,近似点(<0.05s 差)不算遗漏
- 字幕区域随平台/画幅变化(抖音竖屏底部 1/4;B 站横屏底部 10-15%)→ 先抽一帧确认字幕位置再 crop
- 字幕区 crop 参考值:抖音竖屏 720×960 →
crop=720:240:0:720;B 站横屏 1080p →crop=1920:162:0:918(底部 15%) - CRLF 行尾坑:时间戳列表若由 Python/Windows 生成(
\n被转成\r\n),bashwhile read的变量带\r→ ffmpeg-ss "0.0\r"报Invalid duration for option ss全批失败。修复:先tr -d '\r' < times.txt > times_unix.txt再用,或 Python 写文件用newline='\n' - 逐点 -ss 抽帧耗时:700+ 帧约 7 分钟(每帧一次 ffmpeg 启动),务必后台执行(run_in_background);帧序号用 4 位
c_%04d