mirror of
https://github.com/ynput/ayon-core.git
synced 2025-12-24 21:04:40 +01:00
Fix multiple review clips in OTIO review plugins with tests.
This commit is contained in:
parent
7bd382a187
commit
41302936c2
4 changed files with 1969 additions and 45 deletions
|
|
@ -100,30 +100,30 @@ class ExtractOTIOReview(publish.Extractor):
|
|||
for index, r_otio_cl in enumerate(otio_review_clips):
|
||||
# QUESTION: what if transition on clip?
|
||||
|
||||
# check if resolution is the same as source
|
||||
otio_media = r_otio_cl.media_reference
|
||||
media_metadata = otio_media.metadata
|
||||
|
||||
# get from media reference metadata source
|
||||
# TODO 'openpype' prefix should be removed (added 24/09/03)
|
||||
# NOTE it looks like it is set only in hiero integration
|
||||
res_data = {"width": self.to_width, "height": self.to_height}
|
||||
for key in res_data:
|
||||
for meta_prefix in ("ayon.source.", "openpype.source."):
|
||||
meta_key = f"{meta_prefix}.{key}"
|
||||
value = media_metadata.get(meta_key)
|
||||
if value is not None:
|
||||
res_data[key] = value
|
||||
break
|
||||
|
||||
self.to_width, self.to_height = res_data["width"], res_data["height"]
|
||||
self.log.debug("> self.to_width x self.to_height: {} x {}".format(
|
||||
self.to_width, self.to_height
|
||||
))
|
||||
|
||||
# Clip: compute process range from available media range.
|
||||
src_range = r_otio_cl.source_range
|
||||
if isinstance(r_otio_cl, otio.schema.Clip):
|
||||
# check if resolution is the same as source
|
||||
media_ref = r_otio_cl.media_reference
|
||||
media_metadata = media_ref.metadata
|
||||
|
||||
# get from media reference metadata source
|
||||
# TODO 'openpype' prefix should be removed (added 24/09/03)
|
||||
# NOTE it looks like it is set only in hiero integration
|
||||
res_data = {"width": self.to_width, "height": self.to_height}
|
||||
for key in res_data:
|
||||
for meta_prefix in ("ayon.source.", "openpype.source."):
|
||||
meta_key = f"{meta_prefix}.{key}"
|
||||
value = media_metadata.get(meta_key)
|
||||
if value is not None:
|
||||
res_data[key] = value
|
||||
break
|
||||
|
||||
self.to_width, self.to_height = res_data["width"], res_data["height"]
|
||||
self.log.debug("> self.to_width x self.to_height: {} x {}".format(
|
||||
self.to_width, self.to_height
|
||||
))
|
||||
|
||||
available_range = r_otio_cl.available_range()
|
||||
processing_range = None
|
||||
self.actual_fps = available_range.duration.rate
|
||||
|
|
@ -135,7 +135,6 @@ class ExtractOTIOReview(publish.Extractor):
|
|||
# source range for image sequence. Following code maintain
|
||||
# backward-compatibility by adjusting available range
|
||||
# while we are updating those.
|
||||
media_ref = r_otio_cl.media_reference
|
||||
if (
|
||||
is_clip_from_media_sequence(r_otio_cl)
|
||||
and available_range.start_time.to_frames() == media_ref.start_frame
|
||||
|
|
@ -154,11 +153,11 @@ class ExtractOTIOReview(publish.Extractor):
|
|||
duration = src_range.duration
|
||||
|
||||
# Create handle offsets.
|
||||
handle_start = otio.opentime.RationalTime(
|
||||
clip_handle_start = otio.opentime.RationalTime(
|
||||
handle_start,
|
||||
rate=self.actual_fps,
|
||||
)
|
||||
handle_end = otio.opentime.RationalTime(
|
||||
clip_handle_end = otio.opentime.RationalTime(
|
||||
handle_end,
|
||||
rate=self.actual_fps,
|
||||
)
|
||||
|
|
@ -166,16 +165,16 @@ class ExtractOTIOReview(publish.Extractor):
|
|||
# reframing handles conditions
|
||||
if (len(otio_review_clips) > 1) and (index == 0):
|
||||
# more clips | first clip reframing with handle
|
||||
start -= handle_start
|
||||
duration += handle_start
|
||||
start -= clip_handle_start
|
||||
duration += clip_handle_start
|
||||
elif len(otio_review_clips) > 1 \
|
||||
and (index == len(otio_review_clips) - 1):
|
||||
# more clips | last clip reframing with handle
|
||||
duration += handle_end
|
||||
duration += clip_handle_end
|
||||
elif len(otio_review_clips) == 1:
|
||||
# one clip | add both handles
|
||||
start -= handle_start
|
||||
duration += (handle_start + handle_end)
|
||||
start -= clip_handle_start
|
||||
duration += (clip_handle_start + clip_handle_end)
|
||||
|
||||
if available_range:
|
||||
processing_range = self._trim_available_range(
|
||||
|
|
@ -258,9 +257,9 @@ class ExtractOTIOReview(publish.Extractor):
|
|||
# QUESTION: what if nested track composition is in place?
|
||||
else:
|
||||
# at last process a Gap
|
||||
self._render_segment(gap=duration)
|
||||
self._render_segment(gap=duration.to_frames())
|
||||
# generate used frames
|
||||
self._generate_used_frames(duration)
|
||||
self._generate_used_frames(duration.to_frames())
|
||||
|
||||
# creating and registering representation
|
||||
representation = self._create_representation(start, duration)
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load diff
|
|
@ -0,0 +1,289 @@
|
|||
{
|
||||
"OTIO_SCHEMA": "Track.1",
|
||||
"metadata": {},
|
||||
"name": "Video 2",
|
||||
"source_range": null,
|
||||
"effects": [],
|
||||
"markers": [],
|
||||
"enabled": true,
|
||||
"children": [
|
||||
{
|
||||
"OTIO_SCHEMA": "Gap.1",
|
||||
"metadata": {},
|
||||
"name": "",
|
||||
"source_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 2.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
"markers": [],
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"OTIO_SCHEMA": "Clip.2",
|
||||
"metadata": {},
|
||||
"name": "output",
|
||||
"source_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 88.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
"markers": [],
|
||||
"enabled": true,
|
||||
"media_references": {
|
||||
"DEFAULT_MEDIA": {
|
||||
"OTIO_SCHEMA": "ImageSequenceReference.1",
|
||||
"metadata": {
|
||||
"clip.properties.blendfunc": "0",
|
||||
"clip.properties.colourspacename": "default ()",
|
||||
"clip.properties.domainroot": "",
|
||||
"clip.properties.enabled": "1",
|
||||
"clip.properties.expanded": "1",
|
||||
"clip.properties.opacity": "1",
|
||||
"clip.properties.valuesource": "",
|
||||
"foundry.source.audio": "",
|
||||
"foundry.source.bitmapsize": "0",
|
||||
"foundry.source.bitsperchannel": "0",
|
||||
"foundry.source.channelformat": "integer",
|
||||
"foundry.source.colourtransform": "scene_linear",
|
||||
"foundry.source.duration": "101",
|
||||
"foundry.source.filename": "output.%04d.exr 1000-1100",
|
||||
"foundry.source.filesize": "",
|
||||
"foundry.source.fragments": "101",
|
||||
"foundry.source.framerate": "24",
|
||||
"foundry.source.fullpath": "",
|
||||
"foundry.source.height": "1080",
|
||||
"foundry.source.layers": "colour",
|
||||
"foundry.source.pixelAspect": "1",
|
||||
"foundry.source.pixelAspectRatio": "",
|
||||
"foundry.source.pixelformat": "RGBA (Float16) Open Color IO space: 7",
|
||||
"foundry.source.reelID": "",
|
||||
"foundry.source.resolution": "",
|
||||
"foundry.source.samplerate": "Invalid",
|
||||
"foundry.source.shortfilename": "output.%04d.exr 1000-1100",
|
||||
"foundry.source.shot": "",
|
||||
"foundry.source.shotDate": "",
|
||||
"foundry.source.startTC": "",
|
||||
"foundry.source.starttime": "1000",
|
||||
"foundry.source.timecode": "87399",
|
||||
"foundry.source.umid": "bbfe0c90-5b76-424a-6351-4dac36a8dde7",
|
||||
"foundry.source.umidOriginator": "foundry.source.umid",
|
||||
"foundry.source.width": "1920",
|
||||
"foundry.timeline.autodiskcachemode": "Manual",
|
||||
"foundry.timeline.colorSpace": "scene_linear",
|
||||
"foundry.timeline.duration": "101",
|
||||
"foundry.timeline.framerate": "24",
|
||||
"foundry.timeline.outputformat": "",
|
||||
"foundry.timeline.poster": "0",
|
||||
"foundry.timeline.posterLayer": "colour",
|
||||
"foundry.timeline.readParams": "AAAAAQAAAAAAAAAFAAAACmNvbG9yc3BhY2UAAAAFaW50MzIAAAAAAAAAC2VkZ2VfcGl4ZWxzAAAABWludDMyAAAAAAAAABFpZ25vcmVfcGFydF9uYW1lcwAAAARib29sAAAAAAhub3ByZWZpeAAAAARib29sAAAAAB5vZmZzZXRfbmVnYXRpdmVfZGlzcGxheV93aW5kb3cAAAAEYm9vbAE=",
|
||||
"foundry.timeline.samplerate": "Invalid",
|
||||
"isSequence": true,
|
||||
"media.exr.channels": "B:{1 0 1 1},G:{1 0 1 1},R:{1 0 1 1}",
|
||||
"media.exr.compression": "2",
|
||||
"media.exr.compressionName": "Zip (1 scanline)",
|
||||
"media.exr.dataWindow": "1,1,1918,1078",
|
||||
"media.exr.displayWindow": "0,0,1919,1079",
|
||||
"media.exr.lineOrder": "0",
|
||||
"media.exr.nuke.input.frame_rate": "24",
|
||||
"media.exr.nuke.input.timecode": "01:00:41:15",
|
||||
"media.exr.pixelAspectRatio": "1",
|
||||
"media.exr.screenWindowCenter": "0,0",
|
||||
"media.exr.screenWindowWidth": "1",
|
||||
"media.exr.type": "scanlineimage",
|
||||
"media.exr.version": "1",
|
||||
"media.input.bitsperchannel": "16-bit half float",
|
||||
"media.input.ctime": "2024-09-23 08:37:23",
|
||||
"media.input.filereader": "exr",
|
||||
"media.input.filesize": "1095868",
|
||||
"media.input.frame": "1",
|
||||
"media.input.frame_rate": "24",
|
||||
"media.input.height": "1080",
|
||||
"media.input.mtime": "2024-09-23 08:37:23",
|
||||
"media.input.timecode": "01:00:41:15",
|
||||
"media.input.width": "1920",
|
||||
"media.nuke.full_layer_names": "0",
|
||||
"media.nuke.node_hash": "9b",
|
||||
"media.nuke.version": "15.1v2",
|
||||
"openpype.source.colourtransform": "scene_linear",
|
||||
"openpype.source.height": 1080,
|
||||
"openpype.source.pixelAspect": 1.0,
|
||||
"openpype.source.width": 1920,
|
||||
"padding": 4
|
||||
},
|
||||
"name": "",
|
||||
"available_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 101.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 1000.0
|
||||
}
|
||||
},
|
||||
"available_image_bounds": null,
|
||||
"target_url_base": "C:\\with_tc",
|
||||
"name_prefix": "output.",
|
||||
"name_suffix": ".exr",
|
||||
"start_frame": 1000,
|
||||
"frame_step": 1,
|
||||
"rate": 24.0,
|
||||
"frame_zero_padding": 4,
|
||||
"missing_frame_policy": "error"
|
||||
}
|
||||
},
|
||||
"active_media_reference_key": "DEFAULT_MEDIA"
|
||||
},
|
||||
{
|
||||
"OTIO_SCHEMA": "Clip.2",
|
||||
"metadata": {},
|
||||
"name": "output",
|
||||
"source_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 11.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 0.0
|
||||
}
|
||||
},
|
||||
"effects": [],
|
||||
"markers": [],
|
||||
"enabled": true,
|
||||
"media_references": {
|
||||
"DEFAULT_MEDIA": {
|
||||
"OTIO_SCHEMA": "ImageSequenceReference.1",
|
||||
"metadata": {
|
||||
"clip.properties.blendfunc": "0",
|
||||
"clip.properties.colourspacename": "default ()",
|
||||
"clip.properties.domainroot": "",
|
||||
"clip.properties.enabled": "1",
|
||||
"clip.properties.expanded": "1",
|
||||
"clip.properties.opacity": "1",
|
||||
"clip.properties.valuesource": "",
|
||||
"foundry.source.audio": "",
|
||||
"foundry.source.bitmapsize": "0",
|
||||
"foundry.source.bitsperchannel": "0",
|
||||
"foundry.source.channelformat": "integer",
|
||||
"foundry.source.colourtransform": "scene_linear",
|
||||
"foundry.source.duration": "101",
|
||||
"foundry.source.filename": "output.%04d.exr 1000-1100",
|
||||
"foundry.source.filesize": "",
|
||||
"foundry.source.fragments": "101",
|
||||
"foundry.source.framerate": "24",
|
||||
"foundry.source.fullpath": "",
|
||||
"foundry.source.height": "1080",
|
||||
"foundry.source.layers": "colour",
|
||||
"foundry.source.pixelAspect": "1",
|
||||
"foundry.source.pixelAspectRatio": "",
|
||||
"foundry.source.pixelformat": "RGBA (Float16) Open Color IO space: 7",
|
||||
"foundry.source.reelID": "",
|
||||
"foundry.source.resolution": "",
|
||||
"foundry.source.samplerate": "Invalid",
|
||||
"foundry.source.shortfilename": "output.%04d.exr 1000-1100",
|
||||
"foundry.source.shot": "",
|
||||
"foundry.source.shotDate": "",
|
||||
"foundry.source.startTC": "",
|
||||
"foundry.source.starttime": "1000",
|
||||
"foundry.source.timecode": "87399",
|
||||
"foundry.source.umid": "bbfe0c90-5b76-424a-6351-4dac36a8dde7",
|
||||
"foundry.source.umidOriginator": "foundry.source.umid",
|
||||
"foundry.source.width": "1920",
|
||||
"foundry.timeline.autodiskcachemode": "Manual",
|
||||
"foundry.timeline.colorSpace": "scene_linear",
|
||||
"foundry.timeline.duration": "101",
|
||||
"foundry.timeline.framerate": "24",
|
||||
"foundry.timeline.outputformat": "",
|
||||
"foundry.timeline.poster": "0",
|
||||
"foundry.timeline.posterLayer": "colour",
|
||||
"foundry.timeline.readParams": "AAAAAQAAAAAAAAAFAAAACmNvbG9yc3BhY2UAAAAFaW50MzIAAAAAAAAAC2VkZ2VfcGl4ZWxzAAAABWludDMyAAAAAAAAABFpZ25vcmVfcGFydF9uYW1lcwAAAARib29sAAAAAAhub3ByZWZpeAAAAARib29sAAAAAB5vZmZzZXRfbmVnYXRpdmVfZGlzcGxheV93aW5kb3cAAAAEYm9vbAE=",
|
||||
"foundry.timeline.samplerate": "Invalid",
|
||||
"isSequence": true,
|
||||
"media.exr.channels": "B:{1 0 1 1},G:{1 0 1 1},R:{1 0 1 1}",
|
||||
"media.exr.compression": "2",
|
||||
"media.exr.compressionName": "Zip (1 scanline)",
|
||||
"media.exr.dataWindow": "1,1,1918,1078",
|
||||
"media.exr.displayWindow": "0,0,1919,1079",
|
||||
"media.exr.lineOrder": "0",
|
||||
"media.exr.nuke.input.frame_rate": "24",
|
||||
"media.exr.nuke.input.timecode": "01:00:41:15",
|
||||
"media.exr.pixelAspectRatio": "1",
|
||||
"media.exr.screenWindowCenter": "0,0",
|
||||
"media.exr.screenWindowWidth": "1",
|
||||
"media.exr.type": "scanlineimage",
|
||||
"media.exr.version": "1",
|
||||
"media.input.bitsperchannel": "16-bit half float",
|
||||
"media.input.ctime": "2024-09-23 08:37:23",
|
||||
"media.input.filereader": "exr",
|
||||
"media.input.filesize": "1095868",
|
||||
"media.input.frame": "1",
|
||||
"media.input.frame_rate": "24",
|
||||
"media.input.height": "1080",
|
||||
"media.input.mtime": "2024-09-23 08:37:23",
|
||||
"media.input.timecode": "01:00:41:15",
|
||||
"media.input.width": "1920",
|
||||
"media.nuke.full_layer_names": "0",
|
||||
"media.nuke.node_hash": "9b",
|
||||
"media.nuke.version": "15.1v2",
|
||||
"openpype.source.colourtransform": "scene_linear",
|
||||
"openpype.source.height": 1080,
|
||||
"openpype.source.pixelAspect": 1.0,
|
||||
"openpype.source.width": 1920,
|
||||
"padding": 4
|
||||
},
|
||||
"name": "",
|
||||
"available_range": {
|
||||
"OTIO_SCHEMA": "TimeRange.1",
|
||||
"duration": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 101.0
|
||||
},
|
||||
"start_time": {
|
||||
"OTIO_SCHEMA": "RationalTime.1",
|
||||
"rate": 24.0,
|
||||
"value": 1000.0
|
||||
}
|
||||
},
|
||||
"available_image_bounds": null,
|
||||
"target_url_base": "C:\\with_tc",
|
||||
"name_prefix": "output.",
|
||||
"name_suffix": ".exr",
|
||||
"start_frame": 1000,
|
||||
"frame_step": 1,
|
||||
"rate": 24.0,
|
||||
"frame_zero_padding": 4,
|
||||
"missing_frame_policy": "error"
|
||||
}
|
||||
},
|
||||
"active_media_reference_key": "DEFAULT_MEDIA"
|
||||
}
|
||||
],
|
||||
"kind": "Video"
|
||||
}
|
||||
|
|
@ -37,27 +37,31 @@ class CaptureFFmpegCalls():
|
|||
return ["/path/to/ffmpeg"]
|
||||
|
||||
|
||||
def run_process(file_name: str):
|
||||
def run_process(file_name: str, instance_data: dict = None):
|
||||
"""
|
||||
"""
|
||||
# Get OTIO review data from serialized file_name
|
||||
file_path = os.path.join(_RESOURCE_DIR, file_name)
|
||||
clip = otio.schema.Clip.from_json_file(file_path)
|
||||
|
||||
# Prepare dummy instance and capture call object
|
||||
capture_call = CaptureFFmpegCalls()
|
||||
processor = extract_otio_review.ExtractOTIOReview()
|
||||
Anatomy = NamedTuple("Anatomy", project_name=str)
|
||||
instance = MockInstance(
|
||||
{
|
||||
|
||||
if not instance_data:
|
||||
# Get OTIO review data from serialized file_name
|
||||
file_path = os.path.join(_RESOURCE_DIR, file_name)
|
||||
clip = otio.schema.Clip.from_json_file(file_path)
|
||||
|
||||
instance_data = {
|
||||
"otioReviewClips": [clip],
|
||||
"handleStart": 10,
|
||||
"handleEnd": 10,
|
||||
"workfileFrameStart": 1001,
|
||||
"folderPath": "/dummy/path",
|
||||
"anatomy": Anatomy("test_project"),
|
||||
}
|
||||
)
|
||||
|
||||
instance_data.update({
|
||||
"folderPath": "/dummy/path",
|
||||
"anatomy": Anatomy("test_project"),
|
||||
})
|
||||
instance = MockInstance(instance_data)
|
||||
|
||||
# Mock calls to extern and run plugins.
|
||||
with mock.patch.object(
|
||||
|
|
@ -73,9 +77,14 @@ def run_process(file_name: str):
|
|||
with mock.patch.object(
|
||||
processor,
|
||||
"_get_folder_name_based_prefix",
|
||||
return_value="C:/result/output."
|
||||
return_value="output."
|
||||
):
|
||||
processor.process(instance)
|
||||
with mock.patch.object(
|
||||
processor,
|
||||
"staging_dir",
|
||||
return_value="C:/result/"
|
||||
):
|
||||
processor.process(instance)
|
||||
|
||||
# return all calls made to ffmpeg subprocess
|
||||
return capture_call.calls
|
||||
|
|
@ -103,7 +112,7 @@ def test_image_sequence_with_embedded_tc_and_handles_out_of_range():
|
|||
|
||||
# Report from source exr (1001-1101) with enforce framerate
|
||||
"/path/to/ffmpeg -start_number 1000 -framerate 24.0 -i "
|
||||
"C:\\exr_embedded_tc\\output.%04d.exr -start_number 1001 "
|
||||
f"C:\\exr_embedded_tc{os.sep}output.%04d.exr -start_number 1001 "
|
||||
"C:/result/output.%03d.jpg"
|
||||
]
|
||||
|
||||
|
|
@ -133,7 +142,7 @@ def test_image_sequence_and_handles_out_of_range():
|
|||
# 1001-1095 = source range conformed to 25fps
|
||||
# 1096-1096 = additional 1 tail frames
|
||||
"/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i "
|
||||
"C:\\tif_seq\\output.%04d.tif -start_number 996 C:/result/output.%03d.jpg"
|
||||
f"C:\\tif_seq{os.sep}output.%04d.tif -start_number 996 C:/result/output.%03d.jpg"
|
||||
]
|
||||
|
||||
assert calls == expected
|
||||
|
|
@ -203,3 +212,119 @@ def test_short_movie_tail_gap_handles():
|
|||
]
|
||||
|
||||
assert calls == expected
|
||||
|
||||
def test_multiple_review_clips_no_gap():
|
||||
"""
|
||||
Use multiple review clips (image sequence).
|
||||
Timeline 25fps
|
||||
"""
|
||||
file_path = os.path.join(_RESOURCE_DIR, "multiple_review_clips.json")
|
||||
clips = otio.schema.Track.from_json_file(file_path)
|
||||
instance_data = {
|
||||
"otioReviewClips": clips,
|
||||
"handleStart": 10,
|
||||
"handleEnd": 10,
|
||||
"workfileFrameStart": 1001,
|
||||
}
|
||||
|
||||
calls = run_process(
|
||||
None,
|
||||
instance_data=instance_data
|
||||
)
|
||||
|
||||
expected = [
|
||||
# 10 head black frames generated from gap (991-1000)
|
||||
'/path/to/ffmpeg -t 0.4 -r 25.0 -f lavfi -i color=c=black:s=1280x720 -tune '
|
||||
'stillimage -start_number 991 C:/result/output.%03d.jpg',
|
||||
|
||||
# Alternance 25fps tiff sequence and 24fps exr sequence for 100 frames each
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1001 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 24.0 -i '
|
||||
f'C:\\with_tc{os.sep}output.%04d.exr '
|
||||
'-start_number 1102 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1199 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 24.0 -i '
|
||||
f'C:\\with_tc{os.sep}output.%04d.exr '
|
||||
'-start_number 1300 C:/result/output.%03d.jpg',
|
||||
|
||||
# Repeated 25fps tiff sequence multiple times till the end
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1397 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1498 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1599 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1700 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1801 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 1902 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 2003 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 2104 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 25.0 -i '
|
||||
f'C:\\no_tc{os.sep}output.%04d.tif '
|
||||
'-start_number 2205 C:/result/output.%03d.jpg'
|
||||
]
|
||||
|
||||
assert calls == expected
|
||||
|
||||
def test_multiple_review_clips_with_gap():
|
||||
"""
|
||||
Use multiple review clips (image sequence) with gap.
|
||||
Timeline 24fps
|
||||
"""
|
||||
file_path = os.path.join(_RESOURCE_DIR, "multiple_review_clips_gap.json")
|
||||
clips = otio.schema.Track.from_json_file(file_path)
|
||||
instance_data = {
|
||||
"otioReviewClips": clips,
|
||||
"handleStart": 10,
|
||||
"handleEnd": 10,
|
||||
"workfileFrameStart": 1001,
|
||||
}
|
||||
|
||||
calls = run_process(
|
||||
None,
|
||||
instance_data=instance_data
|
||||
)
|
||||
|
||||
expected = [
|
||||
# Gap on review track (12 frames)
|
||||
'/path/to/ffmpeg -t 0.5 -r 24.0 -f lavfi -i color=c=black:s=1280x720 -tune '
|
||||
'stillimage -start_number 991 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 24.0 -i '
|
||||
f'C:\\with_tc{os.sep}output.%04d.exr '
|
||||
'-start_number 1003 C:/result/output.%03d.jpg',
|
||||
|
||||
'/path/to/ffmpeg -start_number 1000 -framerate 24.0 -i '
|
||||
f'C:\\with_tc{os.sep}output.%04d.exr '
|
||||
'-start_number 1091 C:/result/output.%03d.jpg'
|
||||
]
|
||||
|
||||
assert calls == expected
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue