generated from OpenTimelineIO/otio-plugin-template
-
Notifications
You must be signed in to change notification settings - Fork 7
Open
Description
I am trying to export a minimal timeline (only one audio track) with the fcpx_xml adapter, and open the timeline in Final Cut Pro X.
Exporting this timeline without adapters works without any problems. However, when using the fcpx_xml adater it raises an error.
Here is a minimal code example written in python and the stack trace:
import os
from pathlib import Path
from zipfile import ZipFile
from hachoir.parser import createParser
from hachoir.metadata import extractMetadata
import opentimelineio as otio
def write_zipfile(archive_name: str, timeline_file: Path, songfile: Path, clip_files: list[str], logdir: str) -> None:
# writes the timeline_file together with the songfile and clip_files into one zip archive
with ZipFile(archive_name, "w") as archive:
for clip_file in clip_files:
archive.write(os.path.join(logdir, clip_file), os.path.join("media",clip_file))
archive.write(os.path.join(timeline_file), timeline_file.name)
archive.write(songfile, os.path.join("media",songfile.name))
def get_song_duration(songfile_path: Path):
# returns the duration of the songfile in seconds
song_parser = createParser(str(songfile_path.resolve()))
song_metadata = extractMetadata(song_parser)
return song_metadata.get("duration").total_seconds()
def main(songfile_path: Path):
# create the timeline and track objects
tl = otio.schema.Timeline(name="Storyline")
tr_audio = otio.schema.Track(name="Audio", kind=otio.schema.Track.Kind.Audio)
tl.tracks.append(tr_audio)
# create the audio clip and append to the audio track
song_duration = get_song_duration(songfile_path)
cl_audio = otio.schema.Clip(
name=str(songfile_path.stem),
media_reference=otio.schema.ExternalReference(
target_url="media/"+str(songfile_path.name),
available_range=otio.opentime.TimeRange(
start_time=otio.opentime.RationalTime(0, 1),
duration=otio.opentime.RationalTime(song_duration, 1),
)
),
source_range=otio.opentime.TimeRange(
start_time=otio.opentime.RationalTime(0, 1),
duration=otio.opentime.RationalTime(song_duration, 1),
)
)
tr_audio.append(cl_audio)
# export timeline with fcpx_adapter
fcp_xml_timeline_file = "timeline.fcpxml"
otio.adapters.write_to_file(tl, fcp_xml_timeline_file, adapter_name="fcpx_xml")
archive_name = "timeline_fcpx_xml.zip"
write_zipfile(archive_name, Path(fcp_xml_timeline_file), songfile_path, [], "")Traceback (most recent call last):
File "/Users/FPJ21JY/Documents/Videographer/playground_fcpxml_adapter.py", line 60, in <module>
main(songfile_path)
File "/Users/FPJ21JY/Documents/Videographer/playground_fcpxml_adapter.py", line 50, in main
otio.adapters.write_to_file(tl, fcp_xml_timeline_file, adapter_name="fcpx_xml")
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio/adapters/__init__.py", line 192, in write_to_file
return adapter.write_to_file(
^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio/adapters/adapter.py", line 192, in write_to_file
result = self.write_to_string(input_otio, **adapter_argument_map)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio/adapters/adapter.py", line 283, in write_to_string
return self._execute_function(
^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio/plugins/python_plugin.py", line 153, in _execute_function
return (getattr(self.module(), func_name)(**kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 1161, in write_to_string
return FcpxOtio(input_otio).to_xml()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 172, in to_xml
top_sequence = self._stack_to_sequence(project.tracks)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 248, in _stack_to_sequence
self._track_for_spine(track, lane_id, spine, compound_clip)
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 271, in _track_for_spine
offset = self._offset_based_on_parent(
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "/Users/FPJ21JY/anaconda3/envs/videographer/lib/python3.11/site-packages/opentimelineio_contrib/adapters/fcpx_xml.py", line 309, in _offset_based_on_parent
parent.get("offset"),
^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get'
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
No labels