7.7 KiB
Oak Video Editor Project File Reference
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.
Source of truth:
app/node/project.cpp,app/node/node.cpp,app/node/value.*,app/node/keyframe.*,app/node/project/serializer/*.
1. Root Document
<olive version="230220" url="/path/to/project.ove">
...
</olive>
version: serializer version inYYMMDDformat (latest is230220).url: optional source path.
2. Project Container
For full saves, the serializer writes a project container:
<project>
<project>...</project>
<layout>...</layout>
</project>
- Inner
<project>stores actual project data. <layout>stores UI layout (MainWindowLayoutInfo::fromXml).
3. Project Data (Project::Save)
<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.
<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 nodeid).major/minor: OFX plugin version.bundle: bundle directory path (preferred).file: plugin binary path (fallback).
Loading behavior:
- If
pluginsexists, Oak Video Editor adds eachbundle(orfileifbundleempty) 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().
<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: currently1.
3.4 settings
Project settings stored as key/value text elements.
Known keys from code:
cachesettingcustomcachepathcolorconfigfilenamedefaultinputcolorspacecolorreferencespaceroot(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:
<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).countis the array size.
4.3.1 Immediate Values (primary / element)
Each immediate block contains:
<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 ifkeyframingis true.cs*: only written forkColorinputs (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:ykVec3:x:y:zkVec4:x:y:z:wkColor:r:g:b:akBezier:x:y:cp1x:cp1y:cp2x:cp2ykRational:num/den(seerational::toString())kInt: integer as textkBinary: Base64kText,kFont,kFile,kCombo,kStrCombo: stringkTexture,kSamples,kNone: no text
Special cases:
kVideoParams/kAudioParamsare nested objects (see section 5).kSubtitleParamsis skipped on load to avoid overwriting subtitle data.
4.3.4 Keyframes (NodeKeyframe::save)
<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 enumNodeKeyframe::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):
<links>
<link>ptr</link>
</links>
4.5 connections
Input/output connections:
<connections>
<connection input="InputId" element="-1">
<output>ptr</output>
</connection>
</connections>
outputis the serialized pointer (ptr) of the output node.
4.6 hints (Value Hints)
Value hints are per-input UI hints:
<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)
<context>
<node ptr="other_node_ptr">
<x>0</x>
<y>0</y>
<expanded>0|1</expanded>
</node>
</context>
4.8 caches
Node cache UUIDs:
<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.
<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.
<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)keyframesnodes(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
pluginslist ensures Oak Video Editor 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
oliveelementversioncontrols which serializer is used. - Newer files may be rejected with
kProjectTooNewif no serializer exists.