Files
oak-editor/docs/project-file-reference.md
T
2026-01-05 16:22:26 +08:00

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 in YYMMDD format (latest is 230220).
  • 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 node id).
  • major / minor: OFX plugin version.
  • 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 <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: 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:

<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:

<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)

<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).

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>
  • output is 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)
  • 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 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 olive element version controls which serializer is used.
  • Newer files may be rejected with kProjectTooNew if no serializer exists.