Video Process Demo
Rust 后端原样提供 video.h264,Next.js 前端用 WebCodecs 在浏览器里完成流式切帧、本地帧缓存、单画布播放和帧拖动定位。刷新后优先恢复本地帧,不需要重新拉完整视频再解码。
启动后端
cargo run
后端默认监听 http://localhost:8080,视频地址是 http://localhost:8080/video.h264。
仓库里不包含这个大体积示例视频,请把 video.h264 放到项目根目录,或通过 NEXT_PUBLIC_VIDEO_URL 指向你自己的 H.264 地址。
启动前端
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负责切帧、恢复、单画布播放、拖动条跳帧和缓存清理。
运行流程
- 页面先查本地帧会话,命中则直接把
Blob恢复成objectURL,无需重新请求后端。 - 未命中时再去请求
video.h264,并边下载边解析 SPS/PPS 和 access unit。 - 每个
VideoFrame会先画到离屏 canvas,再导出成 WebPBlob,同时生成缩略图对象 URL。 - 全部帧完成后,会把会话写入
IndexedDB,然后尽量清掉原始video.h264的缓存,减少重复占用。 - 播放区只用一个 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/ 是生成物,不建议提交到仓库。你在其他项目里想复用这套分析方式时,可以在目标项目根目录重新生成:
graphify .
增量更新:
graphify . --update
如果你在 Codex 里操作,直接对目标项目说这句就够了:
请对当前项目目录运行 graphify,生成 graphify-out,并重点输出 God Nodes、Surprising Connections 和 Suggested Questions。
生成后会得到这些文件:
graphify-out/graph.jsongraphify-out/graph.htmlgraphify-out/GRAPH_REPORT.mdgraphify-out/manifest.json
备注
前端依赖浏览器的 WebCodecs、Cache Storage 和 IndexedDB 能力,建议使用 Chromium / Edge。
Description
Languages
TypeScript
84.5%
CSS
11.7%
Rust
3.6%
JavaScript
0.2%