添加文档

This commit is contained in:
2026-01-05 02:26:20 +08:00
parent 003c3bb5be
commit 0323c74c83
4 changed files with 791 additions and 1 deletions
-1
View File
@@ -2,7 +2,6 @@
/build*/ /build*/
build build
# Doxygen # Doxygen
/docs/
# Visual Studio (Code) # Visual Studio (Code)
.localhistory/ .localhistory/
+306
View File
@@ -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
<olive version="230220" url="/path/to/project.ove">
...
</olive>
```
- `version`:序列化版本号(`YYMMDD`)。
- `url`:可选的项目文件路径。
## 2. 项目容器
完整保存时,会有 `project` 容器:
```xml
<project>
<project>...</project>
<layout>...</layout>
</project>
```
- 内层 `<project>`:项目数据。
- `<layout>`:界面布局(`MainWindowLayoutInfo::fromXml`)。
## 3. 项目数据(`Project::Save`
```xml
<project version="1">
<uuid>...</uuid>
<plugins>...</plugins>
<nodes>...</nodes>
<settings>...</settings>
</project>
```
### 3.1 `uuid`
项目 UUIDQUuid 字符串)。
### 3.2 `plugins`
项目中使用的 OpenFX 插件列表,用于加载节点前补充插件搜索路径。
```xml
<plugins>
<plugin id="com.vendor.Plugin" major="1" minor="2"
bundle="/path/to/Plugin.ofx.bundle"
file="/path/to/Plugin.ofx.bundle/Contents/MacOS/Plugin" />
</plugins>
```
属性:
- `id`OFX 插件标识符(与节点 `id` 相同)。
- `major` / `minor`:插件版本。
- `bundle`:插件 bundle 目录路径(优先使用)。
- `file`:插件二进制路径(备用)。
加载策略:
- 若存在 `<plugins>`,先把 `bundle`(或 `file`)加入 OFX 搜索路径并扫描,然后注册插件节点,再进入 `<nodes>` 解析。
### 3.3 `nodes`
节点图,节点由 `Node::Save()` 写出:
```xml
<nodes version="1">
<node version="1" id="node.id" ptr="123456">
<label>...</label>
<color>...</color>
<input>...</input>
<links>...</links>
<connections>...</connections>
<hints>...</hints>
<context>...</context>
<caches>...</caches>
<custom>...</custom>
</node>
</nodes>
```
关键属性:
- `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
<input id="InputId">
<primary>...</primary>
<subelements count="N">
<element>...</element>
</subelements>
</input>
```
- `primary`:主元素(element = -1)。
- `subelements`:数组输入,`count` 为数组长度。
#### 4.3.1 立即值结构(`primary` / `element`
```xml
<keyframing>0|1</keyframing>
<standard>
<track>...</track>
</standard>
<keyframes>
<track>
<key ...>...</key>
</track>
</keyframes>
<csinput>...</csinput>
<csdisplay>...</csdisplay>
<csview>...</csview>
<cslook>...</cslook>
```
- `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
<key input="InputId" time="num/den" type="0" inhandlex="0" inhandley="0" outhandlex="0" outhandley="0">value</key>
```
- `input`:输入 ID。
- `time`:理性时间。
- `type`:关键帧类型枚举值。
- `inhandlex` / `inhandley` / `outhandlex` / `outhandley`:贝塞尔控制点。
文本值使用 `NodeValue::ValueToString(data_type, value, true)`
### 4.4 `links`
节点间的“块”链接:
```xml
<links>
<link>ptr</link>
</links>
```
### 4.5 `connections`
输入/输出连接:
```xml
<connections>
<connection input="InputId" element="-1">
<output>ptr</output>
</connection>
</connections>
```
### 4.6 `hints`(输入提示)
```xml
<hints>
<hint input="InputId" element="-1" version="1">
<types>
<type>...</type>
</types>
<index>0</index>
<tag>...</tag>
</hint>
</hints>
```
### 4.7 `context`(节点位置)
```xml
<context>
<node ptr="other_node_ptr">
<x>0</x>
<y>0</y>
<expanded>0|1</expanded>
</node>
</context>
```
### 4.8 `caches`
```xml
<caches>
<audio>uuid</audio>
<video>uuid</video>
<thumb>uuid</thumb>
<waveform>uuid</waveform>
</caches>
```
### 4.9 `custom`
节点自定义内容,默认实现为空;各子类可覆盖。
## 5. VideoParams
`kVideoParams` 输入以子对象保存:
```xml
<width>...</width>
<height>...</height>
<depth>...</depth>
<timebase>num/den</timebase>
<format>int</format>
<channelcount>int</channelcount>
<pixelaspectratio>num/den</pixelaspectratio>
<interlacing>int</interlacing>
<divider>int</divider>
<enabled>0|1</enabled>
<x>float</x>
<y>float</y>
<streamindex>int</streamindex>
<videotype>int</videotype>
<framerate>num/den</framerate>
<starttime>int64</starttime>
<duration>int64</duration>
<premultipliedalpha>0|1</premultipliedalpha>
<colorspace>string</colorspace>
<colorrange>int</colorrange>
```
## 6. AudioParams
`kAudioParams` 输入以子对象保存:
```xml
<samplerate>int</samplerate>
<channellayout>uint64</channellayout>
<format>string</format>
<enabled>0|1</enabled>
<streamindex>int</streamindex>
<duration>int64</duration>
<timebase>num/den</timebase>
```
## 7. 部分保存
序列化器支持写出部分数据:
- `<markers>`
- `<keyframes>`
- `<nodes>`(子集)
## 8. OpenFX 插件兼容
- OpenFX 节点 `id` 等于插件标识符。
- `<plugins>` 记录插件路径,加载时会先扫描并注册插件节点。
- 插件缺失时节点无法实例化并被跳过。
## 9. 版本兼容
- 根元素 `version` 决定使用哪个序列化器。
- 若缺少对应版本,会报 `kProjectTooNew``kProjectTooOld`
+317
View File
@@ -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
<olive version="230220" url="/path/to/project.ove">
...
</olive>
```
- `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
<project>
<project>...</project>
<layout>...</layout>
</project>
```
- Inner `<project>` stores actual project data.
- `<layout>` stores UI layout (`MainWindowLayoutInfo::fromXml`).
## 3. Project Data (`Project::Save`)
```xml
<project version="1">
<uuid>...</uuid>
<plugins>...</plugins>
<nodes>...</nodes>
<settings>...</settings>
</project>
```
### 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
<plugins>
<plugin id="com.vendor.Plugin" major="1" minor="2"
bundle="/path/to/Plugin.ofx.bundle"
file="/path/to/Plugin.ofx.bundle/Contents/MacOS/Plugin" />
</plugins>
```
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 `<nodes>`.
### 3.3 `nodes`
The node graph. Each `<node>` is written by `Node::Save()` and read by `Node::Load()`.
```xml
<nodes version="1">
<node version="1" id="node.id" ptr="123456">
<label>Optional Label</label>
<color>3</color>
<input>...</input>
<links>...</links>
<connections>...</connections>
<hints>...</hints>
<context>...</context>
<caches>...</caches>
<custom>...</custom>
</node>
</nodes>
```
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
<input id="InputId">
<primary>...</primary>
<subelements count="N">
<element>...</element>
</subelements>
</input>
```
- `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
<keyframing>0|1</keyframing>
<standard>
<track>...</track>
...
</standard>
<keyframes>
<track>
<key ...>...</key>
</track>
</keyframes>
<csinput>...</csinput>
<csdisplay>...</csdisplay>
<csview>...</csview>
<cslook>...</cslook>
```
- `keyframing`: whether input is keyframed (only written if input is keyframable).
- `standard`: default/static values (one `<track>` 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
<key input="InputId" time="num/den" type="0" inhandlex="0" inhandley="0" outhandlex="0" outhandley="0">value</key>
```
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
<links>
<link>ptr</link>
</links>
```
### 4.5 `connections`
Input/output connections:
```xml
<connections>
<connection input="InputId" element="-1">
<output>ptr</output>
</connection>
</connections>
```
- `output` is the serialized pointer (`ptr`) of the output node.
### 4.6 `hints` (Value Hints)
Value hints are per-input UI hints:
```xml
<hints>
<hint input="InputId" element="-1" version="1">
<types>
<type>...</type>
</types>
<index>0</index>
<tag>...</tag>
</hint>
</hints>
```
### 4.7 `context` (Node positions in contexts)
```xml
<context>
<node ptr="other_node_ptr">
<x>0</x>
<y>0</y>
<expanded>0|1</expanded>
</node>
</context>
```
### 4.8 `caches`
Node cache UUIDs:
```xml
<caches>
<audio>uuid</audio>
<video>uuid</video>
<thumb>uuid</thumb>
<waveform>uuid</waveform>
</caches>
```
### 4.9 `custom`
Custom node data. Default `Node::SaveCustom()` writes nothing. Specific node subclasses may override.
## 5. VideoParams
Serialized inside `<standard><track>` for inputs of type `kVideoParams`.
```xml
<width>...</width>
<height>...</height>
<depth>...</depth>
<timebase>num/den</timebase>
<format>int</format>
<channelcount>int</channelcount>
<pixelaspectratio>num/den</pixelaspectratio>
<interlacing>int</interlacing>
<divider>int</divider>
<enabled>0|1</enabled>
<x>float</x>
<y>float</y>
<streamindex>int</streamindex>
<videotype>int</videotype>
<framerate>num/den</framerate>
<starttime>int64</starttime>
<duration>int64</duration>
<premultipliedalpha>0|1</premultipliedalpha>
<colorspace>string</colorspace>
<colorrange>int</colorrange>
```
## 6. AudioParams
Serialized inside `<standard><track>` for inputs of type `kAudioParams`.
```xml
<samplerate>int</samplerate>
<channellayout>uint64</channellayout>
<format>string</format>
<enabled>0|1</enabled>
<streamindex>int</streamindex>
<duration>int64</duration>
<timebase>num/den</timebase>
```
## 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.
+168
View File
@@ -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 核心接口。
节点 UINode 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: 连线显示。
参数 UIParam 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 (面板顶部消息)
```