Source code

Revision control

Copy as Markdown

Other Tools

#!/usr/bin/env python3
# E.g. `./gen_combos.py [--write] color_quads/720p.png`
import concurrent.futures
import pathlib
import subprocess
import sys
ARGS = sys.argv
SRC_PATH = pathlib.Path(ARGS.pop())
assert SRC_PATH.exists(), "gen_combos.py [--flags] <src file path>"
DIR = SRC_PATH.parent
# crossCombine([{a:false},{a:5}], [{},{b:5}])
# [{a:false}, {a:true}, {a:false,b:5}, {a:true,b:5}]
def cross_combine(*args):
args = list(args)
def cross_combine2(listA, listB):
listC = []
for a in listA:
for b in listB:
c = dict()
c.update(a)
c.update(b)
listC.append(c)
return listC
res = [dict()]
while True:
try:
next = args.pop(0)
except IndexError:
break
res = cross_combine2(res, next)
return res
def keyed_combiner(key, vals):
res = []
for v in vals:
d = dict()
d[key] = v
res.append(d)
return res
# -
def eprint(*args, **kwargs):
print(*args, file=sys.stderr, **kwargs)
# -
OGG = []
WEBM_CODECS = ["av1", "vp9"]
if "--all" in ARGS:
OGG = cross_combine([{"ext": "ogg"}], keyed_combiner("vcodec", ["vp8", "vp9"]))
WEBM_CODECS += ["vp8"]
MP4 = cross_combine([{"ext": "mp4"}], keyed_combiner("vcodec", ["av1", "h264", "vp9"]))
WEBM = cross_combine([{"ext": "webm"}], keyed_combiner("vcodec", WEBM_CODECS))
# -
FORMAT_LIST = set(
[
"yuv420p",
"yuv420p10",
# 'yuv420p12',
# 'yuv420p16be',
# 'yuv420p16le',
"gbrp",
]
)
if "--all" in ARGS:
FORMAT_LIST |= set(
[
"yuv420p",
"yuv420p10",
"yuv420p12",
"yuv420p16be",
"yuv420p16le",
"yuv422p",
"yuv422p10",
"yuv422p12",
"yuv422p16be",
"yuv422p16le",
"yuv444p",
"yuv444p10",
"yuv444p12",
"yuv444p16be",
"yuv444p16le",
"yuv411p",
"yuv410p",
"yuyv422",
"uyvy422",
"rgb24",
"bgr24",
"rgb8",
"bgr8",
"rgb444be",
"rgb444le",
"bgr444be",
"bgr444le",
# 'nv12', # Encoding not different than yuv420p?
# 'nv21', # Encoding not different than yuv420p?
"gbrp",
"gbrp9be",
"gbrp9le",
"gbrp10be",
"gbrp10le",
"gbrp12be",
"gbrp12le",
"gbrp14be",
"gbrp14le",
"gbrp16be",
"gbrp16le",
]
)
FORMATS = keyed_combiner("format", list(FORMAT_LIST))
RANGE = keyed_combiner("range", ["tv", "pc"])
CSPACE_LIST = set(
[
"bt709",
# 'bt2020',
]
)
if "--all" in ARGS:
CSPACE_LIST |= set(
[
"bt709",
"bt2020",
"bt601-6-525", # aka smpte170m NTSC
"bt601-6-625", # aka bt470bg PAL
]
)
CSPACE_LIST = list(CSPACE_LIST)
# -
COMBOS = cross_combine(
WEBM + MP4 + OGG,
FORMATS,
RANGE,
keyed_combiner("src_cspace", CSPACE_LIST),
keyed_combiner("dst_cspace", CSPACE_LIST),
)
# -
print(f"{len(COMBOS)} combinations...")
todo = []
for c in COMBOS:
dst_name = ".".join(
[
SRC_PATH.name,
c["src_cspace"],
c["dst_cspace"],
c["range"],
c["format"],
c["vcodec"],
c["ext"],
]
)
src_cspace = c["src_cspace"]
vf = f"scale=out_range={c['range']}"
vf += f",colorspace=all={c['dst_cspace']}"
vf += f":iall={src_cspace}"
args = [
"ffmpeg",
"-y",
# For input:
"-color_primaries",
src_cspace,
"-color_trc",
src_cspace,
"-colorspace",
src_cspace,
"-i",
SRC_PATH.as_posix(),
# For output:
"-bitexact", # E.g. don't use true random uuids
"-vf",
vf,
"-pix_fmt",
c["format"],
"-vcodec",
c["vcodec"],
"-crf",
"1", # Not-quite-lossless
(DIR / dst_name).as_posix(),
]
if "-v" in ARGS or "-vv" in ARGS:
print("$ " + " ".join(args))
else:
print(" " + args[-1])
todo.append(args)
# -
with open(DIR / "reftest.list", "r") as f:
reftest_list_text = f.read()
for args in todo:
vid_name = pathlib.Path(args[-1]).name
if vid_name not in reftest_list_text:
print(f"WARNING: Not in reftest.list: {vid_name}")
# -
if "--write" not in ARGS:
print("Use --write to write. Exiting...")
exit(0)
# -
def run_cmd(args):
dest = None
if "-vv" not in ARGS:
dest = subprocess.DEVNULL
try:
subprocess.run(args, stderr=dest)
except FileNotFoundError:
print("FileNotFoundError, is ffmpeg not in your PATH?")
raise
with concurrent.futures.ThreadPoolExecutor() as pool:
fs = []
for cur_args in todo:
f = pool.submit(run_cmd, cur_args)
fs.append(f)
done = 0
for f in concurrent.futures.as_completed(fs):
f.result() # Raise if it raised
done += 1
sys.stdout.write(f"\rEncoded {done}/{len(todo)}")