diff --git a/Sparks_in_Blender_encode.py b/Sparks_in_Blender_encode.py new file mode 100755 index 0000000..70f53a1 --- /dev/null +++ b/Sparks_in_Blender_encode.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +import os + +import time + +import csv + +import ffmpy + +from multiprocessing import cpu_count + +from collections import OrderedDict + +import json + +# always round timestamp to integer +def now(): + return int(time.time()) + + +def write_line( + codec: str, + crf: str, + preset: str, + infile: str, + outfile: str, + outfilesize: float, + enctime: int, + vmafmean: float, + vmafmin: float, +): + """ + Write line to data csv + + Parameters: + codec (str): Codec used + crf (str): CRF used + preset (str): Preset used + infile (str): Input file name + outfile (str): Output file name + outfilesize (float): Size of output file + enctime (int): Time to encode + vmafmean (float): Mean VMAF score + vmafmin (float): Min VMAF score + """ + with open(datafile, "a", newline="") as file: + write = csv.writer(file) + write.writerow( + ( + codec, + crf, + preset, + infile, + outfile, + outfilesize, + enctime, + vmafmean, + vmafmin, + ) + ) + + +if __name__ == "__main__": + encoding = { + "libx264": { + "crf": [15, 20, 25, 30, 35], + "presets": ["fast", "medium", "slow", "veryslow"], + }, + "libx265": { + "crf": [15, 20, 25, 30, 35], + "presets": ["fast", "medium", "slow", "veryslow"], + }, + "libaom-av1": {"crf": [20, 25, 30, 35, 40], "presets": [0, 2, 4, 6]}, + "libsvtav1": {"crf": [20, 25, 30, 35, 40], "presets": [0, 4, 8, 12]}, + } + + if not os.path.isdir("encoded"): + os.mkdir("encoded") + + datafile = "data-" + str(now()) + ".csv" + + with open(datafile, "w", newline="") as file: + write = csv.writer(file) + write.writerow( + ( + "Codec", + "CRF", + "Preset", + "Input file", + "Output file", + "Output file size (MiB)", + "Encode time (s)", + "VMAF Score (mean)", + "VMAF Score (min)", + ) + ) + + for codec in encoding: + for crf in encoding[codec]["crf"]: + for preset in encoding[codec]["presets"]: + outputfile = os.path.join( + "encoded", + ( + "Sparks_in_Blender-codec_" + + codec + + "-crf_" + + str(crf) + + "-preset_" + + str(preset) + + ".mkv" + ), + ) + + # libaom needs additional options + if codec == "libaom-av1": + ff = ffmpy.FFmpeg( + inputs={"Sparks_in_Blender.webm": None}, + outputs={ + outputfile: "-c:v {videocodec} -crf {crf} -b:v 0 -cpu-used {preset} -row-mt 1 -tiles 2x2 -g 240 -map 0:v:0 ".format( + videocodec=codec, + crf=crf, + preset=preset, + ) + }, + ) + else: + ff = ffmpy.FFmpeg( + inputs={"Sparks_in_Blender.webm": None}, + outputs={ + outputfile: "-c:v {videocodec} -crf {crf} -preset {preset} -g 240 -map 0:v:0 ".format( + videocodec=codec, + crf=crf, + preset=preset, + ) + }, + ) + + starttime = now() + ff.run() + endtime = now() + difftime = int(endtime - starttime) + + outputfilesize = os.path.getsize(outputfile) / 1024 / 1024 + + ffvmaf = ffmpy.FFmpeg( + inputs=OrderedDict( + [(outputfile, None), ("Sparks_in_Blender.webm", None)] + ), + outputs={ + "-": "-filter_complex libvmaf=log_fmt=json:n_threads={cputhreads}:log_path=vmaf.json -f null".format( + cputhreads=cpu_count() + ) + }, + ) + + ffvmaf.run() + + with open("vmaf.json", "r") as file: + vmaf = json.load(file) + + write_line( + codec=codec, + crf=crf, + preset=preset, + infile="Sparks_in_Blender.webm", + outfile=outputfile, + outfilesize=outputfilesize, + enctime=difftime, + vmafmean=vmaf["pooled_metrics"]["vmaf"]["mean"], + vmafmin=vmaf["pooled_metrics"]["vmaf"]["min"], + )