kdenlive
Kdenlive 文件格式

<!-- SPDX-FileCopyrightText: 2021-2022 Julius Künzel <julius.kuenzel@kde.org> SPDX-FileCopyrightText: 2015-2023 Jean-Baptiste Mardelle <jb@kdenlive.org> SPDX-License-Identifier: CC0-1.0 -->

Kdenlive 文件格式

Kdenlive 的工程文件(.kdenlive 文件)使用一种基于 MLT 格式的 XML 格式(参见 MLT 的 XML 文档 (opens in a new tab)和 MLT 的 DTD/文档类型定义 (opens in a new tab)),用于描述工程中所使用的源媒体,以及这些媒体在时间线中的使用方式。

对于大多数媒体(如视频、音频、图像),Kdenlive 在工程中只存储引用,而不存储媒体本身。只有少数媒体会直接存储在 Kdenlive 的工程文件内部,最典型的是 Kdenlive 标题片段和颜色片段。

这一文件格式决策的重要方面包括:

  • MLT 能够直接渲染 Kdenlive 工程文件。 MLT 会简单地忽略所有额外的 Kdenlive 专属工程数据,只专注于它自己的渲染信息。Kdenlive 专属数据就像是锦上添花的额外糖霜,让处理工程比在(更底层的)渲染层面编辑容易得多。
  • Kdenlive 可以直接包含并使用 MLT 渲染文件, 就像处理其他媒体一样。事实上,Kdenlive 的库片段就是 MLT 渲染文件,仅此而已。

历史与代际

根据你所使用的 Kdenlive 版本不同,存在不同的文件格式代际。

第 1 代

第 1 代(gen-1)工程是在最高到 0.9.10 版本的 Kdenlive 中创建和最后编辑的。这些是为 KDE 4.x 开发的 Kdenlive 版本。(虽然这并不完全严格成立,但我们不会讨论 Kdenlive 早期的 KDE 3.x 版本。)

gen-1 工程包含大量工程数据,这些数据需要被复制一份到外层的 MLT XML 数据中,MLT 才能知道它需要做什么。作为这种数据双重存储的不幸后果,gen-1 工程常有这样一种"习惯":外层 MLT 数据与内层 Kdenlive 工程数据失去同步。例如有时实际渲染出的效果,与在 Kdenlive 用户界面中设置的效果参数不一致。针对这种情况,Kdenlive 开发者们采取的恰当补救措施,是在把 Kdenlive 移植到 KDE Frameworks 5(KF5)的过程中切换到第 2 代。

第 2 代:KF5

用于 Kdenlive 15.04 至 17.08 版本

在 KF5/Qt5 版本的 Kdenlive 中,我们现在通过 MLT 的 xml 模块存储所有 Kdenlive 数据,以消除 Kdenlive 工程文件结构中的数据双重存储。这种修正后的工程数据模型带来了稳定得多的 Kdenlive 工程行为。另一个积极的副作用是:现在从 Kdenlive 外部手动编辑或创建 Kdenlive XML 工程文件容易得多了。

轻微不合法的 XML?

当你需要使用 XML 工具处理 Kdenlive 工程文件时,对于 gen-2 工程文件,有一个坑(gotcha)需要注意。一旦工程使用了整轨效果,Kdenlive 写出的工程 XML 就会变得不合法。如果只在 Kdenlive 内部编辑 Kdenlive 工程文件并用 MLT 渲染,你察觉不到这一点;只有使用标准 XML 工具编辑时才会发现。

原因是 gen-2 工程文件在一个独立的 "kdenlive" 命名空间内使用了它们自己的属性。不幸的是,Kdenlive 忘记在每个 XML 工程文档开头声明它所使用的这个额外命名空间。一个简单的修复方法是:在用 XML 工具处理 Kdenlive 工程文件之前,自行补上缺失的命名空间声明:

<?xml version='1.0' encoding='utf-8'?>
<mlt xmlns:kdenlive="http://www.kdenlive.org/project" ...>
  ...
</mlt>

第 3 代:Timeline 2

用于 Kdenlive 19.04.0 至 20.04.3 版本

第 3 代工程是指使用搭载新 Timeline 2 引擎的 Kdenlive 版本创建或编辑的工程。

第 4 代:逗号 / 句点

用于 Kdenlive 20.08.0 至 22.12.3 版本,Kdenlive 文档版本:1.00

在 20.08.0 版本中,对工程文件的一次重大重构修复了一个长期存在的小数分隔符 (opens in a new tab)(逗号/句点)冲突问题——该问题曾导致许多崩溃。用 20.08 及之后版本创建的工程不向后兼容。

