diff --git a/docs/project-file-reference.md b/docs/project-file-reference.md index f79e6edf0..8fc5328ca 100644 --- a/docs/project-file-reference.md +++ b/docs/project-file-reference.md @@ -1,10 +1,14 @@ -# Oak Video Editor Project File Reference +# Oak Video Editor Project File Reference / Oak 视频编辑器项目文件格式参考 -This document describes Oak Video Editor's XML project format as implemented in the current codebase. It is intended to be detailed enough to implement a compatible reader/writer. +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. -> Source of truth: `app/node/project.cpp`, `app/node/node.cpp`, `app/node/value.*`, `app/node/keyframe.*`, `app/node/project/serializer/*`. +本文件描述 Oak 视频编辑器当前代码库实现的 XML 项目格式(`.ove`),详细程度足以支持兼容的读写实现。 -## 1. Root Document +> 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 @@ -12,24 +16,31 @@ This document describes Oak Video Editor's XML project format as implemented in ``` -- `version`: serializer version in `YYMMDD` format (latest is `230220`). +- `version`: serializer version in `YYMMDD` format. The latest serializer is `230220` (`ProjectSerializer230220`). + - `version`:序列化器版本,格式为 `YYMMDD`。当前最新为 `230220`(`ProjectSerializer230220`)。 - `url`: optional source path. + - `url`:可选的源文件路径。 -## 2. Project Container +--- + +## 2. Project Container / 项目容器 For full saves, the serializer writes a project container: +完整保存时,序列化器会写入一个项目容器: + ```xml - ... - ... + ... + ... ``` -- Inner `` stores actual project data. -- `` stores UI layout (`MainWindowLayoutInfo::fromXml`). +See `ProjectSerializer230220::Save()` and `Load()` in `app/node/project/serializer/serializer230220.cpp`. -## 3. Project Data (`Project::Save`) +--- + +## 3. Project Data (`Project::Save` / `Project::Load`) / 项目数据 ```xml @@ -41,10 +52,14 @@ For full saves, the serializer writes a project container: ``` ### 3.1 `uuid` -- QUuid string. +- QUuid string identifying the project. +- 项目 UUID 字符串。 -### 3.2 `plugins` -List of OpenFX plugins referenced by nodes in the project. This is used during load to rescan plugin paths **before** nodes are instantiated. +### 3.2 `plugins` / 插件列表 + +List of OpenFX plugins referenced by nodes. This block is loaded **before** `` so that plugin nodes can be registered. + +列出节点引用的 OpenFX 插件。该块在 `` 之前加载,以便注册插件节点。 ```xml @@ -54,18 +69,26 @@ List of OpenFX plugins referenced by nodes in the project. This is used during l ``` -Attributes: +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 `plugins` exists, Oak Video Editor adds each `bundle` (or `file` if `bundle` empty) to the OFX plugin path, scans, then registers plugin nodes before parsing ``. +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` / 节点图 -### 3.3 `nodes` The node graph. Each `` is written by `Node::Save()` and read by `Node::Load()`. +节点图。每个 `` 由 `Node::Save()` 写入、`Node::Load()` 读取。 + ```xml @@ -82,33 +105,47 @@ The node graph. Each `` is written by `Node::Save()` and read by `Node::Lo ``` -Attributes: +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` / 项目设置 -### 3.4 `settings` Project settings stored as key/value text elements. -Known keys from code: +以键值文本元素保存的项目设置。 + +Known keys / 已知键: - `cachesetting` - `customcachepath` - `colorconfigfilename` - `defaultinputcolorspace` - `colorreferencespace` -- `root` (pointer id of the root Folder node) +- `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. 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` / 输入 -### 4.3 `input` Each input is serialized as: +每个输入序列化为: + ```xml ... @@ -119,11 +156,16 @@ Each input is serialized as: ``` - `primary`: element `-1` (the main input). -- `subelements`: array elements (if input is an array). `count` is the array size. + - `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`) / 立即值 -#### 4.3.1 Immediate Values (`primary` / `element`) Each immediate block contains: +每个立即值块包含: + ```xml 0|1 @@ -141,68 +183,93 @@ Each immediate block contains: ... ``` -- `keyframing`: whether input is keyframed (only written if input is keyframable). +- `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. -- `cs*`: only written for `kColor` inputs (color management tags). + - `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 / 轨道数量 -#### 4.3.2 Track Count Track count is determined by `NodeValue::get_number_of_keyframe_tracks()`: -| Type | Tracks | +轨道数量由 `NodeValue::get_number_of_keyframe_tracks()` 决定: + +| Type / 类型 | Tracks / 轨道数 | | --- | --- | -| kVec2 | 2 | -| kVec3 | 3 | -| kVec4 | 4 | -| kColor | 4 | -| kBezier | 6 | -| other | 1 | +| `kVec2` | 2 | +| `kVec3` | 3 | +| `kVec4` | 4 | +| `kColor` | 4 | +| `kBezier` | 6 | +| other / 其他 | 1 | + +#### 4.3.3 Standard Value Encoding / 标准值编码 -#### 4.3.3 Standard Value Encoding Values are written with `NodeValue::ValueToString()` and read with `NodeValue::StringToValue()`. -String encodings: +值通过 `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 +- `kInt`: integer as text / 整数字符串 - `kBinary`: Base64 - `kText`, `kFont`, `kFile`, `kCombo`, `kStrCombo`: string -- `kTexture`, `kSamples`, `kNone`: no text +- `kTexture`, `kSamples`, `kNone`: no text / 无文本 -Special cases: -- `kVideoParams` / `kAudioParams` are nested objects (see section 5). +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`) +#### 4.3.4 Keyframes (`NodeKeyframe::save` / `NodeKeyframe::load`) / 关键帧 ```xml -value +value ``` -Attributes: +Attributes / 属性: - `input`: input id. + - 输入 ID。 - `time`: rational time (`rational::toString()`). -- `type`: integer enum `NodeKeyframe::Type` (e.g., linear/bezier/etc.). + - 有理数时间(`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` / 链接 -### 4.4 `links` Block-to-block link list (for timeline items): +块到块链接列表(用于时间线项目): + ```xml ptr ``` -### 4.5 `connections` +### 4.5 `connections` / 连接 + Input/output connections: +输入/输出连接: + ```xml @@ -212,15 +279,19 @@ Input/output connections: ``` - `output` is the serialized pointer (`ptr`) of the output node. +- `output` 为输出节点的序列化指针(`ptr`)。 -### 4.6 `hints` (Value Hints) -Value hints are per-input UI hints: +### 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 ... @@ -228,7 +299,14 @@ Value hints are per-input UI hints: ``` -### 4.7 `context` (Node positions in contexts) +- `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 @@ -240,9 +318,15 @@ Value hints are per-input UI hints: ``` -### 4.8 `caches` +- 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 @@ -252,12 +336,151 @@ Node cache UUIDs: ``` -### 4.9 `custom` -Custom node data. Default `Node::SaveCustom()` writes nothing. Specific node subclasses may override. +### 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` / 视频参数 -## 5. VideoParams Serialized inside `` for inputs of type `kVideoParams`. +在 `kVideoParams` 类型输入的 `` 中序列化。 + ```xml ... ... @@ -281,9 +504,23 @@ Serialized inside `` for inputs of type `kVideoParams`. int ``` -## 6. AudioParams +- `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 @@ -294,23 +531,122 @@ Serialized inside `` for inputs of type `kAudioParams`. num/den ``` -## 7. Keyframes-only / Markers-only / Nodes-only +- `format`: `SampleFormat::to_string()` value. + - `format`:`SampleFormat::to_string()` 值。 -The serializer can emit partial documents: +--- -- `markers` (timeline markers) -- `keyframes` -- `nodes` (subset for copy/paste) +## 8. Main Window Layout (`MainWindowLayoutInfo`) / 主窗口布局 -These are written by `ProjectSerializer230220::Save()` depending on SaveData. +The `` element stores the state of the main window (open folders, sequences, panel data, and Qt window state). -## 8. OpenFX Node Compatibility Notes +`` 元素保存主窗口状态(打开的文件夹、序列、面板数据和 Qt 窗口状态)。 -- OpenFX nodes are identified by OFX plugin identifier (`Plugin::getIdentifier()`). -- The `plugins` list ensures Oak Video Editor can locate external plugins before instantiating nodes. +```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. - -## 9. Versioning - -- Root `olive` element `version` controls which serializer is used. -- Newer files may be rejected with `kProjectTooNew` if no serializer exists. + - 如果加载时找不到插件,则无法实例化该节点,会被跳过。