type VideoEncodePreset = { id: string; codec: "av1"; preset: 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8; mbitMax?: number; crf: number; maxHeight?: number; audioKbit?: number; depth?: 8 | 10; } | { id: string; codec: "vp9"; crf: number; mbitMax?: number; maxHeight?: number; audioKbit?: number; }; export const videoFormats = [ { id: "au", // AV1 Ultra-High codec: "av1", preset: 1, crf: 28, depth: 10, }, { id: "vu", // VP9 Ultra-High codec: "vp9", crf: 30, }, { id: "ah", // AV1 High preset: 2, codec: "av1", mbitMax: 5, crf: 35, depth: 10, }, { id: "am", // AV1 Medium preset: 2, codec: "av1", mbitMax: 2, crf: 40, maxHeight: 900, }, { id: "vm", // VP9 Medium codec: "vp9", crf: 35, mbitMax: 4, maxHeight: 1080, }, { id: "al", // AV1 Low preset: 2, codec: "av1", mbitMax: 1.25, crf: 40, maxHeight: 600, }, { id: "vl", // VP9 Low codec: "vp9", crf: 45, mbitMax: 2, maxHeight: 600, }, { id: "ad", // AV1 Data-saving codec: "av1", preset: 1, mbitMax: 0.5, crf: 10, maxHeight: 360, }, { id: "vl", // VP9 Low codec: "vp9", crf: 10, mbitMax: 0.75, maxHeight: 360, }, ] satisfies VideoEncodePreset[] as VideoEncodePreset[]; export const imageSizes = [64, 128, 256, 512, 1024, 2048]; export const imagePresets = [ { ext: ".webp", args: [ "-lossless", "0", "-compression_level", "6", "-quality", "95", "-method", "6", ], }, // TODO: avif { ext: ".jxl", args: ["-c:v", "libjxl", "-distance", "0.8", "-effort", "9"], }, ]; export function getVideoArgs(preset: VideoEncodePreset, outbase: string, input: string[]) { const cmd = [...input]; if (preset.codec === "av1") { cmd.push("-c:v", "libsvtav1"); cmd.push( "-svtav1-params", [ `preset=${preset.preset}`, "keyint=2s", preset.depth && `input-depth=${preset.depth}`, // EncoderBitDepth `crf=${preset.crf}`, // ConstantRateFactor preset.mbitMax && `mbr=${preset.mbitMax}m`, // MaxBitRate "tune=1", // Tune, PSNR "enable-overlays=1", // EnableOverlays "fast-decode=1", // FastDecode "scm=2", // ScreenContentMode, adaptive ].filter(Boolean).join(":"), ); } else if (preset.codec === "vp9") { // Not much research has gone into this, since it is only going to be used on old Safari browsers. cmd.push("-c:v", "libvpx-vp9"); cmd.push("-crf", String(preset.crf)); cmd.push("-b:v", preset.mbitMax ? `${preset.mbitMax * 1000}k` : "0"); } else preset satisfies never; if (preset.maxHeight != null) { cmd.push("-vf", `scale=-2:min(${preset.maxHeight}\\,ih)`); } cmd.push("-c:a", "libopus"); cmd.push("-b:a", (preset.audioKbit ?? 192) + "k"); cmd.push("-y"); cmd.push("-f", "hls"); cmd.push("-hls_list_size", "0"); cmd.push("-hls_segment_type", "fmp4"); cmd.push("-hls_time", "2"); cmd.push("-hls_allow_cache", "1"); cmd.push("-hls_fmp4_init_filename", preset.id + ".mp4"); cmd.push(path.join(outbase, preset.id + ".m3u8")); return cmd; } import * as path from "node:path";