为支持新功能,还做了一些小的更新,例如:

  • 20.12.0:引入了同轨混合(Mixes,即同轨转场 in-track-transitions)

第 5 代:当前格式

用于 Kdenlive 23.04.0 起的版本,Kdenlive 文档版本:1.1

Kdenlive 23.04.0 引入了一项重要变化:多时间线序列(multiple sequences)。每个时间线序列片段都嵌入在一个 MLT tractor(牵引器)中。 "main_bin" 播放列表(playlist)以*条目(entries)*的形式列出工程中使用的所有片段和时间线序列。

工程文件中最后一个 tractor 只是最近打开的时间线序列的一个包装器,这样当通过 melt 命令行播放工程文件时,它会播放最后激活的序列片段。

此前,所有时间线属性都以 kdenlive:documentproperty. 的形式存储在 "main_bin" 播放列表中。在新格式下,所有时间线属性都存储在各自的时间线序列内部,形如 kdenlive:sequenceproperty.,而 "main_bin" 中只存储全局工程设置。

工程 XML 结构

Kdenlive 工程文件内部 XML 数据的总体结构大致如下图所示:

<mlt producer="main_bin" ...>
 
  <!-- the profile - definition of the project profile (frame size, aspect ration, etc) -->
  <profile frame_rate_num="25" .../>
 
  <!-- definition of master and timeline clips used in the first sequence clips -->
  <producer id="producer0" .../>
  <producer id="producer1" .../>
 
  <!-- then comes the playlist definition - a list of the empty spaces and clips on a track -->
  <playlist id="playlist0">
    <!-- entries linking to the producers defined above -->
    <entry producer="producer0" in="00:00:00.000" out="00:00:04.960">
      <property name="kdenlive:id">3</property>
    </entry>
    <blank length="00:00:03.720"/> <!-- space between clips -->
    <entry producer="producer1" />
    ...
  <playlist id="playlist1"/>
 
  <!-- After that we have the tracks embedded in a tractor. Each Kdenlive timeline track is made of 2 *tracks* to allow mixes-->
  <tractor id="tractor0" in="00:00:00.000" out="00:02:20.840">
    <property name="kdenlive:..">...</property>
    ...
    <track hide="audio" producer="playlist0"/> <!-- hide audio, because this is a video track -->
    <track hide="audio" producer="playlist1"/>
  </tractor>
 
  <!-- After the tracks definition, we have the first timeline sequence tractor that has a kdenlive:uuid attribute, and transitions between the tracks -->
  <tractor id="tractor6" ...>
    <property name="kdenlive:uuid">...</property>
    <track hide="audio" producer="tractor0"/>
    <track hide="audio" producer="tractor1"/>
 
    <!-- all transitions -->
    <transition id="transition0"/> <!-- user transitions -->
    <transition id="transition1"> <!-- internally added transition (for example audio mix) -->
      <property name="internal_added">237</property>
    </transition>
 
    </tractor>
 
  <!-- If we have multiple timeline sequence clips, we repeat the above steps -->
  <producer id="producer3" .../>
  <playlist id="playlist3" ../>
  <tractor id="tractor7" .../>
  <tractor id="tractor11" ...>
    <property name="kdenlive:uuid">...</property>
    <track hide="audio" producer="tractor7"/>
    <track hide="audio" producer="tractor8"/>
  </tractor>
 
  <!-- The *main bin* playlist, keeping all project settings, and a list of all project bin clips, including the sequence clips  -->
  <playlist id="main_bin">
    <property name="kdenlive:documentproperty...">...</property>
    <entry producer="producer0" .../>
    <entry producer="producer1" .../>
    <entry producer="tractor6" .../>
    <entry producer="tractor11" .../>
  </playlist>
 
  <!-- the last tractor of the xml file only contains one producerm is a the main tractor, containing the default sequence clip that will be played -->
  <tractor id="tractor23" in="00:00:00.000" out="00:00:45.000">
    <property name="kdenlive:projectTractor">1</property>
    <track producer="tractor11" in="00:00:00.000" out="00:00:45.000"/>
 </tractor>
 
</mlt>

我们避免存储任何在外层 MLT 数据层中已经存在的内层 Kdenlive 工程数据,这意味着所有信息都必须存储在 MLT 对象中,如 Tractor、Playlist、Producer 等。

为了把这些属性与其他 MLT 属性区分开,我们给它们加上 kdenlive: 前缀。本页列出了我们在新文件格式中使用的这些属性。

应用于工程片段(MLT Producer 对象)的属性:

