# Video Reader

> 让看不了视频的大模型能"看视频"。当用户给你一个视频文件(.mp4/.mov/.gif 等) 并希望你理解里面发生了什么——尤其是排查 App 滑动/交互问题、复现 bug、 分析用户操作录屏、看动态过程、定位"第几秒发生了什么"时,使用本 skill。 它用纯代码做帧差初筛(自动跳过静止/无动作的片段),把视频翻译成 "带时间戳的关键帧 + 运动时间线",再由你(大模型)看图判断; 支持九宫格概览(grid,一张图看全片节奏)和可选的语音转写(transcribe, 补"画面看不到、只能听到"的旁白/口述/报错语音)。 触发词:视频、录屏、视频文件、看视频、视频里、这段视频、滑动不流畅、 交互问题、复现一下、用户操作、动态、第几秒、video、mp4、screen recording、 帮我看下这个视频、视频卡在哪、面板、手势、视频传不上去、不支持的文件类型、改后缀、压缩包、 视频里说了什么、语音转写、字幕、听听这段、全片概览、一张图看完、整体看看、九宫格、缩略图。 即使用户只是丢一个视频文件过来说"看看这个有什么问题",也应触发本 skill。 注意:很多平台(如 Mira 等)禁止直接上传视频格式,本 skill 支持用户改后缀或压成 zip 绕过上传限制后照常处理。

