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
.fcpxmlfile. When I debug, it throws an error on the format tag withid="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 withid="r120".The
r120reference appears in two tags only, so I removed them and reran the program. This is what to remove:line 1345 (
effecttag)line 3218 to 3387 (
titletag)Lines are approximate
(If you have any information on what
idis 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 withr120.)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 useeach_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!