diff --git a/openpype/plugins/publish/extract_burnin.py b/openpype/plugins/publish/extract_burnin.py index 7999893fee..1e805afba7 100644 --- a/openpype/plugins/publish/extract_burnin.py +++ b/openpype/plugins/publish/extract_burnin.py @@ -3,6 +3,7 @@ import re import json import copy import tempfile +import clique import openpype import openpype.api @@ -269,7 +270,9 @@ class ExtractBurnin(openpype.api.Extractor): "output": temp_data["full_output_path"], "burnin_data": burnin_data, "options": burnin_options, - "values": burnin_values + "values": burnin_values, + "full_input_path": temp_data["full_input_paths"][0], + "first_frame": temp_data["first_frame"] } self.log.debug( @@ -483,32 +486,47 @@ class ExtractBurnin(openpype.api.Extractor): None: This is processing method. """ # TODO we should find better way to know if input is sequence - is_sequence = ( - "sequence" in new_repre["tags"] - and isinstance(new_repre["files"], (tuple, list)) - ) + input_filenames = new_repre["files"] + is_sequence = False + if isinstance(input_filenames, (tuple, list)): + if len(input_filenames) > 1: + is_sequence = True + + # Sequence must have defined first frame + # - not used if input is not a sequence + first_frame = None if is_sequence: - input_filename = new_repre["sequence_file"] - else: - input_filename = new_repre["files"] + collections, _ = clique.assemble(input_filenames) + if not collections: + is_sequence = False + else: + input_filename = new_repre["sequence_file"] + collection = collections[0] + indexes = list(collection.indexes) + padding = len(str(max(indexes))) + head = collection.format("{head}") + tail = collection.format("{tail}") + output_filename = "{}%{:0>2}d{}{}".format( + head, padding, filename_suffix, tail + ) + repre_files = [] + for idx in indexes: + repre_files.append(output_filename % idx) - filepart_start, ext = os.path.splitext(input_filename) - dir_path, basename = os.path.split(filepart_start) + first_frame = min(indexes) - if is_sequence: - # NOTE modified to keep name when multiple dots are in name - basename_parts = basename.split(".") - frame_part = basename_parts.pop(-1) + if not is_sequence: + input_filename = input_filenames + if isinstance(input_filename, (tuple, list)): + input_filename = input_filename[0] - basename_start = ".".join(basename_parts) + filename_suffix - new_basename = ".".join((basename_start, frame_part)) - output_filename = new_basename + ext - - else: + filepart_start, ext = os.path.splitext(input_filename) + dir_path, basename = os.path.split(filepart_start) output_filename = basename + filename_suffix + ext + if dir_path: + output_filename = os.path.join(dir_path, output_filename) - if dir_path: - output_filename = os.path.join(dir_path, output_filename) + repre_files = output_filename stagingdir = new_repre["stagingDir"] full_input_path = os.path.join( @@ -520,6 +538,9 @@ class ExtractBurnin(openpype.api.Extractor): temp_data["full_input_path"] = full_input_path temp_data["full_output_path"] = full_output_path + temp_data["first_frame"] = first_frame + + new_repre["files"] = repre_files self.log.debug("full_input_path: {}".format(full_input_path)) self.log.debug("full_output_path: {}".format(full_output_path)) @@ -527,17 +548,16 @@ class ExtractBurnin(openpype.api.Extractor): # Prepare full paths to input files and filenames for reprensetation full_input_paths = [] if is_sequence: - repre_files = [] - for frame_index in range(1, temp_data["duration"] + 1): - repre_files.append(output_filename % frame_index) - full_input_paths.append(full_input_path % frame_index) + for filename in input_filenames: + filepath = os.path.join( + os.path.normpath(stagingdir), filename + ).replace("\\", "/") + full_input_paths.append(filepath) else: full_input_paths.append(full_input_path) - repre_files = output_filename temp_data["full_input_paths"] = full_input_paths - new_repre["files"] = repre_files def prepare_repre_data(self, instance, repre, burnin_data, temp_data): """Prepare data for representation. diff --git a/openpype/scripts/otio_burnin.py b/openpype/scripts/otio_burnin.py index 5e2a22f1b5..6dcf00e97c 100644 --- a/openpype/scripts/otio_burnin.py +++ b/openpype/scripts/otio_burnin.py @@ -14,7 +14,7 @@ ffprobe_path = openpype.lib.get_ffmpeg_tool_path("ffprobe") FFMPEG = ( - '"{}" -i "%(input)s" %(filters)s %(args)s%(output)s' + '"{}"%(input_args)s -i "%(input)s" %(filters)s %(args)s%(output)s' ).format(ffmpeg_path) FFPROBE = ( @@ -121,10 +121,18 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins): 'font_size': 42 } - def __init__(self, source, streams=None, options_init=None): + def __init__( + self, source, streams=None, options_init=None, first_frame=None + ): if not streams: streams = _streams(source) + input_args = [] + if first_frame: + input_args.append("-start_number {}".format(first_frame)) + + self.input_args = input_args + super().__init__(source, streams) if options_init: @@ -289,7 +297,12 @@ class ModifiedBurnins(ffmpeg_burnins.Burnins): if self.filter_string: filters = '-vf "{}"'.format(self.filter_string) + input_args = "" + if self.input_args: + input_args = " {}".format(" ".join(self.input_args)) + return (FFMPEG % { + 'input_args': input_args, 'input': self.source, 'output': output, 'args': '%s ' % args if args else '', @@ -370,7 +383,8 @@ def example(input_path, output_path): def burnins_from_data( input_path, output_path, data, - codec_data=None, options=None, burnin_values=None, overwrite=True + codec_data=None, options=None, burnin_values=None, overwrite=True, + full_input_path=None, first_frame=None ): """This method adds burnins to video/image file based on presets setting. @@ -427,8 +441,11 @@ def burnins_from_data( "shot": "sh0010" } """ + streams = None + if full_input_path: + streams = _streams(full_input_path) - burnin = ModifiedBurnins(input_path, options_init=options) + burnin = ModifiedBurnins(input_path, streams, options, first_frame) frame_start = data.get("frame_start") frame_end = data.get("frame_end") @@ -591,6 +608,8 @@ if __name__ == "__main__": in_data["burnin_data"], codec_data=in_data.get("codec"), options=in_data.get("options"), - burnin_values=in_data.get("values") + burnin_values=in_data.get("values"), + full_input_path=in_data.get("full_input_path"), + first_frame=in_data.get("first_frame") ) print("* Burnin script has finished")