OpenTimelineIO 导入 FCP XML 失败,无法找到剪辑
我在Final Cut Pro和Adobe Premiere中有几个视频项目,想把它们转换到Kdenlive。我找到了OpenTimelineIO,经过一些尝试和StackOverflow的帮助,我得到了这段代码:
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.")
在Kdenlive中的结果显示,剪辑的布局和时间码是正确的,但所有的剪辑都缺失了:
尽管如此,我手动确认了几个剪辑是存在的。
在XML文件中,有一个示例资产是这样的,里面有一个指向外部硬盘剪辑的链接:
<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>
在这一行中,print(item)
对应的项目是这样的:
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={})
所以OpenTimelineIO适配器没有找到任何资产的文件。
我尝试把HTML实体,比如%20
替换成空格,但结果还是一样。
这里有一个Dropbox链接,里面是一个完整的FCP XML文件,导致了这个错误。
我该如何调整XML文件或者修改代码,以便找到这些在外部硬盘上的剪辑呢?
注意:这是一个后续问题,与猴子补丁OpenTimelineIO适配器以导入Final Cut Pro XML和从使用Kdenlive适配器导出Final Cut Pro文件时的OpenTimelineIO错误不同。
1 个回答
otio.schema.MissingReference
在打印出的 otio.schema.Clip
对象中表示 OTIO 找不到在 FCP XML 中引用的媒体文件。
这个问题可能是因为不同应用程序对文件路径的理解方式不同,尤其是当文件存储在外部硬盘或路径中包含 URL 编码字符(比如 %20
代表空格)时。此外,FCP XML 文件 中的原始媒体路径是绝对路径,如果环境或文件系统结构不同(例如在不同操作系统之间移动,或者驱动器挂载点发生变化),那么 OTIO 或 Kdenlive 可能无法直接找到这些路径。
一种简单但手动的方法是调整 FCP XML 文件中的路径,使其正确指向你系统上媒体文件的当前位置。这可能涉及将 %20
替换为空格,并确保路径符合你当前的文件系统布局。但对于有很多文件的大项目来说,这种方法就不太实际了。
一个更可扩展的解决方案是编写一个 Python 脚本,程序化地调整 OTIO 对象中的媒体文件路径,然后再导出到 Kdenlive。你可以遍历 OTIO 对象的层级,找到带有 MissingReference
媒体引用的 Clip
对象,并用有效的路径替换它们(OTIO 适配器)。
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")
确保你的媒体文件可以被软件访问和读取(权限、文件系统访问等)。有时候,问题也可能出在外部硬盘没有在相同的位置或使用相同的驱动器字母/名称挂载。
作为测试,我把一个文件复制到没有空格的位置,比如
/Volumes/multimedia/assets/sound.mp3
,但导入otio.adapters.read_from_file()
仍然显示它是缺失的引用。
我用正确的路径运行你的函数,它在时间线上工作,但在写入 Kdenlive 文件时失败,出现KeyError: ('avformat-novalidate', '/Volumes/multimedia/assets/sound.mp3', None, None)
的错误。
如果我把那个文件复制到内部硬盘并相应调整路径,也会出现同样的错误。
确保在创建新的 ExternalReference
对象时,它们的格式正确,并且所有必要的属性都已设置。Kdenlive(以及它的 OpenTimelineIO 适配器)可能对 媒体引用 有特定的要求,比如需要额外的元数据或使用特定的 URL 方案。
另外,可以参考 Kdenlive OpenTimelineIO 适配器 作为示例。
clip.media_reference = otio.schema.ExternalReference(target_url="file://" + new_path)
仔细检查 URL 方案(file://
)和路径,确保它们是完全合格并且格式正确的。
错误信息中的 avformat-novalidate
部分表明尝试引用 FFmpeg 格式或编解码器处理时没有进行验证。确保任何必要的 FFmpeg 库或工具已安装并可以被 OpenTimelineIO 或 Kdenlive 适配器访问。这可能涉及设置环境变量或正确配置路径。
尝试增强媒体引用创建和使用过程中的日志记录或调试输出,以准确找出故障发生的地方。这可能会提供更多关于为什么出现 KeyError
的上下文,以及媒体引用的哪个部分没有按预期处理。