Files
oak-editor/docs/zh/proxy-media-v04-plan.md
T

154 lines
6.8 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 代理媒体 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:0CRF 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 通过。