2 小时录像 → 可检索图文纪要:一条不重编码的本地流水线
0. 先定产物,再动手
很多人拿到录像的第一反应是「打开剪辑软件」。停下。会议、课程、访谈这类长视频,你要的通常不是一段剪好的片子,而是三样东西:
notes.md—— 带[00:42:10]时间戳的图文纪要,可以全文搜索chapters.txt—— 章节元数据,写回 MP4,播放器进度条上能直接跳audio.srt—— 逐句字幕,备用
-c:v copy。
1. 目录与工具
work/
├── raw/ # 原始录像,只读,永不修改
├── audio/ # 抽出的音轨
├── asr/ # 转写结果
└── out/ # 最终产物
工具只需要两个:ffmpeg(6.0+,含 ffprobe)和 whisper.cpp(本地转写,音频不出机器)。
2. 体检:先 ffprobe,别急着转码
ffprobe -v error \
-show_entries stream=index,codec_type,codec_name,channels,sample_rate,channel_layout,duration \
-of default=noprint_wrappers=1 raw/meeting.mp4
重点看三件事:
- 音轨数量。 线上会议录制常见双音轨(本地麦克风 + 系统声)。只抽第一条,对方说的话全丢。
- 声道布局。 标着
stereo,但左右声道其实是两个不同的人——这不是立体声,是「双单声道」。直接 downmix 会把两个人叠在一起,转写质量断崖下跌。 - 时长是否一致。 容器时长和音轨时长差几秒很常见,后面所有时间戳要以音轨为基准。
ffmpeg -i raw/meeting.mp4 -t 30 -af "pan=mono|c0=c0" -y /tmp/L.wav
ffmpeg -i raw/meeting.mp4 -t 30 -af "pan=mono|c0=c1" -y /tmp/R.wav
如果两边是不同的人,走分轨路线,别 downmix:
ffmpeg -i raw/meeting.mp4 -map 0:a:0 -af "pan=mono|c0=c0" \
-ar 16000 -c:a pcm_s16le -y audio/ch0.wav
分别转写、分别标记说话人,最后按时间戳合并。这一步做对,后面省两小时。
3. 抽音频:16k 单声道 PCM
ffmpeg -i raw/meeting.mp4 -vn -ac 1 -ar 16000 -c:a pcm_s16le -y audio/full.wav
要点:
16000Hz 是 ASR 的标准输入,再高没有收益,只会拖慢转写。- 用
pcm_s16le,别用 mp3/aac,有损编码引入的伪影会变成转写错误。 - 这一步不要做响度归一化。 先看电平:
ffmpeg -i audio/full.wav -af volumedetect -f null - 2>&1 | grep mean_volume
mean_volume 低于 -30 dB 才考虑统一加增益,用 -af volume=12dB。不要上 loudnorm,它会改变时间轴上的动态,对识别没有帮助,还可能让 whisper 的时间戳变差。
4. 转写:先跑 5 分钟试片
whisper-cli -m models/ggml-large-v3-turbo-q5_0.bin \
-f audio/full.wav \
-l zh \
--output-srt --output-json \
-of asr/full \
-t 8
正式跑之前必须试片:
ffmpeg -i audio/full.wav -t 300 -c copy -y audio/probe.wav
试片要确认的只有一件事:专有名词。产品名、人名、缩写被听错是最常见的问题。把试片里错的词整理成一份替换表,正式转写后用 sed 批量改——比用 prompt 提示更快、更可控、更可复现。
时间预算:2 小时音频,large-v3-turbo 量化版在 8 核 CPU 上约 20–35 分钟,M 系芯片约 8–15 分钟。
5. 章节切分:两个信号叠加
不要凭感觉切。只用两个客观信号。
信号 A:静音间隔。
ffmpeg -i audio/full.wav -af silencedetect=noise=-32dB:d=1.2 -f null - 2>&1 | grep silence_end
输出形如 silence_end: 1843.21 | silence_duration: 2.14。
信号 B:转写文本里的转折词。 从 SRT 里抓这些词最近一次出现的时间戳:接下来、第二个问题、我们看下一、好,那、总结一下、最后。
切分规则,写成脚本跑:
- 候选边界 = 静音结束点 ∩ 转折词时间戳 ±15 秒
- 章节最短 3 分钟。短于 3 分钟的候选点直接丢掉,否则会切出 40 个碎章,比不切还难用
- 首章从 0 开始,末章到音轨末尾
6. 写 chapters.txt 并烧回 MP4
;FFMETADATA1
title=产品评审会 2026-10-05
[CHAPTER]
TIMEBASE=1/1000
START=0
END=372000
title=00:00 开场与议程确认
[CHAPTER]
TIMEBASE=1/1000
START=372000
END=1154000
title=06:12 上季度数据复盘
[CHAPTER]
TIMEBASE=1/1000
START=1154000
END=2100000
title=19:14 定价方案分歧
时间单位是毫秒,START/END 来自上一步的秒数 ×1000。
写回原片,不重编码:
ffmpeg -i raw/meeting.mp4 -i out/chapters.txt \
-map_metadata 1 -map 0 -c copy -y out/meeting_chaptered.mp4
两个参数缺一不可:-map_metadata 1 用第二个输入(章节文件)的元数据覆盖;-map 0 保证原片所有流都被拷过去(多音轨、字幕轨一个都不能少)。
校验:
ffprobe -v error -show_chapters -of default=noprint_wrappers=1 out/meeting_chaptered.mp4
7. 生成可检索纪要
从 SRT 出发,按章节边界聚合,每章保留 3–5 条要点句。挑句规则不用 AI 也够用:
- 单句长度 > 12 字
- 不以「嗯 / 那个 / 就是说」开头
- 含数字、日期、人名,或决策动词(决定 / 确认 / 延期 / 由谁负责)
- 同一章内按时间排序,最多 5 条
## 06:12 上季度数据复盘
[▶ 06:12](meeting_chaptered.mp4#t=372)
- 09:40 上季度转化率 3.2%,环比下降 0.4 个点
- 12:05 决定把投放预算从 A 渠道切 30% 到 B 渠道
- 15:30 数据口径有争议:是否含退款单,待财务确认
`#t=372` 是秒数,VLC、IINA、浏览器原生 `<video>` 都认这个锚点,点一下直接跳。整份 Markdown 丢进笔记软件就能全文搜索。
8. 三条避坑
- 不要在
-c copy之外对原片做任何处理再写章节。 一旦重编码,时间戳基准可能变,章节会整体偏移。 - 不要把 SRT 时间戳直接当章节边界。 一句话一行的粒度太碎,章节必须是「话题级」的。
- 不要删原始音轨。 转写必然有错,唯一的真相来源是音频;纪要和字幕都只是索引,不是存档。