- Skill: `job-yang/video-reader` (Agent Skill, multi-file: 6 files)
- Install (CLI): `npx skillmds@latest add job-yang/video-reader`
- Raw SKILL.md: https://api.skillmd.com/api/skills/job-yang/video-reader/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Coding & Dev Tools
- Author: Job-Yang (https://skillmd.com/u/job-yang)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/job-yang/video-reader

---


# Video Reader — 给大模型配的一副"看视频的眼镜"

## 这个 skill 解决什么问题

你(大模型)能看图,但看不了视频。视频本质就是一串按时间排好的图片。
本 skill 的脚本帮你做两件你做不了或做不好的事:

1. **初筛**:用帧差(相邻帧像素差异,纯数学,不花 token)算出"哪几秒画面在动",
   自动跳过静止段。用户经常从"盘古开天辟地"开始录,前面几十秒对着桌子没动——
   这些会被整段折叠,一帧都不喂给你。
2. **智能抽帧**:只在有动作的地方抽帧,而且支持"先粗后细"两轮下钻,既不漏关键帧,
   又不会把上下文撑爆。

**重要边界:这个 skill 不含任何业务逻辑。** 它不懂"卡顿""面板""跟手""中间态"是什么。
它只负责把视频变成"你能消化的帧 + 时间线"。看懂画面、判断对错、定位 bug——那是你的活。

## 四个子命令,按需要选(别只会 scan)

本 skill 有四个能力,**接到视频任务先想清楚要哪个**,不要永远只用 scan:

| 子命令 | 什么时候用 | 一句话 |
| --- | --- | --- |
| `scan` | 默认起点;要定位"哪几秒在动/出问题" | 帧差初筛+运动时间线+稀疏抽帧 |
| `zoom` | 已知可疑区间,要看那几秒的细节 | 指定区间高密度抽帧 |
| `grid` | 想先要个**全片概览**、一张图看节奏,或视频较长先扫一眼 | 均匀取帧拼成九宫格大图,一次 Read 看全片 |
| `transcribe` | 画面看不出、**需要听**(旁白/口述/报错语音/"他说了啥") | 语音转文字(带时间戳,可选,需 ffmpeg+whisper) |

常见组合:**长视频/不确定从哪看 → 先 `grid` 看全片节奏 → `scan` 看运动时间线 → `zoom` 下钻可疑段;涉及"说了什么" → 加 `transcribe` 与画面时间线对齐。** 用户即使没点名,你也应根据意图主动选对子命令并告诉他你用了哪个、为什么。

## 核心工作流:粗扫 → 下钻(由你驱动)

不要一上来就把整段视频高密度抽帧,那样既慢又炸上下文。标准打法是两步,**你来决定抽哪、抽多细**:

```
第1步  scan(粗扫)
  └─ 脚本输出:运动时间线(文字) + 活动段稀疏抽的几帧
  └─ 你看时间线 + 帧,判断"问题大概在 X-Y 秒"
        ↓
第2步  zoom(下钻)
  └─ 脚本在 X-Y 秒密集抽帧
  └─ 你看细节;若还不够,继续在更小区间 zoom(可多轮)
```

关键心法:**先读时间线,再决定要不要看帧、看哪段的帧。** 很多时候 scan 的运动时间线
(纯文字)就足够让你判断该往哪下钻,这是最省 token 的方式。

## 上传被拦怎么办(很多平台禁视频格式,务必知道)

很多平台(如 Mira 等)在上传时**直接禁掉视频/音频格式**,用户传 `.mp4`/`.mov` 会被提示
"不支持的文件类型",根本传不进来。**这不是死路,有两个绕过办法,你必须主动告诉用户:**

1. **改后缀**:把 `xxx.mp4` 重命名成平台允许的后缀(如 `xxx.txt`/`xxx.bin`)再上传。
   你拿到后**不要被后缀骗了**——它本质还是视频,先把它改回 `.mp4`(或直接用原始路径)再喂给脚本即可。
   OpenCV 按文件内容解码,不认后缀,所以哪怕后缀是 `.txt`,只要内容是视频就能读;
   实在不放心就 `cp 那个文件 /tmp/v.mp4` 再处理。
2. **压成 zip**:把视频压成 `.zip` 上传(zip 通常不被拦)。你收到后先解压拿到里面的视频文件,
   再喂给脚本。**解压是你(大模型)调用解压能力完成的,脚本本身不处理 zip。**

> 一句话:**平台拦的是"后缀/格式",不是"内容"。改后缀或套个 zip 壳就能绕过,
> 拿到真身后照常 scan/zoom。遇到"视频传不上去"先想到这两招,别让用户卡在上传这一步。**

## 怎么调用

脚本路径(用绝对路径调用):
`<SKILL_DIR>/scripts/video_frames.py`

依赖:Python3 + opencv-python-headless + numpy(matplotlib 仅 `--debug` 画曲线图时用)。OpenCV 自带视频解码,**不依赖系统 ffmpeg**。
脚本会**自动检测并安装缺失依赖**(`pip install --user --break-system-packages`,不污染系统),无需手动准备;只有自动安装失败时才会打印一条人话提示让你手动装。

脚本每次启动都会在 stderr 先自报家门(当前解释器路径 / 版本 / user-site)。**若遇到"依赖装了却 import 不到",99% 是机器上多个 `python3` 错配**(装包用解释器 A、跑脚本命中解释器 B,而 `pip --user` 按版本号分目录存包)。这时看启动打印的 `python:` 那行,把跑脚本的解释器对齐到装了包那个(用绝对路径,或建 venv)即可。报错提示里也会带上当前解释器路径,照着做不用手敲 `which -a` 排查。

### scan —— 粗扫全片

```bash
python3 <SKILL_DIR>/scripts/video_frames.py scan <视频路径>
```

输出:stdout 是结构化 JSON(含 timeline、active_segments、frames 列表及每帧路径),
stderr 是给你看的运动时间线概要。先读 timeline 决定下一步。

常用参数:
- `--start <秒> --end <秒>`:只扫某段(用户给了大概范围时用)。
- `--density <N>`:活动段每秒抽几帧,默认 2(粗扫够用)。
- `--max-width <px>`:帧最大宽度,默认 900(省 token);要看清小字可调大。

### zoom —— 对可疑区间高密度抽帧

```bash
python3 <SKILL_DIR>/scripts/video_frames.py zoom <视频路径> --start 10.0 --end 12.0 --density 8
```

`--density` 默认 8(每秒 8 帧),要看某个瞬间(如手指抬起那一刻)可加到 12~15,
区间也尽量收窄(如 10.5–11.0)。

### grid —— 九宫格概览(一张图看全片节奏)

全片(或区间)均匀取帧拼成一张大图,每格左上角标秒数。**一次 Read 一张图就能把握整段视频的节奏/概貌,省 token、好定位**;看完再用 zoom 对可疑那一格的时间段下钻。

```bash
python3 <SKILL_DIR>/scripts/video_frames.py grid <视频路径>
python3 <SKILL_DIR>/scripts/video_frames.py grid <视频路径> --rows 4 --cols 4 --start 0 --end 30
```

- `--rows/--cols`:网格行列,默认 3×3=9 格;长视频可加大(如 4×4)。`--cell-width` 每格宽,默认 320。
- 输出:JSON 里 `grid_path` 是拼好的大图路径,`cells[]` 是每格的 `t`(秒)/行列号。**Read 这张 `grid_path` 即可**,按"从左到右、从上到下"读,每格角上的秒数就是它在视频里的时间。
- 和 scan 互补:**scan 的运动时间线擅长"哪几秒在动",grid 擅长"整段长啥样"**。不确定从哪看、或视频较长时,先 grid 毛估再 scan/zoom。

### transcribe —— (可选)语音转写,补画面看不到的信息

画面只告诉你"看到什么",但旁白、客诉口述、报错语音提示这些**只能听到**的信息,靠这个子命令补。**它是可选软能力,缺依赖只提示并跳过,不影响 scan/zoom:**

```bash
python3 <SKILL_DIR>/scripts/video_frames.py transcribe <视频路径> --model turbo
```

- 依赖:系统 `ffmpeg`(抽音轨) + `openai-whisper`(pip,带 torch 较重,脚本会"用到才按需装")。任一缺失会打印安装方法并以退出码 4 跳过,你据此降级到只看画面即可。
- `--model`:whisper 模型,默认 `turbo`(快且准);要更准可用 `medium`/`large`。`--language zh/en` 可指定语言,默认自动检测。
- 输出:stdout 是 JSON(`text` 全文 + `segments` 带时间戳分段),stderr 是带时间戳的逐段文字。
- **用法心法**:把转写的时间戳和 `scan` 的画面运动时间线**对齐**,就能说出"第 X 秒画面在做什么、同时说了什么",定位更准。无音轨的纯录屏会自动跳过。

### --debug —— 调试模式(默认关闭)

平时不用开。调试技能本身、或想搞清楚"为什么这段被判成静止/运动"时加上 `--debug`:

```bash
python3 <SKILL_DIR>/scripts/video_frames.py scan <视频路径> --debug
```

开了之后:
- 帧不再进随机临时目录,而是存到 **当前目录的 `video_reader_debug/<视频名>_<模式>/`**,稳定可复查。
- 额外产出 `_debug/motion_data.json`(每个采样点的时间+运动分、阈值、分段)和
  `_debug/motion_curve.png`(帧差曲线图,带阈值线和活动段底纹)。看这张图就能一眼判断
  阈值定得对不对、该不该的段有没有被漏掉或误判,据此调 `--threshold`。

### 看帧

JSON 里 `frames[].path` 是每帧的绝对路径,`frames[].t` 是它在视频里的秒数。
**用 Read 工具读这些帧时,务必在心里(或回复里)把每张图和它的 `t` 时间戳绑定**,
这样你才能说出"第几秒发生了什么"。读完即弃,不必保留。

## 怎么把帧"讲"给自己和用户

你的产出不是"我看到一个面板",而是带时间线的客观叙述,例如:

```
3.1s  面板在底部,处于全屏列表态
3.5s  面板开始向上滑动(用户在拖动)
3.8s  手指离开,面板停在约半屏位置
4.5s  面板没有继续吸附,停在中途不动 —— 与"应锚定半屏/全屏"的预期不符
```

如果用户给了上下文(同事的吐槽、预期行为),把它当作对照的参照系:
先客观描述实际发生了什么,再指出哪一帧/哪一秒和预期不一致。
**如果用户没说用户干了啥,就别瞎猜对错,只做客观复述**,把"事实时间线"摆出来,
让用户结合业务去判断。

## 几条实战经验(为什么这么设计)

- **静止段为什么要折叠**:截图是不会"卡"的,静止段对排查交互问题没信息量,
  只会浪费你的注意力和上下文。让代码把它们扔掉,你只看有动作的部分。
- **为什么时间戳用文字绑定而不是烧进画面**:你读文字是 100% 准的,而认画面里烧的字
  可能糊、可能挡画面、可能读错。所以脚本把时间放在文件名/JSON 里,你 Read 时对应上即可。
- **翻拍视频(带手、反光、抖动)怎么办**:帧差用了"缩小+模糊+分块"来吸收噪点和轻微抖动,
  所以翻拍视频也能大致定位到运动段。但手指位置这类细节,翻拍下精度有限,只能定性看方向,
  必要时在回复里说明"这是翻拍视频,手指位置为估计"。
- **GIF / 无音轨 / 元数据缺失**:脚本对 fps 异常做了兜底(默认按 30fps),GIF 也能读。

## 不要做的事

- 不要把整段长视频一次性高密度抽帧再全部 Read —— 这就是上下文爆炸的根源。永远先 scan。
- 不要在 skill 里写死任何业务判断(什么算"正常滑动")。判断交给你和用户,skill 只供帧。
- 不要依赖"屏幕录制小白点"才能工作 —— 大多数视频没有,有就当福利,没有也得能干活。

