Created
October 25, 2019 18:26
-
-
Save cdgriffith/e2608bfee68bb3d7e491cb387e8d75b1 to your computer and use it in GitHub Desktop.
HDR color primaries and luminance passthrough options
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
from subprocess import run, PIPE | |
import re | |
import sys | |
import json | |
su = re.compile(r'",\s*}') | |
def run_ffprobe(video_file): | |
command = (f'ffprobe "{video_file}" -show_streams -select_streams v:0 -read_intervals "%+#10" ' | |
f'-show_frames -show_entries side_data -v quiet -pretty -print_format json -of json') | |
result = run(command, stdout=PIPE) | |
if result.returncode != 0: | |
raise Exception(f"Error while running ffprobe {result}") | |
return json.loads(su.sub('"}', result.stdout.decode("utf-8"))) | |
def parse_json(data): | |
master_display_raw = None | |
max_cll = 0 | |
max_fall = 0 | |
for frame in data["packets_and_frames"]: | |
if frame["type"] != "frame" or "side_data_list" not in frame: | |
continue | |
for item in frame["side_data_list"]: | |
if not master_display_raw and item["side_data_type"] == "Mastering display metadata": | |
master_display_raw = item | |
if item["side_data_type"] == "Content light level metadata": | |
max_cll = item["max_content"] | |
max_fall = item["max_average"] | |
if not master_display_raw: | |
if data["streams"][0]["codec_tag_string"] == "dvhe": | |
raise Exception("This is a dolby vision file, No master display data provided") | |
raise Exception("No master display data found") | |
del master_display_raw['side_data_type'] | |
for key in master_display_raw.keys(): | |
master_display_raw[key] = master_display_raw[key].split("/")[0] | |
return master_display_raw, max_cll, max_fall | |
if __name__ == '__main__': | |
video = sys.argv[1] | |
ffprobe_output = run_ffprobe(video) | |
main_stream = ffprobe_output["streams"][0] | |
mdr, cll, fall = parse_json(ffprobe_output) | |
master_display = ("master-display=" | |
f"G({mdr['green_x']},{mdr['green_y']})" | |
f"B({mdr['blue_x']},{mdr['blue_y']})" | |
f"R({mdr['red_x']},{mdr['red_y']})" | |
f"WP({mdr['white_point_x']},{mdr['white_point_y']})" | |
f"L({mdr['max_luminance']},{mdr['min_luminance']})") | |
max_lum = f"max-cll={cll},{fall}" | |
params = (f'-pix_fmt {main_stream["pix_fmt"]} -x265-params ' | |
f'"aq-mode=1:' | |
f'colorprim={main_stream["color_primaries"]}:' | |
f'colormatrix={main_stream["color_space"]}:' | |
f'transfer={main_stream["color_transfer"]}:' | |
f'chromaloc=2:' | |
f'{master_display}:' | |
f'{max_lum}:' | |
f'hdr-opt=1:hdr=1:info=1:repeat-headers=1"') | |
print(params) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
$
x265_passthrough.py video.mkv
-pix_fmt yuv420p10le -x265-params "aq-mode=1:colorprim=bt2020:colormatrix=bt2020nc:transfer=smpte2084:chromaloc=2:master-display=G(13250,34500)B(7500,3000)R(34000,16000)WP(15635,16450)L(10000000,1):max-cll=0,0:hdr-opt=1:hdr=1:info=1:repeat-headers=1"