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

6.8 KiB
Raw Blame History

代理媒体 v0.4 实施计划

背景

v0.4 已合并“调色、音频与性能”范围,其中代理媒体工作流负责解决 4K/8K 素材在时间线预览、剪辑和调色时的可用性问题。当前代码里已有音频 conform:ConformManager 会把音频流转为 PCM cache,但它不适合作为视频代理的直接扩展,因为视频代理需要保留容器、视频编码参数、文件生命周期和解码路由。

当前状态

实施进度:

  • 阶段 1 已完成:已写计划,新增代理状态、稳定文件名函数、Footage 代理字段和 XML roundtrip 测试。

  • 阶段 2 已完成:已新增 ProxyTaskProxyManager,使用 .working 临时文件、成功 rename、失败清理,并覆盖状态测试。

  • 阶段 3 已完成:FootageJob 携带代理解码信息,预览路径使用 ready 代理,导出/online 路径默认原片,代理缺失自动回退。

  • 阶段 4 已完成:时间线右键已有 Generate ProxyUse ProxyReveal ProxyDelete 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 ProxyUse ProxyReveal ProxyDelete 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 通过。