# 参考视频时间窗裁剪：越界拒绝与保留帧验收

按左闭右开边界制作一秒参考片段。本配方裁剪连续视频区间，不是按时间基准选择一张静帧。

完整包只使用 Node 标准库。FFmpeg 需使用自己已有的安装，本包不分发二进制；不在 PATH 时将 FFMPEG_BIN 设为其绝对路径。

在本目录运行，并选择不存在的新输出目录，脚本拒绝覆盖。受内存管理的工作站可在 Node 命令前加本地串行执行包装器。不需要提供商密钥，夹具不会向设备外发请求。

```sh
node run-recipe.mjs --out ./my-run
```

实际记录：11项检查通过，包含5项预期拒绝，Node v24.18.0。ffmpeg version 6.0 Copyright (c) 2000-2023 the FFmpeg developers

准备

- 准备 Node.js 与 FFmpeg，必要时设置 FFMPEG_BIN。脚本创建 320×180、每秒十帧、三秒长的原创参考夹具。
- 查看 window.json：源时长来自三十个解码帧和本夹具明确的恒定帧率，选定起点为 0.5 秒、终点为 1.5 秒。
- 选择新的输出目录，先用配套 CFR 夹具验证。任意 VFR 或非零起点参考的可用尾部边界，需要另外建立时间戳清单。

## 01. 确认源片真正可用的区间

完整解码原创夹具，确认每秒十帧下确有三十帧，由此建立受控的三秒区间。构建用原始 RGB 暂存会在 finally 清理。这种受控 CFR 时长算法不能直接当成通用 VFR 时长推算。

## 02. 编码前拒绝无效边界

本地校验要求两个值有限、起点不小于零、终点大于起点，且不超过源时长。脚本分别实跑负起点、相等边界、倒序边界、超尾请求和 NaN，不静默纠正。

## 03. 裁剪后重新设置时间原点

实际应用 trim=start=0.5:end=1.5,setpts=PTS-STARTPTS 并重新编码。trim 保留源片连续区间，setpts 让输出从零开始；终点不包含从源片 1.5 秒开始的那一帧。

## 04. 同时比较首尾画面与输出时间

结果应完整解码为十帧，首尾分别与源索引 5、14 的 RGB 比较，再解析真实 showinfo 日志，确认输出 PTS 从 0.0 到 0.9、间隔 0.1 秒。本次首尾最大通道差均为零。

验收

- 源片实际解码为三十帧 320×180，符合受控十 FPS。
- 0.5–1.5 秒通过有限数值与区间边界规则。
- 裁剪片段准确解码为十帧，对应十 FPS 下的一秒。
- 输出首尾分别匹配源索引 5、14，通道差不超过四，本次均为零。
- 实际输出时间戳从零开始，最后为 0.9 秒。
- 五种无效窗口均被拒绝，十一项回执与 showinfo 实际日志一同保留。

排错

第一帧时间仍显示 0.5 秒。只在 trim 后补回 setpts=PTS-STARTPTS，再读取输出 showinfo 时间戳。

片段包含源片 1.5 秒开始的画面。使用配方明确的右开边界，以源索引 14 验收最后一帧，不通过延长终点补偿。

要求的终点超过参考片。只把 endSeconds 降到已确认边界，或获取原本需要的更长参考；不悄悄截成合法值。

公开回执副本仅归一化本地 checkout 路径，publicPathNormalization 保存原始回执 SHA-256；未改动原件保留在非公开资产之外。真实回执位于 executed/。failure-receipt.json 记录预期负向案例，不表示套件断言失败。原创新夹具会重新生成到指定新目录，包内保留实跑输入输出便于复核。子进程使用参数数组、禁用 shell，设15秒超时与8MB输出上限。临时原始数据和本机 HTTP 服务在 finally 清理。

checksums.json 覆盖自身与 ZIP 以外的全部分发文件，避免循环自引用；ZIP 内包含同份清单。下载后可重算，但比较前提是预期清单可信。execution-receipt.json 记录实际脚本运行前后哈希，ZIP 也会由发布目录的资产清单绑定。

把请求时间窗、源片可用区间与解码端点检查一起保存。小型 CFR 夹具证明这次裁剪操作，不代表所有真实参考片的时间戳行为。

2026-10-14 实际读取的来源

- FFmpeg filters: scale, pad, trim, setpts and showinfo：https://ffmpeg.org/ffmpeg-filters.html
- FFmpeg command-line documentation: maps, codecs and error exit：https://ffmpeg.org/ffmpeg.html
- Node.js child process API: bounded argument-array execution：https://nodejs.org/api/child_process.html
