# Video Process Demo Rust 后端原样提供 `video.h264`,Next.js 前端用 WebCodecs 在浏览器里完成流式切帧、本地帧缓存、单画布播放和帧拖动定位。刷新后优先恢复本地帧,不需要重新拉完整视频再解码。 ## 启动后端 ```bash cargo run ``` 后端默认监听 `http://localhost:8080`,视频地址是 `http://localhost:8080/video.h264`。 仓库里不包含这个大体积示例视频,请把 `video.h264` 放到项目根目录,或通过 `NEXT_PUBLIC_VIDEO_URL` 指向你自己的 H.264 地址。 ## 启动前端 ```bash cd web npm install NEXT_PUBLIC_VIDEO_URL=http://localhost:8080/video.h264 npm run dev ``` 打开 `http://localhost:3000` 即可。 ## 前端架构 前端分成四层: - 传输缓存:`web/lib/video-cache.ts` 用 `Cache Storage` 保存原始 `video.h264` 响应。 - 解析切帧:`web/lib/h264.ts` 把 Annex B 字节流拆成 access unit,识别 SPS/PPS 和帧边界。 - 帧持久化:`web/lib/frame-store.ts` 用 `IndexedDB` 保存 `CachedFrameSession`,每帧以 `Blob` 形式落盘,刷新后可直接恢复。 - 播放控制:`web/components/VideoFrameViewer.tsx` 负责切帧、恢复、单画布播放、拖动条跳帧和缓存清理。 ## 运行流程 1. 页面先查本地帧会话,命中则直接把 `Blob` 恢复成 `objectURL`,无需重新请求后端。 2. 未命中时再去请求 `video.h264`,并边下载边解析 SPS/PPS 和 access unit。 3. 每个 `VideoFrame` 会先画到离屏 canvas,再导出成 WebP `Blob`,同时生成缩略图对象 URL。 4. 全部帧完成后,会把会话写入 `IndexedDB`,然后尽量清掉原始 `video.h264` 的缓存,减少重复占用。 5. 播放区只用一个 canvas,通过 `requestAnimationFrame` 按时间戳切帧;拖动条则直接 `jumpToFrame()` 到指定帧。 ## 缓存策略 - 原始视频缓存放在 `Cache Storage`,适合保存完整的 fetch 响应。 - 切好的帧和元数据放在 `IndexedDB`,避免把大体积帧塞进一个 JSON。 - 页面提供“申请持久化”按钮,会调用 `navigator.storage.persist()`,降低浏览器回收缓存的概率。 - “清空缓存”会同时删除帧会话和原始视频缓存;下次打开会重新请求后端并重新切帧。 - 当前实现还保留了旧版 `Cache Storage` 帧清单的迁移逻辑,便于升级已有缓存。 ## 关键文件 - `web/components/VideoFrameViewer.tsx`:主界面、播放、拖动条、缓存状态。 - `web/lib/h264.ts`:H.264 Annex B 解析、SPS/PPS、WebCodecs 配置。 - `web/lib/frame-store.ts`:帧会话读写、校验、迁移。 - `web/lib/video-cache.ts`:原始视频响应缓存。 ## 生成图谱 `graphify-out/` 是生成物,不建议提交到仓库。你在其他项目里想复用这套分析方式时,可以在目标项目根目录重新生成: ```bash graphify . ``` 增量更新: ```bash graphify . --update ``` 如果你在 Codex 里操作,直接对目标项目说这句就够了: ```text 请对当前项目目录运行 graphify,生成 graphify-out,并重点输出 God Nodes、Surprising Connections 和 Suggested Questions。 ``` 生成后会得到这些文件: - `graphify-out/graph.json` - `graphify-out/graph.html` - `graphify-out/GRAPH_REPORT.md` - `graphify-out/manifest.json` ## 备注 前端依赖浏览器的 WebCodecs、Cache Storage 和 IndexedDB 能力,建议使用 Chromium / Edge。