use new functions in extract review slate and otio burnins

This commit is contained in:
Jakub Trllo 2022-03-11 17:59:52 +01:00
parent fbf57760ab
commit 50c0580fef
6 changed files with 53 additions and 221 deletions

View file

@ -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:

View file

@ -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",

View file

@ -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)

View file

@ -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)

View file

@ -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

View file

@ -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: