OpenTimelineIO FCP XML import fails to find clips

32 views Asked by At

I have several video projects in Final Cut Pro and Adobe Premiere that I want to convert to Kdenlive. I found OpenTimelineIO and, through trial-and-error and thanks to StackOverflow, got this code:

import opentimelineio as otio

fp = "/path/to/file/ep4_fixed.fcpxml"
output_fp = fp.replace(".fcpxml", ".kdenlive")
assert fp != output_fp

# Load the FCP XML file
input_otio = otio.adapters.read_from_file(fp)

# Extract the first Timeline from the SerializableCollection
timeline = next((item for item in input_otio if isinstance(item, otio.schema.Timeline)), None)

for item in input_otio:
    if isinstance(item, otio.schema.Timeline):
        print("Timeline found")
        print(item)
    else:
        print("Not a timeline: ", item)

if timeline:
    # Save the timeline as a Kdenlive project
    otio.adapters.write_to_file(timeline, output_fp, adapter_name="kdenlive")
else:
    print("No timeline found in the input file.")

The result in Kdenlive suggests that the layout and timecodes of clips are correct, but all the clips are missing:

project in Kdenlive

And yet, I confirm manually that several of the clips exist.

One example asset in the XML file is this, with a link to the clip in an external drive:

        <asset id="r117" name="Duck" uid="8E011DED69D190CFE0018A6D24E90A31" start="0s" duration="518344/44100s" hasAudio="1" audioSources="1" audioChannels="2" audioRate="44100">
            <media-rep kind="original-media" sig="8E011DED69D190CFE0018A6D24E90A31" src="file:///Volumes/Video/BulgyPT.fcpbundle/ep1-6/Original%20Media/Duck.mp3">
                <bookmark>Ym9va8AEA...EAAAAAAAAAA==</bookmark>
            </media-rep>
            <metadata>
                <md key="com.apple.proapps.mio.ingestDate" value="2020-07-05 18:19:58 +0100"/>
            </metadata>
        </asset>

The corresponding item for this asset in the line print(item) is this:

otio.schema.Clip(name='Duck', media_reference=otio.schema.MissingReference(name='', available_range=None, available_image_bounds=None, metadata={}), source_range=otio.opentime.TimeRange(start_time=otio.opentime.RationalTime(value=0, rate=25), duration=otio.opentime.RationalTime(value=170, rate=25)), metadata={})

So the OpenTimelineIO adapter is not finding the files for any assets.

I tried replacing HTML entities, such as %20 with a space, but I get the same result.

Here is a Dropbox link to a complete FCP XML file that causes this error.

How can I adapt the XML file or monkey-patch the code to find these clips in the external drive?

Note: this is a follow-up question to, and different from Monkey-patching OpenTimelineIO adapter to import Final Cut Pro XML and OpenTimelineIO error from exporting a Final Cut Pro file with the Kdenlive adapter .

1

There are 1 answers

2
VonC On

The otio.schema.MissingReference in the printed otio.schema.Clip objects indicates that OTIO could not locate the media files referenced in the FCP XML.

That problem could be due to differences in how file paths are interpreted by different applications, especially when files are stored on external drives or in locations with paths that include URL-encoded characters (like %20 for spaces). Additionally, the original media paths in the FCP XML file are absolute, and if the environment or file system structure differs (e.g., when moving between operating systems or when the drive mount points change), the paths may not be directly resolvable by OTIO or Kdenlive.

A straightforward but manual approach is to adjust the paths in the FCP XML file to point correctly to the media files' current locations on your system. That might involve replacing %20 with spaces and making sure the paths are correct for your current file system layout. But this would be impractical for large projects with many files.

A more scalable solution involves writing a Python script to programmatically adjust the media file paths in the OTIO object before exporting to Kdenlive. You can traverse the OTIO object's hierarchy, identify Clip objects with MissingReference media references, and replace them with valid paths (OTIO adapter).

import opentimelineio as otio
import urllib.parse

def fix_media_references(timeline, base_path):
    for clip in timeline.each_clip():
        if isinstance(clip.media_reference, otio.schema.MissingReference):
            original_src = clip.name  # Assuming the clip name holds the original file name
            new_path = urllib.parse.unquote(base_path + original_src)
            clip.media_reference = otio.schema.ExternalReference(target_url=new_path)

base_media_path = "/path/to/media/files/" 

# Load the timeline from FCP XML
timeline = otio.adapters.read_from_file("path/to/fcpxml")

# Fix the media references
fix_media_references(timeline, base_media_path)

# Export the fixed timeline to Kdenlive
otio.adapters.write_to_file(timeline, "output_path.kdenlive", adapter_name="kdenlive")

Make sure your media files are accessible and readable by the software (permissions, file system access, etc.). Sometimes, issues can also stem from external drives not being mounted in the same location or with the same drive letter/name across sessions or operating systems.


As a test, I copied one file to a location without spaces, e.g. /Volumes/multimedia/assets/sound.mp3, but the import otio.adapters.read_from_file() still shows it as a missing reference.
I run your function with the correct path, it works for the timeline, but fails when writing to the Kdenlive file with KeyError: ('avformat-novalidate', '/Volumes/multimedia/assets/sound.mp3', None, None).
The same error happens if I copy that file to the internal disk and adjust the path correspondingly.

Make sure, when you are creating new ExternalReference objects, they are correctly formed and that all necessary properties are set. Kdenlive (and by extension, its OpenTimelineIO adapter) may have specific expectations for media references, such as requiring additional metadata or using a particular scheme for URLs.
See also, as an illustration, Kdenlive OpenTimelineIO Adapter

clip.media_reference = otio.schema.ExternalReference(target_url="file://" + new_path)

Double-check the URL scheme (file://) and the path, which must be fully qualified and correctly formatted.

The avformat-novalidate part of the error message suggests an attempt to reference an FFmpeg format or codec handling without validating it. Make sure any necessary FFmpeg libraries or tools are installed and accessible to OpenTimelineIO or the Kdenlive adapter. That might involve setting environment variables or configuring paths correctly.

Try to enhance logging or debugging output around the creation and usage of media references to pinpoint exactly where the failure occurs. That might provide more context about why the KeyError is being raised and what part of the media reference is not being handled as expected.