@rendiv/renderer 0.1.13 → 0.1.15
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/browser.d.ts +5 -1
- package/dist/browser.d.ts.map +1 -1
- package/dist/browser.js +20 -3
- package/dist/browser.js.map +1 -1
- package/dist/extract-frame.d.ts.map +1 -1
- package/dist/extract-frame.js +2 -3
- package/dist/extract-frame.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/render-frames.d.ts +4 -0
- package/dist/render-frames.d.ts.map +1 -1
- package/dist/render-frames.js +8 -6
- package/dist/render-frames.js.map +1 -1
- package/dist/render-media.d.ts +11 -0
- package/dist/render-media.d.ts.map +1 -1
- package/dist/render-media.js +7 -1
- package/dist/render-media.js.map +1 -1
- package/dist/stitch-frames-to-video.d.ts +6 -0
- package/dist/stitch-frames-to-video.d.ts.map +1 -1
- package/dist/stitch-frames-to-video.js +28 -8
- package/dist/stitch-frames-to-video.js.map +1 -1
- package/package.json +2 -2
package/dist/browser.d.ts
CHANGED
|
@@ -1,5 +1,9 @@
|
|
|
1
1
|
import { type Browser, type Page } from 'playwright';
|
|
2
|
-
export
|
|
2
|
+
export type GlRenderer = 'swiftshader' | 'egl' | 'angle';
|
|
3
|
+
export interface OpenBrowserOptions {
|
|
4
|
+
gl?: GlRenderer;
|
|
5
|
+
}
|
|
6
|
+
export declare function openBrowser(options?: OpenBrowserOptions): Promise<Browser>;
|
|
3
7
|
export declare function closeBrowser(): Promise<void>;
|
|
4
8
|
export declare function ensureBrowser(): Promise<Browser>;
|
|
5
9
|
export declare function openPage(browser: Browser, url: string, viewport: {
|
package/dist/browser.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.d.ts","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAY,KAAK,OAAO,EAAE,KAAK,IAAI,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,MAAM,UAAU,GAAG,aAAa,GAAG,KAAK,GAAG,OAAO,CAAC;AAEzD,MAAM,WAAW,kBAAkB;IACjC,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAiBD,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,CAAC,CAwBhF;AAED,wBAAsB,YAAY,IAAI,OAAO,CAAC,IAAI,CAAC,CAKlD;AAED,wBAAsB,aAAa,IAAI,OAAO,CAAC,OAAO,CAAC,CAEtD;AAED,wBAAsB,QAAQ,CAC5B,OAAO,EAAE,OAAO,EAChB,GAAG,EAAE,MAAM,EACX,QAAQ,EAAE;IAAE,KAAK,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GAC1C,OAAO,CAAC,IAAI,CAAC,CAQf"}
|
package/dist/browser.js
CHANGED
|
@@ -1,9 +1,27 @@
|
|
|
1
1
|
import { chromium } from 'playwright';
|
|
2
2
|
let browserInstance = null;
|
|
3
|
-
|
|
3
|
+
let currentGl = 'swiftshader';
|
|
4
|
+
function glArgs(gl) {
|
|
5
|
+
switch (gl) {
|
|
6
|
+
case 'egl':
|
|
7
|
+
return ['--use-gl=egl'];
|
|
8
|
+
case 'angle':
|
|
9
|
+
return ['--use-gl=angle'];
|
|
10
|
+
case 'swiftshader':
|
|
11
|
+
default:
|
|
12
|
+
return ['--use-gl=angle', '--use-angle=swiftshader'];
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export async function openBrowser(options) {
|
|
16
|
+
const gl = options?.gl ?? 'swiftshader';
|
|
17
|
+
if (browserInstance && browserInstance.isConnected() && gl !== currentGl) {
|
|
18
|
+
await browserInstance.close();
|
|
19
|
+
browserInstance = null;
|
|
20
|
+
}
|
|
4
21
|
if (browserInstance && browserInstance.isConnected()) {
|
|
5
22
|
return browserInstance;
|
|
6
23
|
}
|
|
24
|
+
currentGl = gl;
|
|
7
25
|
browserInstance = await chromium.launch({
|
|
8
26
|
headless: true,
|
|
9
27
|
args: [
|
|
@@ -11,8 +29,7 @@ export async function openBrowser() {
|
|
|
11
29
|
'--disable-features=IsolateOrigins',
|
|
12
30
|
'--disable-site-isolation-trials',
|
|
13
31
|
'--no-sandbox',
|
|
14
|
-
|
|
15
|
-
'--use-angle=swiftshader',
|
|
32
|
+
...glArgs(gl),
|
|
16
33
|
],
|
|
17
34
|
});
|
|
18
35
|
return browserInstance;
|
package/dist/browser.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAA2B,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"browser.js","sourceRoot":"","sources":["../src/browser.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAA2B,MAAM,YAAY,CAAC;AAQ/D,IAAI,eAAe,GAAmB,IAAI,CAAC;AAC3C,IAAI,SAAS,GAAe,aAAa,CAAC;AAE1C,SAAS,MAAM,CAAC,EAAc;IAC5B,QAAQ,EAAE,EAAE,CAAC;QACX,KAAK,KAAK;YACR,OAAO,CAAC,cAAc,CAAC,CAAC;QAC1B,KAAK,OAAO;YACV,OAAO,CAAC,gBAAgB,CAAC,CAAC;QAC5B,KAAK,aAAa,CAAC;QACnB;YACE,OAAO,CAAC,gBAAgB,EAAE,yBAAyB,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA4B;IAC5D,MAAM,EAAE,GAAG,OAAO,EAAE,EAAE,IAAI,aAAa,CAAC;IAExC,IAAI,eAAe,IAAI,eAAe,CAAC,WAAW,EAAE,IAAI,EAAE,KAAK,SAAS,EAAE,CAAC;QACzE,MAAM,eAAe,CAAC,KAAK,EAAE,CAAC;QAC9B,eAAe,GAAG,IAAI,CAAC;IACzB,CAAC;IAED,IAAI,eAAe,IAAI,eAAe,CAAC,WAAW,EAAE,EAAE,CAAC;QACrD,OAAO,eAAe,CAAC;IACzB,CAAC;IAED,SAAS,GAAG,EAAE,CAAC;IACf,eAAe,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;QACtC,QAAQ,EAAE,IAAI;QACd,IAAI,EAAE;YACJ,wBAAwB;YACxB,mCAAmC;YACnC,iCAAiC;YACjC,cAAc;YACd,GAAG,MAAM,CAAC,EAAE,CAAC;SACd;KACF,CAAC,CAAC;IACH,OAAO,eAAe,CAAC;AACzB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,eAAe,EAAE,CAAC;QACpB,MAAM,eAAe,CAAC,KAAK,EAAE,CAAC;QAC9B,eAAe,GAAG,IAAI,CAAC;IACzB,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,OAAO,WAAW,EAAE,CAAC;AACvB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,OAAgB,EAChB,GAAW,EACX,QAA2C;IAE3C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CAAC;QACvC,QAAQ;QACR,iBAAiB,EAAE,CAAC;KACrB,CAAC,CAAC;IACH,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,OAAO,EAAE,CAAC;IACrC,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,aAAa,EAAE,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-frame.d.ts","sourceRoot":"","sources":["../src/extract-frame.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"extract-frame.d.ts","sourceRoot":"","sources":["../src/extract-frame.ts"],"names":[],"mappings":"AAMA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,MAAM,CAAC;CACvB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,MAAM,CAAC,CA2C1E"}
|
package/dist/extract-frame.js
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { spawn } from 'node:child_process';
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
const ffmpegPath = ffmpegInstaller.path;
|
|
2
|
+
import ffmpegStatic from 'ffmpeg-static';
|
|
3
|
+
const ffmpegPath = ffmpegStatic;
|
|
5
4
|
/**
|
|
6
5
|
* Extract a single frame from a video file at the given timestamp using FFmpeg.
|
|
7
6
|
* Uses hybrid seeking: fast keyframe seek + decode-accurate sub-seek for precision.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"extract-frame.js","sourceRoot":"","sources":["../src/extract-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,
|
|
1
|
+
{"version":3,"file":"extract-frame.js","sourceRoot":"","sources":["../src/extract-frame.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAE3C,OAAO,YAAY,MAAM,eAAe,CAAC;AAEzC,MAAM,UAAU,GAAW,YAAiC,CAAC;AAO7D;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,OAA4B;IACvD,MAAM,EAAE,SAAS,EAAE,aAAa,EAAE,GAAG,OAAO,CAAC;IAE7C,+EAA+E;IAC/E,qEAAqE;IACrE,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,aAAa,GAAG,CAAC,CAAC,CAAC;IAC/C,MAAM,SAAS,GAAG,aAAa,GAAG,OAAO,CAAC;IAE1C,MAAM,IAAI,GAAa;QACrB,KAAK,EAAE,MAAM,CAAC,OAAO,CAAC,EAAQ,yBAAyB;QACvD,IAAI,EAAE,SAAS;QACf,KAAK,EAAE,MAAM,CAAC,SAAS,CAAC,EAAM,4BAA4B;QAC1D,WAAW,EAAE,GAAG,EAAc,0BAA0B;QACxD,IAAI,EAAE,YAAY,EAAY,cAAc;QAC5C,SAAS,EAAE,KAAK,EAAc,gBAAgB;QAC9C,GAAG,EAA2B,kBAAkB;KACjD,CAAC;IAEF,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,IAAI,GAAG,KAAK,CAAC,UAAU,EAAE,IAAI,EAAE;YACnC,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;SAClC,CAAC,CAAC;QAEH,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QAE9D,IAAI,MAAM,GAAG,EAAE,CAAC;QAChB,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,IAAY,EAAE,EAAE;YACtC,MAAM,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;QAC5B,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;YACxB,IAAI,IAAI,KAAK,CAAC,EAAE,CAAC;gBACf,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;YACjC,CAAC;iBAAM,CAAC;gBACN,MAAM,CAAC,IAAI,KAAK,CAAC,wCAAwC,IAAI,MAAM,MAAM,EAAE,CAAC,CAAC,CAAC;YAChF,CAAC;QACH,CAAC,CAAC,CAAC;QAEH,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;YACvB,MAAM,CAAC,IAAI,KAAK,CAAC,2BAA2B,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;QAC9D,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
export { renderMedia, type RenderMediaOptions } from './render-media.js';
|
|
2
|
-
export { renderFrames, type RenderFramesOptions, type RenderFramesResult } from './render-frames.js';
|
|
2
|
+
export { renderFrames, type RenderFramesOptions, type RenderFramesResult, type ImageFormat } from './render-frames.js';
|
|
3
3
|
export { renderStill, type RenderStillOptions } from './render-still.js';
|
|
4
4
|
export { stitchFramesToVideo, type StitchOptions } from './stitch-frames-to-video.js';
|
|
5
5
|
export { getCompositions, selectComposition } from './get-compositions.js';
|
|
6
|
-
export { openBrowser, closeBrowser, ensureBrowser } from './browser.js';
|
|
6
|
+
export { openBrowser, closeBrowser, ensureBrowser, type GlRenderer, type OpenBrowserOptions } from './browser.js';
|
|
7
7
|
export { makeCancelSignal, type CancelSignal } from './cancel-signal.js';
|
|
8
8
|
export type { AudioSourceInfo, CompositionInfo } from './types.js';
|
|
9
9
|
//# sourceMappingURL=index.d.ts.map
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,KAAK,kBAAkB,EAAE,KAAK,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACvH,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAE,KAAK,aAAa,EAAE,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,UAAU,EAAE,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAE,KAAK,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACzE,YAAY,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC"}
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,YAAY,EAAuE,MAAM,oBAAoB,CAAC;AACvH,OAAO,EAAE,WAAW,EAA2B,MAAM,mBAAmB,CAAC;AACzE,OAAO,EAAE,mBAAmB,EAAsB,MAAM,6BAA6B,CAAC;AACtF,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC3E,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAA4C,MAAM,cAAc,CAAC;AAClH,OAAO,EAAE,gBAAgB,EAAqB,MAAM,oBAAoB,CAAC"}
|
package/dist/render-frames.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { type OpenBrowserOptions } from './browser.js';
|
|
1
2
|
import type { AudioSourceInfo, CompositionInfo } from './types.js';
|
|
3
|
+
export type ImageFormat = 'png' | 'jpeg';
|
|
2
4
|
export interface RenderFramesOptions {
|
|
3
5
|
serveUrl: string;
|
|
4
6
|
composition: CompositionInfo;
|
|
@@ -12,6 +14,8 @@ export interface RenderFramesOptions {
|
|
|
12
14
|
}) => void;
|
|
13
15
|
cancelSignal?: AbortSignal;
|
|
14
16
|
timeoutPerFrame?: number;
|
|
17
|
+
imageFormat?: ImageFormat;
|
|
18
|
+
gl?: OpenBrowserOptions['gl'];
|
|
15
19
|
}
|
|
16
20
|
export interface RenderFramesResult {
|
|
17
21
|
audioSources: AudioSourceInfo[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-frames.d.ts","sourceRoot":"","sources":["../src/render-frames.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"render-frames.d.ts","sourceRoot":"","sources":["../src/render-frames.ts"],"names":[],"mappings":"AAGA,OAAO,EAAyB,KAAK,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAE9E,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAEnE,MAAM,MAAM,WAAW,GAAG,KAAK,GAAG,MAAM,CAAC;AAEzC,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,eAAe,CAAC;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACnE,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,WAAW,CAAC,EAAE,WAAW,CAAC;IAC1B,EAAE,CAAC,EAAE,kBAAkB,CAAC,IAAI,CAAC,CAAC;CAC/B;AA+BD,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,EAAE,CAAC;CACjC;AAED,wBAAsB,YAAY,CAAC,OAAO,EAAE,mBAAmB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAyF5F"}
|
package/dist/render-frames.js
CHANGED
|
@@ -2,7 +2,7 @@ import fs from 'node:fs';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { openBrowser, openPage } from './browser.js';
|
|
4
4
|
import { startServer } from './serve.js';
|
|
5
|
-
async function renderSingleFrame(page, frame, outputDir, timeoutPerFrame) {
|
|
5
|
+
async function renderSingleFrame(page, frame, outputDir, timeoutPerFrame, imageFormat) {
|
|
6
6
|
// Set the frame and wait for it to be ready
|
|
7
7
|
await page.evaluate((f) => {
|
|
8
8
|
return window.__RENDIV_SET_FRAME__(f);
|
|
@@ -11,19 +11,21 @@ async function renderSingleFrame(page, frame, outputDir, timeoutPerFrame) {
|
|
|
11
11
|
await page.waitForFunction(() => window.__RENDIV_PENDING_HOLDS__() === 0, { timeout: timeoutPerFrame });
|
|
12
12
|
// Screenshot
|
|
13
13
|
const paddedFrame = String(frame).padStart(6, '0');
|
|
14
|
+
const ext = imageFormat === 'jpeg' ? 'jpeg' : 'png';
|
|
14
15
|
await page.screenshot({
|
|
15
|
-
path: path.join(outputDir, `frame-${paddedFrame}
|
|
16
|
-
type:
|
|
16
|
+
path: path.join(outputDir, `frame-${paddedFrame}.${ext}`),
|
|
17
|
+
type: imageFormat,
|
|
17
18
|
animations: 'disabled',
|
|
19
|
+
...(imageFormat === 'jpeg' ? { quality: 80 } : {}),
|
|
18
20
|
});
|
|
19
21
|
}
|
|
20
22
|
export async function renderFrames(options) {
|
|
21
|
-
const { serveUrl, composition, outputDir, inputProps = {}, concurrency = 1, frameRange, onFrameRendered, cancelSignal, timeoutPerFrame = 30000, } = options;
|
|
23
|
+
const { serveUrl, composition, outputDir, inputProps = {}, concurrency = 1, frameRange, onFrameRendered, cancelSignal, timeoutPerFrame = 30000, imageFormat = 'png', gl, } = options;
|
|
22
24
|
const [startFrame, endFrame] = frameRange ?? [0, composition.durationInFrames - 1];
|
|
23
25
|
const totalFrames = endFrame - startFrame + 1;
|
|
24
26
|
fs.mkdirSync(outputDir, { recursive: true });
|
|
25
27
|
const server = await startServer(serveUrl);
|
|
26
|
-
const browser = await openBrowser();
|
|
28
|
+
const browser = await openBrowser({ gl });
|
|
27
29
|
try {
|
|
28
30
|
// Create page pool
|
|
29
31
|
const pages = [];
|
|
@@ -53,7 +55,7 @@ export async function renderFrames(options) {
|
|
|
53
55
|
if (cancelSignal?.aborted)
|
|
54
56
|
return;
|
|
55
57
|
const frame = frameQueue.shift();
|
|
56
|
-
await renderSingleFrame(page, frame, outputDir, timeoutPerFrame);
|
|
58
|
+
await renderSingleFrame(page, frame, outputDir, timeoutPerFrame, imageFormat);
|
|
57
59
|
completedFrames++;
|
|
58
60
|
onFrameRendered?.({ frame: completedFrames, total: totalFrames });
|
|
59
61
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-frames.js","sourceRoot":"","sources":["../src/render-frames.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,WAAW,EAAE,QAAQ,
|
|
1
|
+
{"version":3,"file":"render-frames.js","sourceRoot":"","sources":["../src/render-frames.ts"],"names":[],"mappings":"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"}
|
package/dist/render-media.d.ts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { CompositionInfo } from './types.js';
|
|
2
|
+
import type { GlRenderer } from './browser.js';
|
|
2
3
|
export interface RenderMediaOptions {
|
|
3
4
|
composition: CompositionInfo;
|
|
4
5
|
serveUrl: string;
|
|
@@ -13,6 +14,16 @@ export interface RenderMediaOptions {
|
|
|
13
14
|
}) => void;
|
|
14
15
|
frameRange?: [number, number];
|
|
15
16
|
cancelSignal?: AbortSignal;
|
|
17
|
+
/** Intermediate frame image format. Default: png */
|
|
18
|
+
imageFormat?: 'png' | 'jpeg';
|
|
19
|
+
/** FFmpeg encoding preset (ultrafast, fast, medium, slow, veryslow). */
|
|
20
|
+
encodingPreset?: string;
|
|
21
|
+
/** Quality factor (0–51, lower = better). Default: 18 */
|
|
22
|
+
crf?: number;
|
|
23
|
+
/** Video encoder override (e.g. libx264, h264_videotoolbox, h264_nvenc). */
|
|
24
|
+
videoEncoder?: string;
|
|
25
|
+
/** GL renderer for headless Chromium. Default: swiftshader */
|
|
26
|
+
gl?: GlRenderer;
|
|
16
27
|
}
|
|
17
28
|
export declare function renderMedia(options: RenderMediaOptions): Promise<void>;
|
|
18
29
|
//# sourceMappingURL=render-media.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-media.d.ts","sourceRoot":"","sources":["../src/render-media.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"render-media.d.ts","sourceRoot":"","sources":["../src/render-media.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAE/C,MAAM,WAAW,kBAAkB;IACjC,WAAW,EAAE,eAAe,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IAC/F,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC9B,YAAY,CAAC,EAAE,WAAW,CAAC;IAC3B,oDAAoD;IACpD,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC7B,wEAAwE;IACxE,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,yDAAyD;IACzD,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4EAA4E;IAC5E,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,EAAE,CAAC,EAAE,UAAU,CAAC;CACjB;AAED,wBAAsB,WAAW,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC,IAAI,CAAC,CAiF5E"}
|
package/dist/render-media.js
CHANGED
|
@@ -4,7 +4,7 @@ import fs from 'node:fs';
|
|
|
4
4
|
import { renderFrames } from './render-frames.js';
|
|
5
5
|
import { stitchFramesToVideo } from './stitch-frames-to-video.js';
|
|
6
6
|
export async function renderMedia(options) {
|
|
7
|
-
const { composition, serveUrl, codec = 'mp4', outputLocation, inputProps, concurrency, onProgress, frameRange, cancelSignal, } = options;
|
|
7
|
+
const { composition, serveUrl, codec = 'mp4', outputLocation, inputProps, concurrency, onProgress, frameRange, cancelSignal, imageFormat, encodingPreset, crf, videoEncoder, gl, } = options;
|
|
8
8
|
const totalFrames = frameRange
|
|
9
9
|
? frameRange[1] - frameRange[0] + 1
|
|
10
10
|
: composition.durationInFrames;
|
|
@@ -22,6 +22,8 @@ export async function renderMedia(options) {
|
|
|
22
22
|
inputProps,
|
|
23
23
|
concurrency,
|
|
24
24
|
frameRange,
|
|
25
|
+
imageFormat,
|
|
26
|
+
gl,
|
|
25
27
|
onFrameRendered: ({ frame, total }) => {
|
|
26
28
|
onProgress?.({
|
|
27
29
|
progress: (frame / total) * 0.9, // 90% for frame rendering
|
|
@@ -44,6 +46,10 @@ export async function renderMedia(options) {
|
|
|
44
46
|
outputPath: outputLocation,
|
|
45
47
|
fps: composition.fps,
|
|
46
48
|
codec,
|
|
49
|
+
crf,
|
|
50
|
+
encodingPreset,
|
|
51
|
+
videoEncoder,
|
|
52
|
+
imageFormat,
|
|
47
53
|
audioSources,
|
|
48
54
|
assetsDir: serveUrl,
|
|
49
55
|
});
|
package/dist/render-media.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-media.js","sourceRoot":"","sources":["../src/render-media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;
|
|
1
|
+
{"version":3,"file":"render-media.js","sourceRoot":"","sources":["../src/render-media.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,EAAE,MAAM,SAAS,CAAC;AACzB,OAAO,EAAE,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,mBAAmB,EAAE,MAAM,6BAA6B,CAAC;AA0BlE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,OAA2B;IAC3D,MAAM,EACJ,WAAW,EACX,QAAQ,EACR,KAAK,GAAG,KAAK,EACb,cAAc,EACd,UAAU,EACV,WAAW,EACX,UAAU,EACV,UAAU,EACV,YAAY,EACZ,WAAW,EACX,cAAc,EACd,GAAG,EACH,YAAY,EACZ,EAAE,GACH,GAAG,OAAO,CAAC;IAEZ,MAAM,WAAW,GAAG,UAAU;QAC5B,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,GAAG,UAAU,CAAC,CAAC,CAAC,GAAG,CAAC;QACnC,CAAC,CAAC,WAAW,CAAC,gBAAgB,CAAC;IAEjC,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,MAAM,EAAE,EAAE,iBAAiB,IAAI,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IACrE,EAAE,CAAC,SAAS,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE1C,iCAAiC;IACjC,MAAM,SAAS,GAAG,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,CAAC;IAC/C,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAE7C,IAAI,CAAC;QACH,mDAAmD;QACnD,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,YAAY,CAAC;YAC1C,QAAQ;YACR,WAAW;YACX,SAAS,EAAE,MAAM;YACjB,UAAU;YACV,WAAW;YACX,UAAU;YACV,WAAW;YACX,EAAE;YACF,eAAe,EAAE,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,EAAE;gBACpC,UAAU,EAAE,CAAC;oBACX,QAAQ,EAAE,CAAC,KAAK,GAAG,KAAK,CAAC,GAAG,GAAG,EAAE,0BAA0B;oBAC3D,cAAc,EAAE,KAAK;oBACrB,WAAW,EAAE,KAAK;iBACnB,CAAC,CAAC;YACL,CAAC;YACD,YAAY;SACb,CAAC,CAAC;QAEH,IAAI,YAAY,EAAE,OAAO;YAAE,OAAO;QAElC,2DAA2D;QAC3D,UAAU,EAAE,CAAC;YACX,QAAQ,EAAE,GAAG;YACb,cAAc,EAAE,WAAW;YAC3B,WAAW;SACZ,CAAC,CAAC;QAEH,MAAM,mBAAmB,CAAC;YACxB,SAAS,EAAE,MAAM;YACjB,UAAU,EAAE,cAAc;YAC1B,GAAG,EAAE,WAAW,CAAC,GAAG;YACpB,KAAK;YACL,GAAG;YACH,cAAc;YACd,YAAY;YACZ,WAAW;YACX,YAAY;YACZ,SAAS,EAAE,QAAQ;SACpB,CAAC,CAAC;QAEH,UAAU,EAAE,CAAC;YACX,QAAQ,EAAE,GAAG;YACb,cAAc,EAAE,WAAW;YAC3B,WAAW;SACZ,CAAC,CAAC;IACL,CAAC;YAAS,CAAC;QACT,sBAAsB;QACtB,EAAE,CAAC,MAAM,CAAC,MAAM,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,CAAC;AACH,CAAC"}
|
|
@@ -6,6 +6,12 @@ export interface StitchOptions {
|
|
|
6
6
|
codec?: 'mp4' | 'webm';
|
|
7
7
|
crf?: number;
|
|
8
8
|
pixelFormat?: string;
|
|
9
|
+
/** FFmpeg encoding preset (e.g. ultrafast, fast, medium, slow, veryslow). Only applies to H.264 encoders. */
|
|
10
|
+
encodingPreset?: string;
|
|
11
|
+
/** Video encoder override (e.g. libx264, h264_videotoolbox, h264_nvenc, libvpx-vp9). */
|
|
12
|
+
videoEncoder?: string;
|
|
13
|
+
/** Image format used for intermediate frames. Default: png */
|
|
14
|
+
imageFormat?: 'png' | 'jpeg';
|
|
9
15
|
onProgress?: (progress: number) => void;
|
|
10
16
|
/** Audio sources collected from Audio/Video components */
|
|
11
17
|
audioSources?: AudioSourceInfo[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stitch-frames-to-video.d.ts","sourceRoot":"","sources":["../src/stitch-frames-to-video.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"stitch-frames-to-video.d.ts","sourceRoot":"","sources":["../src/stitch-frames-to-video.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAclD,MAAM,WAAW,aAAa;IAC5B,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IACvB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,6GAA6G;IAC7G,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,wFAAwF;IACxF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,8DAA8D;IAC9D,WAAW,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,0DAA0D;IAC1D,YAAY,CAAC,EAAE,eAAe,EAAE,CAAC;IACjC,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA0J/E"}
|
|
@@ -1,12 +1,21 @@
|
|
|
1
|
-
import { spawn } from 'node:child_process';
|
|
1
|
+
import { spawn, spawnSync } from 'node:child_process';
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import fs from 'node:fs';
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
4
|
+
import ffmpegStatic from 'ffmpeg-static';
|
|
5
|
+
const ffmpegPath = ffmpegStatic;
|
|
6
|
+
/** Check if a file contains an audio stream using ffmpeg probe. */
|
|
7
|
+
function hasAudioStream(filePath) {
|
|
8
|
+
const result = spawnSync(ffmpegPath, ['-i', filePath, '-hide_banner'], {
|
|
9
|
+
encoding: 'utf-8',
|
|
10
|
+
timeout: 5000,
|
|
11
|
+
});
|
|
12
|
+
const output = result.stderr || '';
|
|
13
|
+
return /Stream #\d+:\d+.*Audio:/.test(output);
|
|
14
|
+
}
|
|
7
15
|
export async function stitchFramesToVideo(options) {
|
|
8
|
-
const { framesDir, outputPath, fps, codec = 'mp4', crf = 18, pixelFormat = 'yuv420p', audioSources = [], assetsDir, } = options;
|
|
9
|
-
const
|
|
16
|
+
const { framesDir, outputPath, fps, codec = 'mp4', crf = 18, pixelFormat = 'yuv420p', encodingPreset, videoEncoder, imageFormat = 'png', audioSources = [], assetsDir, } = options;
|
|
17
|
+
const ext = imageFormat === 'jpeg' ? 'jpeg' : 'png';
|
|
18
|
+
const inputPattern = path.join(framesDir, `frame-%06d.${ext}`);
|
|
10
19
|
// Resolve audio sources to absolute file paths, filtering out missing files
|
|
11
20
|
const resolvedAudio = [];
|
|
12
21
|
if (assetsDir && audioSources.length > 0) {
|
|
@@ -14,6 +23,11 @@ export async function stitchFramesToVideo(options) {
|
|
|
14
23
|
const cleaned = source.src.startsWith('/') ? source.src.slice(1) : source.src;
|
|
15
24
|
const filePath = path.resolve(assetsDir, cleaned);
|
|
16
25
|
if (fs.existsSync(filePath)) {
|
|
26
|
+
// Video-type sources may not have an audio track (e.g. screen recordings).
|
|
27
|
+
// Probe the file and skip it if no audio stream is present.
|
|
28
|
+
if (source.type === 'video' && !hasAudioStream(filePath)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
17
31
|
resolvedAudio.push({ ...source, filePath });
|
|
18
32
|
}
|
|
19
33
|
else {
|
|
@@ -81,13 +95,19 @@ export async function stitchFramesToVideo(options) {
|
|
|
81
95
|
args.push('-map', '0:v', '-map', '[aout]');
|
|
82
96
|
}
|
|
83
97
|
if (codec === 'mp4') {
|
|
84
|
-
|
|
98
|
+
const encoder = videoEncoder ?? 'libx264';
|
|
99
|
+
args.push('-c:v', encoder, '-crf', String(crf));
|
|
100
|
+
if (encodingPreset) {
|
|
101
|
+
args.push('-preset', encodingPreset);
|
|
102
|
+
}
|
|
103
|
+
args.push('-pix_fmt', pixelFormat, '-movflags', '+faststart');
|
|
85
104
|
if (resolvedAudio.length > 0) {
|
|
86
105
|
args.push('-c:a', 'aac', '-b:a', '192k');
|
|
87
106
|
}
|
|
88
107
|
}
|
|
89
108
|
else {
|
|
90
|
-
|
|
109
|
+
const encoder = videoEncoder ?? 'libvpx-vp9';
|
|
110
|
+
args.push('-c:v', encoder, '-crf', String(crf), '-b:v', '0');
|
|
91
111
|
if (resolvedAudio.length > 0) {
|
|
92
112
|
args.push('-c:a', 'libopus', '-b:a', '128k');
|
|
93
113
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"stitch-frames-to-video.js","sourceRoot":"","sources":["../src/stitch-frames-to-video.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"stitch-frames-to-video.js","sourceRoot":"","sources":["../src/stitch-frames-to-video.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@rendiv/renderer",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.15",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
"dist"
|
|
16
16
|
],
|
|
17
17
|
"dependencies": {
|
|
18
|
-
"
|
|
18
|
+
"ffmpeg-static": "^5.2.0",
|
|
19
19
|
"playwright": "^1.49.0"
|
|
20
20
|
},
|
|
21
21
|
"devDependencies": {
|