# 离线练习包：按准确帧数组装视频分镜

本包包含可运行源码、原创几何输入与一份已经记录的 22 帧本地夹具。它不生成 MiniMax H3 视频。请使用已有的 Node.js、FFmpeg 和 ffprobe；包内不含这些可执行文件。

## 1. 解压并准备输入

在解压后包含 `run-recipe.mjs`、`frame-budget.mjs`、`original-inputs.mjs` 的目录打开终端。无需检出网站仓库或安装项目依赖。

```sh
node --test frame-budget.test.mjs encoded-negative-cases.test.mjs
node run-recipe.mjs --out ./my-new-inputs-01
```

每个输出目录都必须是新目录。第二条命令绘制 25 张原创 PNG、三份 SVG 设计，并写入 `mediaExecuted:false` 的准备状态；它不编码视频、不请求提供商，也不下载软件。纯测试通过不是媒体执行证据。

## 2. 不调用工具，直接阅读已有记录

查看 `media-runs/actual-small-root-20261017-02/`：

| 文件 | 检查内容 |
| --- | --- |
| `assembled-review.mp4` | 实际 22 帧正片 |
| `media-execution-receipt.json`、`run-status.json` | 已记录的本地执行与限定检查 |
| `tool-versions.json`、`command-log.json` | 实际版本与 48 次成功工具调用 |
| `original-input-manifest.json` | 25 张原创 PNG 定义；回执记录运行前后哈希 |
| `shot-a.probe.raw.json`、`shot-b.probe.raw.json`、`shot-c.probe.raw.json` | 未改写的源探针观测 |
| `decoded-inventory.json`、`edl.actual.json`、`frame-map.json` | 源时序、整数镜头预算与全部输出选帧 |
| `expected-marker-proof.json`、`output-probe.json` | 源/帧标记身份及解码输出网格 |
| `negative-media/` | 三个真实受控负例 MP4、探针与拒绝记录 |

本次运行日期为 **2026 年 10 月 17 日**，使用 Node v24.18.0、FFmpeg 6.0 与 ffprobe n4.4.1。尚未进行人工播放与观感评审。这是小型本地技术夹具，不是模型效果实测，也没有编码 204 秒视频。

## 3. 理解输入与输出规则

原输入中 A 有 8 张、B 有 10 张、C 有 7 张图。编码再解码得到 8、10、8 帧：C 的 concat 输入重复末张图，并不是新画出了第 26 张输入。

- A：实测 `24000/1001` fps，time base 为 `1/48000`。
- B：相邻 PTS 间距 40ms，time base 为 `1/51200`。
- C：起点非零，PTS 依次为 `2.00, 2.04, 2.12, 2.24, 2.28, 2.36, 2.40, 2.44` 秒。

不要用名义 FPS 代替源 PTS。C 的原始 `pkt_duration` 观测仍是 40ms。在声明的 `active-at-or-before-no-interpolation` 规则下，非末帧的保持窗口**根据下一实际 PTS 推导**，不能把推导值写成探针报告的 packet 时长。末帧必须有真实且为正的时长观测。

EDL 绑定每份源文件 SHA、相对源起点的偏移与整数输出帧预算。已记录预算为 **7 + 7 + 8 = 22**，输出 `24/1` fps，准确时长 `11/12` 秒。从 0 编号的两个切点为 **6/7** 和 **13/14**。规则可以重复或丢弃图像，不合成新运动，也不悄悄变速。

## 4. 另开一次小型媒体运行

使用另一个不存在的输出目录，把工具路径替换为本机已有可执行文件：

```sh
ALLOW_LOCAL_MEDIA_EXECUTION=1 node run-recipe.mjs --out ./my-new-media-run-01 --execute-media --ffmpeg /absolute/path/to/ffmpeg --ffprobe /absolute/path/to/ffprobe
```

显式开关启用本地编码与解码。夹具使用 96×64 输入、串行调用、单线程设置、超时与有上限的缓冲区。它要求对应滤镜及 FFV1/libx264 能力；其他构建可能失败。命令不安装工具，也不请求模型或提供商。

## 5. 核对成片与负例

以下条件需要同时成立，不能只看播放器显示的时长：

- 实际解码图像、frame 观测与 packet 都恰为 22。
- 全部输出 PTS/DTS 在 `24/1` 网格上，正常帧与末帧时长均为 `1/24`。
- 全部 22 个源/帧标记与规划相符，包括每个切点的前后两侧。
- 三个真实负例各自只出现预期的一条校验问题。

| 负例 | 受控缺陷 | 实际唯一问题 |
| --- | --- | --- |
| `short-21-of-22.mp4` | 图像/frame/packet 只有 21 | `OUTPUT_FRAME_COUNT` |
| `wrong-cut-image.mp4` | 从 0 编号的第 7 帧图像错误 | `OUTPUT_FRAME_ID_MISMATCH` |
| `bad-terminal-duration.mp4` | 图像、PTS 与编码 payload 不变；在 `1/24000` time base 下，末 sample 从 1,000 改为 500 tick | 第 21 帧 `OUTPUT_TERMINAL_DURATION` |

末帧负例修改真实 MP4 时序字节，不修改探针 JSON。修改器只支持本夹具的单轨、无分片、无编辑列表/显示重排且末尾 `moov` 位于 `mdat` 之后的布局。编码/探测失败或布局不支持，都不能算负例成功。

已记录正片的 SHA-256 为：

```text
3b624e031f6a082e2ac2ae89b8c36cb91873bd67c5d64f8c5fa1427059db96f1
```

把输入、原始探针、EDL、帧映射、标记证明与命令日志和输出成套保存。工具构建变化可能改变编码字节，因此除哈希外，也要比较实际时序与身份检查。时序正确不证明运动好看、光线匹配、声音同步或叙事连贯；使用自己的素材时需分别检查。

## 许可与参考

原创源码与夹具随附 `LICENSE.txt`。包内不含 FFmpeg、ffprobe 可执行文件，示例也不依赖字体、外部图片或模型输出。技术参考：FFmpeg 官方 [concat](https://ffmpeg.org/ffmpeg-filters.html#concat)、[fps](https://ffmpeg.org/ffmpeg-filters.html#fps-1)、[setpts](https://ffmpeg.org/ffmpeg-filters.html#setpts_002c-asetpts)。
