diff --git a/openpype/lib/transcoding.py b/openpype/lib/transcoding.py index d52b4a8133..ace95002d9 100644 --- a/openpype/lib/transcoding.py +++ b/openpype/lib/transcoding.py @@ -1229,37 +1229,45 @@ def split_cmd_args(in_args): def get_rescaled_command_arguments( - app, + application, input_path, - input_width, - input_height, - input_par, target_width, target_height, - target_par, + target_par=None, bg_color=None, log=None ): """Get command arguments for rescaling input to target size. Args: - app (str): Application for which command should be created. + application (str): Application for which command should be created. Currently supported are "ffmpeg" and "oiiotool". input_path (str): Path to input file. - input_width (int): Width of input. - input_height (int): Height of input. - input_par (float): Pixel aspect ratio of input. target_width (int): Width of target. target_height (int): Height of target. - target_par (float): Pixel aspect ratio of target. - bg_color (list[float]): List of float values for background color. - Should be in range 0.0 - 1.0. - log (logging.Logger): Logger used for logging. + target_par (Optional[float]): Pixel aspect ratio of target. + bg_color (Optional[list[int]]): List of 8bit int values for + background color. Should be in range 0 - 255. + log (Optional[logging.Logger]): Logger used for logging. Returns: list[str]: List of command arguments. """ command_args = [] + target_par = target_par or 1.0 + input_par = 1.0 + + # ffmpeg command + input_file_metadata = get_ffprobe_data(input_path, logger=log) + input_width = int(input_file_metadata["streams"][0]["width"]) + input_height = int(input_file_metadata["streams"][0]["height"]) + stream_input_par = input_file_metadata["streams"][0].get( + "sample_aspect_ratio") + if stream_input_par: + input_par = ( + float(stream_input_par.split(":")[0]) + / float(stream_input_par.split(":")[1]) + ) # recalculating input and target width input_width = int(input_width * input_par) target_width = int(target_width * target_par) @@ -1281,7 +1289,7 @@ def get_rescaled_command_arguments( rescaled_width_shift = int((target_width - rescaled_width) / 2) rescaled_height_shift = int((target_height - rescaled_height) / 2) - if app == "ffmpeg": + if application == "ffmpeg": # create scale command scale = "scale={0}:{1}".format(input_width, input_height) pad = "pad={0}:{1}:({2}-iw)/2:({3}-ih)/2".format( @@ -1300,11 +1308,11 @@ def get_rescaled_command_arguments( ) if bg_color: - color = convert_color_float_to_hex(bg_color) + color = convert_color_values(application, bg_color) pad += ":{0}".format(color) command_args.extend(["-vf", "{0},{1}".format(scale, pad)]) - elif app == "oiiotool": + elif application == "oiiotool": input_info = get_oiio_info_for_input(input_path, logger=log) # Collect channels to export _, channels_arg = get_oiio_input_and_channel_args( @@ -1347,11 +1355,11 @@ def get_rescaled_command_arguments( "{0}x{1}".format(target_width, target_height) ] if bg_color: - color_str = ",".join([str(c) for c in bg_color]) + color = convert_color_values(application, bg_color) fullsize.extend([ "--pattern", - "constant:color={0}".format(color_str), + "constant:color={0}".format(color), "{0}x{1}".format(target_width, target_height), "4", # 4 channels "--over" @@ -1359,33 +1367,41 @@ def get_rescaled_command_arguments( command_args.extend(fullsize) else: - raise ValueError("app should be either \"ffmpeg\" or \"oiiotool\"") + raise ValueError( + "\"application\" input argument should " + "be either \"ffmpeg\" or \"oiiotool\"" + ) return command_args -def convert_color_float_to_hex(color_value): - """Get color mapping for ffmpeg. +def convert_color_values(application, color_value): + """Get color mapping for ffmpeg and oiiotool. Args: - color_value (list[float]): List of float values + application (str): Application for which command should be created. + color_value (list[int]): List of 8bit int values for RGBA. Returns: - str: String with color values in hex format. + str: ffmpeg returns hex string, oiiotool is string with floats. """ red, green, blue, alpha = color_value - # clamp values to max 1.0 and convert 255 range - red = int(min(red, 1.0) * 255) - green = int(min(green, 1.0) * 255) - blue = int(min(blue, 1.0) * 255) - alpha = min(alpha, 1.0) + if application == "ffmpeg": + return "{0:0>2X}{1:0>2X}{2:0>2X}@{3}".format( + red, green, blue, (alpha / 255.0) + ) + elif application == "oiiotool": + red = float(red / 255) + green = float(green / 255) + blue = float(blue / 255) + alpha = float(alpha / 255) - print("red: {0}, green: {1}, blue: {2}, alpha: {3}".format( - red, green, blue, alpha) - ) - # convert to 0-255 range - return "{0:0>2X}{1:0>2X}{2:0>2X}@{3}".format( - red, green, blue, alpha - ) + return "{0:.2f},{1:.2f},{2:.2f},{3:.2f}".format( + red, green, blue, alpha) + else: + raise ValueError( + "\"application\" input argument should " + "be either \"ffmpeg\" or \"oiiotool\"" + ) def get_oiio_input_and_channel_args(oiio_input_info, alpha_default=None): diff --git a/openpype/plugins/publish/extract_thumbnail.py b/openpype/plugins/publish/extract_thumbnail.py index 66473a76aa..7265b9c164 100644 --- a/openpype/plugins/publish/extract_thumbnail.py +++ b/openpype/plugins/publish/extract_thumbnail.py @@ -36,6 +36,7 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "width": 1920, "height": 1080 } + background_color = None duration_split = 0.5 ffmpeg_args = None @@ -287,7 +288,6 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): video_data = get_ffprobe_data(video_file_path, logger=self.log) duration = float(video_data["format"]["duration"]) - resolution_arg = self._get_resolution_arg("ffmpeg") cmd_args = [ "-y", "-ss", str(duration * self.duration_split), @@ -296,6 +296,12 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): "-probesize", max_int, "-vframes", "1" ] + + # get resolution arg + resolution_arg = self._get_resolution_arg( + "ffmpeg", + video_file_path, + ) if resolution_arg: cmd_args.extend(resolution_arg) @@ -320,25 +326,24 @@ class ExtractThumbnail(pyblish.api.InstancePlugin): ) return None - def _get_resolution_arg(self, application): + def _get_resolution_arg( + self, + application, + input_path, + ): # get settings if self.target_size.get("type") == "source": return [] target_width = self.target_size["width"] target_height = self.target_size["height"] - target_par = self.target_size.get("par", 1.0) # form arg string per application return get_rescaled_command_arguments( application, - str(input_path), - input_width, - input_height, - input_par, + input_path, target_width, target_height, - target_par, - bg_color, + bg_color=self.background_color, log=self.log ) diff --git a/openpype/settings/defaults/project_settings/global.json b/openpype/settings/defaults/project_settings/global.json index 5633e81526..c585d1b00e 100644 --- a/openpype/settings/defaults/project_settings/global.json +++ b/openpype/settings/defaults/project_settings/global.json @@ -71,6 +71,12 @@ "ExtractThumbnail": { "enabled": true, "integrate_thumbnail": false, + "background_color": [ + 0, + 0, + 0, + 255 + ], "duration_split": 0.5, "target_size": { "type": "resize", diff --git a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json index b00301d8a2..23739c7520 100644 --- a/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json +++ b/openpype/settings/entities/schemas/projects_schema/schemas/schema_global_publish.json @@ -254,6 +254,11 @@ } ] }, + { + "type": "color", + "label": "Background color", + "key": "background_color" + }, { "key": "duration_split", "label": "Duration split ratio",