# Oak Video Editor Project File Reference / Oak 视频编辑器项目文件格式参考 This document describes Oak Video Editor's XML project format (`.ove`) as implemented in the current codebase. It is intended to be detailed enough to implement a compatible reader/writer. 本文件描述 Oak 视频编辑器当前代码库实现的 XML 项目格式(`.ove`),详细程度足以支持兼容的读写实现。 > Source of truth / 权威源码:`app/node/project.cpp`, `app/node/node.cpp`, `app/node/value.*`, `app/node/keyframe.*`, `app/node/project/serializer/*`, `app/node/project/footage/footage.cpp`, `app/node/output/viewer/viewer.cpp`, `app/node/output/track/track.cpp`, `app/node/group/group.cpp`, `app/window/mainwindow/mainwindowlayoutinfo.cpp`. --- ## 1. Root Document / 根文档 ```xml ... ``` - `version`: serializer version in `YYMMDD` format. The latest serializer is `230220` (`ProjectSerializer230220`). - `version`:序列化器版本,格式为 `YYMMDD`。当前最新为 `230220`(`ProjectSerializer230220`)。 - `url`: optional source path. - `url`:可选的源文件路径。 --- ## 2. Project Container / 项目容器 For full saves, the serializer writes a project container: 完整保存时,序列化器会写入一个项目容器: ```xml ... ... ``` See `ProjectSerializer230220::Save()` and `Load()` in `app/node/project/serializer/serializer230220.cpp`. --- ## 3. Project Data (`Project::Save` / `Project::Load`) / 项目数据 ```xml ... ... ... ... ``` ### 3.1 `uuid` - QUuid string identifying the project. - 项目 UUID 字符串。 ### 3.2 `plugins` / 插件列表 List of OpenFX plugins referenced by nodes. This block is loaded **before** `` so that plugin nodes can be registered. 列出节点引用的 OpenFX 插件。该块在 `` 之前加载,以便注册插件节点。 ```xml ``` Attributes / 属性: - `id`: OFX plugin identifier (matches node `id`). - OFX 插件标识符(与节点 `id` 一致)。 - `major` / `minor`: OFX plugin version. - OFX 插件版本。 - `bundle`: bundle directory path (preferred). - 包目录路径(优先使用)。 - `file`: plugin binary path (fallback). - 插件二进制路径(回退)。 Loading behavior / 加载行为: - If `` exists, each `bundle` (or `file` if `bundle` is empty) is added to the OFX plugin path, the cache scans the paths, and plugin nodes are registered before `` is parsed. - 如果存在 ``,则把每个 `bundle`(若 `bundle` 为空则使用 `file`)加入 OFX 插件路径,扫描缓存,并在解析 `` 前注册插件节点。 ### 3.3 `nodes` / 节点图 The node graph. Each `` is written by `Node::Save()` and read by `Node::Load()`. 节点图。每个 `` 由 `Node::Save()` 写入、`Node::Load()` 读取。 ```xml 3 ... ... ... ... ... ... ... ``` Attributes / 属性: - `id`: node type identifier. For OpenFX nodes, this equals the OFX plugin identifier. - 节点类型标识符。对于 OpenFX 节点,等于 OFX 插件标识符。 - `ptr`: numeric pointer ID used to resolve connections and context positions. - 数字指针 ID,用于解析连接和上下文位置。 - `version`: currently `1`. - 当前为 `1`。 ### 3.4 `settings` / 项目设置 Project settings stored as key/value text elements. 以键值文本元素保存的项目设置。 Known keys / 已知键: - `cachesetting` - `customcachepath` - `colorconfigfilename` - `defaultinputcolorspace` - `colorreferencespace` - `root` — pointer id of the root `Folder` node, resolved after all nodes are loaded. - `root`:根 `Folder` 节点的指针 ID,在所有节点加载完成后解析。 --- ## 4. Node Serialization (`Node::Save` / `Node::Load`) / 节点序列化 ### 4.1 `label` User-visible node label. 用户可见的节点标签。 ### 4.2 `color` Override color index (integer), only written if not `-1`. 覆盖颜色索引(整数),只有不为 `-1` 时才写出。 ### 4.3 `input` / 输入 Each input is serialized as: 每个输入序列化为: ```xml ... ... ``` - `primary`: element `-1` (the main input). - `primary`:元素 `-1`(主输入)。 - `subelements`: array elements (if the input is an array). `count` is the array size. - `subelements`:数组元素(如果输入是数组)。`count` 为数组大小。 #### 4.3.1 Immediate Values (`primary` / `element`) / 立即值 Each immediate block contains: 每个立即值块包含: ```xml 0|1 ... ... ... ... ... ... ... ``` - `keyframing`: whether the input is keyframed (only written if the input is keyframable). - `keyframing`:输入是否启用关键帧(仅当输入可关键帧化时写出)。 - `standard`: default/static values (one `` per keyframe track). - `standard`:默认值/静态值(每个关键帧轨道一个 ``)。 - `keyframes`: only written if `keyframing` is true. - `keyframes`:仅在 `keyframing` 为 true 时写出。 - `cs*`: only written for `kColor` inputs; stored as input properties `col_input`, `col_display`, `col_view`, `col_look`. - `cs*`:仅对 `kColor` 输入写出;保存为输入属性 `col_input`、`col_display`、`col_view`、`col_look`。 #### 4.3.2 Track Count / 轨道数量 Track count is determined by `NodeValue::get_number_of_keyframe_tracks()`: 轨道数量由 `NodeValue::get_number_of_keyframe_tracks()` 决定: | Type / 类型 | Tracks / 轨道数 | | --- | --- | | `kVec2` | 2 | | `kVec3` | 3 | | `kVec4` | 4 | | `kColor` | 4 | | `kBezier` | 6 | | other / 其他 | 1 | #### 4.3.3 Standard Value Encoding / 标准值编码 Values are written with `NodeValue::ValueToString()` and read with `NodeValue::StringToValue()`. 值通过 `NodeValue::ValueToString()` 写入,通过 `NodeValue::StringToValue()` 读取。 String encodings / 字符串编码: - `kVec2`: `x:y` - `kVec3`: `x:y:z` - `kVec4`: `x:y:z:w` - `kColor`: `r:g:b:a` - `kBezier`: `x:y:cp1x:cp1y:cp2x:cp2y` - `kRational`: `num/den` (see `rational::toString()`) - `kInt`: integer as text / 整数字符串 - `kBinary`: Base64 - `kText`, `kFont`, `kFile`, `kCombo`, `kStrCombo`: string - `kTexture`, `kSamples`, `kNone`: no text / 无文本 Special cases / 特例: - `kVideoParams` / `kAudioParams` are nested objects (see sections 5 and 6). - `kVideoParams` / `kAudioParams` 为嵌套对象(见第 5、6 节)。 - `kSubtitleParams` is **skipped on load** to avoid overwriting subtitle data. - `kSubtitleParams` 在加载时**被跳过**,以避免覆盖字幕数据。 #### 4.3.4 Keyframes (`NodeKeyframe::save` / `NodeKeyframe::load`) / 关键帧 ```xml value ``` Attributes / 属性: - `input`: input id. - 输入 ID。 - `time`: rational time (`rational::toString()`). - 有理数时间(`rational::toString()`)。 - `type`: integer enum `NodeKeyframe::Type` (`0` = linear, etc.). - 整数枚举 `NodeKeyframe::Type`(`0` 为线性等)。 - `inhandlex`, `inhandley`, `outhandlex`, `outhandley`: bezier handle coordinates. - 贝塞尔手柄坐标。 Text value uses `NodeValue::ValueToString(data_type, value, true)`. 文本值使用 `NodeValue::ValueToString(data_type, value, true)`。 ### 4.4 `links` / 链接 Block-to-block link list (for timeline items): 块到块链接列表(用于时间线项目): ```xml ptr ``` ### 4.5 `connections` / 连接 Input/output connections: 输入/输出连接: ```xml ptr ``` - `output` is the serialized pointer (`ptr`) of the output node. - `output` 为输出节点的序列化指针(`ptr`)。 ### 4.6 `hints` (Value Hints) / 值提示 Value hints are per-input UI hints stored by `Node::ValueHint::save()` / `load()`: 值提示是按输入保存的 UI 提示,由 `Node::ValueHint::save()` / `load()` 读写: ```xml 0 0 ... ``` - `types`: list of allowed `NodeValue::Type` integers. - `types`:允许的 `NodeValue::Type` 整数列表。 - `index`: hint index. - `index`:提示索引。 - `tag`: hint tag string. - `tag`:提示标签字符串。 ### 4.7 `context` (Node positions in contexts) / 上下文中的节点位置 ```xml 0 0 0|1 ``` - Stores the position and expanded state of other nodes inside this node's context (e.g. inside a NodeGroup). - 保存其他节点在该节点上下文(例如 NodeGroup 内部)中的位置和展开状态。 ### 4.8 `caches` / 缓存 UUID Node cache UUIDs: 节点缓存 UUID: ```xml uuid uuid ``` ### 4.9 `custom` / 自定义节点数据 Default `Node::SaveCustom()` writes nothing. Specific node subclasses may override. 默认 `Node::SaveCustom()` 不写任何内容。具体子类可重写。 --- ## 5. Node-specific Custom Data / 节点专属自定义数据 ### 5.1 `Footage` (`app/node/project/footage/footage.cpp`) ```xml 1740000000 /path/to/proxy.mp4 1/25 ... ``` - ``: media modification timestamp (epoch milliseconds). - ``:媒体修改时间戳(Unix 毫秒)。 - ``: proxy media state. - ``:代理媒体状态。 - Attributes / 属性: - `enabled`: `0` or `1`. - `enabled`:`0` 或 `1`。 - `state`: string from `ProxyManager::ProxyStateToString()` (e.g. `missing`, `ready`, `generating`, `failed`). - `state`:`ProxyManager::ProxyStateToString()` 返回的字符串(如 `missing`、`ready`、`generating`、`failed`)。 - `stream`: video stream index used for the proxy. - `stream`:代理使用的视频流索引。 - `preset`: proxy preset version. - `preset`:代理预设版本。 - Text content: proxy file path (may be empty if `enabled` is true but proxy is not yet generated). - 文本内容:代理文件路径(如果 `enabled` 为 true 但代理尚未生成,则可能为空)。 - ``: source start time offset. - ``:源起始时间偏移。 - `source` attribute: source identifier (e.g. `timecode`). - `source` 属性:源标识符(如 `timecode`)。 - Text: rational `numerator/denominator`. - 文本:有理数 `numerator/denominator`。 - ``: see `ViewerOutput` below. - ``:见下文 `ViewerOutput`。 ### 5.2 `ViewerOutput` (`app/node/output/viewer/viewer.cpp`) Used by `Footage`, `Sequence`, etc. `Footage`、`Sequence` 等使用。 ```xml 0|1 num/den num/den ``` - ``: render/export work area. - ``:渲染/导出工作区。 - ``: timeline markers. - ``:时间线标记。 - Marker attributes / 标记属性: - `name`: marker name. - `name`:标记名称。 - `in` / `out`: rational time range. - `in` / `out`:有理数时间范围。 - `color`: color index. - `color`:颜色索引。 ### 5.3 `Track` (`app/node/output/track/track.cpp`) ```xml 48 ``` - ``: track height in the timeline. - ``:时间线中轨道的显示高度。 ### 5.4 `NodeGroup` (`app/node/group/group.cpp`) ```xml ptr InputId 0 PassthroughId Display Name 0 float ... ... ... ptr ``` - ``: maps an inner node's input to a group-level passthrough input. - ``:将内部节点输入映射到组级别的透传输入。 - Child elements / 子元素: - ``: pointer id of the inner node. - ``:内部节点的指针 ID。 - ``: inner input id. - ``:内部输入 ID。 - ``: element index. - ``:元素索引。 - ``: passthrough input id on the group. - ``:组上的透传输入 ID。 - ``: display name. - ``:显示名称。 - ``: input flags (integer bitmask). - ``:输入标志(整数位掩码)。 - ``: `NodeValue` type name (see `NodeValue::GetDataTypeName()`). - ``:`NodeValue` 类型名称(见 `NodeValue::GetDataTypeName()`)。 - ``: default value encoded with `NodeValue::ValueToString(type, ..., false)`. - ``:使用 `NodeValue::ValueToString(type, ..., false)` 编码的默认值。 - ``: arbitrary key/value property pairs. - ``:任意键值属性对。 - ``: pointer id of the node that provides the group's output. - ``:提供组输出的节点指针 ID。 --- ## 6. `VideoParams` / 视频参数 Serialized inside `` for inputs of type `kVideoParams`. 在 `kVideoParams` 类型输入的 `` 中序列化。 ```xml ... ... ... num/den int int num/den int int 0|1 float float int int num/den int64 int64 0|1 string int ``` - `format`: `PixelFormat::Format` integer (`U8`, `U10`, `U16`, `F16`, `F32`). - `format`:`PixelFormat::Format` 整数(`U8`、`U10`、`U16`、`F16`、`F32`)。 - `interlacing`: `VideoParams::Interlacing` integer. - `interlacing`:`VideoParams::Interlacing` 整数。 - `videotype`: `VideoParams::Type` integer. - `videotype`:`VideoParams::Type` 整数。 - `colorrange`: `VideoParams::ColorRange` integer (`0` = limited, `1` = full). - `colorrange`:`VideoParams::ColorRange` 整数(`0` 为 limited,`1` 为 full)。 --- ## 7. `AudioParams` / 音频参数 Serialized inside `` for inputs of type `kAudioParams`. 在 `kAudioParams` 类型输入的 `` 中序列化。 ```xml int uint64 string 0|1 int int64 num/den ``` - `format`: `SampleFormat::to_string()` value. - `format`:`SampleFormat::to_string()` 值。 --- ## 8. Main Window Layout (`MainWindowLayoutInfo`) / 主窗口布局 The `` element stores the state of the main window (open folders, sequences, panel data, and Qt window state). `` 元素保存主窗口状态(打开的文件夹、序列、面板数据和 Qt 窗口状态)。 ```xml ptr ptr ptr base64 ``` - ``: pointer ids of open project folders. - ``:打开的项目文件夹指针 ID。 - ``: pointer ids of open sequences. - ``:打开的序列指针 ID。 - ``: same as `` in this implementation. - ``:当前实现与 `` 相同。 - ``: per-panel persistent data. - ``:每个面板的持久化数据。 - ``: base64-encoded Qt window/toolbar/dock state. - ``:Base64 编码的 Qt 窗口/工具栏/停靠状态。 --- ## 9. Partial Documents / 部分文档 `ProjectSerializer230220` can emit three kinds of partial documents for copy/paste and interchange: `ProjectSerializer230220` 可输出三种部分文档,用于复制/粘贴和交换: ### 9.1 `markers` ```xml ``` ### 9.2 `keyframes` ```xml ... ``` ### 9.3 `nodes` / `timeline` For copy/paste of nodes (`kOnlyNodes`) the root is ``; for clip paste (`kOnlyClips`) the root is ``. 复制/粘贴节点(`kOnlyNodes`)时根为 ``;剪辑粘贴(`kOnlyClips`)时根为 ``。 ```xml ... value ``` - `items`: comma-separated pointer ids of items that depend on this node; used to avoid duplicating shared dependencies. - `items`:依赖该节点的项目指针 ID 逗号列表,用于避免重复共享依赖。 - ``: opaque string key/value pairs attached to nodes during copy/paste. - ``:复制/粘贴时附加到节点的任意字符串键值对。 --- ## 10. Versioning / 版本管理 - Root `` selects the serializer. - 根元素 `` 选择序列化器。 - Newer files may be rejected with `kProjectTooNew` if no matching serializer exists. - 如果没有匹配的序列化器,较新的文件可能以 `kProjectTooNew` 拒绝加载。 - Each major block (`project`, `nodes`, `workarea`, etc.) has its own internal `version` attribute for future expansion. - 每个主要块(`project`、`nodes`、`workarea` 等)都有自己的内部 `version` 属性,便于未来扩展。 --- ## 11. OpenFX Node Compatibility Notes / OpenFX 节点兼容性说明 - OpenFX nodes are identified by the OFX plugin identifier (`Plugin::getIdentifier()`). - OpenFX 节点由 OFX 插件标识符(`Plugin::getIdentifier()`)标识。 - The `` list ensures Oak Video Editor can locate external plugins before instantiating nodes. - `` 列表确保 Oak 在实例化节点前能够定位外部插件。 - If a plugin cannot be found at load time, the node cannot be instantiated and will be skipped. - 如果加载时找不到插件,则无法实例化该节点,会被跳过。