From 8d1dc0d825bcc9b8b570cbc829d67282c6892f59 Mon Sep 17 00:00:00 2001 From: chloe caruso Date: Fri, 27 Jun 2025 22:35:03 -0700 Subject: [PATCH] start av1 encoding ??? --- src/file-viewer/bin/scan3.ts | 75 +++++++++++++++++++++++++++++++++--- 1 file changed, 70 insertions(+), 5 deletions(-) diff --git a/src/file-viewer/bin/scan3.ts b/src/file-viewer/bin/scan3.ts index 26cf868..b8a1fcd 100644 --- a/src/file-viewer/bin/scan3.ts +++ b/src/file-viewer/bin/scan3.ts @@ -394,7 +394,6 @@ const imageSubsets = [ const procImageSubsets: Process = { name: "encode image subsets", include: rules.extsImage, - enable: false, depends: ["calculate dimensions"], async run({ absPath, mediaFile, stat, spin }) { const { width, height } = UNWRAP(mediaFile.parseDimensions()); @@ -443,11 +442,75 @@ const procImageSubsets: Process = { }, }; -const videoFormats = [ - { - name: "webm", - }, +type VideoEncodePreset = { + id: string; + codec: "av1"; + mbit: number; + crf?: number; + maxHeight?: number; + audioKbit?: number; +} | { + id: string; + codec: "vp9"; + mbit: number; + maxHeight?: number; + audioKbit?: number; +}; +// const av1Pass1 = [ +// '-c:v', 'libsvtav1 -b:v 2M -pass 1 -svtav1-params "rc=1:tbr=2000000" -preset 8 -f null NUL +// ]; +// const av1BaseArgs = [ +// ["-c:v", "libsvtav1"], +// ["-preset", "3"], +// ["-c:a", "libopus"], +// ["-b:a", "192k"], +// ].flat(); +// const webmBaseArgs = [ +// "-c:v", +// "libsvtav1", +// ["-vf",], +// ]; +const presets: VideoEncodePreset[] = [ + { id: "av1-max", codec: "av1", mbit: 5 }, + { id: "av1-hq", codec: "av1", mbit: 2, maxHeight: 900 }, + { id: "av1-md", codec: "av1", mbit: 0.5, maxHeight: 720 }, + { id: "av1-lq", codec: "av1", mbit: 0.2, maxHeight: 640 }, ]; +const procVideos = presets.map((preset) => ({ + name: "encode image subsets", + include: rules.extsImage, + async run({ absPath, mediaFile, stat, spin }) { + await produceAsset(`${mediaFile}/${preset.id}`, (base) => { + const root = path.dirname(base); + const pass1 = [ffmpeg!, ...ffmpegOptions, "-i", absPath]; + if (preset.codec === "av1") { + pass1.push("-c:v", "libstvav1"); + pass1.push("-b:v", preset.mbit + "M"); + if (preset.crf) pass1.push("-crf", preset.crf.toString()); + pass1.push( + "-svtav1-params", + ["rc=1", `tbr=${preset.mbit * 1_000_000}`].join(":"), + ); + } else if (preset.codec === "vp9") { + pass1.push("-c:v", "libvpx-vp9"); + } else preset satisfies never; + + if (preset.maxHeight != null) { + pass1.push("-vf", `scale=-2:min(${preset.maxHeight}\\,ih)`); + } + + const logfile = path.join(preset.id + ".log"); + pass1.push("-passlogfile", logfile); + const pass2 = pass1.slice(); + + pass1.push("-f", "null"); + pass1.push(os.devNull); + + pass2.push("-c:a", "libopus"); + pass2.push("-b:a", (preset.audioKbit ?? 192) + "k"); + }); + }, +} satisfies Process)); const processors = [ procDimensions, @@ -455,6 +518,7 @@ const processors = [ procLoadTextContents, procHighlightCode, procImageSubsets, + ...procVideos, ] .map((process, id, all) => { const strIndex = (id: number) => @@ -581,6 +645,7 @@ import * as path from "node:path"; import * as child_process from "node:child_process"; import * as util from "node:util"; import * as crypto from "node:crypto"; +import * as os from "node:os"; import { MediaFile, MediaFileKind } from "@/file-viewer/models/MediaFile.ts"; import { AssetRef } from "@/file-viewer/models/AssetRef.ts";