From 382ad931c670adbdd52fdf8996bb1d4115d37744 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Nov 2023 14:13:08 +0100 Subject: [PATCH 1/7] resolve: frame duration and handles operation --- openpype/hosts/resolve/api/plugin.py | 53 ++++++++++++++++------------ 1 file changed, 30 insertions(+), 23 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 5c4a92df89..0f6f4d14bd 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -405,26 +405,41 @@ class ClipLoader: self.active_bin ) _clip_property = media_pool_item.GetClipProperty + source_in = int(_clip_property("Start")) + source_out = int(_clip_property("End")) + source_duration = int(_clip_property("Frames")) - # get handles + # get version data frame data from db + frame_start = self.data["versionData"].get("frameStart") + frame_end = self.data["versionData"].get("frameEnd") handle_start = self.data["versionData"].get("handleStart") handle_end = self.data["versionData"].get("handleEnd") - if handle_start is None: - handle_start = int(self.data["assetData"]["handleStart"]) - if handle_end is None: - handle_end = int(self.data["assetData"]["handleEnd"]) - # check frame duration from versionData or assetData - frame_start = self.data["versionData"].get("frameStart") - if frame_start is None: - frame_start = self.data["assetData"]["frameStart"] + # check if source duration is shorter than db frame duration + source_with_handles = True + # make sure all frame data is available + if ( + frame_start is None or + frame_end is None or + handle_start is None or + handle_end is None + ): + # if not then rather assume that source has no handles + source_with_handles = False + else: + # calculate db frame duration + db_frame_duration = ( + # include handles + int(handle_start) + int(handle_end) + + # include frame duration + (int(frame_end) - int(frame_start) + 1) + ) - # check frame duration from versionData or assetData - frame_end = self.data["versionData"].get("frameEnd") - if frame_end is None: - frame_end = self.data["assetData"]["frameEnd"] - - db_frame_duration = int(frame_end) - int(frame_start) + 1 + # compare source duration with db frame duration + # and assume that source has no handles if source duration + # is shorter than db frame duration + if source_duration < db_frame_duration: + source_with_handles = False # get timeline in timeline_start = self.active_timeline.GetStartFrame() @@ -436,14 +451,6 @@ class ClipLoader: timeline_in = int( timeline_start + self.data["assetData"]["clipIn"]) - source_in = int(_clip_property("Start")) - source_out = int(_clip_property("End")) - source_duration = int(_clip_property("Frames")) - - # check if source duration is shorter than db frame duration - source_with_handles = True - if source_duration < db_frame_duration: - source_with_handles = False # only exclude handles if source has no handles or # if user wants to load without handles From e5e278201b359772e51ae7dafae188753de06a3e Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Fri, 3 Nov 2023 16:18:04 +0100 Subject: [PATCH 2/7] better code explanation --- openpype/hosts/resolve/api/plugin.py | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 0f6f4d14bd..09c5a69d73 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -415,6 +415,19 @@ class ClipLoader: handle_start = self.data["versionData"].get("handleStart") handle_end = self.data["versionData"].get("handleEnd") + """ + There are cases where representation could be published without + handles if the "Extract review output tags" is set to "no_handles". + This would result in a shorter source duration compared to the + db frame-range. In such cases, we need to assume that the source + has no handles. + + To address this, we should compare the duration of the source + frame with the db frame-range. The duration of the db frame-range + should be calculated from the version data. If, for any reason, + the frame data is missing in the version data, we should again + assume that the source has no handles. + """ # check if source duration is shorter than db frame duration source_with_handles = True # make sure all frame data is available @@ -771,7 +784,7 @@ class PublishClip: # increasing steps by index of rename iteration self.count_steps *= self.rename_index - hierarchy_formatting_data = dict() + hierarchy_formatting_data = {} _data = self.timeline_item_default_data.copy() if self.ui_inputs: # adding tag metadata from ui @@ -867,7 +880,7 @@ class PublishClip: def _convert_to_entity(self, key): """ Converting input key to key with type. """ # convert to entity type - entity_type = self.types.get(key, None) + entity_type = self.types.get(key) assert entity_type, "Missing entity type for `{}`".format( key From 2c0d1b5c2bd3efb9e0740b0d5324a588533459e1 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 9 Nov 2023 13:56:08 +0100 Subject: [PATCH 3/7] improving the logic for handles operation --- openpype/hosts/resolve/api/plugin.py | 23 ++++++++++++++--------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 09c5a69d73..886615c7aa 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -410,10 +410,16 @@ class ClipLoader: source_duration = int(_clip_property("Frames")) # get version data frame data from db - frame_start = self.data["versionData"].get("frameStart") - frame_end = self.data["versionData"].get("frameEnd") - handle_start = self.data["versionData"].get("handleStart") - handle_end = self.data["versionData"].get("handleEnd") + version_data = self.data["versionData"] + frame_start = version_data.get("frameStart") + frame_end = version_data.get("frameEnd") + + if self.with_handles: + handle_start = version_data.get("handleStart") or 0 + handle_end = version_data.get("handleEnd") or 0 + else: + handle_start = 0 + handle_end = 0 """ There are cases where representation could be published without @@ -434,8 +440,8 @@ class ClipLoader: if ( frame_start is None or frame_end is None or - handle_start is None or - handle_end is None + handle_start is 0 or + handle_end is 0 ): # if not then rather assume that source has no handles source_with_handles = False @@ -464,12 +470,11 @@ class ClipLoader: timeline_in = int( timeline_start + self.data["assetData"]["clipIn"]) - # only exclude handles if source has no handles or # if user wants to load without handles if ( - not self.with_handles - or not source_with_handles + not self.with_handles # set by user + or not source_with_handles # result of source duration check ): source_in += handle_start source_out -= handle_end From 6fa92ebc14204c3c723a0b2a1d42ba492d10ff30 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 9 Nov 2023 14:40:33 +0100 Subject: [PATCH 4/7] resolve: clip data should be integer rather then timecode --- openpype/hosts/resolve/api/lib.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/openpype/hosts/resolve/api/lib.py b/openpype/hosts/resolve/api/lib.py index aef9caca78..3866477c77 100644 --- a/openpype/hosts/resolve/api/lib.py +++ b/openpype/hosts/resolve/api/lib.py @@ -298,7 +298,7 @@ def create_timeline_item( if source_end: clip_data["endFrame"] = source_end if timecode_in: - clip_data["recordFrame"] = timecode_in + clip_data["recordFrame"] = timeline_in # add to timeline media_pool.AppendToTimeline([clip_data]) From 85bad0ae3d6f43732b9087583af2e09de55fed40 Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Thu, 9 Nov 2023 14:42:30 +0100 Subject: [PATCH 5/7] hound --- openpype/hosts/resolve/api/plugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 886615c7aa..7cf5913b67 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -440,8 +440,8 @@ class ClipLoader: if ( frame_start is None or frame_end is None or - handle_start is 0 or - handle_end is 0 + handle_start == 0 or + handle_end == 0 ): # if not then rather assume that source has no handles source_with_handles = False @@ -473,8 +473,8 @@ class ClipLoader: # only exclude handles if source has no handles or # if user wants to load without handles if ( - not self.with_handles # set by user - or not source_with_handles # result of source duration check + not self.with_handles # set by user + or not source_with_handles # result of source duration check ): source_in += handle_start source_out -= handle_end From 497e3ec9624e3d8090c9fa16caa49b1ab5a8c7a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jakub=20Je=C5=BEek?= Date: Tue, 28 Nov 2023 21:32:42 +0100 Subject: [PATCH 6/7] Update openpype/hosts/resolve/api/plugin.py Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- openpype/hosts/resolve/api/plugin.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 9f1d8fc1c7..2f1f4d3545 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -439,10 +439,10 @@ class ClipLoader: source_with_handles = True # make sure all frame data is available if ( - frame_start is None or - frame_end is None or - handle_start == 0 or - handle_end == 0 + frame_start is None + or frame_end is None + or handle_start == 0 + or handle_end == 0 ): # if not then rather assume that source has no handles source_with_handles = False From 7c25e4a664fc062b581ee183329d2811f784ec7c Mon Sep 17 00:00:00 2001 From: Jakub Jezek Date: Tue, 28 Nov 2023 21:49:05 +0100 Subject: [PATCH 7/7] fixing the logic from @bigroy https://github.com/ynput/OpenPype/pull/5863/files#r1381847587 --- openpype/hosts/resolve/api/plugin.py | 83 ++++++++++------------------ 1 file changed, 28 insertions(+), 55 deletions(-) diff --git a/openpype/hosts/resolve/api/plugin.py b/openpype/hosts/resolve/api/plugin.py index 2f1f4d3545..a00933405f 100644 --- a/openpype/hosts/resolve/api/plugin.py +++ b/openpype/hosts/resolve/api/plugin.py @@ -410,56 +410,38 @@ class ClipLoader: source_out = int(_clip_property("End")) source_duration = int(_clip_property("Frames")) - # get version data frame data from db - version_data = self.data["versionData"] - frame_start = version_data.get("frameStart") - frame_end = version_data.get("frameEnd") - - if self.with_handles: - handle_start = version_data.get("handleStart") or 0 - handle_end = version_data.get("handleEnd") or 0 - else: + if not self.with_handles: + # Load file without the handles of the source media + # We remove the handles from the source in and source out + # so that the handles are excluded in the timeline handle_start = 0 handle_end = 0 - """ - There are cases where representation could be published without - handles if the "Extract review output tags" is set to "no_handles". - This would result in a shorter source duration compared to the - db frame-range. In such cases, we need to assume that the source - has no handles. + # get version data frame data from db + version_data = self.data["versionData"] + frame_start = version_data.get("frameStart") + frame_end = version_data.get("frameEnd") - To address this, we should compare the duration of the source - frame with the db frame-range. The duration of the db frame-range - should be calculated from the version data. If, for any reason, - the frame data is missing in the version data, we should again - assume that the source has no handles. - """ - # check if source duration is shorter than db frame duration - source_with_handles = True - # make sure all frame data is available - if ( - frame_start is None - or frame_end is None - or handle_start == 0 - or handle_end == 0 - ): - # if not then rather assume that source has no handles - source_with_handles = False - else: - # calculate db frame duration - db_frame_duration = ( - # include handles - int(handle_start) + int(handle_end) + - # include frame duration - (int(frame_end) - int(frame_start) + 1) - ) - - # compare source duration with db frame duration - # and assume that source has no handles if source duration - # is shorter than db frame duration - if source_duration < db_frame_duration: - source_with_handles = False + # The version data usually stored the frame range + handles of the + # media however certain representations may be shorter because they + # exclude those handles intentionally. Unfortunately the + # representation does not store that in the database currently; + # so we should compensate for those cases. If the media is shorter + # than the frame range specified in the database we assume it is + # without handles and thus we do not need to remove the handles + # from source and out + if frame_start is not None and frame_end is not None: + # Version has frame range data, so we can compare media length + handle_start = version_data.get("handleStart", 0) + handle_end = version_data.get("handleEnd", 0) + frame_start_handle = frame_start - handle_start + frame_end_handle = frame_start + handle_end + database_frame_duration = int( + frame_end_handle - frame_start_handle + 1 + ) + if source_duration >= database_frame_duration: + source_in += handle_start + source_out -= handle_end # get timeline in timeline_start = self.active_timeline.GetStartFrame() @@ -471,15 +453,6 @@ class ClipLoader: timeline_in = int( timeline_start + self.data["assetData"]["clipIn"]) - # only exclude handles if source has no handles or - # if user wants to load without handles - if ( - not self.with_handles # set by user - or not source_with_handles # result of source duration check - ): - source_in += handle_start - source_out -= handle_end - # make track item from source in bin as item timeline_item = lib.create_timeline_item( media_pool_item,