I've now settled for Kdenlive. It's cross-platform: Windows, Linux, and macOS. It has a GUI, the source files are text and XML (about 50kB) and can be easily copied, version-controlled and edited with a text editor. The program keeps the rendering cache separate from the source files and it can generate scripts to batch-render multiple files at once. I've been using it for a year and migrated all my relevant projects to it.
It is based on MLT (melt
):
Kdenlive's project files (.kdenlive files) use an XML format, based on MLT's format (see MLT’s XML documentation and MLT’s DTD/document type definition) to describe the source media used in a project, as well as the use of that media as in the timeline.
Here is example project file from the GitHub documentation:
<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>
With some luck, you can export XML from iMovie to Final Cut Pro and then to Premiere, then to OpenTimelineIO, and import into Kdenlive (see a series of threads on StackOverflow about it:
https://stackoverflow.com/questions/77846715/monkey-patching-opentimelineio-adapter-to-import-final-cut-pro-xml
https://stackoverflow.com/questions/78238366/opentimelineio-fcp-xml-import-fails-to-find-clips
https://stackoverflow.com/questions/77974108/opentimelineio-error-from-exporting-a-final-cut-pro-file-with-the-kdenlive-adapt
melt
did you? mltframework.org/docs/meltmelt
) looks very cool! I have never tried it, no. From your other comments, I realized that it's the basis for rendering in Kdenlive and I edited the answer. If you do try it, please consider adding an answer with sample code.