From 50c0580feff4142db32f183452d17a801d2dcf13 Mon Sep 17 00:00:00 2001 From: Jakub Trllo Date: Fri, 11 Mar 2022 17:59:52 +0100 Subject: [PATCH] use new functions in extract review slate and otio burnins --- .../publish/collect_published_files.py | 8 +- openpype/lib/__init__.py | 2 + openpype/lib/transcoding.py | 20 ++ openpype/lib/vendor_bin_utils.py | 20 -- .../plugins/publish/extract_review_slate.py | 52 ++---- openpype/scripts/otio_burnin.py | 172 ++---------------- 6 files changed, 53 insertions(+), 221 deletions(-) diff --git a/openpype/hosts/webpublisher/plugins/publish/collect_published_files.py b/openpype/hosts/webpublisher/plugins/publish/collect_published_files.py index be33e6bb4e..65cef14703 100644 --- a/openpype/hosts/webpublisher/plugins/publish/collect_published_files.py +++ b/openpype/hosts/webpublisher/plugins/publish/collect_published_files.py @@ -17,9 +17,9 @@ import pyblish.api from openpype.lib import ( prepare_template_data, get_asset, - get_ffprobe_streams + get_ffprobe_streams, + convert_ffprobe_fps_value, ) -from openpype.lib.vendor_bin_utils import get_fps from openpype.lib.plugin_tools import ( parse_json, get_subset_name_with_asset_doc @@ -292,7 +292,9 @@ class CollectPublishedFiles(pyblish.api.ContextPlugin): "nb_frames {} not convertible".format(nb_frames)) duration = stream.get("duration") - frame_rate = get_fps(stream.get("r_frame_rate", '0/0')) + frame_rate = convert_ffprobe_fps_value( + stream.get("r_frame_rate", '0/0') + ) self.log.debug("duration:: {} frame_rate:: {}".format( duration, frame_rate)) try: diff --git a/openpype/lib/__init__.py b/openpype/lib/__init__.py index 523ced8022..d5cde3031f 100644 --- a/openpype/lib/__init__.py +++ b/openpype/lib/__init__.py @@ -88,6 +88,7 @@ from .transcoding import ( get_ffprobe_streams, get_ffmpeg_codec_args, get_ffmpeg_format_args, + convert_ffprobe_fps_value, ) from .avalon_context import ( CURRENT_DOC_SCHEMAS, @@ -234,6 +235,7 @@ __all__ = [ "get_ffprobe_streams", "get_ffmpeg_codec_args", "get_ffmpeg_format_args", + "convert_ffprobe_fps_value", "CURRENT_DOC_SCHEMAS", "PROJECT_NAME_ALLOWED_SYMBOLS", diff --git a/openpype/lib/transcoding.py b/openpype/lib/transcoding.py index 554fad8813..6181ff6d13 100644 --- a/openpype/lib/transcoding.py +++ b/openpype/lib/transcoding.py @@ -732,3 +732,23 @@ def _ffmpeg_dnxhd_codec_args(stream_data, source_ffmpeg_cmd): output.extend(["-g", "1"]) return output + + +def convert_ffprobe_fps_value(str_value): + """Returns (str) value of fps from ffprobe frame format (120/1)""" + if str_value == "0/0": + print("WARNING: Source has \"r_frame_rate\" value set to \"0/0\".") + return "Unknown" + + items = str_value.split("/") + if len(items) == 1: + fps = float(items[0]) + + elif len(items) == 2: + fps = float(items[0]) / float(items[1]) + + # Check if fps is integer or float number + if int(fps) == fps: + fps = int(fps) + + return str(fps) diff --git a/openpype/lib/vendor_bin_utils.py b/openpype/lib/vendor_bin_utils.py index 36510f4238..23e28ea304 100644 --- a/openpype/lib/vendor_bin_utils.py +++ b/openpype/lib/vendor_bin_utils.py @@ -152,23 +152,3 @@ def is_oiio_supported(): )) return False return True - - -def get_fps(str_value): - """Returns (str) value of fps from ffprobe frame format (120/1)""" - if str_value == "0/0": - print("WARNING: Source has \"r_frame_rate\" value set to \"0/0\".") - return "Unknown" - - items = str_value.split("/") - if len(items) == 1: - fps = float(items[0]) - - elif len(items) == 2: - fps = float(items[0]) / float(items[1]) - - # Check if fps is integer or float number - if int(fps) == fps: - fps = int(fps) - - return str(fps) diff --git a/openpype/plugins/publish/extract_review_slate.py b/openpype/plugins/publish/extract_review_slate.py index e27a0b28bd..460d546340 100644 --- a/openpype/plugins/publish/extract_review_slate.py +++ b/openpype/plugins/publish/extract_review_slate.py @@ -4,7 +4,10 @@ import pyblish from openpype.lib import ( path_to_subprocess_arg, get_ffmpeg_tool_path, + get_ffprobe_data, get_ffprobe_streams, + get_ffmpeg_codec_args, + get_ffmpeg_format_args, ) @@ -161,7 +164,7 @@ class ExtractReviewSlate(openpype.api.Extractor): output_args.extend(repre["_profile"].get('output', [])) else: # Codecs are copied from source for whole input - codec_args = self.codec_args(repre) + codec_args = self._get_codec_args(repre) output_args.extend(codec_args) # make sure colors are correct @@ -335,7 +338,7 @@ class ExtractReviewSlate(openpype.api.Extractor): return vf_back - def codec_args(self, repre): + def _get_codec_args(self, repre): """Detect possible codec arguments from representation.""" codec_args = [] @@ -349,7 +352,7 @@ class ExtractReviewSlate(openpype.api.Extractor): try: # Get information about input file via ffprobe tool - streams = get_ffprobe_streams(full_input_path, self.log) + ffprobe_data = get_ffprobe_data(full_input_path, self.log) except Exception: self.log.warning( "Could not get codec data from input.", @@ -357,42 +360,11 @@ class ExtractReviewSlate(openpype.api.Extractor): ) return codec_args - # Try to find first stream that is not an audio - no_audio_stream = None - for stream in streams: - if stream.get("codec_type") != "audio": - no_audio_stream = stream - break + codec_args.extend( + get_ffmpeg_format_args(ffprobe_data) + ) + codec_args.extend( + get_ffmpeg_codec_args(ffprobe_data, logger=self.log) + ) - if no_audio_stream is None: - self.log.warning(( - "Couldn't find stream that is not an audio from file \"{}\"" - ).format(full_input_path)) - return codec_args - - codec_name = no_audio_stream.get("codec_name") - if codec_name: - codec_args.append("-codec:v {}".format(codec_name)) - - profile_name = no_audio_stream.get("profile") - if profile_name: - # Rest of arguments is prores_kw specific - if codec_name == "prores_ks": - codec_tag_to_profile_map = { - "apco": "proxy", - "apcs": "lt", - "apcn": "standard", - "apch": "hq", - "ap4h": "4444", - "ap4x": "4444xq" - } - codec_tag_str = no_audio_stream.get("codec_tag_string") - if codec_tag_str: - profile = codec_tag_to_profile_map.get(codec_tag_str) - if profile: - codec_args.extend(["-profile:v", profile]) - - pix_fmt = no_audio_stream.get("pix_fmt") - if pix_fmt: - codec_args.append("-pix_fmt {}".format(pix_fmt)) return codec_args diff --git a/openpype/scripts/otio_burnin.py b/openpype/scripts/otio_burnin.py index 874c08064a..1f57891b84 100644 --- a/openpype/scripts/otio_burnin.py +++ b/openpype/scripts/otio_burnin.py @@ -5,12 +5,17 @@ import subprocess import platform import json import opentimelineio_contrib.adapters.ffmpeg_burnins as ffmpeg_burnins -import openpype.lib -from openpype.lib.vendor_bin_utils import get_fps + +from openpype.lib import ( + get_ffmpeg_tool_path, + get_ffmpeg_codec_args, + get_ffmpeg_format_args, + convert_ffprobe_fps_value, +) -ffmpeg_path = openpype.lib.get_ffmpeg_tool_path("ffmpeg") -ffprobe_path = openpype.lib.get_ffmpeg_tool_path("ffprobe") +ffmpeg_path = get_ffmpeg_tool_path("ffmpeg") +ffprobe_path = get_ffmpeg_tool_path("ffprobe") FFMPEG = ( @@ -51,157 +56,6 @@ def _get_ffprobe_data(source): return json.loads(out) -def _prores_codec_args(stream_data, source_ffmpeg_cmd): - output = [] - - tags = stream_data.get("tags") or {} - encoder = tags.get("encoder") or "" - if encoder.endswith("prores_ks"): - codec_name = "prores_ks" - - elif encoder.endswith("prores_aw"): - codec_name = "prores_aw" - - else: - codec_name = "prores" - - output.extend(["-codec:v", codec_name]) - - pix_fmt = stream_data.get("pix_fmt") - if pix_fmt: - output.extend(["-pix_fmt", pix_fmt]) - - # Rest of arguments is prores_kw specific - if codec_name == "prores_ks": - codec_tag_to_profile_map = { - "apco": "proxy", - "apcs": "lt", - "apcn": "standard", - "apch": "hq", - "ap4h": "4444", - "ap4x": "4444xq" - } - codec_tag_str = stream_data.get("codec_tag_string") - if codec_tag_str: - profile = codec_tag_to_profile_map.get(codec_tag_str) - if profile: - output.extend(["-profile:v", profile]) - - return output - - -def _h264_codec_args(stream_data, source_ffmpeg_cmd): - output = ["-codec:v", "h264"] - - # Use arguments from source if are available source arguments - if source_ffmpeg_cmd: - copy_args = ( - "-crf", - "-b:v", "-vb", - "-minrate", "-minrate:", - "-maxrate", "-maxrate:", - "-bufsize", "-bufsize:" - ) - args = source_ffmpeg_cmd.split(" ") - for idx, arg in enumerate(args): - if arg in copy_args: - output.extend([arg, args[idx + 1]]) - - pix_fmt = stream_data.get("pix_fmt") - if pix_fmt: - output.extend(["-pix_fmt", pix_fmt]) - - output.extend(["-intra"]) - output.extend(["-g", "1"]) - - return output - - -def _dnxhd_codec_args(stream_data, source_ffmpeg_cmd): - output = ["-codec:v", "dnxhd"] - - # Use source profile (profiles in metadata are not usable in args directly) - profile = stream_data.get("profile") or "" - # Lower profile and replace space with underscore - cleaned_profile = profile.lower().replace(" ", "_") - dnx_profiles = { - "dnxhd", - "dnxhr_lb", - "dnxhr_sq", - "dnxhr_hq", - "dnxhr_hqx", - "dnxhr_444" - } - if cleaned_profile in dnx_profiles: - output.extend(["-profile:v", cleaned_profile]) - - pix_fmt = stream_data.get("pix_fmt") - if pix_fmt: - output.extend(["-pix_fmt", pix_fmt]) - - # Use arguments from source if are available source arguments - if source_ffmpeg_cmd: - copy_args = ( - "-b:v", "-vb", - ) - args = source_ffmpeg_cmd.split(" ") - for idx, arg in enumerate(args): - if arg in copy_args: - output.extend([arg, args[idx + 1]]) - - output.extend(["-g", "1"]) - return output - - -def _mxf_format_args(ffprobe_data, source_ffmpeg_cmd): - input_format = ffprobe_data["format"] - format_tags = input_format.get("tags") or {} - product_name = format_tags.get("product_name") or "" - output = [] - if "opatom" in product_name.lower(): - output.extend(["-f", "mxf_opatom"]) - return output - - -def get_format_args(ffprobe_data, source_ffmpeg_cmd): - input_format = ffprobe_data.get("format") or {} - if input_format.get("format_name") == "mxf": - return _mxf_format_args(ffprobe_data, source_ffmpeg_cmd) - return [] - - -def get_codec_args(ffprobe_data, source_ffmpeg_cmd): - stream_data = ffprobe_data["streams"][0] - codec_name = stream_data.get("codec_name") - # Codec "prores" - if codec_name == "prores": - return _prores_codec_args(stream_data, source_ffmpeg_cmd) - - # Codec "h264" - if codec_name == "h264": - return _h264_codec_args(stream_data, source_ffmpeg_cmd) - - # Coded DNxHD - if codec_name == "dnxhd": - return _dnxhd_codec_args(stream_data, source_ffmpeg_cmd) - - output = [] - if codec_name: - output.extend(["-codec:v", codec_name]) - - bit_rate = stream_data.get("bit_rate") - if bit_rate: - output.extend(["-b:v", bit_rate]) - - pix_fmt = stream_data.get("pix_fmt") - if pix_fmt: - output.extend(["-pix_fmt", pix_fmt]) - - output.extend(["-g", "1"]) - - return output - - class ModifiedBurnins(ffmpeg_burnins.Burnins): ''' This is modification of OTIO FFmpeg Burnin adapter. @@ -592,7 +446,9 @@ def burnins_from_data( data["resolution_height"] = stream.get("height", MISSING_KEY_VALUE) if "fps" not in data: - data["fps"] = get_fps(stream.get("r_frame_rate", "0/0")) + data["fps"] = convert_ffprobe_fps_value( + stream.get("r_frame_rate", "0/0") + ) # Check frame start and add expression if is available if frame_start is not None: @@ -703,10 +559,10 @@ def burnins_from_data( else: ffmpeg_args.extend( - get_format_args(burnin.ffprobe_data, source_ffmpeg_cmd) + get_ffmpeg_format_args(burnin.ffprobe_data, source_ffmpeg_cmd) ) ffmpeg_args.extend( - get_codec_args(burnin.ffprobe_data, source_ffmpeg_cmd) + get_ffmpeg_codec_args(burnin.ffprobe_data, source_ffmpeg_cmd) ) # Use arguments from source if are available source arguments if source_ffmpeg_cmd: