From 5bb3d2f407714d259cdc364c7a34ca1878fbbbdd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 8 Apr 2025 16:34:58 +0200 Subject: [PATCH 01/46] Refactored existing logic for reusing last rendered frame --- .../plugins/publish/extract_review.py | 47 ++++++++++++------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index df87abba91..f3adfdcf74 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -403,12 +403,25 @@ class ExtractReview(pyblish.api.InstancePlugin): files_to_clean = [] if temp_data["input_is_sequence"]: self.log.debug("Checking sequence to fill gaps in sequence..") - files_to_clean = self.fill_sequence_gaps( - files=temp_data["origin_repre"]["files"], - staging_dir=new_repre["stagingDir"], - start_frame=temp_data["frame_start"], - end_frame=temp_data["frame_end"] - ) + + files = temp_data["origin_repre"]["files"] + collections = clique.assemble( + files, + patterns=[clique.PATTERNS["frames"]], + minimum_items=1 + )[0] + if len(collections) != 1: + raise KnownPublishError( + "Multiple collections {} found.".format(collections)) + + collection = collections[0] + if fill_type == "existing": + files_to_clean = self.fill_sequence_gaps_from_existing( + collection=collection, + staging_dir=new_repre["stagingDir"], + start_frame=temp_data["frame_start"], + end_frame=temp_data["frame_end"], + ) # create or update outputName output_name = new_repre.get("outputName", "") @@ -883,6 +896,13 @@ class ExtractReview(pyblish.api.InstancePlugin): def fill_sequence_gaps(self, files, staging_dir, start_frame, end_frame): # type: (list, str, int, int) -> list + def fill_sequence_gaps_from_existing( + self, + collection, + staging_dir: str, + start_frame: int, + end_frame: int + ) -> list: """Fill missing files in sequence by duplicating existing ones. This will take nearest frame file and copy it with so as to fill @@ -890,7 +910,7 @@ class ExtractReview(pyblish.api.InstancePlugin): hole ahead. Args: - files (list): List of representation files. + collection (clique.collection) staging_dir (str): Path to staging directory. start_frame (int): Sequence start (no matter what files are there) end_frame (int): Sequence end (no matter what files are there) @@ -903,19 +923,12 @@ class ExtractReview(pyblish.api.InstancePlugin): KnownPublishError: if more than one collection is obtained. """ - collections = clique.assemble(files)[0] - if len(collections) != 1: - raise KnownPublishError( - "Multiple collections {} found.".format(collections)) - - col = collections[0] - # Prepare which hole is filled with what frame # - the frame is filled only with already existing frames - prev_frame = next(iter(col.indexes)) + prev_frame = next(iter(collection.indexes)) hole_frame_to_nearest = {} for frame in range(int(start_frame), int(end_frame) + 1): - if frame in col.indexes: + if frame in collection.indexes: prev_frame = frame else: # Use previous frame as source for hole @@ -923,7 +936,7 @@ class ExtractReview(pyblish.api.InstancePlugin): # Calculate paths added_files = [] - col_format = col.format("{head}{padding}{tail}") + col_format = collection.format("{head}{padding}{tail}") for hole_frame, src_frame in hole_frame_to_nearest.items(): hole_fpath = os.path.join(staging_dir, col_format % hole_frame) src_fpath = os.path.join(staging_dir, col_format % src_frame) From 25a94412396175d3e8934ceb0f838b5c934aa751 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 8 Apr 2025 16:35:50 +0200 Subject: [PATCH 02/46] Added extension to temp_data --- client/ayon_core/plugins/publish/extract_review.py | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index f3adfdcf74..5c1de70c24 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -591,6 +591,8 @@ class ExtractReview(pyblish.api.InstancePlugin): ext = os.path.splitext(repre["files"][0])[1].replace(".", "") if ext.lower() in self.alpha_exts: input_allow_bg = True + else: + ext = os.path.splitext(repre["files"])[1].replace(".", "") return { "fps": float(instance.data["fps"]), @@ -611,7 +613,8 @@ class ExtractReview(pyblish.api.InstancePlugin): "input_allow_bg": input_allow_bg, "with_audio": with_audio, "without_handles": without_handles, - "handles_are_set": handles_are_set + "handles_are_set": handles_are_set, + "ext": ext } def _ffmpeg_arguments( From b5170670065e76baff535076c409d429765ac5ac Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 8 Apr 2025 16:38:37 +0200 Subject: [PATCH 03/46] Implemented new blank frame fills --- .../plugins/publish/extract_review.py | 62 ++++++++++++++++++- 1 file changed, 60 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 5c1de70c24..83893443d9 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -422,6 +422,15 @@ class ExtractReview(pyblish.api.InstancePlugin): start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) + elif fill_type == "blank": + files_to_clean = self.fill_sequence_gaps_with_blanks( + collection=collection, + staging_dir=new_repre["stagingDir"], + resolution_width=temp_data["resolution_width"], + resolution_height=temp_data["resolution_height"], + extension=temp_data["ext"], + ) + # create or update outputName output_name = new_repre.get("outputName", "") @@ -897,8 +906,57 @@ class ExtractReview(pyblish.api.InstancePlugin): return all_args - def fill_sequence_gaps(self, files, staging_dir, start_frame, end_frame): - # type: (list, str, int, int) -> list + def fill_sequence_gaps_with_blanks( + self, + collection: str, + staging_dir: str, + resolution_width: int, + resolution_height: int, + extension: str, + ): + """Fills missing files by blank frame. + + Args: + collection (clique.collection) + staging_dir (str): Path to staging directory. + resolution_width (int): width of source frame + resolution_height (int): height of source frame + extension (str) + + Returns: + list of added files. Those should be cleaned after work + is done. + + """ + blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") + command = get_ffmpeg_tool_args("ffmpeg") + + command.extend([ + "-f", "lavfi", + "-i", "color=c=black:s={}x{}:d=1".format( + resolution_width, resolution_height + ), + "-tune", "stillimage", + "-frames: v" , 1, + blank_frame_path + ]) + + self.log.debug("Executing: {}".format(" ".join(command))) + output = run_subprocess( + command, logger=self.log + ) + self.log.debug("Output: {}".format(output)) + + added_files = [blank_frame_path] + + for missing_frame_name in collection.holes(): + hole_fpath = os.path.join(staging_dir, missing_frame_name) + speedcopy.copyfile(blank_frame_path, hole_fpath) + added_files.append(hole_fpath) + + return added_files + + def fill_sequence_gaps_from_existing( self, collection, From d076f152fd4c13cf4b66ef668537d2ce41cfcecb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 9 Apr 2025 18:22:07 +0200 Subject: [PATCH 04/46] Renamed files_to_clean as now its dictionary --- client/ayon_core/plugins/publish/extract_review.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 83893443d9..ec2569e3f6 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -416,14 +416,14 @@ class ExtractReview(pyblish.api.InstancePlugin): collection = collections[0] if fill_type == "existing": - files_to_clean = self.fill_sequence_gaps_from_existing( + added_frames_and_files = self.fill_sequence_gaps_from_existing( collection=collection, staging_dir=new_repre["stagingDir"], start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) elif fill_type == "blank": - files_to_clean = self.fill_sequence_gaps_with_blanks( + added_frames_and_files = self.fill_sequence_gaps_with_blanks( collection=collection, staging_dir=new_repre["stagingDir"], resolution_width=temp_data["resolution_width"], @@ -487,8 +487,8 @@ class ExtractReview(pyblish.api.InstancePlugin): run_subprocess(subprcs_cmd, shell=True, logger=self.log) # delete files added to fill gaps - if files_to_clean: - for f in files_to_clean: + if added_frames_and_files: + for f in added_frames_and_files.values(): os.unlink(f) new_repre.update({ From 6c404c88e970c872ba4acf860d1d1850d91e80fb Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 9 Apr 2025 18:23:43 +0200 Subject: [PATCH 05/46] Added filling by previous published version --- .../plugins/publish/extract_review.py | 124 +++++++++++++++++- 1 file changed, 123 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index ec2569e3f6..1cffcaf68c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1,3 +1,5 @@ +from __future__ import annotations + import os import re import copy @@ -5,6 +7,7 @@ import json import shutil import subprocess from abc import ABC, abstractmethod +from typing import Dict, Any import clique import speedcopy @@ -29,6 +32,7 @@ from ayon_core.pipeline.publish import ( get_publish_instance_label, ) from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup +from ayon_api import get_last_version_by_product_name, get_representations def frame_to_timecode(frame: int, fps: float) -> str: @@ -430,7 +434,24 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_height=temp_data["resolution_height"], extension=temp_data["ext"], ) - + elif fill_type == "previous": + added_frames_and_files = self.fill_sequence_gaps_with_previous( + collection=collection, + staging_dir=new_repre["stagingDir"], + instance=instance, + current_repre=repre, + start_frame=temp_data["frame_start"], + end_frame=temp_data["frame_end"], + ) + # fallback to original workflow + if added_frames_and_files is None: + added_frames_and_files = self.fill_sequence_gaps_from_existing( + collection=collection, + staging_dir=new_repre["stagingDir"], + start_frame=temp_data["frame_start"], + end_frame=temp_data["frame_end"], + ) + temp_data["filled_files"] = added_frames_and_files # create or update outputName output_name = new_repre.get("outputName", "") @@ -906,6 +927,99 @@ class ExtractReview(pyblish.api.InstancePlugin): return all_args + def fill_sequence_gaps_with_previous( + self, + collection: str, + staging_dir: str, + instance: pyblish.plugin.Instance, + current_repre: Dict[Any, Any], + start_frame: int, + end_frame: int + ) -> Dict[int, str] | None: + """Tries to replace missing frames from ones from last version""" + repre_file_paths = self._get_last_version_files( + instance, current_repre) + if repre_file_paths is None: + # issues in getting last version files, falling back + return None + + prev_collection = clique.assemble( + repre_file_paths, + patterns=[clique.PATTERNS["frames"]], + minimum_items=1 + )[0][0] + prev_col_format = prev_collection.format("{head}{padding}{tail}") + + added_files = {} + anatomy = instance.context.data["anatomy"] + col_format = collection.format("{head}{padding}{tail}") + for frame in range(start_frame, end_frame + 1): + if frame in collection.indexes: + continue + hole_fpath = os.path.join(staging_dir, col_format % frame) + + previous_version_path = prev_col_format % frame + # limits too large padding coming from Anatomy + previous_version_path = ( + os.path.join( + anatomy.fill_root(os.path.dirname(previous_version_path)), + os.path.basename(previous_version_path) + ) + ) + if not os.path.exists(previous_version_path): + self.log.warning( + "Missing frame should be replaced from " + f"'{previous_version_path}' but that doesn't exist. " + "Falling back to filling from currently last rendered." + ) + return None + + self.log.warning( + f"Replacing missing '{hole_fpath}' with " + f"'{previous_version_path}'" + ) + speedcopy.copyfile(previous_version_path, hole_fpath) + added_files[frame] = hole_fpath + + return added_files + + def _get_last_version_files( + self, + instance: pyblish.plugin.Instance, + current_repre: Dict[Any, Any], + ): + product_name = instance.data["productName"] + project_name = instance.data["projectEntity"]["name"] + folder_entity = instance.data["folderEntity"] + + version_entity = get_last_version_by_product_name( + project_name, + product_name, + folder_entity["id"], + fields={"id"} + ) + if not version_entity: + return None + + repres = get_representations( + project_name, + version_ids=[version_entity["id"]] + ) + matching_repre = None + for repre in repres: + if repre["name"] == current_repre["name"]: + matching_repre = repre + break + if not matching_repre: + return None + + repre_file_paths = [ + file_info["path"] + for file_info in matching_repre["files"] + ] + + return repre_file_paths + def fill_sequence_gaps_with_blanks( self, collection: str, @@ -1052,6 +1166,14 @@ class ExtractReview(pyblish.api.InstancePlugin): # Make sure to have full path to one input file full_input_path_single_file = full_input_path + filled_files = temp_data.get("filled_files", {}) + if filled_files: + first_frame, first_file = list(filled_files.items())[0] + if first_file < full_input_path_single_file: + self.log.warning(f"Using filled frame: '{first_file}'") + full_input_path_single_file = first_file + temp_data["first_sequence_frame"] = first_frame + filename_suffix = output_def["filename_suffix"] output_ext = output_def.get("ext") From be54d9deb815aa03c615bf5629af8bd6f708f0bd Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 9 Apr 2025 18:24:27 +0200 Subject: [PATCH 06/46] Missed renamed variable initialization --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 1cffcaf68c..61fbf2d90d 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -404,7 +404,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ) temp_data = self.prepare_temp_data(instance, repre, output_def) - files_to_clean = [] + added_frames_and_files = {} if temp_data["input_is_sequence"]: self.log.debug("Checking sequence to fill gaps in sequence..") From 3fe0c251dfdf449dc037706368cc87585c5771dc Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 9 Apr 2025 18:29:20 +0200 Subject: [PATCH 07/46] Refactored filling by blanks --- .../plugins/publish/extract_review.py | 31 +++++++------------ 1 file changed, 12 insertions(+), 19 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 61fbf2d90d..8c3186d390 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -430,6 +430,8 @@ class ExtractReview(pyblish.api.InstancePlugin): added_frames_and_files = self.fill_sequence_gaps_with_blanks( collection=collection, staging_dir=new_repre["stagingDir"], + start_frame=temp_data["frame_start"], + end_frame=temp_data["frame_end"], resolution_width=temp_data["resolution_width"], resolution_height=temp_data["resolution_height"], extension=temp_data["ext"], @@ -1024,24 +1026,13 @@ class ExtractReview(pyblish.api.InstancePlugin): self, collection: str, staging_dir: str, + start_frame: int, + end_frame: int, resolution_width: int, resolution_height: int, extension: str, - ): - """Fills missing files by blank frame. - - Args: - collection (clique.collection) - staging_dir (str): Path to staging directory. - resolution_width (int): width of source frame - resolution_height (int): height of source frame - extension (str) - - Returns: - list of added files. Those should be cleaned after work - is done. - - """ + ) -> Dict[int, str] | None: + """Fills missing files by blank frame.""" blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") command = get_ffmpeg_tool_args("ffmpeg") @@ -1063,14 +1054,16 @@ class ExtractReview(pyblish.api.InstancePlugin): added_files = [blank_frame_path] - for missing_frame_name in collection.holes(): - hole_fpath = os.path.join(staging_dir, missing_frame_name) + col_format = collection.format("{head}{padding}{tail}") + for frame in range(start_frame, end_frame + 1): + if frame in collection.indexes: + continue + hole_fpath = os.path.join(staging_dir, col_format % frame) speedcopy.copyfile(blank_frame_path, hole_fpath) - added_files.append(hole_fpath) + added_files[frame] = hole_fpath return added_files - def fill_sequence_gaps_from_existing( self, collection, From 0860fd130254a7a93916f50155e2370a5285d753 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 9 Apr 2025 18:29:45 +0200 Subject: [PATCH 08/46] Updated return type --- client/ayon_core/plugins/publish/extract_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 8c3186d390..fdb7a887f8 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1084,7 +1084,7 @@ class ExtractReview(pyblish.api.InstancePlugin): end_frame (int): Sequence end (no matter what files are there) Returns: - list of added files. Those should be cleaned after work + dict[int, str] of added files. Those should be cleaned after work is done. Raises: @@ -1113,7 +1113,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "Missing previously detected file: {}".format(src_fpath)) speedcopy.copyfile(src_fpath, hole_fpath) - added_files.append(hole_fpath) + added_files[hole_frame] = hole_fpath return added_files From f14a00b51024d876076c0c6b1a1d534d16ddb13d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 14:59:36 +0200 Subject: [PATCH 09/46] Implemented review from explicit frames --- .../plugins/publish/extract_review.py | 48 ++++++++++++++++--- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index fdb7a887f8..1d6aec6d1d 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -453,6 +453,14 @@ class ExtractReview(pyblish.api.InstancePlugin): start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) + elif fill_type == "only_rendered": + temp_data["explicit_frames"] = [ + os.path.join( + new_repre["stagingDir"], file + ).replace("\\", "/") + for file in files + ] + temp_data["filled_files"] = added_frames_and_files # create or update outputName @@ -514,6 +522,10 @@ class ExtractReview(pyblish.api.InstancePlugin): for f in added_frames_and_files.values(): os.unlink(f) + if (temp_data["explicit_frames_metadata_path"] + and os.path.exists(temp_data["explicit_frames_metadata_path"])): + os.unlink(temp_data["explicit_frames_metadata_path"]) + new_repre.update({ "fps": temp_data["fps"], "name": "{}_{}".format(output_name, output_ext), @@ -646,7 +658,9 @@ class ExtractReview(pyblish.api.InstancePlugin): "with_audio": with_audio, "without_handles": without_handles, "handles_are_set": handles_are_set, - "ext": ext + "ext": ext, + "explicit_frames": [], # absolute paths to rendered files + "explicit_frames_metadata_path": None # abs path to metadata file } def _ffmpeg_arguments( @@ -728,7 +742,8 @@ class ExtractReview(pyblish.api.InstancePlugin): if layer_name: ffmpeg_input_args.extend(["-layer", layer_name]) - if temp_data["input_is_sequence"]: + explicit_frames = temp_data["explicit_frames"] + if temp_data["input_is_sequence"] and not explicit_frames: # Set start frame of input sequence (just frame in filename) # - definition of input filepath # - add handle start if output should be without handles @@ -755,7 +770,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "-to", "{:0.10f}".format(duration_seconds) ]) - if temp_data["output_is_sequence"]: + if temp_data["output_is_sequence"] and not explicit_frames: # Set start frame of output sequence (just frame in filename) # - this is definition of an output ffmpeg_output_args.extend([ @@ -786,10 +801,29 @@ class ExtractReview(pyblish.api.InstancePlugin): "-frames:v", str(output_frames_len) ]) - # Add video/image input path - ffmpeg_input_args.extend([ - "-i", path_to_subprocess_arg(temp_data["full_input_path"]) - ]) + if not explicit_frames: + # Add video/image input path + ffmpeg_input_args.extend([ + "-i", path_to_subprocess_arg(temp_data["full_input_path"]) + ]) + else: + staging_dir = os.path.dirname(temp_data["full_input_path"]) + explicit_frames_path = os.path.join( + staging_dir, "explicit_frames.txt") + with open(explicit_frames_path, "w") as fp: + lines = [ + f"file {file}" + for file in temp_data["explicit_frames"] + ] + fp.write("\n".join(lines)) + temp_data["explicit_frames_metadata_path"] = explicit_frames_path + + # let ffmpeg use only rendered files, might have gaps + ffmpeg_input_args.extend([ + "-f", "concat", + "-safe", "0", + "-i", path_to_subprocess_arg(explicit_frames_path) + ]) # Add audio arguments if there are any. Skipped when output are images. if not temp_data["output_ext_is_image"] and temp_data["with_audio"]: From c210f62e1980a0784d231477d7488be45b38d09d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:12:15 +0200 Subject: [PATCH 10/46] Added fill_missing_frames to settings --- server/settings/publish_plugins.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index 39a9c028f9..3a0e932606 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -12,6 +12,14 @@ from ayon_server.settings import ( from ayon_server.types import ColorRGBA_uint8 +def _handle_missing_frames_enum(): + return [ + {"value": "closest_existing", "label": "Use closest existing"}, + {"value": "blank", "label": "Generate blank frame"}, + {"value": "previous_version", "label": "Use previous version"}, + {"value": "only_rendered", "label": "Use only rendered"}, + ] + class EnabledModel(BaseSettingsModel): enabled: bool = SettingsField(True) @@ -642,6 +650,12 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): default_factory=ExtractReviewLetterBox, title="Letter Box" ) + fill_missing_frames:str = SettingsField( + title="Handle missing frames", + description="How to handle frames that are missing from entity frame " + "range.", + enum_resolver=_handle_missing_frames_enum + ) @validator("name") def validate_name(cls, value): @@ -1261,7 +1275,8 @@ DEFAULT_PUBLISH_VALUES = { "fill_color": [0, 0, 0, 1.0], "line_thickness": 0, "line_color": [255, 0, 0, 1.0] - } + }, + "fill_missing_frames": "closest_existing" }, { "name": "h264", @@ -1311,7 +1326,8 @@ DEFAULT_PUBLISH_VALUES = { "fill_color": [0, 0, 0, 1.0], "line_thickness": 0, "line_color": [255, 0, 0, 1.0] - } + }, + "fill_missing_frames": "closest_existing" } ] } From deea9366bc4fde68efcdccf30d78a59015573548 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:20:51 +0200 Subject: [PATCH 11/46] Fix initialization --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 1d6aec6d1d..66841203b6 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1137,7 +1137,7 @@ class ExtractReview(pyblish.api.InstancePlugin): hole_frame_to_nearest[frame] = prev_frame # Calculate paths - added_files = [] + added_files = {} col_format = collection.format("{head}{padding}{tail}") for hole_frame, src_frame in hole_frame_to_nearest.items(): hole_fpath = os.path.join(staging_dir, col_format % hole_frame) From 8a9c95a69b150f5b40db44d9f6bea7d2ed2609ce Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:38:49 +0200 Subject: [PATCH 12/46] Use fill_missing_frames from Settings --- client/ayon_core/plugins/publish/extract_review.py | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 66841203b6..1299b16f84 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -420,13 +420,16 @@ class ExtractReview(pyblish.api.InstancePlugin): collection = collections[0] if fill_type == "existing": + + fill_missing_frames = _output_def["fill_missing_frames"] + if fill_missing_frames == "closest_existing": added_frames_and_files = self.fill_sequence_gaps_from_existing( collection=collection, staging_dir=new_repre["stagingDir"], start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) - elif fill_type == "blank": + elif fill_missing_frames == "blank": added_frames_and_files = self.fill_sequence_gaps_with_blanks( collection=collection, staging_dir=new_repre["stagingDir"], @@ -436,7 +439,7 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_height=temp_data["resolution_height"], extension=temp_data["ext"], ) - elif fill_type == "previous": + elif fill_missing_frames == "previous_version": added_frames_and_files = self.fill_sequence_gaps_with_previous( collection=collection, staging_dir=new_repre["stagingDir"], @@ -453,7 +456,7 @@ class ExtractReview(pyblish.api.InstancePlugin): start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) - elif fill_type == "only_rendered": + elif fill_missing_frames == "only_rendered": temp_data["explicit_frames"] = [ os.path.join( new_repre["stagingDir"], file From 050db01c82eb18af31d7cd0adf18d095c3e41ed7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:39:45 +0200 Subject: [PATCH 13/46] Remove blank frame --- client/ayon_core/plugins/publish/extract_review.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 1299b16f84..a3892bec62 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -438,6 +438,7 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_width=temp_data["resolution_width"], resolution_height=temp_data["resolution_height"], extension=temp_data["ext"], + temp_data=temp_data ) elif fill_missing_frames == "previous_version": added_frames_and_files = self.fill_sequence_gaps_with_previous( @@ -525,9 +526,8 @@ class ExtractReview(pyblish.api.InstancePlugin): for f in added_frames_and_files.values(): os.unlink(f) - if (temp_data["explicit_frames_metadata_path"] - and os.path.exists(temp_data["explicit_frames_metadata_path"])): - os.unlink(temp_data["explicit_frames_metadata_path"]) + for f in temp_data["paths_to_remove"]: + os.unlink(f) new_repre.update({ "fps": temp_data["fps"], @@ -663,7 +663,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "handles_are_set": handles_are_set, "ext": ext, "explicit_frames": [], # absolute paths to rendered files - "explicit_frames_metadata_path": None # abs path to metadata file + "paths_to_remove": [] } def _ffmpeg_arguments( @@ -819,7 +819,7 @@ class ExtractReview(pyblish.api.InstancePlugin): for file in temp_data["explicit_frames"] ] fp.write("\n".join(lines)) - temp_data["explicit_frames_metadata_path"] = explicit_frames_path + temp_data["paths_to_remove"].append(explicit_frames_path) # let ffmpeg use only rendered files, might have gaps ffmpeg_input_args.extend([ @@ -1068,9 +1068,11 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_width: int, resolution_height: int, extension: str, + temp_data: Dict[str, Any] ) -> Dict[int, str] | None: """Fills missing files by blank frame.""" blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") + temp_data["paths_to_remove"].append(blank_frame_path) command = get_ffmpeg_tool_args("ffmpeg") command.extend([ From 9415668912a43b96de29c77e34607f64af4ae2d0 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:40:07 +0200 Subject: [PATCH 14/46] Fix initialization --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index a3892bec62..9b4e36ca8e 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1091,7 +1091,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ) self.log.debug("Output: {}".format(output)) - added_files = [blank_frame_path] + added_files = {} col_format = collection.format("{head}{padding}{tail}") for frame in range(start_frame, end_frame + 1): From 488c29e97942a8107d65ca5697ce9c5ba2ba39a7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:40:19 +0200 Subject: [PATCH 15/46] Fix command --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 9b4e36ca8e..06743d476c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1081,7 +1081,7 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_width, resolution_height ), "-tune", "stillimage", - "-frames: v" , 1, + "-frames:v", "1", blank_frame_path ]) From 12b2ed84a3064fc541007a228a0e38d923ea021a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:57:19 +0200 Subject: [PATCH 16/46] Fix local rendering --- client/ayon_core/plugins/publish/extract_review.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 06743d476c..1370aa1fd1 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -411,15 +411,12 @@ class ExtractReview(pyblish.api.InstancePlugin): files = temp_data["origin_repre"]["files"] collections = clique.assemble( files, - patterns=[clique.PATTERNS["frames"]], - minimum_items=1 )[0] if len(collections) != 1: raise KnownPublishError( "Multiple collections {} found.".format(collections)) collection = collections[0] - if fill_type == "existing": fill_missing_frames = _output_def["fill_missing_frames"] if fill_missing_frames == "closest_existing": From 832beb1732ede03e7babc2ea2c497fb28cfe1a0a Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 11 Apr 2025 18:59:57 +0200 Subject: [PATCH 17/46] Refactor names --- .../plugins/publish/extract_review.py | 21 ++++++++++--------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 1370aa1fd1..ed789ae895 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -404,7 +404,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ) temp_data = self.prepare_temp_data(instance, repre, output_def) - added_frames_and_files = {} + new_frame_files = {} if temp_data["input_is_sequence"]: self.log.debug("Checking sequence to fill gaps in sequence..") @@ -420,14 +420,14 @@ class ExtractReview(pyblish.api.InstancePlugin): fill_missing_frames = _output_def["fill_missing_frames"] if fill_missing_frames == "closest_existing": - added_frames_and_files = self.fill_sequence_gaps_from_existing( + new_frame_files = self.fill_sequence_gaps_from_existing( collection=collection, staging_dir=new_repre["stagingDir"], start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) elif fill_missing_frames == "blank": - added_frames_and_files = self.fill_sequence_gaps_with_blanks( + new_frame_files = self.fill_sequence_gaps_with_blanks( collection=collection, staging_dir=new_repre["stagingDir"], start_frame=temp_data["frame_start"], @@ -438,7 +438,7 @@ class ExtractReview(pyblish.api.InstancePlugin): temp_data=temp_data ) elif fill_missing_frames == "previous_version": - added_frames_and_files = self.fill_sequence_gaps_with_previous( + new_frame_files = self.fill_sequence_gaps_with_previous( collection=collection, staging_dir=new_repre["stagingDir"], instance=instance, @@ -447,13 +447,14 @@ class ExtractReview(pyblish.api.InstancePlugin): end_frame=temp_data["frame_end"], ) # fallback to original workflow - if added_frames_and_files is None: - added_frames_and_files = self.fill_sequence_gaps_from_existing( + if new_frame_files is None: + new_frame_files = ( + self.fill_sequence_gaps_from_existing( collection=collection, staging_dir=new_repre["stagingDir"], start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], - ) + )) elif fill_missing_frames == "only_rendered": temp_data["explicit_frames"] = [ os.path.join( @@ -462,7 +463,7 @@ class ExtractReview(pyblish.api.InstancePlugin): for file in files ] - temp_data["filled_files"] = added_frames_and_files + temp_data["filled_files"] = new_frame_files # create or update outputName output_name = new_repre.get("outputName", "") @@ -519,8 +520,8 @@ class ExtractReview(pyblish.api.InstancePlugin): run_subprocess(subprcs_cmd, shell=True, logger=self.log) # delete files added to fill gaps - if added_frames_and_files: - for f in added_frames_and_files.values(): + if new_frame_files: + for f in new_frame_files.values(): os.unlink(f) for f in temp_data["paths_to_remove"]: From e61266bc82be539911209cce6fc433fcc9c70ac7 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 14 Apr 2025 12:14:00 +0200 Subject: [PATCH 18/46] Skip validation for explicit frames --- client/ayon_core/plugins/publish/extract_review.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index ed789ae895..31cb3763da 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -462,6 +462,13 @@ class ExtractReview(pyblish.api.InstancePlugin): ).replace("\\", "/") for file in files ] + frame_start = min(collection.indexes) + frame_end = max(collection.indexes) + # modify range for burnins + instance.data["frameStart"] = frame_start + instance.data["frameEnd"] = frame_end + temp_data["frame_start"] = frame_start + temp_data["frame_end"] = frame_end temp_data["filled_files"] = new_frame_files From a4db943903af482f0689f6574013042ff4051963 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 14 Apr 2025 14:22:24 +0200 Subject: [PATCH 19/46] Added default directly to enum Used if additional output defs are present. --- server/settings/publish_plugins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index 3a0e932606..f9893add1d 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -652,6 +652,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): ) fill_missing_frames:str = SettingsField( title="Handle missing frames", + default="closest_existing", description="How to handle frames that are missing from entity frame " "range.", enum_resolver=_handle_missing_frames_enum From c82537008f2439fc4591475939d281b651246ee6 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 13:56:43 +0200 Subject: [PATCH 20/46] Refactor proper variable names --- client/ayon_core/plugins/publish/extract_review.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 31cb3763da..93f1098f4c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -528,11 +528,11 @@ class ExtractReview(pyblish.api.InstancePlugin): # delete files added to fill gaps if new_frame_files: - for f in new_frame_files.values(): - os.unlink(f) + for filepath in new_frame_files.values(): + os.unlink(filepath) - for f in temp_data["paths_to_remove"]: - os.unlink(f) + for filepath in temp_data["paths_to_remove"]: + os.unlink(filepath) new_repre.update({ "fps": temp_data["fps"], From 1019eded3bd2dccd479c396f37ae83184d9530b0 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 13:59:01 +0200 Subject: [PATCH 21/46] Refactor filled_files are always initialized --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 93f1098f4c..f39bc0cff8 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1203,7 +1203,7 @@ class ExtractReview(pyblish.api.InstancePlugin): # Make sure to have full path to one input file full_input_path_single_file = full_input_path - filled_files = temp_data.get("filled_files", {}) + filled_files = temp_data["filled_files"] if filled_files: first_frame, first_file = list(filled_files.items())[0] if first_file < full_input_path_single_file: From 4c305d9596ce1f8bc1907e83968b55a750940811 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 14:00:17 +0200 Subject: [PATCH 22/46] Refactor renamed explicit_frames to explicit_input_paths --- client/ayon_core/plugins/publish/extract_review.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index f39bc0cff8..6e31d11dce 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -456,7 +456,7 @@ class ExtractReview(pyblish.api.InstancePlugin): end_frame=temp_data["frame_end"], )) elif fill_missing_frames == "only_rendered": - temp_data["explicit_frames"] = [ + temp_data["explicit_input_paths"] = [ os.path.join( new_repre["stagingDir"], file ).replace("\\", "/") @@ -667,7 +667,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "without_handles": without_handles, "handles_are_set": handles_are_set, "ext": ext, - "explicit_frames": [], # absolute paths to rendered files + "explicit_input_paths": [], # absolute paths to rendered files "paths_to_remove": [] } @@ -750,8 +750,8 @@ class ExtractReview(pyblish.api.InstancePlugin): if layer_name: ffmpeg_input_args.extend(["-layer", layer_name]) - explicit_frames = temp_data["explicit_frames"] - if temp_data["input_is_sequence"] and not explicit_frames: + explicit_input_paths = temp_data["explicit_input_paths"] + if temp_data["input_is_sequence"] and not explicit_input_paths: # Set start frame of input sequence (just frame in filename) # - definition of input filepath # - add handle start if output should be without handles @@ -778,7 +778,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "-to", "{:0.10f}".format(duration_seconds) ]) - if temp_data["output_is_sequence"] and not explicit_frames: + if temp_data["output_is_sequence"] and not explicit_input_paths: # Set start frame of output sequence (just frame in filename) # - this is definition of an output ffmpeg_output_args.extend([ @@ -809,7 +809,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "-frames:v", str(output_frames_len) ]) - if not explicit_frames: + if not explicit_input_paths: # Add video/image input path ffmpeg_input_args.extend([ "-i", path_to_subprocess_arg(temp_data["full_input_path"]) @@ -821,7 +821,7 @@ class ExtractReview(pyblish.api.InstancePlugin): with open(explicit_frames_path, "w") as fp: lines = [ f"file {file}" - for file in temp_data["explicit_frames"] + for file in temp_data["explicit_input_paths"] ] fp.write("\n".join(lines)) temp_data["paths_to_remove"].append(explicit_frames_path) From 8b8d29042a6eb83b3c7973ee1d07fda4db552a62 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 14:01:26 +0200 Subject: [PATCH 23/46] Refactor reordered import --- client/ayon_core/plugins/publish/extract_review.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 6e31d11dce..0192964422 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -13,6 +13,8 @@ import clique import speedcopy import pyblish.api +from ayon_api import get_last_version_by_product_name, get_representations + from ayon_core.lib import ( get_ffmpeg_tool_args, filter_profiles, @@ -32,7 +34,6 @@ from ayon_core.pipeline.publish import ( get_publish_instance_label, ) from ayon_core.pipeline.publish.lib import add_repre_files_for_cleanup -from ayon_api import get_last_version_by_product_name, get_representations def frame_to_timecode(frame: int, fps: float) -> str: From efb3a01f4b4fe79de85e73e35b28ceab025a8594 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 14:02:15 +0200 Subject: [PATCH 24/46] Removed unnecessary import --- client/ayon_core/plugins/publish/extract_review.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 0192964422..0a1089ec9f 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1,5 +1,3 @@ -from __future__ import annotations - import os import re import copy From cdf8764bb13c452eca607fa5aa9a05db14921724 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Tue, 15 Apr 2025 17:18:28 +0200 Subject: [PATCH 25/46] Fix return type --- client/ayon_core/plugins/publish/extract_review.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 0a1089ec9f..3a7c6a6b1e 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -5,7 +5,7 @@ import json import shutil import subprocess from abc import ABC, abstractmethod -from typing import Dict, Any +from typing import Dict, Any, Union import clique import speedcopy @@ -978,7 +978,7 @@ class ExtractReview(pyblish.api.InstancePlugin): current_repre: Dict[Any, Any], start_frame: int, end_frame: int - ) -> Dict[int, str] | None: + ) -> Union[Dict[int, str], None]: """Tries to replace missing frames from ones from last version""" repre_file_paths = self._get_last_version_files( instance, current_repre) @@ -1073,7 +1073,7 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_height: int, extension: str, temp_data: Dict[str, Any] - ) -> Dict[int, str] | None: + ) -> Union[Dict[int, str], None]: """Fills missing files by blank frame.""" blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") temp_data["paths_to_remove"].append(blank_frame_path) From ba80b3b9b459d74d5aface7b39509316cd6d808b Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 17 Apr 2025 17:31:08 +0200 Subject: [PATCH 26/46] Added flags for ffmpeg not skipping some frames because DTS --- client/ayon_core/plugins/publish/extract_review.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index e8ed4c80fc..3615cc53c9 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -829,7 +829,9 @@ class ExtractReview(pyblish.api.InstancePlugin): ffmpeg_input_args.extend([ "-f", "concat", "-safe", "0", - "-i", path_to_subprocess_arg(explicit_frames_path) + "-fflags", "+genpts+igndts", + "-i", path_to_subprocess_arg(explicit_frames_path), + "-r", "25" ]) # Add audio arguments if there are any. Skipped when output are images. From 71d37d8b59ee3be0b5dcb784b4b478d40c5d2288 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:04:41 +0200 Subject: [PATCH 27/46] Updated command creation Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_review.py | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 3615cc53c9..a4eb1140ac 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1079,9 +1079,8 @@ class ExtractReview(pyblish.api.InstancePlugin): """Fills missing files by blank frame.""" blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") temp_data["paths_to_remove"].append(blank_frame_path) - command = get_ffmpeg_tool_args("ffmpeg") - - command.extend([ + command = get_ffmpeg_tool_args( + "ffmpeg", "-f", "lavfi", "-i", "color=c=black:s={}x{}:d=1".format( resolution_width, resolution_height @@ -1089,7 +1088,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "-tune", "stillimage", "-frames:v", "1", blank_frame_path - ]) + ) self.log.debug("Executing: {}".format(" ".join(command))) output = run_subprocess( From c53de6d226ff48b8c30baaf4889563eb373e058f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:05:08 +0200 Subject: [PATCH 28/46] Formatting change Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- server/settings/publish_plugins.py | 1 + 1 file changed, 1 insertion(+) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index d487649f65..dbbbb9609d 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -20,6 +20,7 @@ def _handle_missing_frames_enum(): {"value": "only_rendered", "label": "Use only rendered"}, ] + class EnabledModel(BaseSettingsModel): enabled: bool = SettingsField(True) From 46d27ff7a4942fee39edf42ccab72cc05226fe40 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:05:24 +0200 Subject: [PATCH 29/46] Formatting change Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- server/settings/publish_plugins.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index dbbbb9609d..cbe3894975 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -651,7 +651,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): default_factory=ExtractReviewLetterBox, title="Letter Box" ) - fill_missing_frames:str = SettingsField( + fill_missing_frames: str = SettingsField( title="Handle missing frames", default="closest_existing", description="How to handle frames that are missing from entity frame " From 6d008edbada3d1ac3776b1ae51dc044c6454cb25 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:05:56 +0200 Subject: [PATCH 30/46] Refactor first file query Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index a4eb1140ac..265bbb0828 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1205,7 +1205,7 @@ class ExtractReview(pyblish.api.InstancePlugin): filled_files = temp_data["filled_files"] if filled_files: - first_frame, first_file = list(filled_files.items())[0] + first_frame, first_file = next(iter(filled_files.items())) if first_file < full_input_path_single_file: self.log.warning(f"Using filled frame: '{first_file}'") full_input_path_single_file = first_file From cc1ba078ed9f65608eb2a3035597bcf25c668d51 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:07:33 +0200 Subject: [PATCH 31/46] Changed variable name Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 265bbb0828..48bb2819ff 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -819,8 +819,8 @@ class ExtractReview(pyblish.api.InstancePlugin): staging_dir, "explicit_frames.txt") with open(explicit_frames_path, "w") as fp: lines = [ - f"file {file}" - for file in temp_data["explicit_input_paths"] + f"file {path}" + for path in temp_data["explicit_input_paths"] ] fp.write("\n".join(lines)) temp_data["paths_to_remove"].append(explicit_frames_path) From 24ec921ff6abce87a11f34a1162c11c310fbb634 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:08:18 +0200 Subject: [PATCH 32/46] Formatting change Co-authored-by: Jakub Trllo <43494761+iLLiCiTiT@users.noreply.github.com> --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 48bb2819ff..cec6dd742c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -829,7 +829,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ffmpeg_input_args.extend([ "-f", "concat", "-safe", "0", - "-fflags", "+genpts+igndts", + "-fflags", "+genpts+igndts", "-i", path_to_subprocess_arg(explicit_frames_path), "-r", "25" ]) From ed2d0baaf27d25053c7b755e8587815346f9ea63 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:12:43 +0200 Subject: [PATCH 33/46] Renamed key --- client/ayon_core/plugins/publish/extract_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index cec6dd742c..b8c75ff60a 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -433,7 +433,7 @@ class ExtractReview(pyblish.api.InstancePlugin): end_frame=temp_data["frame_end"], resolution_width=temp_data["resolution_width"], resolution_height=temp_data["resolution_height"], - extension=temp_data["ext"], + extension=temp_data["input_ext"], temp_data=temp_data ) elif fill_missing_frames == "previous_version": @@ -665,7 +665,7 @@ class ExtractReview(pyblish.api.InstancePlugin): "with_audio": with_audio, "without_handles": without_handles, "handles_are_set": handles_are_set, - "ext": ext, + "input_ext": ext, "explicit_input_paths": [], # absolute paths to rendered files "paths_to_remove": [] } From 1836daad6251065e684b2bb4c7908475fecd2851 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:14:04 +0200 Subject: [PATCH 34/46] Refactor condition --- client/ayon_core/plugins/publish/extract_review.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index b8c75ff60a..252b3c7b6f 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -624,6 +624,8 @@ class ExtractReview(pyblish.api.InstancePlugin): input_is_sequence = self.input_is_sequence(repre) input_allow_bg = False first_sequence_frame = None + + ext = os.path.splitext(repre["files"])[1].replace(".", "") if input_is_sequence and repre["files"]: # Calculate first frame that should be used cols, _ = clique.assemble(repre["files"]) @@ -642,8 +644,6 @@ class ExtractReview(pyblish.api.InstancePlugin): ext = os.path.splitext(repre["files"][0])[1].replace(".", "") if ext.lower() in self.alpha_exts: input_allow_bg = True - else: - ext = os.path.splitext(repre["files"])[1].replace(".", "") return { "fps": float(instance.data["fps"]), From 3e042f4bcd1003793c1498822f88d37ca64538e2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:17:19 +0200 Subject: [PATCH 35/46] Fixed return type --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 252b3c7b6f..9b2a139515 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1114,7 +1114,7 @@ class ExtractReview(pyblish.api.InstancePlugin): staging_dir: str, start_frame: int, end_frame: int - ) -> list: + ) -> Dict[int, str]: """Fill missing files in sequence by duplicating existing ones. This will take nearest frame file and copy it with so as to fill From 23bd9706d6b83d2b8b81d54d49d0111bf4579cda Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:20:45 +0200 Subject: [PATCH 36/46] Replaced Union with Optional --- client/ayon_core/plugins/publish/extract_review.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 9b2a139515..2577714675 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -5,7 +5,7 @@ import json import shutil import subprocess from abc import ABC, abstractmethod -from typing import Dict, Any, Union +from typing import Dict, Any, Optional import clique import speedcopy @@ -980,7 +980,7 @@ class ExtractReview(pyblish.api.InstancePlugin): current_repre: Dict[Any, Any], start_frame: int, end_frame: int - ) -> Union[Dict[int, str], None]: + ) -> Optional[Dict[int, str]]: """Tries to replace missing frames from ones from last version""" repre_file_paths = self._get_last_version_files( instance, current_repre) @@ -1075,7 +1075,7 @@ class ExtractReview(pyblish.api.InstancePlugin): resolution_height: int, extension: str, temp_data: Dict[str, Any] - ) -> Union[Dict[int, str], None]: + ) -> Optional[Dict[int, str]]: """Fills missing files by blank frame.""" blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") temp_data["paths_to_remove"].append(blank_frame_path) From f73c6eccefe73ba61757231b5627cb6524959a8d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:29:17 +0200 Subject: [PATCH 37/46] Simplified argument --- client/ayon_core/plugins/publish/extract_review.py | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 2577714675..699bf42876 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -441,7 +441,7 @@ class ExtractReview(pyblish.api.InstancePlugin): collection=collection, staging_dir=new_repre["stagingDir"], instance=instance, - current_repre=repre, + current_repre_name=repre["name"], start_frame=temp_data["frame_start"], end_frame=temp_data["frame_end"], ) @@ -977,13 +977,13 @@ class ExtractReview(pyblish.api.InstancePlugin): collection: str, staging_dir: str, instance: pyblish.plugin.Instance, - current_repre: Dict[Any, Any], + current_repre_name: str, start_frame: int, end_frame: int ) -> Optional[Dict[int, str]]: """Tries to replace missing frames from ones from last version""" repre_file_paths = self._get_last_version_files( - instance, current_repre) + instance, current_repre_name) if repre_file_paths is None: # issues in getting last version files, falling back return None @@ -1031,7 +1031,7 @@ class ExtractReview(pyblish.api.InstancePlugin): def _get_last_version_files( self, instance: pyblish.plugin.Instance, - current_repre: Dict[Any, Any], + current_repre_name: str, ): product_name = instance.data["productName"] project_name = instance.data["projectEntity"]["name"] @@ -1052,7 +1052,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ) matching_repre = None for repre in repres: - if repre["name"] == current_repre["name"]: + if repre["name"] == current_repre_name: matching_repre = repre break if not matching_repre: From fe78983491556d82716d146a0e83f3e44de0e190 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Wed, 23 Apr 2025 14:53:56 +0200 Subject: [PATCH 38/46] Fix condition --- client/ayon_core/plugins/publish/extract_review.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 699bf42876..312b594acd 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -625,7 +625,6 @@ class ExtractReview(pyblish.api.InstancePlugin): input_allow_bg = False first_sequence_frame = None - ext = os.path.splitext(repre["files"])[1].replace(".", "") if input_is_sequence and repre["files"]: # Calculate first frame that should be used cols, _ = clique.assemble(repre["files"]) @@ -644,6 +643,8 @@ class ExtractReview(pyblish.api.InstancePlugin): ext = os.path.splitext(repre["files"][0])[1].replace(".", "") if ext.lower() in self.alpha_exts: input_allow_bg = True + else: + ext = os.path.splitext(repre["files"])[1].replace(".", "") return { "fps": float(instance.data["fps"]), From bc509fcf0084d465ff4d51f0f3391a03298e799f Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 11:37:26 +0200 Subject: [PATCH 39/46] Simplified querying for old repre --- .../ayon_core/plugins/publish/extract_review.py | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 312b594acd..b56e5a2ac0 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1047,17 +1047,16 @@ class ExtractReview(pyblish.api.InstancePlugin): if not version_entity: return None - repres = get_representations( + matching_repres = get_representations( project_name, - version_ids=[version_entity["id"]] + version_ids=[version_entity["id"]], + representation_names=[current_repre_name], + fields={"files"} ) - matching_repre = None - for repre in repres: - if repre["name"] == current_repre_name: - matching_repre = repre - break - if not matching_repre: + + if not matching_repres: return None + matching_repre = list(matching_repres)[0] repre_file_paths = [ file_info["path"] From e9d3462da28bf114bef0b950f897f9ef740cf9a9 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 11:39:44 +0200 Subject: [PATCH 40/46] Fix description --- server/settings/publish_plugins.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/server/settings/publish_plugins.py b/server/settings/publish_plugins.py index cbe3894975..47dd5ebfb0 100644 --- a/server/settings/publish_plugins.py +++ b/server/settings/publish_plugins.py @@ -654,8 +654,7 @@ class ExtractReviewOutputDefModel(BaseSettingsModel): fill_missing_frames: str = SettingsField( title="Handle missing frames", default="closest_existing", - description="How to handle frames that are missing from entity frame " - "range.", + description="How to handle gaps in sequence frame ranges.", enum_resolver=_handle_missing_frames_enum ) From 5410d69ad2137a91d51a1260f254470e605da125 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 12:09:54 +0200 Subject: [PATCH 41/46] Simplified fill_root logic I must be wrong in my previous tests, it works even this simple way. --- client/ayon_core/plugins/publish/extract_review.py | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index b56e5a2ac0..a53e8eee8f 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1005,13 +1005,7 @@ class ExtractReview(pyblish.api.InstancePlugin): hole_fpath = os.path.join(staging_dir, col_format % frame) previous_version_path = prev_col_format % frame - # limits too large padding coming from Anatomy - previous_version_path = ( - os.path.join( - anatomy.fill_root(os.path.dirname(previous_version_path)), - os.path.basename(previous_version_path) - ) - ) + previous_version_path = anatomy.fill_root(previous_version_path) if not os.path.exists(previous_version_path): self.log.warning( "Missing frame should be replaced from " From 4a38e1175f4b6c9304ce233fe3bf8af58d2c41b8 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 13:20:33 +0200 Subject: [PATCH 42/46] Fix rendering explicit frames This seems only safe way --- .../plugins/publish/extract_review.py | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index a53e8eee8f..0c4b99cf66 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -526,12 +526,12 @@ class ExtractReview(pyblish.api.InstancePlugin): run_subprocess(subprcs_cmd, shell=True, logger=self.log) # delete files added to fill gaps - if new_frame_files: - for filepath in new_frame_files.values(): - os.unlink(filepath) - - for filepath in temp_data["paths_to_remove"]: - os.unlink(filepath) + # if new_frame_files: + # for filepath in new_frame_files.values(): + # # os.unlink(filepath) + # + # for filepath in temp_data["paths_to_remove"]: + # os.unlink(filepath) new_repre.update({ "fps": temp_data["fps"], @@ -818,9 +818,10 @@ class ExtractReview(pyblish.api.InstancePlugin): staging_dir = os.path.dirname(temp_data["full_input_path"]) explicit_frames_path = os.path.join( staging_dir, "explicit_frames.txt") + frame_duration = 1 / temp_data["fps"] with open(explicit_frames_path, "w") as fp: lines = [ - f"file {path}" + f"file '{path}'{os.linesep}duration {frame_duration}" for path in temp_data["explicit_input_paths"] ] fp.write("\n".join(lines)) @@ -830,9 +831,8 @@ class ExtractReview(pyblish.api.InstancePlugin): ffmpeg_input_args.extend([ "-f", "concat", "-safe", "0", - "-fflags", "+genpts+igndts", "-i", path_to_subprocess_arg(explicit_frames_path), - "-r", "25" + "-r", str(temp_data["fps"]) ]) # Add audio arguments if there are any. Skipped when output are images. From e5d673c0209c065112bcd8e192c5889b68b5d16e Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 13:23:40 +0200 Subject: [PATCH 43/46] Reverted unwanted commenting out --- client/ayon_core/plugins/publish/extract_review.py | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index 0c4b99cf66..daa58e0e93 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -525,13 +525,13 @@ class ExtractReview(pyblish.api.InstancePlugin): run_subprocess(subprcs_cmd, shell=True, logger=self.log) - # delete files added to fill gaps - # if new_frame_files: - # for filepath in new_frame_files.values(): - # # os.unlink(filepath) - # - # for filepath in temp_data["paths_to_remove"]: - # os.unlink(filepath) + #delete files added to fill gaps + if new_frame_files: + for filepath in new_frame_files.values(): + os.unlink(filepath) + + for filepath in temp_data["paths_to_remove"]: + os.unlink(filepath) new_repre.update({ "fps": temp_data["fps"], From 026ec6419673c8c896524bb83ce74fd315243050 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Thu, 24 Apr 2025 14:19:53 +0200 Subject: [PATCH 44/46] Fix typo Co-authored-by: Roy Nieterau --- client/ayon_core/plugins/publish/extract_review.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index daa58e0e93..f824e1db3c 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -525,7 +525,7 @@ class ExtractReview(pyblish.api.InstancePlugin): run_subprocess(subprcs_cmd, shell=True, logger=self.log) - #delete files added to fill gaps + # delete files added to fill gaps if new_frame_files: for filepath in new_frame_files.values(): os.unlink(filepath) From 8ef5c45eba8d074a01432c8f4373239baa33210d Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Mon, 5 May 2025 16:05:26 +0200 Subject: [PATCH 45/46] Generate blank frame only if necessary --- .../plugins/publish/extract_review.py | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index f824e1db3c..de1c785475 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -1071,8 +1071,35 @@ class ExtractReview(pyblish.api.InstancePlugin): temp_data: Dict[str, Any] ) -> Optional[Dict[int, str]]: """Fills missing files by blank frame.""" + + blank_frame_path = None + + added_files = {} + + col_format = collection.format("{head}{padding}{tail}") + for frame in range(start_frame, end_frame + 1): + if frame in collection.indexes: + continue + hole_fpath = os.path.join(staging_dir, col_format % frame) + if blank_frame_path is None: + blank_frame_path = self._create_blank_frame( + staging_dir, extension, resolution_width, resolution_height + ) + temp_data["paths_to_remove"].append(blank_frame_path) + speedcopy.copyfile(blank_frame_path, hole_fpath) + added_files[frame] = hole_fpath + + return added_files + + def _create_blank_frame( + self, + staging_dir, + extension, + resolution_width, + resolution_height + ): blank_frame_path = os.path.join(staging_dir, f"blank.{extension}") - temp_data["paths_to_remove"].append(blank_frame_path) + command = get_ffmpeg_tool_args( "ffmpeg", "-f", "lavfi", @@ -1090,17 +1117,7 @@ class ExtractReview(pyblish.api.InstancePlugin): ) self.log.debug("Output: {}".format(output)) - added_files = {} - - col_format = collection.format("{head}{padding}{tail}") - for frame in range(start_frame, end_frame + 1): - if frame in collection.indexes: - continue - hole_fpath = os.path.join(staging_dir, col_format % frame) - speedcopy.copyfile(blank_frame_path, hole_fpath) - added_files[frame] = hole_fpath - - return added_files + return blank_frame_path def fill_sequence_gaps_from_existing( self, From 9bf848f1a81d5f6d0ec041f5c97f7df017ddd7e2 Mon Sep 17 00:00:00 2001 From: Petr Kalis Date: Fri, 9 May 2025 11:30:24 +0200 Subject: [PATCH 46/46] Create explicit_frames.txt as temp file --- client/ayon_core/plugins/publish/extract_review.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/client/ayon_core/plugins/publish/extract_review.py b/client/ayon_core/plugins/publish/extract_review.py index de1c785475..87208f5574 100644 --- a/client/ayon_core/plugins/publish/extract_review.py +++ b/client/ayon_core/plugins/publish/extract_review.py @@ -6,6 +6,7 @@ import shutil import subprocess from abc import ABC, abstractmethod from typing import Dict, Any, Optional +import tempfile import clique import speedcopy @@ -815,10 +816,13 @@ class ExtractReview(pyblish.api.InstancePlugin): "-i", path_to_subprocess_arg(temp_data["full_input_path"]) ]) else: - staging_dir = os.path.dirname(temp_data["full_input_path"]) - explicit_frames_path = os.path.join( - staging_dir, "explicit_frames.txt") frame_duration = 1 / temp_data["fps"] + + explicit_frames_meta = tempfile.NamedTemporaryFile( + mode="w", prefix="explicit_frames", suffix=".txt", delete=False + ) + explicit_frames_meta.close() + explicit_frames_path = explicit_frames_meta.name with open(explicit_frames_path, "w") as fp: lines = [ f"file '{path}'{os.linesep}duration {frame_duration}"