From 0323c74c8328c9ac7c1675d185beb4d7d7408a06 Mon Sep 17 00:00:00 2001 From: Mike Solar Date: Mon, 5 Jan 2026 02:26:20 +0800 Subject: [PATCH] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E6=96=87=E6=A1=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .gitignore | 1 - docs/project-file-reference-zh.md | 306 ++++++++++++++++++++++++++++ docs/project-file-reference.md | 317 ++++++++++++++++++++++++++++++ docs/structure-zh.md | 168 ++++++++++++++++ 4 files changed, 791 insertions(+), 1 deletion(-) create mode 100644 docs/project-file-reference-zh.md create mode 100644 docs/project-file-reference.md create mode 100644 docs/structure-zh.md diff --git a/.gitignore b/.gitignore index 920df8e17..1fd4fdcf0 100644 --- a/.gitignore +++ b/.gitignore @@ -2,7 +2,6 @@ /build*/ build # Doxygen -/docs/ # Visual Studio (Code) .localhistory/ diff --git a/docs/project-file-reference-zh.md b/docs/project-file-reference-zh.md new file mode 100644 index 000000000..95f7ea515 --- /dev/null +++ b/docs/project-file-reference-zh.md @@ -0,0 +1,306 @@ +# Olive 项目文件参考手册(详细版) + +本文档基于当前源代码实现,描述 Olive 的 XML 项目文件格式,目标是足够详细以实现兼容读写器。 + +> 代码来源:`app/node/project.cpp`、`app/node/node.cpp`、`app/node/value.*`、`app/node/keyframe.*`、`app/node/project/serializer/*`。 + +## 1. 根元素 + +```xml + + ... + +``` + +- `version`:序列化版本号(`YYMMDD`)。 +- `url`:可选的项目文件路径。 + +## 2. 项目容器 + +完整保存时,会有 `project` 容器: + +```xml + + ... + ... + +``` + +- 内层 ``:项目数据。 +- ``:界面布局(`MainWindowLayoutInfo::fromXml`)。 + +## 3. 项目数据(`Project::Save`) + +```xml + + ... + ... + ... + ... + +``` + +### 3.1 `uuid` +项目 UUID(QUuid 字符串)。 + +### 3.2 `plugins` +项目中使用的 OpenFX 插件列表,用于加载节点前补充插件搜索路径。 + +```xml + + + +``` + +属性: +- `id`:OFX 插件标识符(与节点 `id` 相同)。 +- `major` / `minor`:插件版本。 +- `bundle`:插件 bundle 目录路径(优先使用)。 +- `file`:插件二进制路径(备用)。 + +加载策略: +- 若存在 ``,先把 `bundle`(或 `file`)加入 OFX 搜索路径并扫描,然后注册插件节点,再进入 `` 解析。 + +### 3.3 `nodes` +节点图,节点由 `Node::Save()` 写出: + +```xml + + + + ... + ... + ... + ... + ... + ... + ... + ... + + +``` + +关键属性: +- `id`:节点类型标识。OpenFX 节点为插件标识符。 +- `ptr`:序列化指针 ID,用于恢复连接与位置。 +- `version`:当前为 `1`。 + +### 3.4 `settings` +项目设置,键值对形式保存: + +已知键: +- `cachesetting` +- `customcachepath` +- `colorconfigfilename` +- `defaultinputcolorspace` +- `colorreferencespace` +- `root` + +## 4. 节点序列化(`Node::Save` / `Node::Load`) + +### 4.1 `label` +节点显示名。 + +### 4.2 `color` +节点覆盖颜色(整数索引)。 + +### 4.3 `input` +每个输入: + +```xml + + ... + + ... + + +``` + +- `primary`:主元素(element = -1)。 +- `subelements`:数组输入,`count` 为数组长度。 + +#### 4.3.1 立即值结构(`primary` / `element`) + +```xml +0|1 + + ... + + + + ... + + +... +... +... +... +``` + +- `keyframing`:是否启用关键帧(仅在输入可关键帧时写出)。 +- `standard`:默认值(每条 track 一份)。 +- `keyframes`:仅当 `keyframing=1` 时写出。 +- `cs*`:仅用于 `kColor`,保存色彩管理信息。 + +#### 4.3.2 Track 数量 +由 `NodeValue::get_number_of_keyframe_tracks()` 决定: + +| 类型 | Track 数量 | +| --- | --- | +| kVec2 | 2 | +| kVec3 | 3 | +| kVec4 | 4 | +| kColor | 4 | +| kBezier | 6 | +| 其他 | 1 | + +#### 4.3.3 标准值编码 +由 `NodeValue::ValueToString()` 写出,`NodeValue::StringToValue()` 读入: + +- `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` +- `kInt`: 整数文本 +- `kBinary`: Base64 +- `kText` / `kFont` / `kFile` / `kCombo` / `kStrCombo`: 纯文本 +- `kTexture` / `kSamples` / `kNone`: 无文本 + +特殊情况: +- `kVideoParams` / `kAudioParams` 以子对象形式保存(见第 5/6 节)。 +- `kSubtitleParams` 在加载时被跳过(避免覆盖实际字幕数据)。 + +#### 4.3.4 关键帧(`NodeKeyframe::save`) + +```xml +value +``` + +- `input`:输入 ID。 +- `time`:理性时间。 +- `type`:关键帧类型枚举值。 +- `inhandlex` / `inhandley` / `outhandlex` / `outhandley`:贝塞尔控制点。 + +文本值使用 `NodeValue::ValueToString(data_type, value, true)`。 + +### 4.4 `links` +节点间的“块”链接: + +```xml + + ptr + +``` + +### 4.5 `connections` +输入/输出连接: + +```xml + + + ptr + + +``` + +### 4.6 `hints`(输入提示) + +```xml + + + + ... + + 0 + ... + + +``` + +### 4.7 `context`(节点位置) + +```xml + + + 0 + 0 + 0|1 + + +``` + +### 4.8 `caches` + +```xml + + + + uuid + uuid + +``` + +### 4.9 `custom` +节点自定义内容,默认实现为空;各子类可覆盖。 + +## 5. VideoParams +`kVideoParams` 输入以子对象保存: + +```xml +... +... +... +num/den +int +int +num/den +int +int +0|1 +float +float +int +int +num/den +int64 +int64 +0|1 +string +int +``` + +## 6. AudioParams +`kAudioParams` 输入以子对象保存: + +```xml +int +uint64 +string +0|1 +int +int64 +num/den +``` + +## 7. 部分保存 +序列化器支持写出部分数据: + +- `` +- `` +- ``(子集) + +## 8. OpenFX 插件兼容 + +- OpenFX 节点 `id` 等于插件标识符。 +- `` 记录插件路径,加载时会先扫描并注册插件节点。 +- 插件缺失时节点无法实例化并被跳过。 + +## 9. 版本兼容 + +- 根元素 `version` 决定使用哪个序列化器。 +- 若缺少对应版本,会报 `kProjectTooNew` 或 `kProjectTooOld`。 + diff --git a/docs/project-file-reference.md b/docs/project-file-reference.md new file mode 100644 index 000000000..cf3830dbc --- /dev/null +++ b/docs/project-file-reference.md @@ -0,0 +1,317 @@ +# Olive Project File Reference + +This document describes Olive's XML project format 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/*`. + +## 1. Root Document + +```xml + + ... + +``` + +- `version`: serializer version in `YYMMDD` format (latest is `230220`). +- `url`: optional source path. + +## 2. Project Container + +For full saves, the serializer writes a project container: + +```xml + + ... + ... + +``` + +- Inner `` stores actual project data. +- `` stores UI layout (`MainWindowLayoutInfo::fromXml`). + +## 3. Project Data (`Project::Save`) + +```xml + + ... + ... + ... + ... + +``` + +### 3.1 `uuid` +- QUuid string. + +### 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. + +```xml + + + +``` + +Attributes: +- `id`: OFX plugin identifier (matches node `id`). +- `major` / `minor`: OFX plugin version. +- `bundle`: bundle directory path (preferred). +- `file`: plugin binary path (fallback). + +Loading behavior: +- If `plugins` exists, Olive adds each `bundle` (or `file` if `bundle` empty) to the OFX plugin path, scans, then registers plugin nodes before parsing ``. + +### 3.3 `nodes` +The node graph. Each `` is written by `Node::Save()` and read by `Node::Load()`. + +```xml + + + + 3 + ... + ... + ... + ... + ... + ... + ... + + +``` + +Attributes: +- `id`: node type identifier. For OpenFX nodes, this equals the OFX plugin identifier. +- `ptr`: numeric pointer ID used to resolve connections and context positions. +- `version`: currently `1`. + +### 3.4 `settings` +Project settings stored as key/value text elements. + +Known keys from code: +- `cachesetting` +- `customcachepath` +- `colorconfigfilename` +- `defaultinputcolorspace` +- `colorreferencespace` +- `root` (pointer id of the root Folder node) + +## 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`. + +### 4.3 `input` +Each input is serialized as: + +```xml + + ... + + ... + + +``` + +- `primary`: element `-1` (the main input). +- `subelements`: array elements (if input is an array). `count` is the array size. + +#### 4.3.1 Immediate Values (`primary` / `element`) +Each immediate block contains: + +```xml +0|1 + + ... + ... + + + + ... + + +... +... +... +... +``` + +- `keyframing`: whether input is keyframed (only written if input is keyframable). +- `standard`: default/static values (one `` per keyframe track). +- `keyframes`: only written if `keyframing` is true. +- `cs*`: only written for `kColor` inputs (color management tags). + +#### 4.3.2 Track Count +Track count is determined by `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()`. + +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 section 5). +- `kSubtitleParams` is **skipped on load** to avoid overwriting subtitle data. + +#### 4.3.4 Keyframes (`NodeKeyframe::save`) + +```xml +value +``` + +Attributes: +- `input`: input id. +- `time`: rational time (`rational::toString()`). +- `type`: integer enum `NodeKeyframe::Type` (e.g., linear/bezier/etc.). +- `inhandlex`, `inhandley`, `outhandlex`, `outhandley`: bezier handle coordinates. + +Text value uses `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. + +### 4.6 `hints` (Value Hints) +Value hints are per-input UI hints: + +```xml + + + + ... + + 0 + ... + + +``` + +### 4.7 `context` (Node positions in contexts) + +```xml + + + 0 + 0 + 0|1 + + +``` + +### 4.8 `caches` +Node cache UUIDs: + +```xml + + + + uuid + uuid + +``` + +### 4.9 `custom` +Custom node data. Default `Node::SaveCustom()` writes nothing. Specific node subclasses may override. + +## 5. VideoParams +Serialized inside `` for inputs of type `kVideoParams`. + +```xml +... +... +... +num/den +int +int +num/den +int +int +0|1 +float +float +int +int +num/den +int64 +int64 +0|1 +string +int +``` + +## 6. AudioParams +Serialized inside `` for inputs of type `kAudioParams`. + +```xml +int +uint64 +string +0|1 +int +int64 +num/den +``` + +## 7. Keyframes-only / Markers-only / Nodes-only + +The serializer can emit partial documents: + +- `markers` (timeline markers) +- `keyframes` +- `nodes` (subset for copy/paste) + +These are written by `ProjectSerializer230220::Save()` depending on SaveData. + +## 8. OpenFX Node Compatibility Notes + +- OpenFX nodes are identified by OFX plugin identifier (`Plugin::getIdentifier()`). +- The `plugins` list ensures Olive can locate external plugins before instantiating nodes. +- 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. + diff --git a/docs/structure-zh.md b/docs/structure-zh.md new file mode 100644 index 000000000..b64bc2440 --- /dev/null +++ b/docs/structure-zh.md @@ -0,0 +1,168 @@ +Olive 项目结构概览(中文) +========================== + +这份文档是基于当前仓库目录组织的快速导航,便于后续查找代码位置。 + +顶层目录 +-------- +- app: 主应用源码入口,涵盖核心、渲染、UI、插件、节点系统等。 +- cmake: CMake 相关脚本与模块。 +- docker: 构建/运行相关的容器配置。 +- docs: 项目文档(你现在正在看的位置)。 +- ext: 可能包含外部依赖或子模块(按需查看)。 +- tests: 测试代码与用例。 +- third_party: 第三方库及其源码(如 OpenFX HostSupport)。 +- build、cmake-build-debug、test_compile: 构建产物或构建目录(通常不需要手动改)。 + +app 目录(核心模块) +------------------- +- app/core.*: 应用核心入口、初始化流程。 +- app/main.cpp: 程序入口点。 +- app/version.*: 版本信息与构建元数据。 +- app/common: 通用基础设施与工具类(日志、路径、字符串等)。 +- app/config: 配置加载与项目设置。 +- app/render: 渲染子系统(帧缓存、渲染管线、插件渲染桥接等)。 +- app/node: 节点系统,节点类型与图结构的核心逻辑。 +- app/widget: UI 控件与节点视图(节点图、参数面板等)。 +- app/panel: UI 面板组织与管理。 +- app/window: 窗口与主界面。 +- app/timeline: 时间线与剪辑管理。 +- app/tool: 交互工具(选择、裁剪等)。 +- app/undo: 撤销/重做系统。 +- app/task: 异步任务与后台作业。 +- app/audio: 音频处理与播放。 +- app/codec: 编解码相关支持。 +- app/shaders: 渲染着色器资源。 +- app/ts: 时间/时间轴相关通用类型。 +- app/dialog: 对话框与提示类 UI。 +- app/cli: 命令行工具入口或相关实现。 +- app/pluginSupport: OpenFX 插件 Host 侧实现(Clip/Image/Param/Host/PluginInstance 等)。 +- app/packaging: 打包或发布相关逻辑。 + +重点文件索引(按模块) +---------------------- +下面列的是“常用/核心入口”文件,不是完整清单,但足够定位主要流程。 + +核心入口与全局 +------------- +- app/main.cpp: 程序入口。 +- app/core.h、app/core.cpp: 应用生命周期与初始化总控。 +- app/version.h、app/version.cpp: 版本与构建信息。 + +渲染系统 +-------- +- app/render/renderer.h、app/render/renderer.cpp: 渲染主调度。 +- app/render/rendermanager.h、app/render/rendermanager.cpp: 渲染队列与任务管理。 +- app/render/renderticket.h、app/render/renderticket.cpp: 单次渲染请求。 +- app/render/renderprocessor.h、app/render/renderprocessor.cpp: 渲染处理管线。 +- app/render/texture.h、app/render/texture.cpp: 纹理/帧数据容器。 +- app/render/videoparams.h、app/render/videoparams.cpp: 视频格式参数。 +- app/render/job/pluginjob.h、app/render/job/pluginjob.cpp: 插件渲染作业。 +- app/render/plugin/pluginrenderer.h、app/render/plugin/pluginrenderer.cpp: OpenFX 插件渲染桥接。 + +节点系统 +-------- +- app/node/node.h、app/node/node.cpp: 节点基类与生命周期。 +- app/node/param.h、app/node/param.cpp: 节点参数与动画/关键帧。 +- app/node/value.h、app/node/value.cpp: 节点值与运行时数据。 +- app/node/factory.h、app/node/factory.cpp: 节点注册与创建。 +- app/node/traverser.h、app/node/traverser.cpp: 图遍历与求值。 +- app/node/plugins/Plugin.h、app/node/plugins/Plugin.cpp: OpenFX 插件节点。 + +OpenFX Host 侧实现 +------------------ +- app/pluginSupport/OliveHost.h、app/pluginSupport/OliveHost.cpp: OpenFX Host 入口与消息接口。 +- app/pluginSupport/OlivePluginInstance.h、app/pluginSupport/OlivePluginInstance.cpp: 插件实例生命周期与参数管理。 +- app/pluginSupport/OliveClip.h、app/pluginSupport/OliveClip.cpp: Clip 实例与图像读写桥接。 +- app/pluginSupport/image.h、app/pluginSupport/image.cpp: OpenFX Image 封装与数据映射。 +- app/pluginSupport/paraminstance.h、app/pluginSupport/paraminstance.cpp: 参数实例实现。 +- third_party/openfx/HostSupport/include/ofxhImageEffect.h: HostSupport 核心接口。 + +节点 UI(Node View) +------------------- +- app/widget/nodeview/nodeview.h、app/widget/nodeview/nodeview.cpp: 节点视图主控。 +- app/widget/nodeview/nodeviewitem.h、app/widget/nodeview/nodeviewitem.cpp: 节点渲染与交互。 +- app/widget/nodeview/nodeviewscene.h、app/widget/nodeview/nodeviewscene.cpp: QGraphicsScene 逻辑。 +- app/widget/nodeview/nodeviewedge.h、app/widget/nodeview/nodeviewedge.cpp: 连线显示。 + +参数 UI(Param View) +-------------------- +- app/widget/nodeparamview/nodeparamview.h、app/widget/nodeparamview/nodeparamview.cpp: 参数面板主控。 +- app/widget/nodeparamview/nodeparamviewitem.h、app/widget/nodeparamview/nodeparamviewitem.cpp: 参数项容器与布局。 +- app/widget/nodeparamview/nodeparamviewwidgetbridge.h、app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp: 参数类型到控件的桥接。 +- app/widget/nodeparamview/nodeparamviewtextedit.h、app/widget/nodeparamview/nodeparamviewtextedit.cpp: 多行文本参数控件。 + +面板与窗口 +---------- +- app/panel/panelmanager.h、app/panel/panelmanager.cpp: 面板管理器与切换逻辑。 +- app/panel/timebased/timebased.h、app/panel/timebased/timebased.cpp: 时间基面板基类(时间轴/视图共享逻辑)。 +- app/panel/node/node.h、app/panel/node/node.cpp: 节点面板入口。 +- app/panel/param/param.h、app/panel/param/param.cpp: 参数面板入口。 +- app/window: 主窗口与窗口级 UI 结构。 + +时间线/播放核心 +-------------- +- app/node/output/viewer/viewer.h、app/node/output/viewer/viewer.cpp: Viewer 输出节点(播放头/长度/渲染请求)。 +- app/widget/viewer/viewer.h、app/widget/viewer/viewer.cpp: Viewer 面板与播放控制。 +- app/widget/timelinewidget/timelinewidget.h、app/widget/timelinewidget/timelinewidget.cpp: 时间线 UI 与交互主控。 + +进度与任务 UI +------------ +- app/dialog/progress/progress.h、app/dialog/progress/progress.cpp: 通用进度对话框。 +- app/widget/taskview/taskviewitem.h、app/widget/taskview/taskviewitem.cpp: 任务进度条展示。 + +撤销/编辑分组 +------------ +- app/undo/undocommand.h、app/undo/undocommand.cpp: UndoCommand 与 MultiUndoCommand 的基础实现。 +- app/undo/undostack.h、app/undo/undostack.cpp: 撤销栈(无原生“批量编辑”接口)。 +- app/pluginSupport/OlivePluginInstance.h、app/pluginSupport/OlivePluginInstance.cpp: OpenFX editBegin/editEnd 触发时创建批量撤销分组。 +- app/pluginSupport/OlivePluginInstance.cpp: DeferredRedoCommand 包装已应用的命令,避免批量 push 时重复执行。 +- app/pluginSupport/paraminstance.h、app/pluginSupport/paraminstance.cpp: 参数 Set 走统一的 SubmitUndoCommand 接口,支持批量合并。 + +与 OpenFX 相关的主要位置 +----------------------- +- app/pluginSupport: OpenFX HostSupport 的封装与 Olive 侧实现。 +- app/render/plugin: 插件渲染调度与帧处理逻辑。 +- app/node/plugins: 插件节点定义与 UI 参数桥接。 +- third_party/openfx: OpenFX HostSupport 源码与接口头文件。 + +构建与配置 +---------- +- CMakeLists.txt: 根构建配置入口。 +- cmake/: 自定义 CMake 模块与工具链脚本。 + +其他说明 +-------- +- README.md: 项目整体说明与开发入口。 +- TODO-zh.md: OpenFX 支持的中文 TODO 说明。 + +流程图/调用关系(ASCII) +----------------------- +OpenFX 插件渲染主流程(逻辑简化): +``` +Node(Graph) + -> app/node/plugins/Plugin.cpp + -> app/render/plugin/pluginrenderer.cpp + -> app/pluginSupport/OlivePluginInstance.cpp + -> app/pluginSupport/OliveClip.cpp + -> app/pluginSupport/image.cpp + -> app/render/texture.cpp / AVFrame 映射 +``` + +OpenFX 参数 UI 生成流程(逻辑简化): +``` +OFX Param Descriptor + -> app/pluginSupport/OlivePluginInstance.cpp (newParam) + -> app/node/plugins/Plugin.cpp (Node Input 生成) + -> app/widget/nodeparamview/nodeparamview.cpp + -> app/widget/nodeparamview/nodeparamviewwidgetbridge.cpp (控件桥接) +``` + +插件消息展示流程(逻辑简化): +``` +OFX Host Message + -> app/pluginSupport/OliveHost.cpp (保存消息) + -> app/pluginSupport/OlivePluginInstance.cpp (发出消息数量变化) + -> app/widget/nodeview/nodeviewitem.cpp (节点右上角徽标) + -> app/widget/nodeparamview/nodeparamviewitem.cpp (面板顶部消息) +```