From 76c7d90c8c1c8c1eeb81c893adead84f6be5f7c7 Mon Sep 17 00:00:00 2001 From: "robin@ynput.io" Date: Tue, 14 Jan 2025 18:15:01 +0100 Subject: [PATCH] Add fix + test for image sequence frozen frame. --- client/ayon_core/pipeline/editorial.py | 8 +- .../resources/img_seq_freeze_frame.json | 160 ++++++++++++++++++ .../test_media_range_with_retimes.py | 31 ++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 tests/client/ayon_core/pipeline/editorial/resources/img_seq_freeze_frame.json diff --git a/client/ayon_core/pipeline/editorial.py b/client/ayon_core/pipeline/editorial.py index c027d90d47..9a241087f6 100644 --- a/client/ayon_core/pipeline/editorial.py +++ b/client/ayon_core/pipeline/editorial.py @@ -256,8 +256,14 @@ def remap_range_on_file_sequence(otio_clip, otio_range): rate=available_range_rate, ).to_frames() + # e.g.: + # duration = 10 frames at 24fps + # if frame_in = 1001 then + # frame_out = 1010 + offset_duration = max(0, otio_range.duration.to_frames() - 1) + frame_out = otio.opentime.RationalTime.from_frames( - frame_in + otio_range.duration.to_frames() - 1, + frame_in + offset_duration, rate=available_range_rate, ).to_frames() diff --git a/tests/client/ayon_core/pipeline/editorial/resources/img_seq_freeze_frame.json b/tests/client/ayon_core/pipeline/editorial/resources/img_seq_freeze_frame.json new file mode 100644 index 0000000000..05b48370b2 --- /dev/null +++ b/tests/client/ayon_core/pipeline/editorial/resources/img_seq_freeze_frame.json @@ -0,0 +1,160 @@ +{ + "OTIO_SCHEMA": "Clip.2", + "metadata": {}, + "name": "sh010", + "source_range": { + "OTIO_SCHEMA": "TimeRange.1", + "duration": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 23.976024627685547, + "value": 5.0 + }, + "start_time": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 23.976024627685547, + "value": 909990.8339241028 + } + }, + "effects": [ + { + "OTIO_SCHEMA": "FreezeFrame.1", + "metadata": {}, + "name": "FreezeFrame", + "effect_name": "FreezeFrame", + "time_scalar": 0.0 + } + ], + "markers": [ + { + "OTIO_SCHEMA": "Marker.2", + "metadata": { + "applieswhole": "1", + "hiero_source_type": "TrackItem", + "json_metadata": "{\"hiero_sub_products\": {\"io.ayon.creators.hiero.shot\": {\"id\": \"pyblish.avalon.instance\", \"productType\": \"shot\", \"productName\": \"shotMain\", \"active\": true, \"creator_identifier\": \"io.ayon.creators.hiero.shot\", \"variant\": \"main\", \"folderPath\": \"/shots/hiero_freeze_frame/sh010\", \"task\": null, \"clip_index\": \"85ABEEEA-6A90-CE47-9DE2-73BAB11EE31D\", \"hierarchy\": \"shots/hiero_freeze_frame\", \"folder\": \"shots\", \"episode\": \"ep01\", \"sequence\": \"hiero_freeze_frame\", \"track\": \"Video_1\", \"shot\": \"sh010\", \"reviewableSource\": \"Video 1\", \"sourceResolution\": false, \"workfileFrameStart\": 1001, \"handleStart\": 10, \"handleEnd\": 10, \"parents\": [{\"entity_type\": \"folder\", \"folder_type\": \"folder\", \"entity_name\": \"shots\"}, {\"entity_type\": \"sequence\", \"folder_type\": \"sequence\", \"entity_name\": \"hiero_freeze_frame\"}], \"hierarchyData\": {\"folder\": \"shots\", \"episode\": \"ep01\", \"sequence\": \"hiero_freeze_frame\", \"track\": \"Video_1\"}, \"heroTrack\": true, \"uuid\": \"08ba1c0a-fc51-4275-b6c8-1cb81381b043\", \"reviewTrack\": \"Video 1\", \"review\": true, \"folderName\": \"sh010\", \"label\": \"/shots/hiero_freeze_frame/sh010 shotMain\", \"newHierarchyIntegration\": true, \"instance_id\": \"892de813-fc78-4d92-b25f-4ea5c4791bb8\", \"creator_attributes\": {\"workfileFrameStart\": 1001, \"handleStart\": 10, \"handleEnd\": 10, \"frameStart\": 1001, \"frameEnd\": 1006, \"clipIn\": 0, \"clipOut\": 4, \"clipDuration\": 5, \"sourceIn\": 181.0, \"sourceOut\": 181.0, \"fps\": \"from_selection\"}, \"publish_attributes\": {\"CollectSlackFamilies\": {\"additional_message\": \"\"}}}, \"io.ayon.creators.hiero.plate\": {\"id\": \"pyblish.avalon.instance\", \"productType\": \"plate\", \"productName\": \"plateVideo_1\", \"active\": true, \"creator_identifier\": \"io.ayon.creators.hiero.plate\", \"variant\": \"Video_1\", \"folderPath\": \"/shots/hiero_freeze_frame/sh010\", \"task\": null, \"clip_index\": \"85ABEEEA-6A90-CE47-9DE2-73BAB11EE31D\", \"hierarchy\": \"shots/hiero_freeze_frame\", \"folder\": \"shots\", \"episode\": \"ep01\", \"sequence\": \"hiero_freeze_frame\", \"track\": \"Video_1\", \"shot\": \"sh010\", \"reviewableSource\": \"Video 1\", \"sourceResolution\": false, \"workfileFrameStart\": 1001, \"handleStart\": 10, \"handleEnd\": 10, \"parents\": [{\"entity_type\": \"folder\", \"folder_type\": \"folder\", \"entity_name\": \"shots\"}, {\"entity_type\": \"sequence\", \"folder_type\": \"sequence\", \"entity_name\": \"hiero_freeze_frame\"}], \"hierarchyData\": {\"folder\": \"shots\", \"episode\": \"ep01\", \"sequence\": \"hiero_freeze_frame\", \"track\": \"Video_1\"}, \"heroTrack\": true, \"uuid\": \"08ba1c0a-fc51-4275-b6c8-1cb81381b043\", \"reviewTrack\": \"Video 1\", \"review\": true, \"folderName\": \"sh010\", \"parent_instance_id\": \"892de813-fc78-4d92-b25f-4ea5c4791bb8\", \"label\": \"/shots/hiero_freeze_frame/sh010 plateVideo_1\", \"newHierarchyIntegration\": true, \"instance_id\": \"24eb8386-4c42-4439-ac41-17ec4efb0073\", \"creator_attributes\": {\"parentInstance\": \"/shots/hiero_freeze_frame/sh010 shotMain\", \"review\": true, \"reviewableSource\": \"Video 1\"}, \"publish_attributes\": {\"CollectSlackFamilies\": {\"additional_message\": \"\"}}}}, \"clip_index\": \"85ABEEEA-6A90-CE47-9DE2-73BAB11EE31D\"}", + "label": "AYONdata_a8304fcf", + "note": "AYON data container" + }, + "name": "AYONdata_a8304fcf", + "color": "RED", + "marked_range": { + "OTIO_SCHEMA": "TimeRange.1", + "duration": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 23.976024627685547, + "value": 0.0 + }, + "start_time": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 23.976024627685547, + "value": 0.0 + } + } + } + ], + "enabled": true, + "media_references": { + "DEFAULT_MEDIA": { + "OTIO_SCHEMA": "ImageSequenceReference.1", + "metadata": { + "ayon.source.colorspace": "ACES - ACES2065-1", + "ayon.source.height": 720, + "ayon.source.pixelAspect": 1.0, + "ayon.source.width": 1280, + "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": "ACES - ACES2065-1", + "foundry.source.duration": "301", + "foundry.source.filename": "output.%07d.exr 948674-948974", + "foundry.source.filesize": "", + "foundry.source.fragments": "301", + "foundry.source.framerate": "25", + "foundry.source.fullpath": "", + "foundry.source.height": "720", + "foundry.source.layers": "colour", + "foundry.source.path": "C:/Users/robin/OneDrive/Bureau/dev_ayon/data/img_sequence/exr_long_frameRange/output.%07d.exr 948674-948974", + "foundry.source.pixelAspect": "1", + "foundry.source.pixelAspectRatio": "", + "foundry.source.pixelformat": "RGBA (Float16) Open Color IO space: 11", + "foundry.source.reelID": "", + "foundry.source.resolution": "", + "foundry.source.samplerate": "Invalid", + "foundry.source.shortfilename": "output.%07d.exr 948674-948974", + "foundry.source.shot": "", + "foundry.source.shotDate": "", + "foundry.source.startTC": "", + "foundry.source.starttime": "948674", + "foundry.source.timecode": "948674", + "foundry.source.umid": "28c4702f-5af7-4980-52c9-6eb875968890", + "foundry.source.umidOriginator": "foundry.source.umid", + "foundry.source.width": "1280", + "foundry.timeline.autodiskcachemode": "Manual", + "foundry.timeline.colorSpace": "ACES - ACES2065-1", + "foundry.timeline.duration": "301", + "foundry.timeline.framerate": "25", + "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,1278,718", + "media.exr.displayWindow": "0,0,1279,719", + "media.exr.lineOrder": "0", + "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": "2025-01-13 14:26:25", + "media.input.filename": "C:/Users/robin/OneDrive/Bureau/dev_ayon/data/img_sequence/exr_long_frameRange/output.0948674.exr", + "media.input.filereader": "exr", + "media.input.filesize": "214941", + "media.input.frame": "1", + "media.input.height": "720", + "media.input.mtime": "2025-01-13 14:26:25", + "media.input.width": "1280", + "media.nuke.full_layer_names": "0", + "media.nuke.node_hash": "b13e3153b31d8f14", + "media.nuke.version": "15.0v5", + "padding": 7 + }, + "name": "", + "available_range": { + "OTIO_SCHEMA": "TimeRange.1", + "duration": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 25.0, + "value": 301.0 + }, + "start_time": { + "OTIO_SCHEMA": "RationalTime.1", + "rate": 25.0, + "value": 948674.0 + } + }, + "available_image_bounds": null, + "target_url_base": "C:/Users/robin/OneDrive/Bureau/dev_ayon/data/img_sequence/exr_long_frameRange\\", + "name_prefix": "output.", + "name_suffix": ".exr", + "start_frame": 948674, + "frame_step": 1, + "rate": 25.0, + "frame_zero_padding": 7, + "missing_frame_policy": "error" + } + }, + "active_media_reference_key": "DEFAULT_MEDIA" +} \ No newline at end of file diff --git a/tests/client/ayon_core/pipeline/editorial/test_media_range_with_retimes.py b/tests/client/ayon_core/pipeline/editorial/test_media_range_with_retimes.py index da257eca58..1041dfe4dd 100644 --- a/tests/client/ayon_core/pipeline/editorial/test_media_range_with_retimes.py +++ b/tests/client/ayon_core/pipeline/editorial/test_media_range_with_retimes.py @@ -351,3 +351,34 @@ def test_img_sequence_2x_speed_resolve(): handle_start=10, handle_end=10, ) + + +def test_img_sequence_frozen_frame(): + """ + Img sequence clip + available files = 948674-948974 25fps + source_range = 909990.8339241028 + - 909995.8339241028 23.976fps + speed = 0.0 + """ + expected_data = { + 'mediaIn': 948855, + 'mediaOut': 948855, + 'handleStart': 0, + 'handleEnd': 0, + 'speed': 0.0, + 'versionData': { + 'retime': True, + 'speed': 0.0, + 'timewarps': [], + 'handleStart': 0, + 'handleEnd': 0, + } + } + + _check_expected_retimed_values( + "img_seq_freeze_frame.json", + expected_data, + handle_start=10, + handle_end=10, + )