Skip to content

Instantly share code, notes, and snippets.

@vkbo
Created August 27, 2023 20:40
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
Star You must be signed in to star a gist
Embed
What would you like to do?
Script used to upscale ST:DS9 from DVD to HD using Topaz Video AI
"""
Upscale: Star Trek Deep Space Nine
"""
import sys
import subprocess
from pathlib import Path
if sys.platform == "win32":
BASE = Path("D:/Upscale")
WORK = Path("C:/Program Files/Topaz Labs LLC/Topaz Video AI")
else:
BASE = Path("~/Video/Upscale")
WORK = Path(".")
SRC = BASE / "Input"
DST = BASE / "Output"
EXT = ".mkv"
JOBS = [
# Season 1
# {"file": "DS9_1_1_t00.mkv", "crop": "w=702:h=572:x=12:y=2", "params": "S1"},
# {"file": "DS9_1_1_t01.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_1_t02.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_2_t00.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_2_t01.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_2_t02.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_2_t03.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_3_t00.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_3_t01.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_3_t02.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_3_t03.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_4_t00.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_4_t01.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_4_t02.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_4_t03.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_5_t00.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_5_t01.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_5_t02.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
# {"file": "DS9_1_5_t03.mkv", "crop": "w=702:h=572:x=11:y=2", "params": "S1"},
]
AI_PARAMS = {
"S1": "compression=0.30:details=0.13:blur=0.28:noise=0.06:halo=0.09:preblur=-0.05:blend=0.2",
}
DO_FULL = True
DO_SAMPLE = True
OVERWRITE_SAMPLES = False
SAMPLE_TIME = ("00:15:00", "00:00:20") # Start, Length
PROCESS = Path(__file__).parent / "process.txt"
# Colours: https://github.com/bbc/qtff-parameter-editor#video-characteristics
INPUT_SPEC = {
"sws_flags": "spline+accurate_rnd+full_chroma_int",
"color_trc": "2", # Unknown
"colorspace": "2", # Unknown
"color_primaries": "2", # Unknown
# "color_trc": "5", # Gamma 2.8 curve
# "colorspace": "5", # BT470BG
# "color_primaries": "5", # ITU-R BT.470BG
}
COMPLEX_FILTER = [
"crop={crop}",
"scale=w=768:h=576",
"setsar=1",
"tvai_up=model=iris-1:scale=2:{params}:device=0:vram=1:instances=1",
"scale=w=1440:h=1080:flags=lanczos:threads=0",
]
VIDEO_ENC = {
# x264
# "c:v": "libx264",
# VP9 (Very Slow)
# "c:v": "libvpx-vp9",
# "pix_fmt": "yuv420p",
# "row-mt": "1",
# "deadline": "best",
# "b:v": "0",
# AMD h264
# "c:v": "h264_amf",
# "profile:v": "high",
# "pix_fmt": "yuv420p",
# "b:v": "0",
# "quality": "0",
# "rc": "cqp",
# "qp_i": "10",
# "qp_p": "12",
# "qp_b": "12",
# Apple ProRes LT
"c:v": "prores_ks",
"profile:v": "1",
"vendor": "apl0",
"quant_mat": "lt",
"bits_per_mb": "525",
"pix_fmt": "yuv422p10le",
# Apple ProRes Standard
# "c:v": "prores_ks",
# "profile:v": "2",
# "vendor": "apl0",
# "quant_mat": "hq",
# "bits_per_mb": "1350",
# "pix_fmt": "yuv422p10le",
}
AUDIO_ENC = {
"map": "0:a",
"c:a": "copy",
}
META_DATA = {
"map_metadata": "0",
"map_metadata:s:v": "0:s:v",
"map_metadata:s:a:0": "0:s:i:0",
}
def extendArgs(args: list[str], data: dict[str, str]) -> None:
args.extend(m for n in [[f"-{k}", f"{v}"] for k, v in data.items()] for m in n)
return
if DO_SAMPLE:
sampleDir = DST / "Samples"
sampleDir.mkdir(exist_ok=True)
for n, job in enumerate(JOBS, start=1):
inputFile = SRC / job["file"]
origFile = sampleDir / Path(f"{inputFile.stem}_original").with_suffix(EXT)
outputFile = sampleDir / Path(f"{inputFile.stem}_sample").with_suffix(EXT)
if OVERWRITE_SAMPLES or not origFile.exists():
print("")
print(f"Creating Sample {n} of {len(JOBS)}")
print("="*80)
print(f"Original: {origFile}")
print(f"Output: {outputFile}")
args = [
"ffmpeg",
"-ss", SAMPLE_TIME[0], "-t", SAMPLE_TIME[1],
"-i", str(inputFile),
"-map_metadata", "0",
"-vcodec", "copy",
"-acodec", "copy",
str(origFile)
]
command = " ".join(args)
print(f"Command: {command}")
print("")
print("-"*80)
print("")
origFile.unlink(missing_ok=True)
subprocess.run(command, cwd=WORK, shell=True)
if OVERWRITE_SAMPLES or not outputFile.exists():
args = [
"ffmpeg",
"-ss", SAMPLE_TIME[0], "-t", SAMPLE_TIME[1],
"-i", str(inputFile),
]
extendArgs(args, INPUT_SPEC)
extendArgs(args, META_DATA)
complexFilter = ",".join(COMPLEX_FILTER).format(
crop=job["crop"],
params=AI_PARAMS[job["params"]],
)
args.extend(["-filter_complex", complexFilter])
extendArgs(args, VIDEO_ENC)
extendArgs(args, AUDIO_ENC)
args.append(str(outputFile))
command = " ".join(args)
print("")
print("-"*80)
print(f"Command: {command}")
print("")
print("-"*80)
print("")
outputFile.unlink(missing_ok=True)
subprocess.run(command, cwd=WORK, shell=True)
if DO_FULL:
for n, job in enumerate(JOBS, start=1):
if PROCESS.exists() and PROCESS.read_text().strip().lower() == "stop":
print("")
print("****************************")
print("* Stopping upscale job ... *")
print("****************************")
print("")
break
inputFile = SRC / job["file"]
outputFile = DST / Path(f"{inputFile.stem}_upscale").with_suffix(EXT)
print("")
print(f"Upscaling Video {n} of {len(JOBS)}")
print("="*80)
if outputFile.exists():
print(f"File Exists: {outputFile}")
continue
else:
print(f"Output: {outputFile}")
args = ["ffmpeg", "-i", str(inputFile)]
extendArgs(args, INPUT_SPEC)
extendArgs(args, META_DATA)
complexFilter = ",".join(COMPLEX_FILTER).format(
crop=job["crop"],
params=AI_PARAMS[job["params"]],
)
args.extend(["-filter_complex", complexFilter])
extendArgs(args, VIDEO_ENC)
extendArgs(args, AUDIO_ENC)
args.append(str(outputFile))
command = " ".join(args)
print(f"Command: {command}")
print("")
print("-"*80)
print("")
subprocess.run(command, cwd=WORK, shell=True)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment