154 lines
6.8 KiB
Markdown
154 lines
6.8 KiB
Markdown
# 代理媒体 v0.4 实施计划
|
||
|
||
## 背景
|
||
|
||
v0.4 已合并“调色、音频与性能”范围,其中代理媒体工作流负责解决 4K/8K 素材在时间线预览、剪辑和调色时的可用性问题。当前代码里已有音频 conform:`ConformManager` 会把音频流转为 PCM cache,但它不适合作为视频代理的直接扩展,因为视频代理需要保留容器、视频编码参数、文件生命周期和解码路由。
|
||
|
||
## 当前状态
|
||
|
||
实施进度:
|
||
|
||
- 阶段 1 已完成:已写计划,新增代理状态、稳定文件名函数、`Footage` 代理字段和 XML roundtrip 测试。
|
||
- 阶段 2 已完成:已新增 `ProxyTask` 和 `ProxyManager`,使用 `.working` 临时文件、成功 rename、失败清理,并覆盖状态测试。
|
||
- 阶段 3 已完成:`FootageJob` 携带代理解码信息,预览路径使用 ready 代理,导出/online 路径默认原片,代理缺失自动回退。
|
||
- 阶段 4 已完成:时间线右键已有 `Generate Proxy`、`Use Proxy`、`Reveal Proxy`、`Delete Proxy`。
|
||
- 阶段 5 自动验证已完成;仍需实际 4K/8K 素材做手工播放、重开项目和导出确认。
|
||
|
||
- `app/codec/conformmanager.{h,cpp}` 只处理音频 PCM conform,输出按声道拆分的 `.pcm` 文件。
|
||
- `app/task/conform/conform.{h,cpp}` 只调用 `Decoder::ConformAudio()`。
|
||
- `Decoder::CodecStream` 当前只包含原始 `filename + stream index + block`,解码时会检查该文件存在。
|
||
- `RenderProcessor::ProcessVideoFootage()` 和 `ProcessAudioFootage()` 通过 `FootageJob` 的 filename/decoder/stream index 打开素材。
|
||
- `Footage` 当前保存原始文件名、探测参数、source start time 等项目级元数据,但还没有代理文件状态。
|
||
- timeline 已有 cache/thumbnail/waveform 机制,但这是渲染缓存,不是替代源媒体的代理媒体。
|
||
|
||
## 目标
|
||
|
||
第一阶段交付一个最小但完整的代理工作流:
|
||
|
||
- 右键选中项目素材或时间线 clip 可生成代理。
|
||
- 代理文件写入项目 cache/proxy 目录,使用稳定 hash 命名。
|
||
- `Footage` 记录代理状态,项目保存/加载后仍能识别代理。
|
||
- 播放/预览时可选择使用代理,导出默认使用原始素材。
|
||
- 代理缺失、生成中、失败时能安全回退原始素材。
|
||
- 生成任务进入现有 `TaskManager`,支持取消和失败清理。
|
||
|
||
## 非目标
|
||
|
||
- 不在第一版实现复杂代理 preset UI。
|
||
- 不在第一版实现云端/跨机器代理 relink。
|
||
- 不在第一版替代现有 sequence render cache。
|
||
- 不改变音频 conform 的 PCM 路径。
|
||
- 不让导出默认走代理,避免质量风险。
|
||
|
||
## 设计
|
||
|
||
### 1. 新增 ProxyManager
|
||
|
||
新增 `app/codec/proxymanager.{h,cpp}`,职责类似但独立于 `ConformManager`:
|
||
|
||
- 根据源文件、stream index、代理参数生成目标文件名。
|
||
- 判断代理状态:missing、generating、ready、failed。
|
||
- 避免同一素材重复生成任务。
|
||
- 使用 `.working` 临时文件,成功后原子 rename。
|
||
- 发出 `ProxyReady` 信号通知 UI/缓存失效。
|
||
|
||
### 2. 新增 ProxyTask
|
||
|
||
新增 `app/task/proxy/proxy.{h,cpp}`:
|
||
|
||
- 输入原始文件、decoder id、视频 stream、代理参数、输出路径。
|
||
- 第一版优先使用 FFmpeg CLI 或内部 FFmpeg 编码路径生成 H.264/MP4 代理。
|
||
- 目标默认参数:较短边不超过 720p,保持宽高比,8-bit 4:2:0,CRF 23 左右。
|
||
- 失败时写清晰 error,删除 `.working`。
|
||
|
||
如果当前构建环境不适合直接调用外部 `ffmpeg`,则优先使用项目内部编码接口;否则在任务内检测 `ffmpeg` 可执行文件并给出失败信息。
|
||
|
||
### 3. 扩展 Footage 代理元数据
|
||
|
||
在 `Footage` 中增加:
|
||
|
||
- `proxy_enabled`
|
||
- `proxy_path`
|
||
- `proxy_state`
|
||
- `proxy_video_stream_index`
|
||
- `proxy_generation_preset/version`
|
||
|
||
项目 XML 写入 `<proxy enabled="..." state="..." stream="..." preset="...">path</proxy>`。
|
||
|
||
`Clear()` 不能无条件清掉已保存代理路径,只有换源文件或重新探测时才重置不兼容代理。
|
||
|
||
### 4. 解码路由
|
||
|
||
提供统一方法选择实际解码源:
|
||
|
||
- 在线预览/时间线播放:如果项目/素材启用代理且代理 ready,则使用代理文件。
|
||
- 离线渲染/导出:默认使用原文件。
|
||
- 用户以后可加“导出使用代理”选项,但默认关闭。
|
||
|
||
优先在 `FootageJob` 构造或 `RenderProcessor::ProcessVideoFootage()` 前完成选择,避免把代理逻辑散落到 decoder 内部。
|
||
|
||
### 5. UI 入口
|
||
|
||
第一版入口:
|
||
|
||
- 时间线 clip 右键:`Generate Proxy`、`Use Proxy`、`Reveal Proxy`、`Delete Proxy`。
|
||
- 项目素材右键若已有菜单结构可复用,也增加同样入口;如果项目素材菜单结构分散,先实现时间线入口。
|
||
- 菜单启用规则:仅视频素材可生成代理;代理生成中禁用重复生成;代理缺失时 `Use Proxy` 可显示但禁用。
|
||
|
||
### 6. 缓存和失效
|
||
|
||
代理 ready 后:
|
||
|
||
- 触发相关 footage/clip 的 video frame cache、thumbnail cache invalidation。
|
||
- 不触碰 audio conform cache。
|
||
- 不删除已有原始媒体 render cache,避免用户切换代理/原片时状态不可恢复。
|
||
|
||
## 实施阶段
|
||
|
||
### 阶段 1:计划和基础数据结构
|
||
|
||
- 写本计划。
|
||
- 添加 proxy 状态枚举和 filename 生成函数。
|
||
- 添加 `Footage` 代理字段和 XML 保存/加载测试。
|
||
|
||
### 阶段 2:代理生成任务
|
||
|
||
- 添加 `ProxyTask`。
|
||
- 添加 `ProxyManager`。
|
||
- 生成 `.working` 文件,成功 rename。
|
||
- 增加单元测试覆盖文件名稳定性和状态转换。
|
||
|
||
### 阶段 3:解码路由
|
||
|
||
- 扩展 `FootageJob` 或其创建点,携带“实际解码文件”。
|
||
- 在线模式优先代理,离线/导出默认原片。
|
||
- 代理缺失自动回退原片。
|
||
|
||
### 阶段 4:时间线 UI
|
||
|
||
- 时间线右键增加生成/启用/删除代理动作。
|
||
- 动作进入 undo 或直接项目状态变更;代理生成任务本身不进 undo。
|
||
- 代理 ready 后刷新 timeline/viewer。
|
||
|
||
### 阶段 5:验证
|
||
|
||
- `ninja -C cmake-build-debug olive-gtest olive-editor -j22`
|
||
- 代理字段 XML roundtrip 测试。
|
||
- ProxyManager 状态测试。
|
||
- 手工测试:导入 4K 素材、生成代理、启用代理、播放、关闭重开项目、删除代理、导出确认默认原片。
|
||
|
||
## 风险
|
||
|
||
- 外部 `ffmpeg` 依赖不可用会让代理生成失败;需要清晰错误并不影响原片播放。
|
||
- 代理视频 stream index 可能不同于原片,需要解码路由在代理文件里使用正确 stream。
|
||
- 代理分辨率改变会影响 thumbnails/cache,需要切换后明确 invalidation。
|
||
- 项目保存相对/绝对代理路径策略要谨慎;第一版使用 cache 目录内路径并可重建。
|
||
|
||
## 完成标准
|
||
|
||
- 用户能从时间线对视频 clip 生成代理。
|
||
- 代理生成结束后,启用代理的在线预览路径实际读取代理文件。
|
||
- 项目重开后代理状态保留。
|
||
- 代理缺失或生成失败时不影响原始素材播放。
|
||
- 相关构建和 gtest 通过。
|