@nodetool-ai/video-nodes 0.8.2 → 0.8.4-a13.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/.nodetool-build-stamp +1 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -0
- package/dist/index.js.map +1 -1
- package/dist/nodes/ffmpeg-helpers.d.ts +2 -1
- package/dist/nodes/ffmpeg-helpers.d.ts.map +1 -1
- package/dist/nodes/ffmpeg-helpers.js +4 -5
- package/dist/nodes/ffmpeg-helpers.js.map +1 -1
- package/dist/nodes/model3d/convert.d.ts +2 -1
- package/dist/nodes/model3d/convert.d.ts.map +1 -1
- package/dist/nodes/model3d/convert.js +3 -3
- package/dist/nodes/model3d/convert.js.map +1 -1
- package/dist/nodes/model3d/render3d-headless.d.ts +15 -5
- package/dist/nodes/model3d/render3d-headless.d.ts.map +1 -1
- package/dist/nodes/model3d/render3d-headless.js +154 -36
- package/dist/nodes/model3d/render3d-headless.js.map +1 -1
- package/dist/nodes/model3d/types.d.ts +1 -0
- package/dist/nodes/model3d/types.d.ts.map +1 -1
- package/dist/nodes/model3d/utils.d.ts +6 -13
- package/dist/nodes/model3d/utils.d.ts.map +1 -1
- package/dist/nodes/model3d/utils.js +22 -65
- package/dist/nodes/model3d/utils.js.map +1 -1
- package/dist/nodes/storyboard.d.ts +36 -7
- package/dist/nodes/storyboard.d.ts.map +1 -1
- package/dist/nodes/storyboard.js +157 -7
- package/dist/nodes/storyboard.js.map +1 -1
- package/dist/nodes/timeline/browserRender.d.ts +83 -0
- package/dist/nodes/timeline/browserRender.d.ts.map +1 -0
- package/dist/nodes/timeline/browserRender.js +541 -0
- package/dist/nodes/timeline/browserRender.js.map +1 -0
- package/dist/nodes/timeline/browserSources.d.ts +26 -0
- package/dist/nodes/timeline/browserSources.d.ts.map +1 -0
- package/dist/nodes/timeline/browserSources.js +83 -0
- package/dist/nodes/timeline/browserSources.js.map +1 -0
- package/dist/nodes/timeline/compositeRender.d.ts.map +1 -1
- package/dist/nodes/timeline/compositeRender.js +31 -15
- package/dist/nodes/timeline/compositeRender.js.map +1 -1
- package/dist/nodes/timeline/pngSequence.d.ts +19 -0
- package/dist/nodes/timeline/pngSequence.d.ts.map +1 -1
- package/dist/nodes/timeline/pngSequence.js +21 -6
- package/dist/nodes/timeline/pngSequence.js.map +1 -1
- package/dist/nodes/timeline/rawFrames.d.ts +34 -1
- package/dist/nodes/timeline/rawFrames.d.ts.map +1 -1
- package/dist/nodes/timeline/rawFrames.js +68 -15
- package/dist/nodes/timeline/rawFrames.js.map +1 -1
- package/dist/nodes/timeline/renderPage.d.ts +14 -0
- package/dist/nodes/timeline/renderPage.d.ts.map +1 -0
- package/dist/nodes/timeline/renderPage.js +75 -0
- package/dist/nodes/timeline/renderPage.js.map +1 -0
- package/dist/nodes/timeline.d.ts +21 -24
- package/dist/nodes/timeline.d.ts.map +1 -1
- package/dist/nodes/timeline.js +366 -112
- package/dist/nodes/timeline.js.map +1 -1
- package/dist/nodes/video.d.ts +1 -4
- package/dist/nodes/video.d.ts.map +1 -1
- package/dist/nodes/video.js +21 -3
- package/dist/nodes/video.js.map +1 -1
- package/dist/timeline-render-page.js +6903 -0
- package/package.json +12 -11
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `RenderTimeline` in headless Chromium.
|
|
3
|
+
*
|
|
4
|
+
* The editor exports a timeline with `renderTimeline`
|
|
5
|
+
* (`web/src/components/timeline/render/TimelineRenderer.ts`): the live
|
|
6
|
+
* preview's compositor and scene model, WebCodecs decode, mediabunny mux. This
|
|
7
|
+
* runs that same exporter on the server so a workflow render is the picture
|
|
8
|
+
* the preview showed, and variable-frame-rate clips decode by their own
|
|
9
|
+
* timestamps instead of through a per-frame ffmpeg seek.
|
|
10
|
+
*
|
|
11
|
+
* A loopback HTTP server, bound to 127.0.0.1 behind a random path prefix,
|
|
12
|
+
* serves the page (`renderPage.ts`), the clip media (with byte ranges, which
|
|
13
|
+
* WebCodecs and `<video>` both read through) and the bundled and Google
|
|
14
|
+
* fonts, and receives the output: muxed chunks at their byte positions, or
|
|
15
|
+
* one PNG per frame. Playwright drives the page and blocks every request to
|
|
16
|
+
* any other origin. Nothing is held whole in the page or here.
|
|
17
|
+
*
|
|
18
|
+
* What the browser writes depends on what it can encode
|
|
19
|
+
* ({@link encodingsFor}): H.264 MP4 and VP9 WebM are written as they are;
|
|
20
|
+
* MP4 from a Chromium without an H.264 encoder (Playwright's own build) comes
|
|
21
|
+
* back as VP9 or AV1 and ffmpeg transcodes it; ProRes MOV, a PNG sequence and
|
|
22
|
+
* alpha WebM from a browser without a VP9 alpha encoder come back as PNG
|
|
23
|
+
* frames that ffmpeg encodes or the zip writer stores.
|
|
24
|
+
*
|
|
25
|
+
* Audio is not mixed here. The caller mixes it with ffmpeg, as it does for the
|
|
26
|
+
* other render path, so the soundtrack does not depend on which path ran.
|
|
27
|
+
*/
|
|
28
|
+
import { type TimelineSequence } from "@nodetool-ai/timeline";
|
|
29
|
+
import { type HeadlessRenderEncoding } from "@nodetool-ai/timeline/render";
|
|
30
|
+
import type { ResolvedTimelineOutput } from "./outputFormats.js";
|
|
31
|
+
/**
|
|
32
|
+
* No headless browser could be started here: Playwright is not installed, or
|
|
33
|
+
* no Chromium it can launch is. The caller falls back to the Node compositor.
|
|
34
|
+
*/
|
|
35
|
+
export declare class BrowserRenderUnavailableError extends Error {
|
|
36
|
+
constructor(message: string, options?: ErrorOptions);
|
|
37
|
+
}
|
|
38
|
+
export interface BrowserRenderOptions {
|
|
39
|
+
sequence: TimelineSequence;
|
|
40
|
+
/** Output size; the sequence's own size is the layout reference. */
|
|
41
|
+
width: number;
|
|
42
|
+
height: number;
|
|
43
|
+
fps: number;
|
|
44
|
+
durationMs: number;
|
|
45
|
+
output: ResolvedTimelineOutput;
|
|
46
|
+
/** Video bitrate in bits per second; 0 leaves it to the encoder. */
|
|
47
|
+
bitrate: number;
|
|
48
|
+
resolveAssetPath: (assetId: string) => Promise<string | null>;
|
|
49
|
+
/** Destination: the video container, or the PNG sequence's zip. */
|
|
50
|
+
outPath: string;
|
|
51
|
+
/** Scratch space for an intermediate file the server transcodes. */
|
|
52
|
+
workDir: string;
|
|
53
|
+
onProgress?: (frame: number, totalFrames: number) => void;
|
|
54
|
+
signal?: AbortSignal;
|
|
55
|
+
}
|
|
56
|
+
export interface BrowserRenderResult {
|
|
57
|
+
/** The compositor the page drew with. */
|
|
58
|
+
backend: "webgpu" | "canvas2d";
|
|
59
|
+
adapter: string | null;
|
|
60
|
+
/** Why the page drew with Canvas 2D although it had WebGPU, else null. */
|
|
61
|
+
webgpuUnusable: string | null;
|
|
62
|
+
/** Which browser ran: a path, a Playwright channel, or "bundled". */
|
|
63
|
+
browser: string;
|
|
64
|
+
encoding: HeadlessRenderEncoding;
|
|
65
|
+
/** Whether ffmpeg re-encoded what the browser wrote. */
|
|
66
|
+
transcoded: boolean;
|
|
67
|
+
frames: number;
|
|
68
|
+
degradedBakes: number;
|
|
69
|
+
/** Google font families the page asked for that could not be resolved. */
|
|
70
|
+
fontsUnavailable: string[];
|
|
71
|
+
/** Clips converted to VP9 first because the browser cannot decode them. */
|
|
72
|
+
convertedSources: number;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* What to ask the page for, in preference order. The last entry is always
|
|
76
|
+
* PNG frames, which every browser can produce and ffmpeg encodes to any of
|
|
77
|
+
* the formats, so a missing WebCodecs encoder never fails the render.
|
|
78
|
+
*/
|
|
79
|
+
export declare function encodingsFor(output: ResolvedTimelineOutput): HeadlessRenderEncoding[];
|
|
80
|
+
/** Re-encode the browser's intermediate file with the output's own encoder. */
|
|
81
|
+
export declare function transcodeIntermediate(inPath: string, outPath: string, output: ResolvedTimelineOutput): Promise<void>;
|
|
82
|
+
export declare function renderTimelineInBrowser(opts: BrowserRenderOptions): Promise<BrowserRenderResult>;
|
|
83
|
+
//# sourceMappingURL=browserRender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserRender.d.ts","sourceRoot":"","sources":["../../../src/nodes/timeline/browserRender.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AAUH,OAAO,EAGL,KAAK,gBAAgB,EACtB,MAAM,uBAAuB,CAAC;AAC/B,OAAO,EAIL,KAAK,sBAAsB,EAI5B,MAAM,8BAA8B,CAAC;AAGtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,oBAAoB,CAAC;AAMjE;;;GAGG;AACH,qBAAa,6BAA8B,SAAQ,KAAK;IACtD,YAAY,OAAO,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,YAAY,EAGlD;CACF;AAED,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,oEAAoE;IACpE,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,sBAAsB,CAAC;IAC/B,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,gBAAgB,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAC;IAC9D,mEAAmE;IACnE,OAAO,EAAE,MAAM,CAAC;IAChB,oEAAoE;IACpE,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;IAC1D,MAAM,CAAC,EAAE,WAAW,CAAC;CACtB;AAED,MAAM,WAAW,mBAAmB;IAClC,yCAAyC;IACzC,OAAO,EAAE,QAAQ,GAAG,UAAU,CAAC;IAC/B,OAAO,EAAE,MAAM,GAAG,IAAI,CAAC;IACvB,0EAA0E;IAC1E,cAAc,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,qEAAqE;IACrE,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,EAAE,sBAAsB,CAAC;IACjC,wDAAwD;IACxD,UAAU,EAAE,OAAO,CAAC;IACpB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,0EAA0E;IAC1E,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,2EAA2E;IAC3E,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AA8GD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,sBAAsB,GAAG,sBAAsB,EAAE,CAkBrF;AAUD,+EAA+E;AAC/E,wBAAsB,qBAAqB,CACzC,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,sBAAsB,GAC7B,OAAO,CAAC,IAAI,CAAC,CAKf;AA6ID,wBAAsB,uBAAuB,CAC3C,IAAI,EAAE,oBAAoB,GACzB,OAAO,CAAC,mBAAmB,CAAC,CAwQ9B"}
|
|
@@ -0,0 +1,541 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `RenderTimeline` in headless Chromium.
|
|
3
|
+
*
|
|
4
|
+
* The editor exports a timeline with `renderTimeline`
|
|
5
|
+
* (`web/src/components/timeline/render/TimelineRenderer.ts`): the live
|
|
6
|
+
* preview's compositor and scene model, WebCodecs decode, mediabunny mux. This
|
|
7
|
+
* runs that same exporter on the server so a workflow render is the picture
|
|
8
|
+
* the preview showed, and variable-frame-rate clips decode by their own
|
|
9
|
+
* timestamps instead of through a per-frame ffmpeg seek.
|
|
10
|
+
*
|
|
11
|
+
* A loopback HTTP server, bound to 127.0.0.1 behind a random path prefix,
|
|
12
|
+
* serves the page (`renderPage.ts`), the clip media (with byte ranges, which
|
|
13
|
+
* WebCodecs and `<video>` both read through) and the bundled and Google
|
|
14
|
+
* fonts, and receives the output: muxed chunks at their byte positions, or
|
|
15
|
+
* one PNG per frame. Playwright drives the page and blocks every request to
|
|
16
|
+
* any other origin. Nothing is held whole in the page or here.
|
|
17
|
+
*
|
|
18
|
+
* What the browser writes depends on what it can encode
|
|
19
|
+
* ({@link encodingsFor}): H.264 MP4 and VP9 WebM are written as they are;
|
|
20
|
+
* MP4 from a Chromium without an H.264 encoder (Playwright's own build) comes
|
|
21
|
+
* back as VP9 or AV1 and ffmpeg transcodes it; ProRes MOV, a PNG sequence and
|
|
22
|
+
* alpha WebM from a browser without a VP9 alpha encoder come back as PNG
|
|
23
|
+
* frames that ffmpeg encodes or the zip writer stores.
|
|
24
|
+
*
|
|
25
|
+
* Audio is not mixed here. The caller mixes it with ffmpeg, as it does for the
|
|
26
|
+
* other render path, so the soundtrack does not depend on which path ran.
|
|
27
|
+
*/
|
|
28
|
+
import { randomBytes } from "node:crypto";
|
|
29
|
+
import { createReadStream } from "node:fs";
|
|
30
|
+
import { open, rename, stat } from "node:fs/promises";
|
|
31
|
+
import { createServer } from "node:http";
|
|
32
|
+
import path from "node:path";
|
|
33
|
+
import { importOptionalModule } from "@nodetool-ai/config";
|
|
34
|
+
import { BUNDLED_FONT_FILES, googleFontFaceCss } from "@nodetool-ai/timeline";
|
|
35
|
+
import { HEADLESS_RENDER_ENTRY, HEADLESS_RENDER_PATHS, HEADLESS_RENDER_PROGRESS } from "@nodetool-ai/timeline/render";
|
|
36
|
+
import { execFfmpeg, FFMPEG_MAX_BUFFER } from "../ffmpeg-helpers.js";
|
|
37
|
+
import { DECODER_PROBES, openSourceConverter } from "./browserSources.js";
|
|
38
|
+
import { openPngZipWriter } from "./pngSequence.js";
|
|
39
|
+
import { openPngFrameEncoder } from "./rawFrames.js";
|
|
40
|
+
import { loadTimelineRenderPage } from "./renderPage.js";
|
|
41
|
+
/**
|
|
42
|
+
* No headless browser could be started here: Playwright is not installed, or
|
|
43
|
+
* no Chromium it can launch is. The caller falls back to the Node compositor.
|
|
44
|
+
*/
|
|
45
|
+
export class BrowserRenderUnavailableError extends Error {
|
|
46
|
+
constructor(message, options) {
|
|
47
|
+
super(message, options);
|
|
48
|
+
this.name = "BrowserRenderUnavailableError";
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Flags for a GPU-less host as much as a laptop. WebGPU stays behind a flag
|
|
53
|
+
* on Linux, where an adapter is SwiftShader or a Vulkan driver (lavapipe);
|
|
54
|
+
* macOS gets Metal without asking.
|
|
55
|
+
*/
|
|
56
|
+
const CHROMIUM_ARGS = [
|
|
57
|
+
"--enable-unsafe-webgpu",
|
|
58
|
+
"--enable-unsafe-swiftshader",
|
|
59
|
+
"--ignore-gpu-blocklist",
|
|
60
|
+
"--disable-dev-shm-usage",
|
|
61
|
+
"--autoplay-policy=no-user-gesture-required",
|
|
62
|
+
"--mute-audio",
|
|
63
|
+
// A long render must not be throttled as a background tab.
|
|
64
|
+
"--disable-background-timer-throttling",
|
|
65
|
+
"--disable-renderer-backgrounding",
|
|
66
|
+
// Headless Linux composites a WebGPU canvas only over Vulkan: without
|
|
67
|
+
// these, the first `getCurrentTexture()` loses the device ("A valid
|
|
68
|
+
// external Instance reference no longer exists"). macOS uses Metal.
|
|
69
|
+
...(process.platform === "linux" ? ["--enable-features=Vulkan", "--use-angle=vulkan"] : [])
|
|
70
|
+
];
|
|
71
|
+
/**
|
|
72
|
+
* The browsers to try, in order. `CHROME_PATH` names the host's Chromium
|
|
73
|
+
* (the Docker image sets it). `chrome` is an installed Google Chrome, whose
|
|
74
|
+
* WebCodecs encode H.264; the Playwright build cannot. The bundled Chromium
|
|
75
|
+
* is the last resort.
|
|
76
|
+
*/
|
|
77
|
+
function launchCandidates() {
|
|
78
|
+
const candidates = [];
|
|
79
|
+
const executablePath = process.env["CHROME_PATH"]?.trim();
|
|
80
|
+
if (executablePath)
|
|
81
|
+
candidates.push({ label: executablePath, options: { executablePath } });
|
|
82
|
+
candidates.push({ label: "chrome", options: { channel: "chrome" } });
|
|
83
|
+
candidates.push({ label: "bundled", options: { channel: "chromium" } });
|
|
84
|
+
return candidates;
|
|
85
|
+
}
|
|
86
|
+
async function launchBrowser() {
|
|
87
|
+
let playwright;
|
|
88
|
+
try {
|
|
89
|
+
playwright = await importOptionalModule("playwright", { commonJs: true });
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
throw new BrowserRenderUnavailableError("The browser render needs the Playwright package, which is not installed.", { cause: error });
|
|
93
|
+
}
|
|
94
|
+
const failures = [];
|
|
95
|
+
for (const candidate of launchCandidates()) {
|
|
96
|
+
try {
|
|
97
|
+
const browser = await playwright.chromium.launch({
|
|
98
|
+
headless: true,
|
|
99
|
+
args: CHROMIUM_ARGS,
|
|
100
|
+
...candidate.options
|
|
101
|
+
});
|
|
102
|
+
return { browser, label: candidate.label };
|
|
103
|
+
}
|
|
104
|
+
catch (error) {
|
|
105
|
+
const message = error instanceof Error ? error.message.split("\n")[0] : String(error);
|
|
106
|
+
failures.push(`${candidate.label}: ${message}`);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
throw new BrowserRenderUnavailableError(`No Chromium could be launched for the browser render (${failures.join("; ")}).`);
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* What to ask the page for, in preference order. The last entry is always
|
|
113
|
+
* PNG frames, which every browser can produce and ffmpeg encodes to any of
|
|
114
|
+
* the formats, so a missing WebCodecs encoder never fails the render.
|
|
115
|
+
*/
|
|
116
|
+
export function encodingsFor(output) {
|
|
117
|
+
const png = { kind: "png" };
|
|
118
|
+
if (output.format === "png_sequence" || output.format === "mov")
|
|
119
|
+
return [png];
|
|
120
|
+
if (output.format === "webm") {
|
|
121
|
+
return [{ kind: "video", container: "webm", codec: "vp9" }, png];
|
|
122
|
+
}
|
|
123
|
+
// mp4 is H.264 unless the caller named another ffmpeg encoder, which only a
|
|
124
|
+
// transcode can honour.
|
|
125
|
+
const direct = output.requiredEncoder === "libx264"
|
|
126
|
+
? [{ kind: "video", container: "mp4", codec: "avc" }]
|
|
127
|
+
: [];
|
|
128
|
+
return [
|
|
129
|
+
...direct,
|
|
130
|
+
{ kind: "video", container: "webm", codec: "vp9", intermediate: true },
|
|
131
|
+
{ kind: "video", container: "mp4", codec: "av1", intermediate: true },
|
|
132
|
+
png
|
|
133
|
+
];
|
|
134
|
+
}
|
|
135
|
+
/** Whether the browser's file is the requested one, with no second encode. */
|
|
136
|
+
function isFinal(encoding, output) {
|
|
137
|
+
if (encoding.kind === "png")
|
|
138
|
+
return output.format === "png_sequence";
|
|
139
|
+
return encoding.intermediate !== true &&
|
|
140
|
+
((output.format === "mp4" && encoding.container === "mp4") ||
|
|
141
|
+
(output.format === "webm" && encoding.container === "webm"));
|
|
142
|
+
}
|
|
143
|
+
/** Re-encode the browser's intermediate file with the output's own encoder. */
|
|
144
|
+
export async function transcodeIntermediate(inPath, outPath, output) {
|
|
145
|
+
await execFfmpeg(["-y", "-v", "error", "-i", inPath, "-map", "0:v:0", ...output.encoderArgs, outPath], { maxBuffer: FFMPEG_MAX_BUFFER });
|
|
146
|
+
}
|
|
147
|
+
/** Media type a `<video>`/`<img>` needs to hear; only SVG is not sniffed. */
|
|
148
|
+
async function sniffContentType(file) {
|
|
149
|
+
const handle = await open(file, "r");
|
|
150
|
+
try {
|
|
151
|
+
const head = Buffer.alloc(1024);
|
|
152
|
+
const { bytesRead } = await handle.read(head, 0, head.length, 0);
|
|
153
|
+
const text = head.subarray(0, bytesRead).toString("utf8");
|
|
154
|
+
return /<svg[\s>]/i.test(text) ? "image/svg+xml" : "application/octet-stream";
|
|
155
|
+
}
|
|
156
|
+
finally {
|
|
157
|
+
await handle.close();
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
/** Serve `file`, honouring a single `bytes=` range. */
|
|
161
|
+
async function sendFile(request, response, file, contentType) {
|
|
162
|
+
const { size } = await stat(file);
|
|
163
|
+
const range = /^bytes=(\d*)-(\d*)$/.exec(request.headers.range ?? "");
|
|
164
|
+
let start = 0;
|
|
165
|
+
let end = size - 1;
|
|
166
|
+
if (range) {
|
|
167
|
+
if (range[1] === "") {
|
|
168
|
+
start = Math.max(0, size - Number(range[2]));
|
|
169
|
+
}
|
|
170
|
+
else {
|
|
171
|
+
start = Number(range[1]);
|
|
172
|
+
if (range[2] !== "")
|
|
173
|
+
end = Math.min(end, Number(range[2]));
|
|
174
|
+
}
|
|
175
|
+
if (start > end || start >= size) {
|
|
176
|
+
response.writeHead(416, { "content-range": `bytes */${size}` });
|
|
177
|
+
response.end();
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
const headers = {
|
|
182
|
+
"content-type": contentType,
|
|
183
|
+
"content-length": String(end - start + 1),
|
|
184
|
+
"accept-ranges": "bytes"
|
|
185
|
+
};
|
|
186
|
+
if (range)
|
|
187
|
+
headers["content-range"] = `bytes ${start}-${end}/${size}`;
|
|
188
|
+
response.writeHead(range ? 206 : 200, headers);
|
|
189
|
+
if (request.method === "HEAD") {
|
|
190
|
+
response.end();
|
|
191
|
+
return;
|
|
192
|
+
}
|
|
193
|
+
createReadStream(file, { start, end }).pipe(response);
|
|
194
|
+
}
|
|
195
|
+
async function readBody(request) {
|
|
196
|
+
const chunks = [];
|
|
197
|
+
for await (const chunk of request)
|
|
198
|
+
chunks.push(chunk);
|
|
199
|
+
return Buffer.concat(chunks);
|
|
200
|
+
}
|
|
201
|
+
function openOutputWriter(output, outPath, intermediatePath, options) {
|
|
202
|
+
let file = null;
|
|
203
|
+
const zip = output.format === "png_sequence"
|
|
204
|
+
? openPngZipWriter({ outPath, ...options, alpha: output.alpha })
|
|
205
|
+
: null;
|
|
206
|
+
let pngEncoder = null;
|
|
207
|
+
let nextFrame = 0;
|
|
208
|
+
return {
|
|
209
|
+
async write(data, position) {
|
|
210
|
+
file ??= open(intermediatePath, "w");
|
|
211
|
+
const handle = await file;
|
|
212
|
+
let written = 0;
|
|
213
|
+
while (written < data.length) {
|
|
214
|
+
const { bytesWritten } = await handle.write(data, written, data.length - written, position + written);
|
|
215
|
+
written += bytesWritten;
|
|
216
|
+
}
|
|
217
|
+
},
|
|
218
|
+
async frame(index, png) {
|
|
219
|
+
// The page awaits each upload, so frames arrive in order; a gap would
|
|
220
|
+
// shift every later frame in an image2 stream.
|
|
221
|
+
if (index !== nextFrame) {
|
|
222
|
+
throw new Error(`Frame ${index} arrived where frame ${nextFrame} was expected`);
|
|
223
|
+
}
|
|
224
|
+
nextFrame += 1;
|
|
225
|
+
if (zip) {
|
|
226
|
+
zip.addPng(png);
|
|
227
|
+
return;
|
|
228
|
+
}
|
|
229
|
+
pngEncoder ??= openPngFrameEncoder({
|
|
230
|
+
outPath,
|
|
231
|
+
fps: options.fps,
|
|
232
|
+
encoderArgs: output.encoderArgs
|
|
233
|
+
});
|
|
234
|
+
await pngEncoder.write(png);
|
|
235
|
+
},
|
|
236
|
+
async finish() {
|
|
237
|
+
if (file)
|
|
238
|
+
await (await file).close();
|
|
239
|
+
if (zip)
|
|
240
|
+
await zip.finish();
|
|
241
|
+
if (pngEncoder)
|
|
242
|
+
await pngEncoder.finish();
|
|
243
|
+
},
|
|
244
|
+
abort() {
|
|
245
|
+
void file?.then((handle) => handle.close()).catch(() => undefined);
|
|
246
|
+
zip?.abort();
|
|
247
|
+
pngEncoder?.abort();
|
|
248
|
+
}
|
|
249
|
+
};
|
|
250
|
+
}
|
|
251
|
+
/** The page's own HTML: one module script and nothing else. */
|
|
252
|
+
const PAGE_HTML = '<!doctype html><html><head><meta charset="utf-8"></head>' +
|
|
253
|
+
'<body style="margin:0"><script type="module" src="render.js"></script></body></html>';
|
|
254
|
+
const FONT_CONTENT_TYPES = {
|
|
255
|
+
ttf: "font/ttf",
|
|
256
|
+
otf: "font/otf",
|
|
257
|
+
woff2: "font/woff2"
|
|
258
|
+
};
|
|
259
|
+
function fontContentType(file) {
|
|
260
|
+
return FONT_CONTENT_TYPES[file.slice(file.lastIndexOf(".") + 1).toLowerCase()] ?? "application/octet-stream";
|
|
261
|
+
}
|
|
262
|
+
/** Bundled fonts, as the API server serves them to the editor. */
|
|
263
|
+
const BUNDLED_FONT_PREFIX = "/api/assets/packages/timeline/fonts/";
|
|
264
|
+
/** Google font CSS, the path `fontLoading.ts` requests. */
|
|
265
|
+
const GOOGLE_FONT_CSS = /^\/api\/assets\/packages\/timeline\/fonts\/google\/([^/]+)\/css$/;
|
|
266
|
+
export async function renderTimelineInBrowser(opts) {
|
|
267
|
+
const { sequence, output, signal } = opts;
|
|
268
|
+
signal?.throwIfAborted();
|
|
269
|
+
const script = await loadTimelineRenderPage();
|
|
270
|
+
const token = randomBytes(16).toString("hex");
|
|
271
|
+
const prefix = `/${token}/`;
|
|
272
|
+
const intermediatePath = path.join(opts.workDir, `browser-render.${output.format === "webm" ? "webm" : "mp4"}`);
|
|
273
|
+
const writer = openOutputWriter(output, opts.outPath, intermediatePath, {
|
|
274
|
+
width: opts.width,
|
|
275
|
+
height: opts.height,
|
|
276
|
+
fps: opts.fps
|
|
277
|
+
});
|
|
278
|
+
const assetFiles = [];
|
|
279
|
+
const assetIndex = new Map();
|
|
280
|
+
const googleFontFiles = [];
|
|
281
|
+
const fontsUnavailable = new Set();
|
|
282
|
+
const { bundledFontsDir } = await import("@nodetool-ai/timeline/fonts/node");
|
|
283
|
+
const fontsDir = bundledFontsDir();
|
|
284
|
+
// Set once the page reports its decoders, before the render asks for media.
|
|
285
|
+
let sources = null;
|
|
286
|
+
const handle = async (request, response) => {
|
|
287
|
+
const url = new URL(request.url ?? "/", "http://127.0.0.1");
|
|
288
|
+
const pathname = url.pathname;
|
|
289
|
+
if (request.method === "GET" && pathname.startsWith(BUNDLED_FONT_PREFIX)) {
|
|
290
|
+
const css = GOOGLE_FONT_CSS.exec(pathname);
|
|
291
|
+
if (css) {
|
|
292
|
+
const family = decodeURIComponent(css[1] ?? "").trim();
|
|
293
|
+
const requests = (url.searchParams.get("weights") ?? "400")
|
|
294
|
+
.split(",")
|
|
295
|
+
.map((token) => /^(\d{1,3})(i)?$/.exec(token.trim()))
|
|
296
|
+
.filter((match) => match !== null)
|
|
297
|
+
.map((match) => ({ weight: Number(match[1]), style: match[2] ? "italic" : "normal" }));
|
|
298
|
+
const { resolveGoogleFontFamily } = await import("@nodetool-ai/timeline/fonts/google-fetch");
|
|
299
|
+
const resolution = await resolveGoogleFontFamily(family, requests).catch(() => null);
|
|
300
|
+
if (!resolution) {
|
|
301
|
+
fontsUnavailable.add(family);
|
|
302
|
+
response.writeHead(404).end();
|
|
303
|
+
return;
|
|
304
|
+
}
|
|
305
|
+
const faces = resolution.faces.map((face) => {
|
|
306
|
+
googleFontFiles.push(face.file);
|
|
307
|
+
return { style: face.style, weights: face.weights, file: String(googleFontFiles.length - 1) };
|
|
308
|
+
});
|
|
309
|
+
response.writeHead(200, { "content-type": "text/css; charset=utf-8" });
|
|
310
|
+
response.end(googleFontFaceCss(resolution.family, faces, `${prefix}font`));
|
|
311
|
+
return;
|
|
312
|
+
}
|
|
313
|
+
const name = pathname.slice(BUNDLED_FONT_PREFIX.length);
|
|
314
|
+
if (!fontsDir || !BUNDLED_FONT_FILES.includes(name)) {
|
|
315
|
+
response.writeHead(404).end();
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
await sendFile(request, response, path.join(fontsDir, name), fontContentType(name));
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
if (!pathname.startsWith(prefix)) {
|
|
322
|
+
response.writeHead(404).end();
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
const route = pathname.slice(prefix.length);
|
|
326
|
+
if (request.method === "GET" && route === "") {
|
|
327
|
+
response.writeHead(200, { "content-type": "text/html; charset=utf-8" });
|
|
328
|
+
response.end(PAGE_HTML);
|
|
329
|
+
}
|
|
330
|
+
else if (request.method === "GET" && route === "render.js") {
|
|
331
|
+
response.writeHead(200, { "content-type": "text/javascript; charset=utf-8" });
|
|
332
|
+
response.end(script);
|
|
333
|
+
}
|
|
334
|
+
else if (request.method === "GET" && route === HEADLESS_RENDER_PATHS.resolve) {
|
|
335
|
+
const id = url.searchParams.get("id") ?? "";
|
|
336
|
+
let index = assetIndex.get(id);
|
|
337
|
+
if (index === undefined) {
|
|
338
|
+
const found = id ? await opts.resolveAssetPath(id) : null;
|
|
339
|
+
const file = found && sources ? await sources.prepare(found) : found;
|
|
340
|
+
index = file ? assetFiles.push(file) - 1 : null;
|
|
341
|
+
assetIndex.set(id, index);
|
|
342
|
+
}
|
|
343
|
+
if (index === null) {
|
|
344
|
+
response.writeHead(404).end();
|
|
345
|
+
return;
|
|
346
|
+
}
|
|
347
|
+
response.writeHead(200, { "content-type": "application/json" });
|
|
348
|
+
response.end(JSON.stringify({ url: `asset/${index}` }));
|
|
349
|
+
}
|
|
350
|
+
else if ((request.method === "GET" || request.method === "HEAD") && route.startsWith("asset/")) {
|
|
351
|
+
const file = assetFiles[Number(route.slice("asset/".length))];
|
|
352
|
+
if (!file) {
|
|
353
|
+
response.writeHead(404).end();
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
await sendFile(request, response, file, await sniffContentType(file));
|
|
357
|
+
}
|
|
358
|
+
else if (request.method === "GET" && route.startsWith("font/")) {
|
|
359
|
+
const file = googleFontFiles[Number(route.slice("font/".length).split("/")[0])];
|
|
360
|
+
if (!file) {
|
|
361
|
+
response.writeHead(404).end();
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
await sendFile(request, response, file, fontContentType(file));
|
|
365
|
+
}
|
|
366
|
+
else if (request.method === "POST" && route === HEADLESS_RENDER_PATHS.out) {
|
|
367
|
+
const position = Number(url.searchParams.get("position"));
|
|
368
|
+
if (!Number.isSafeInteger(position) || position < 0) {
|
|
369
|
+
response.writeHead(400).end();
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
await writer.write(await readBody(request), position);
|
|
373
|
+
response.writeHead(204).end();
|
|
374
|
+
}
|
|
375
|
+
else if (request.method === "POST" && route === HEADLESS_RENDER_PATHS.frame) {
|
|
376
|
+
await writer.frame(Number(url.searchParams.get("index")), await readBody(request));
|
|
377
|
+
response.writeHead(204).end();
|
|
378
|
+
}
|
|
379
|
+
else {
|
|
380
|
+
response.writeHead(404).end();
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
const server = createServer((request, response) => {
|
|
384
|
+
handle(request, response).catch((error) => {
|
|
385
|
+
if (!response.headersSent) {
|
|
386
|
+
response.writeHead(500, { "content-type": "text/plain" });
|
|
387
|
+
}
|
|
388
|
+
response.end(error instanceof Error ? error.message : String(error));
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
let browser = null;
|
|
392
|
+
const pageErrors = [];
|
|
393
|
+
let rejectAbort;
|
|
394
|
+
const aborted = new Promise((_resolve, reject) => {
|
|
395
|
+
rejectAbort = reject;
|
|
396
|
+
});
|
|
397
|
+
// Closing the browser is what stops the work: the page, its GPU process and
|
|
398
|
+
// its encoders go with it, whatever frame they were on.
|
|
399
|
+
const onAbort = () => {
|
|
400
|
+
void browser?.close().catch(() => undefined);
|
|
401
|
+
rejectAbort?.(new DOMException("Timeline render cancelled", "AbortError"));
|
|
402
|
+
};
|
|
403
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
404
|
+
// Swallowed unless something awaits it: the race below does.
|
|
405
|
+
aborted.catch(() => undefined);
|
|
406
|
+
try {
|
|
407
|
+
await new Promise((resolve, reject) => {
|
|
408
|
+
server.once("error", reject);
|
|
409
|
+
server.listen(0, "127.0.0.1", resolve);
|
|
410
|
+
});
|
|
411
|
+
const origin = `http://127.0.0.1:${server.address().port}`;
|
|
412
|
+
const launched = await Promise.race([launchBrowser(), aborted]);
|
|
413
|
+
browser = launched.browser;
|
|
414
|
+
if (signal?.aborted)
|
|
415
|
+
onAbort();
|
|
416
|
+
const context = await browser.newContext({ serviceWorkers: "block" });
|
|
417
|
+
await context.route("**/*", async (route) => {
|
|
418
|
+
if (new URL(route.request().url()).origin === origin) {
|
|
419
|
+
await route.continue();
|
|
420
|
+
}
|
|
421
|
+
else {
|
|
422
|
+
await route.abort("blockedbyclient");
|
|
423
|
+
}
|
|
424
|
+
});
|
|
425
|
+
const page = await context.newPage();
|
|
426
|
+
// A render runs for as long as the timeline needs; the abort signal, not
|
|
427
|
+
// a timeout, is what ends one early.
|
|
428
|
+
page.setDefaultTimeout(0);
|
|
429
|
+
// An error while the script loads leaves the entry undefined forever, and
|
|
430
|
+
// nothing else would end the wait for it.
|
|
431
|
+
let rejectLoad;
|
|
432
|
+
const loadFailed = new Promise((_resolve, reject) => {
|
|
433
|
+
rejectLoad = reject;
|
|
434
|
+
});
|
|
435
|
+
loadFailed.catch(() => undefined);
|
|
436
|
+
page.on("pageerror", (error) => {
|
|
437
|
+
pageErrors.push(error.message);
|
|
438
|
+
rejectLoad?.(new Error(`The render page failed to load: ${error.message}`));
|
|
439
|
+
});
|
|
440
|
+
page.on("console", (message) => {
|
|
441
|
+
if (message.type() === "error")
|
|
442
|
+
pageErrors.push(message.text());
|
|
443
|
+
});
|
|
444
|
+
await page.exposeFunction(HEADLESS_RENDER_PROGRESS, (progress) => {
|
|
445
|
+
if (progress.phase === "video")
|
|
446
|
+
opts.onProgress?.(progress.frame, progress.totalFrames);
|
|
447
|
+
});
|
|
448
|
+
await Promise.race([page.goto(`${origin}${prefix}`), aborted, loadFailed]);
|
|
449
|
+
await Promise.race([
|
|
450
|
+
page.waitForFunction(`typeof window.${HEADLESS_RENDER_ENTRY} === "function"`),
|
|
451
|
+
aborted,
|
|
452
|
+
loadFailed
|
|
453
|
+
]);
|
|
454
|
+
rejectLoad = undefined;
|
|
455
|
+
const decodable = await Promise.race([
|
|
456
|
+
page.evaluate(async (probes) => {
|
|
457
|
+
const found = [];
|
|
458
|
+
for (const [name, codec] of probes) {
|
|
459
|
+
try {
|
|
460
|
+
if ((await VideoDecoder.isConfigSupported({ codec })).supported)
|
|
461
|
+
found.push(name);
|
|
462
|
+
}
|
|
463
|
+
catch {
|
|
464
|
+
// An unknown codec string is a codec this browser lacks.
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
return found;
|
|
468
|
+
}, DECODER_PROBES),
|
|
469
|
+
aborted
|
|
470
|
+
]);
|
|
471
|
+
sources = openSourceConverter({ workDir: opts.workDir, decodable: new Set(decodable), signal });
|
|
472
|
+
const request = {
|
|
473
|
+
tracks: sequence.tracks,
|
|
474
|
+
clips: sequence.clips,
|
|
475
|
+
mediaTracks: sequence.mediaTracks,
|
|
476
|
+
camera2d: sequence.camera2d,
|
|
477
|
+
tempo: sequence.tempo,
|
|
478
|
+
width: opts.width,
|
|
479
|
+
height: opts.height,
|
|
480
|
+
referenceWidth: sequence.width > 0 ? sequence.width : opts.width,
|
|
481
|
+
referenceHeight: sequence.height > 0 ? sequence.height : opts.height,
|
|
482
|
+
fps: opts.fps,
|
|
483
|
+
durationMs: opts.durationMs,
|
|
484
|
+
alpha: output.alpha,
|
|
485
|
+
bitrate: opts.bitrate,
|
|
486
|
+
motionBlur: output.motionBlur,
|
|
487
|
+
encodings: encodingsFor(output)
|
|
488
|
+
};
|
|
489
|
+
let report;
|
|
490
|
+
try {
|
|
491
|
+
report = await Promise.race([
|
|
492
|
+
page.evaluate(([entry, payload]) => {
|
|
493
|
+
const run = window[entry];
|
|
494
|
+
if (!run)
|
|
495
|
+
throw new Error("The render page did not load");
|
|
496
|
+
return run(payload);
|
|
497
|
+
}, [HEADLESS_RENDER_ENTRY, request]),
|
|
498
|
+
aborted
|
|
499
|
+
]);
|
|
500
|
+
}
|
|
501
|
+
catch (error) {
|
|
502
|
+
if (signal?.aborted)
|
|
503
|
+
throw error;
|
|
504
|
+
const detail = error instanceof Error ? error.message : String(error);
|
|
505
|
+
const logged = pageErrors.length > 0 ? ` (page: ${pageErrors.slice(-3).join(" | ")})` : "";
|
|
506
|
+
throw new Error(`The browser render failed: ${detail}${logged}`, { cause: error });
|
|
507
|
+
}
|
|
508
|
+
signal?.throwIfAborted();
|
|
509
|
+
await writer.finish();
|
|
510
|
+
const transcoded = !isFinal(report.encoding, output) && report.encoding.kind === "video";
|
|
511
|
+
if (transcoded) {
|
|
512
|
+
await transcodeIntermediate(intermediatePath, opts.outPath, output);
|
|
513
|
+
}
|
|
514
|
+
else if (report.encoding.kind === "video") {
|
|
515
|
+
await rename(intermediatePath, opts.outPath);
|
|
516
|
+
}
|
|
517
|
+
return {
|
|
518
|
+
backend: report.backend,
|
|
519
|
+
adapter: report.adapter,
|
|
520
|
+
webgpuUnusable: report.webgpuUnusable ?? null,
|
|
521
|
+
browser: launched.label,
|
|
522
|
+
encoding: report.encoding,
|
|
523
|
+
transcoded,
|
|
524
|
+
frames: report.frames,
|
|
525
|
+
degradedBakes: report.degradedBakes,
|
|
526
|
+
fontsUnavailable: [...fontsUnavailable],
|
|
527
|
+
convertedSources: sources.converted
|
|
528
|
+
};
|
|
529
|
+
}
|
|
530
|
+
catch (error) {
|
|
531
|
+
writer.abort();
|
|
532
|
+
throw error;
|
|
533
|
+
}
|
|
534
|
+
finally {
|
|
535
|
+
signal?.removeEventListener("abort", onAbort);
|
|
536
|
+
await browser?.close().catch(() => undefined);
|
|
537
|
+
server.closeAllConnections();
|
|
538
|
+
await new Promise((resolve) => server.close(() => resolve()));
|
|
539
|
+
}
|
|
540
|
+
}
|
|
541
|
+
//# sourceMappingURL=browserRender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browserRender.js","sourceRoot":"","sources":["../../../src/nodes/timeline/browserRender.ts"],"names":[],"mappings":"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"}
|