名称描述
kdenlive:clipname存储该片段在工程素材箱(Project Bin)中显示的名称。
kdenlive:folderid存储一个字符串,包含该片段所在文件夹的 id(若片段位于根文件夹则为空)。
kdenlive:zone_in存储为该片段定义的播放区域的 "in"(入点)。
kdenlive:zone_out存储为该片段定义的播放区域的 "out"(出点)。
kdenlive:originalurl存储片段的原始 url。在片段被代理(proxy)后,可用于取回原始 url。
kdenlive:proxy存储代理片段的 url;若该片段不应使用代理,则为 "-"。
kdenlive:clip_type
kdenlive:id
kdenlive:file_size
kdenlive:file_hash
kdenlive:audio_max1

素材箱(Project Bin)

(工程)素材箱(bin)由一个具有众所周知 id "main_bin" 的 MLT <playlist> 元素表示。该元素保存工程专属的(元)数据、素材箱文件夹及其层级结构、片段组,以及其他一些内容。

注意

尽管 Kdenlive 现在提到早先的"project bin(工程箱)"时主要使用"bin(素材箱)"一词,但早期形成的内部名称 "name bin" 自 Kdenlive 创建之初就一直沿用至今。

应用于素材箱播放列表(MLT Playlist 对象 "main_bin")的属性:

名称描述
kdenlive:folder.xxx.yyy此属性存储在工程素材箱中创建的文件夹名称。xxx 是父文件夹的 id(根文件夹为 -1),yyy 是该文件夹自身的 id。此属性的值即文件夹的名称。
kdenlive:docproperties.*有一系列带此前缀的属性,持有与当前工程相关的设置,例如代理尺寸
kdenlive:documentnotes
kdenlive:docproperties.groups此属性持有一个 json 结构,表示时间线上的片段组

时间线轨道

时间线轨道的布局由一个 MLT <tractor> 元素表示,这个 "maintractor" 可以通过它是文件中最后一个 <tractor> 来识别。其内部的元素就是各个时间线轨道:这些轨道以引用的形式出现,而实际轨道则是 MLT 生产器(producer)。

各个 Kdenlive 时间线轨道以持有 <playlist> 元素的 MLT <tractor> 元素的形式存在。它们也很容易按其 "tractor#"/"playlist#" 的 id 命名方案来识别;其中 "#" 是 Kdenlive 内部维护的一个编号。这些轨道还带有额外的属性,描述其标题、锁定状态以及其他一些信息。之所以多出 <playlist> 元素这一层结构,是为了支持混合(mixes,见下文)。

这里有一条半内部性质的轨道,即内置的 "black_track"。从这里可以看到,它虽然内置于 Kdenlive,却并不内置于 MLT。对 MLT 而言,这只是又一条恰好由 Kdenlive 创建的轨道。Kdenlive 从不会在时间线上把这条背景轨道作为单独轨道显示出来。但你可以在转场(transition)中引用它(指 composite 合成类转场)。

字幕轨道

对用户而言,这条字幕轨道感觉上就像一条音频或视频轨道,但事实上它并不是。它是一条"假"轨道,内部其实是一个滤镜(filter),更确切地说是 avfilter.subtitles (opens in a new tab) 滤镜(另见 这份 ffmpeg 文档 (opens in a new tab))。如果检测到内部的 avfilter.subtitles,字幕轨道就会被启用。

字幕存储在项目旁边的一个 *.srt 文件中。如果你的工程名为 mymovie.kdenlive,字幕文件就是 mymovie.kdenlive.srt。只有在保存工程时该文件才会更新;而在编辑工作期间,仅靠内部字幕模型是不够的,因为 avfilter.subtitles 需要一个 *.srt 文件才能在监视器中始终呈现最新的工作状态。因此在临时目录(Linux 上为 /tmp)中还有另一个 *.srt 文件。

字幕轨道在 kdenlive xml 中的表示方式如下:

  <filter id="filter9">
   <property name="mlt_service">avfilter.subtitles</property>
   <property name="internal_added">237</property>
   <property name="av.filename">/tmp/1654509160006.srt</property>
   <property name="kdenlive:locked">1</property>
  </filter>

转场(Compositions)

转场有两(三)种风味,但一律以 MLT <transition> 元素表示:

  • 用户转场(user transitions)是由——你猜到了——用户添加的转场。它们就是目前在时间线轨道及其片段之上略微下移、叠加显示的那些转场。
  • 内部添加的转场(internally added transitions)基本上是一种便利机制,让时间线能够在多条轨道间自动进行音频混合,以及(在较新的 Kdenlive 版本中)实现透明轨道。

同轨转场(Mixes)

TODO

滤镜(效果)

TODO

未展示部分

  • 素材箱片段生产器(bin clip producers)
  • 代理片段(proxy clips)

延伸阅读