Skip to content

Instantly share code, notes, and snippets.

@Riebart
Last active September 27, 2023 21:44
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Riebart/929c736f92f5e0a684dd6c9597de3b97 to your computer and use it in GitHub Desktop.
Save Riebart/929c736f92f5e0a684dd6c9597de3b97 to your computer and use it in GitHub Desktop.
Generate a matrix of ffmpeg commands from a set of inputs.
{
"hevc_nvenc": {
"preset": [
"p7"
],
"tune": [
"hq"
],
"rc:v": [
"vbr"
],
"cq:v": [
"18",
"24",
"30",
"36",
"42",
"48"
],
"b:v": [
"0"
],
"multipass": [
"0",
"2"
],
"tier": [
"high"
],
"qmin": "cq:v",
"qmax": "cq:v"
},
"libx265": {
"crf": [
"18",
"24",
"30",
"36",
"42",
"48"
],
"qp": "crf",
"preset": [
"veryslow"
],
"tune": [
null,
"ssim"
]
}
}
#!/usr/bin/env python3
# cmds=$(cat ../encoding_options.json | python3 ../options_to_commands.py *.mp4); echo "$cmds" | md5sum; echo "$cmds" | tail -n1 > opt_mapping.json; echo "$cmds" | grep "c:v hevc_nvenc" > nvenc.list ; echo "$cmds" | grep "c:v libx265" > libx265.list
import json
import sys
import hashlib
binary="tsp ffmpeg.exe"
out_path = "variants/"
metadata = {"nvenc_arch": "turing"}
filenames = sys.argv[1:]
input_options = " ".join([f"-{io}" for io in [
"noautorotate"
]])
audio_options = " ".join([f"-{ao}" for ao in [
"c:a aac",
"b:a 128k"
]])
variants = json.loads(sys.stdin.read())
def build_option_string(options):
next_options = dict()
alias_keys = [k for k, v in options.items() if isinstance(v, str)]
this_option = alias_keys[0] if alias_keys != [] else list(options.keys())[0]
if len(options) > 1:
next_options.update(options)
del next_options[this_option]
cmdlines = build_option_string(next_options)
else:
cmdlines = [dict()]
next_cmdlines = []
if isinstance(options[this_option], str):
for cmdline in cmdlines:
n = dict()
n.update(cmdline)
n[this_option] = cmdline[options[this_option]]
next_cmdlines.append(n)
else:
for value in options[this_option]:
for cmdline in cmdlines:
if value is not None:
n = dict()
n.update(cmdline)
n[this_option] = value
next_cmdlines.append(n)
else:
next_cmdlines.append(cmdline)
return next_cmdlines
cmds = []
opt_mapping = dict()
for encoder, options in variants.items():
cmdline = f"-c:v {encoder}"
# option_lines = [f"{cmdline} {opts}" for opts in build_option_string(options, dict())]
option_lines = build_option_string(options)
for option in option_lines:
opts = " ".join([f"-{k} {v}" for k, v in option.items()])
for fname in filenames:
c = f"{binary} {input_options} -i {fname} -c:v {encoder} {opts} {audio_options}"
ofname = hashlib.md5((c + (str(metadata) if metadata else "")).encode("utf-8")).hexdigest()[:8]
cmds.append(
f"{c} {out_path}{ofname}.mp4"
)
opt_mapping[ofname] = {"opts": option, "file": fname, "encoder": encoder}
opt_mapping[ofname].update(metadata)
[print(c) for c in cmds]
print(json.dumps(opt_mapping))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment