I have several video projects from Final Cut Pro that I want to use in KdenLive. I found the OpenTimelineIO project and it would solve all my problems. I installed with
$ python3 -m pip install opentimelineio
...
$ python3 -m pip show opentimelineio
Name: OpenTimelineIO
Version: 0.15.0
I tried the sample code provided on GitHub:
import opentimelineio as otio
timeline = otio.adapters.read_from_file("/path/to/file.fcpxml")
for clip in timeline.find_clips():
print(clip.name, clip.duration())
and I get the error:
File "~/Library/Python/3.8/lib/python/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 998, in _format_id_for_clip
resource = self._compound_clip_by_id(
AttributeError: 'NoneType' object has no attribute 'find'
Following "AttributeError: 'NoneType' object has no attribute 'find'" when converting with OpenTimelineIO , I monkey-patch the source code, changing around line 991:
def _format_id_for_clip(self, clip, default_format):
if not clip.get("ref", None) or clip.tag == "gap":
return default_format
resource = self._asset_by_id(clip.get("ref"))
if resource is None:
resource = self._compound_clip_by_id(
clip.get("ref")
).find("sequence")
To:
def _format_id_for_clip(self, clip, default_format):
if not clip.get("ref", None) or clip.tag == "gap":
return default_format
resource = self._asset_by_id(clip.get("ref"))
if resource is None:
resource = self._compound_clip_by_id(
clip.get("ref")
)
if resource is None:
return default_format
else:
resource = resource.find("sequence")
return resource.get("format", default_format)
Then I get another error:
File "/usr/local/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 1054, in _format_frame_duration
total, rate = media_format.get("frameDuration").split("/")
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'split'
The offending lines are:
# --------------------
# time helpers
# --------------------
def _format_frame_duration(self, format_id):
media_format = self._format_by_id(format_id)
total, rate = media_format.get("frameDuration").split("/")
rate = rate.replace("s", "")
return total, rate
So I printed details on clips, and it seems most are 100/2500s
, so I return that:
def _format_frame_duration(self, format_id):
media_format = self._format_by_id(format_id)
print(media_format)
print(dir(media_format))
try:
print(media_format.__dict__)
print(media_format.__dict__())
except AttributeError:
pass
print([attr for attr in dir(media_format) if attr[:2] + attr[-2:] != '____' and not callable(getattr(media_format,attr))])
print(media_format.attrib)
print(media_format.tag)
print(media_format.tail)
print(media_format.text)
if None is media_format.get("frameDuration"):
return "100", "2500"
total, rate = media_format.get("frameDuration").split("/")
rate = rate.replace("s", "")
return total, rate
And then that command runs, but the next throws an error:
for clip in timeline.find_clips():
^^^^^^^^^^^^^^^^^^^
AttributeError: 'opentimelineio._otio.SerializableCollection' object has no attribute 'find_clips'
I try running the import from Kdenlive and get this error:
File "/usr/local/lib/python3.11/dist-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 938, in _timing_clip
while clip.tag not in ("clip", "asset-clip", "ref-clip"):
^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'tag'
Here is a Dropbox link to a complete FCP XML file that causes this error.
I submitted an issue on GitHub about the second error that I monkey-patched and it has had no activity for 3 months. These issues raise the bar quite a bit and require some knowledge of opentimelineio, so I ask or help here.
How can I further monkey-patch the OpenTimelineIO code to convert this project to Kdenlive?
I think the problem is with your .fcpxml
file. When I debug, it throws an error on the format tag with id="r110"
:
Other format tags have more attributes like frameDuration, as you mentioned:
If you know the correct values for this entry, you can add it on line 1256 and change it from:
<format id="r110" name="FFVideoFormatRateUndefined" width="1920" height="1080"/>
To something like:
<format id="r110" name="FFVideoFormatRateUndefined" width="1920" height="1080" frameDuration="100/2500s"/>
When you fix this, the next error is this:
'NoneType' object has no attribute 'find'
When you face this error, the running variables are:
Which corresponds to the line 3219 of the file:
<title ref="r120" offset="1848900/7500s" name="© Atletismo Emocional para crianças, 2020 - Scrolling" start="3600s" duration="57300/2500s">
The error happens because there are no <asset>
or <media>
elements with id="r120"
.
The r120
reference appears in two tags only, so I removed them and reran the program. This is what to remove:
line 1345 (effect
tag)
line 3218 to 3387 (title
tag)
Lines are approximate
(If you have any information on what id
is used for this reference, put it in the <title>
element, and also you have to create a <format>
element as I saw the code extracts that too. If you don't have the info, then just remove the tags with r120
.)
Now it passes that line and throws another error:
'opentimelineio._otio.SerializableCollection' object has no attribute 'find_clips'
. This is awkward because the problem is with the module itself. The object does not have the method mentioned, and I think the substitution is to use each_clip().
So, to fix it, you have to change this:
timeline.find_clips() -> timeline.each_clip()
This will fix the problem, and it runs without any monkey-patches!