| ... | @@ -394,7 +394,6 @@ const imageSubsets = [ | ... | @@ -394,7 +394,6 @@ const imageSubsets = [ |
| 394 | const procImageSubsets: Process = {
| 394 | const procImageSubsets: Process = {
|
| 395 | name: "encode image subsets",
| 395 | name: "encode image subsets",
|
| 396 | include: rules.extsImage,
| 396 | include: rules.extsImage,
|
| 397 | enable: false,
| | |
| 398 | depends: ["calculate dimensions"],
| 397 | depends: ["calculate dimensions"],
|
| 399 | async run({ absPath, mediaFile, stat, spin }) {
| 398 | async run({ absPath, mediaFile, stat, spin }) {
|
| 400 | const { width, height } = UNWRAP(mediaFile.parseDimensions());
| 399 | const { width, height } = UNWRAP(mediaFile.parseDimensions());
|
| ... | @@ -443,11 +442,75 @@ const procImageSubsets: Process = { | ... | @@ -443,11 +442,75 @@ const procImageSubsets: Process = { |
| 443 | },
| 442 | },
|
| 444 | };
| 443 | };
|
| 445 |
| 444 |
|
| 446 | const videoFormats = [
| 445 | type VideoEncodePreset = {
|
| 447 | {
| 446 | id: string;
|
| 448 | name: "webm",
| 447 | codec: "av1";
|
| 449 | },
| 448 | mbit: number;
|
| | 449 | crf?: number;
|
| | 450 | maxHeight?: number;
|
| | 451 | audioKbit?: number;
|
| | 452 | } | {
|
| | 453 | id: string;
|
| | 454 | codec: "vp9";
|
| | 455 | mbit: number;
|
| | 456 | maxHeight?: number;
|
| | 457 | audioKbit?: number;
|
| | 458 | };
|
| | 459 | // const av1Pass1 = [
|
| | 460 | // '-c:v', 'libsvtav1 -b:v 2M -pass 1 -svtav1-params "rc=1:tbr=2000000" -preset 8 -f null NUL
|
| | 461 | // ];
|
| | 462 | // const av1BaseArgs = [
|
| | 463 | // ["-c:v", "libsvtav1"],
|
| | 464 | // ["-preset", "3"],
|
| | 465 | // ["-c:a", "libopus"],
|
| | 466 | // ["-b:a", "192k"],
|
| | 467 | // ].flat();
|
| | 468 | // const webmBaseArgs = [
|
| | 469 | // "-c:v",
|
| | 470 | // "libsvtav1",
|
| | 471 | // ["-vf",],
|
| | 472 | // ];
|
| | 473 | const presets: VideoEncodePreset[] = [
|
| | 474 | { id: "av1-max", codec: "av1", mbit: 5 },
|
| | 475 | { id: "av1-hq", codec: "av1", mbit: 2, maxHeight: 900 },
|
| | 476 | { id: "av1-md", codec: "av1", mbit: 0.5, maxHeight: 720 },
|
| | 477 | { id: "av1-lq", codec: "av1", mbit: 0.2, maxHeight: 640 },
|
| 450 | ];
| 478 | ];
|
| | 479 | const procVideos = presets.map((preset) => ({
|
| | 480 | name: "encode image subsets",
|
| | 481 | include: rules.extsImage,
|
| | 482 | async run({ absPath, mediaFile, stat, spin }) {
|
| | 483 | await produceAsset(`${mediaFile}/${preset.id}`, (base) => {
|
| | 484 | const root = path.dirname(base);
|
| | 485 | const pass1 = [ffmpeg!, ...ffmpegOptions, "-i", absPath];
|
| | 486 | if (preset.codec === "av1") {
|
| | 487 | pass1.push("-c:v", "libstvav1");
|
| | 488 | pass1.push("-b:v", preset.mbit + "M");
|
| | 489 | if (preset.crf) pass1.push("-crf", preset.crf.toString());
|
| | 490 | pass1.push(
|
| | 491 | "-svtav1-params",
|
| | 492 | ["rc=1", `tbr=${preset.mbit * 1_000_000}`].join(":"),
|
| | 493 | );
|
| | 494 | } else if (preset.codec === "vp9") {
|
| | 495 | pass1.push("-c:v", "libvpx-vp9");
|
| | 496 | } else preset satisfies never;
|
| | 497 |
|
| | 498 | if (preset.maxHeight != null) {
|
| | 499 | pass1.push("-vf", `scale=-2:min(${preset.maxHeight}\\,ih)`);
|
| | 500 | }
|
| | 501 |
|
| | 502 | const logfile = path.join(preset.id + ".log");
|
| | 503 | pass1.push("-passlogfile", logfile);
|
| | 504 | const pass2 = pass1.slice();
|
| | 505 |
|
| | 506 | pass1.push("-f", "null");
|
| | 507 | pass1.push(os.devNull);
|
| | 508 |
|
| | 509 | pass2.push("-c:a", "libopus");
|
| | 510 | pass2.push("-b:a", (preset.audioKbit ?? 192) + "k");
|
| | 511 | });
|
| | 512 | },
|
| | 513 | } satisfies Process));
|
| 451 |
| 514 |
|
| 452 | const processors = [
| 515 | const processors = [
|
| 453 | procDimensions,
| 516 | procDimensions,
|
| ... | @@ -455,6 +518,7 @@ const processors = [ | ... | @@ -455,6 +518,7 @@ const processors = [ |
| 455 | procLoadTextContents,
| 518 | procLoadTextContents,
|
| 456 | procHighlightCode,
| 519 | procHighlightCode,
|
| 457 | procImageSubsets,
| 520 | procImageSubsets,
|
| | 521 | ...procVideos,
|
| 458 | ]
| 522 | ]
|
| 459 | .map((process, id, all) => {
| 523 | .map((process, id, all) => {
|
| 460 | const strIndex = (id: number) =>
| 524 | const strIndex = (id: number) =>
|
| ... | @@ -581,6 +645,7 @@ import * as path from "node:path"; | ... | @@ -581,6 +645,7 @@ import * as path from "node:path"; |
| 581 | import * as child_process from "node:child_process";
| 645 | import * as child_process from "node:child_process";
|
| 582 | import * as util from "node:util";
| 646 | import * as util from "node:util";
|
| 583 | import * as crypto from "node:crypto";
| 647 | import * as crypto from "node:crypto";
|
| | 648 | import * as os from "node:os";
|
| 584 |
| 649 |
|
| 585 | import { MediaFile, MediaFileKind } from "@/file-viewer/models/MediaFile.ts";
| 650 | import { MediaFile, MediaFileKind } from "@/file-viewer/models/MediaFile.ts";
|
| 586 | import { AssetRef } from "@/file-viewer/models/AssetRef.ts";
| 651 | import { AssetRef } from "@/file-viewer/models/AssetRef.ts";
|