@hyperframes/engine 0.6.119 → 0.6.121
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/package.json +24 -7
- package/scripts/generate-lut-reference.py +0 -168
- package/scripts/test-fitTextFontSize-browser.ts +0 -135
- package/src/cdp-headless-experimental.d.ts +0 -54
- package/src/config.test.ts +0 -213
- package/src/config.ts +0 -417
- package/src/index.ts +0 -273
- package/src/services/audioMixer.test.ts +0 -326
- package/src/services/audioMixer.ts +0 -604
- package/src/services/audioMixer.types.ts +0 -35
- package/src/services/audioVolumeEnvelope.test.ts +0 -176
- package/src/services/audioVolumeEnvelope.ts +0 -138
- package/src/services/browserManager.test.ts +0 -330
- package/src/services/browserManager.ts +0 -670
- package/src/services/chunkEncoder.test.ts +0 -1415
- package/src/services/chunkEncoder.ts +0 -831
- package/src/services/chunkEncoder.types.ts +0 -60
- package/src/services/extractionCache.test.ts +0 -199
- package/src/services/extractionCache.ts +0 -216
- package/src/services/fileServer.ts +0 -110
- package/src/services/frameCapture-discardWarmup.test.ts +0 -183
- package/src/services/frameCapture-namePolyfill.test.ts +0 -78
- package/src/services/frameCapture-pollImagesReady.test.ts +0 -153
- package/src/services/frameCapture-staticDedupIndex.test.ts +0 -76
- package/src/services/frameCapture-warmupTicks.test.ts +0 -174
- package/src/services/frameCapture.test.ts +0 -192
- package/src/services/frameCapture.ts +0 -1934
- package/src/services/hdrCapture.test.ts +0 -159
- package/src/services/hdrCapture.ts +0 -315
- package/src/services/parallelCoordinator.test.ts +0 -139
- package/src/services/parallelCoordinator.ts +0 -437
- package/src/services/screenshotService.test.ts +0 -510
- package/src/services/screenshotService.ts +0 -615
- package/src/services/streamingEncoder.test.ts +0 -832
- package/src/services/streamingEncoder.ts +0 -594
- package/src/services/systemMemory.test.ts +0 -324
- package/src/services/systemMemory.ts +0 -180
- package/src/services/videoFrameExtractor.test.ts +0 -1062
- package/src/services/videoFrameExtractor.ts +0 -1139
- package/src/services/videoFrameInjector.test.ts +0 -300
- package/src/services/videoFrameInjector.ts +0 -687
- package/src/services/vp9Options.ts +0 -13
- package/src/types.ts +0 -191
- package/src/utils/alphaBlit.test.ts +0 -1349
- package/src/utils/alphaBlit.ts +0 -1015
- package/src/utils/assertSwiftShader.test.ts +0 -130
- package/src/utils/assertSwiftShader.ts +0 -126
- package/src/utils/ffmpegBinaries.test.ts +0 -43
- package/src/utils/ffmpegBinaries.ts +0 -63
- package/src/utils/ffprobe.test.ts +0 -342
- package/src/utils/ffprobe.ts +0 -457
- package/src/utils/gpuEncoder.test.ts +0 -140
- package/src/utils/gpuEncoder.ts +0 -268
- package/src/utils/hdr.test.ts +0 -191
- package/src/utils/hdr.ts +0 -137
- package/src/utils/hdrCompositing.test.ts +0 -130
- package/src/utils/htmlTemplate.test.ts +0 -42
- package/src/utils/htmlTemplate.ts +0 -42
- package/src/utils/layerCompositor.test.ts +0 -150
- package/src/utils/layerCompositor.ts +0 -58
- package/src/utils/parityContract.ts +0 -1
- package/src/utils/processTracker.test.ts +0 -74
- package/src/utils/processTracker.ts +0 -41
- package/src/utils/readWebGlVendorInfoFromCanvas.ts +0 -52
- package/src/utils/runFfmpeg.test.ts +0 -102
- package/src/utils/runFfmpeg.ts +0 -136
- package/src/utils/shaderTransitions.test.ts +0 -738
- package/src/utils/shaderTransitions.ts +0 -1130
- package/src/utils/uint16-alignment-audit.test.ts +0 -125
- package/src/utils/urlDownloader.test.ts +0 -65
- package/src/utils/urlDownloader.ts +0 -143
- package/tsconfig.json +0 -19
- package/vitest.config.ts +0 -7
package/src/config.ts
DELETED
|
@@ -1,417 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Engine Configuration
|
|
3
|
-
*
|
|
4
|
-
* Typed configuration for the rendering pipeline. Replaces the PRODUCER_*
|
|
5
|
-
* env var sprawl with a structured interface. Env vars still work as
|
|
6
|
-
* fallbacks for backward compatibility during migration.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import {
|
|
10
|
-
getSystemTotalMb,
|
|
11
|
-
isLowMemorySystem,
|
|
12
|
-
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
13
|
-
} from "./services/systemMemory.js";
|
|
14
|
-
import { DEFAULT_VP9_CPU_USED, normalizeVp9CpuUsed } from "./services/vp9Options.js";
|
|
15
|
-
|
|
16
|
-
/**
|
|
17
|
-
* Full engine configuration. All fields are wired through the config
|
|
18
|
-
* object; env vars serve as backward-compatible fallbacks resolved
|
|
19
|
-
* in `resolveConfig()`.
|
|
20
|
-
*/
|
|
21
|
-
export interface EngineConfig {
|
|
22
|
-
// ── Rendering ────────────────────────────────────────────────────────
|
|
23
|
-
fps: 24 | 30 | 60;
|
|
24
|
-
quality: "draft" | "standard" | "high";
|
|
25
|
-
format: "jpeg" | "png";
|
|
26
|
-
jpegQuality: number;
|
|
27
|
-
|
|
28
|
-
// ── Parallelism ──────────────────────────────────────────────────────
|
|
29
|
-
/** Max worker count. "auto" uses CPU-based heuristic. */
|
|
30
|
-
concurrency: number | "auto";
|
|
31
|
-
/** CPU cores allocated per worker. */
|
|
32
|
-
coresPerWorker: number;
|
|
33
|
-
/** Minimum frames before parallel workers are used. */
|
|
34
|
-
minParallelFrames: number;
|
|
35
|
-
/** Frame count threshold for "large render" heuristics. */
|
|
36
|
-
largeRenderThreshold: number;
|
|
37
|
-
|
|
38
|
-
// ── Browser ──────────────────────────────────────────────────────────
|
|
39
|
-
chromePath?: string;
|
|
40
|
-
disableGpu: boolean;
|
|
41
|
-
/**
|
|
42
|
-
* Chrome/WebGL rendering backend.
|
|
43
|
-
* - "software": SwiftShader (CPU-only). Always works; ~5-50× slower than GPU.
|
|
44
|
-
* - "hardware": host GPU via platform-native ANGLE backend (Metal/D3D11/EGL).
|
|
45
|
-
* Errors if no usable GPU is reachable from Chrome.
|
|
46
|
-
* - "auto": probe Chrome for WebGL availability on first launch in this
|
|
47
|
-
* process; fall back to software if hardware-mode WebGL is unavailable.
|
|
48
|
-
* Cost: one extra Chrome launch (~1-2 s) per process; result cached.
|
|
49
|
-
*/
|
|
50
|
-
browserGpuMode: "software" | "hardware" | "auto";
|
|
51
|
-
enableBrowserPool: boolean;
|
|
52
|
-
browserTimeout: number;
|
|
53
|
-
protocolTimeout: number;
|
|
54
|
-
/** Expected Chromium major version (optional validation). */
|
|
55
|
-
expectedChromiumMajor?: number;
|
|
56
|
-
/** Force screenshot capture mode (skip BeginFrame even on Linux). */
|
|
57
|
-
forceScreenshot: boolean;
|
|
58
|
-
/**
|
|
59
|
-
* Static-frame dedup: reuse byte-identical frames instead of re-seeking +
|
|
60
|
-
* re-screenshotting (anchor-verified at init). Default ON; disable via
|
|
61
|
-
* `HF_STATIC_DEDUP` in {false,0,off}. Only arms in screenshot capture mode.
|
|
62
|
-
*/
|
|
63
|
-
staticFrameDedup: boolean;
|
|
64
|
-
/**
|
|
65
|
-
* Low-memory render profile. When `true`, the orchestrator collapses the
|
|
66
|
-
* pipeline to its cheapest shape on memory-constrained hosts: it skips the
|
|
67
|
-
* throwaway auto-worker calibration browser, pins capture to a single
|
|
68
|
-
* worker (unless the user passed an explicit `--workers`), and prefers
|
|
69
|
-
* screenshot capture over BeginFrame. Resolved automatically from total
|
|
70
|
-
* RAM (`isLowMemorySystem()`); force on/off via `PRODUCER_LOW_MEMORY_MODE`
|
|
71
|
-
* or the `--low-memory-mode` CLI flag.
|
|
72
|
-
*/
|
|
73
|
-
lowMemoryMode: boolean;
|
|
74
|
-
/**
|
|
75
|
-
* Opt-in: page-side shader-transition compositing.
|
|
76
|
-
*
|
|
77
|
-
* When `true`, shader transitions for SDR compositions run their blend
|
|
78
|
-
* inside Chrome via WebGL on a page-side compositor canvas instead of
|
|
79
|
-
* Node-side per-pixel blending (the hf#677 layered pipeline). The engine
|
|
80
|
-
* then captures ONE opaque RGB frame per output frame via the streaming
|
|
81
|
-
* capture path, skipping per-scene transparent screenshots and the
|
|
82
|
-
* Node-side shader-blend worker pool entirely.
|
|
83
|
-
*
|
|
84
|
-
* The feature stacks on top of the hf#677 chain — it does not undo it.
|
|
85
|
-
* When this flag is OFF (the default), behaviour is byte-identical to the
|
|
86
|
-
* current path. When ON and the composition has no shader transitions or
|
|
87
|
-
* has HDR content (which forces the layered path regardless), this flag
|
|
88
|
-
* is a no-op.
|
|
89
|
-
*
|
|
90
|
-
* Mac viability: Chrome on Mac accelerates page-side WebGL canvases via
|
|
91
|
-
* Metal/CoreAnimation natively. This is the lever for Mac users who
|
|
92
|
-
* cannot use `--enable-begin-frame-control` (Chromium structural limit,
|
|
93
|
-
* crbug.com/40656275).
|
|
94
|
-
*
|
|
95
|
-
* Determinism: page-side WebGL is f32, not f64. Byte-equality fixture
|
|
96
|
-
* pins are NOT compatible with this path; the new path's correctness
|
|
97
|
-
* pin is PSNR-based. Default OFF preserves the existing pins for the
|
|
98
|
-
* hf#677 chain.
|
|
99
|
-
*
|
|
100
|
-
* Env fallback: `HF_PAGE_SIDE_COMPOSITING=true`.
|
|
101
|
-
*/
|
|
102
|
-
enablePageSideCompositing: boolean;
|
|
103
|
-
|
|
104
|
-
// ── Encoding ─────────────────────────────────────────────────────────
|
|
105
|
-
/**
|
|
106
|
-
* libvpx-vp9 speed/quality tradeoff. Higher values encode faster with a
|
|
107
|
-
* larger quality/size tradeoff. FFmpeg accepts integer values from -8 to 8.
|
|
108
|
-
*/
|
|
109
|
-
vp9CpuUsed: number;
|
|
110
|
-
enableChunkedEncode: boolean;
|
|
111
|
-
chunkSizeFrames: number;
|
|
112
|
-
enableStreamingEncode: boolean;
|
|
113
|
-
/**
|
|
114
|
-
* Max composition duration eligible for streaming encode (seconds).
|
|
115
|
-
* Mirrors GSAP rendering's 4-minute streaming guard: production has seen
|
|
116
|
-
* ffmpeg's streaming pipe hit FFMPEG_STREAMING_TIMEOUT_MS on longer videos.
|
|
117
|
-
*/
|
|
118
|
-
streamingEncodeMaxDurationSeconds: number;
|
|
119
|
-
|
|
120
|
-
// ── FFmpeg timeouts ──────────────────────────────────────────────────
|
|
121
|
-
/** Timeout for FFmpeg frame encoding (ms). Default: 600_000 */
|
|
122
|
-
ffmpegEncodeTimeout: number;
|
|
123
|
-
/** Timeout for FFmpeg mux/faststart processes (ms). Default: 300_000 */
|
|
124
|
-
ffmpegProcessTimeout: number;
|
|
125
|
-
/**
|
|
126
|
-
* Inactivity timeout for FFmpeg streaming encode (ms). The timer resets on
|
|
127
|
-
* every successful `writeFrame` call, so this caps the duration of a
|
|
128
|
-
* single "no frame arrived" gap (capture hang, dead Chrome), not the total
|
|
129
|
-
* render time. Default: 600_000 (10 minutes without any frame = dead).
|
|
130
|
-
*/
|
|
131
|
-
ffmpegStreamingTimeout: number;
|
|
132
|
-
|
|
133
|
-
// ── HDR ──────────────────────────────────────────────────────────────
|
|
134
|
-
/** HDR output transfer function. false = SDR output (default). */
|
|
135
|
-
hdr: { transfer: "hlg" | "pq" } | false;
|
|
136
|
-
/** Auto-detect HDR from video sources when hdr is not explicitly set. */
|
|
137
|
-
hdrAutoDetect: boolean;
|
|
138
|
-
|
|
139
|
-
// ── Media ────────────────────────────────────────────────────────────
|
|
140
|
-
audioGain: number;
|
|
141
|
-
/**
|
|
142
|
-
* Hard upper bound on entries kept in the video frame data URI cache.
|
|
143
|
-
* Acts as a sanity cap; the byte budget below normally fires first on
|
|
144
|
-
* high-resolution renders. At 1080p with ~6 MB per JPEG frame the default
|
|
145
|
-
* 256 entries fit inside ~1.5 GB. At 4K the byte budget evicts long
|
|
146
|
-
* before this cap is reached.
|
|
147
|
-
*/
|
|
148
|
-
frameDataUriCacheLimit: number;
|
|
149
|
-
/**
|
|
150
|
-
* Memory budget for the cache, in megabytes. Eviction kicks in once the
|
|
151
|
-
* sum of cached data-URI string lengths exceeds this. Sized so a worker
|
|
152
|
-
* stays comfortably under a few GB even at 4K (where each PNG frame is
|
|
153
|
-
* ~25 MB and the base64 data URI is ~33 MB).
|
|
154
|
-
*/
|
|
155
|
-
frameDataUriCacheBytesLimitMb: number;
|
|
156
|
-
|
|
157
|
-
// ── Timeouts ─────────────────────────────────────────────────────────
|
|
158
|
-
playerReadyTimeout: number;
|
|
159
|
-
renderReadyTimeout: number;
|
|
160
|
-
/**
|
|
161
|
-
* Puppeteer `page.goto()` navigation timeout for the entry HTML, in ms.
|
|
162
|
-
* The browser must reach `domcontentloaded` within this budget — heavy
|
|
163
|
-
* compositions (many videos, large fonts, hundreds of asset requests)
|
|
164
|
-
* can blow past the default 60s on cold cache. Default: 60_000.
|
|
165
|
-
*
|
|
166
|
-
* Env fallback: `PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS`.
|
|
167
|
-
* CLI flag: `--browser-timeout <seconds>`.
|
|
168
|
-
*/
|
|
169
|
-
pageNavigationTimeout: number;
|
|
170
|
-
|
|
171
|
-
// ── Runtime ──────────────────────────────────────────────────────────
|
|
172
|
-
/** Verify Hyperframe runtime SHA256 checksums. */
|
|
173
|
-
verifyRuntime: boolean;
|
|
174
|
-
/** Custom manifest path for Hyperframe runtime. */
|
|
175
|
-
runtimeManifestPath?: string;
|
|
176
|
-
|
|
177
|
-
// ── Cache ────────────────────────────────────────────────────────────
|
|
178
|
-
/**
|
|
179
|
-
* Directory where the content-addressed extraction cache persists frame
|
|
180
|
-
* bundles keyed on (path, mtime, size, mediaStart, duration, fps, format).
|
|
181
|
-
* Undefined disables caching — extraction runs into the render's workDir
|
|
182
|
-
* and cleanup removes it when the render ends, preserving the pre-cache
|
|
183
|
-
* behaviour.
|
|
184
|
-
*
|
|
185
|
-
* **Single-writer.** The cache is not safe for concurrent renders pointing
|
|
186
|
-
* at the same directory. A `.hf-complete` sentinel prevents another render
|
|
187
|
-
* from serving an entry that hasn't finished extracting, but individual
|
|
188
|
-
* frame files are written non-atomically — a second render reading during
|
|
189
|
-
* the write window can observe a truncated frame. Give each concurrent
|
|
190
|
-
* render pipeline its own `extractCacheDir`, or gate with an external mutex.
|
|
191
|
-
*
|
|
192
|
-
* **Network filesystems.** `mtime` resolution on NFS/SMB mounts can be
|
|
193
|
-
* coarser than expected (seconds rather than nanoseconds), which may
|
|
194
|
-
* produce spurious cache hits if a source file is overwritten within the
|
|
195
|
-
* same mtime tick. Local filesystems are the intended deployment target.
|
|
196
|
-
*
|
|
197
|
-
* Env fallback: `HYPERFRAMES_EXTRACT_CACHE_DIR`.
|
|
198
|
-
*/
|
|
199
|
-
extractCacheDir?: string;
|
|
200
|
-
|
|
201
|
-
// ── Debug ────────────────────────────────────────────────────────────
|
|
202
|
-
debug: boolean;
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/** Default configuration — sensible for Hyperframes compositions. */
|
|
206
|
-
export const DEFAULT_CONFIG: EngineConfig = {
|
|
207
|
-
fps: 30,
|
|
208
|
-
quality: "standard",
|
|
209
|
-
format: "jpeg",
|
|
210
|
-
jpegQuality: 80,
|
|
211
|
-
|
|
212
|
-
concurrency: "auto",
|
|
213
|
-
coresPerWorker: 2.5,
|
|
214
|
-
minParallelFrames: 120,
|
|
215
|
-
largeRenderThreshold: 1000,
|
|
216
|
-
|
|
217
|
-
disableGpu: false,
|
|
218
|
-
browserGpuMode: "software",
|
|
219
|
-
enableBrowserPool: true,
|
|
220
|
-
browserTimeout: 120_000,
|
|
221
|
-
protocolTimeout: 300_000,
|
|
222
|
-
forceScreenshot: false,
|
|
223
|
-
staticFrameDedup: true,
|
|
224
|
-
// Auto-detected per host in `resolveConfig`; defaults off for the raw
|
|
225
|
-
// DEFAULT_CONFIG (used directly by tests and worker-sizing fallbacks).
|
|
226
|
-
lowMemoryMode: false,
|
|
227
|
-
enablePageSideCompositing: true,
|
|
228
|
-
|
|
229
|
-
vp9CpuUsed: DEFAULT_VP9_CPU_USED,
|
|
230
|
-
enableChunkedEncode: false,
|
|
231
|
-
chunkSizeFrames: 360,
|
|
232
|
-
enableStreamingEncode: true,
|
|
233
|
-
streamingEncodeMaxDurationSeconds: 240,
|
|
234
|
-
|
|
235
|
-
ffmpegEncodeTimeout: 600_000,
|
|
236
|
-
ffmpegProcessTimeout: 300_000,
|
|
237
|
-
ffmpegStreamingTimeout: 600_000,
|
|
238
|
-
|
|
239
|
-
hdr: false,
|
|
240
|
-
hdrAutoDetect: true,
|
|
241
|
-
|
|
242
|
-
audioGain: 1,
|
|
243
|
-
frameDataUriCacheLimit: 256,
|
|
244
|
-
frameDataUriCacheBytesLimitMb: 1500,
|
|
245
|
-
|
|
246
|
-
playerReadyTimeout: 45_000,
|
|
247
|
-
renderReadyTimeout: 15_000,
|
|
248
|
-
pageNavigationTimeout: 60_000,
|
|
249
|
-
|
|
250
|
-
verifyRuntime: true,
|
|
251
|
-
|
|
252
|
-
debug: false,
|
|
253
|
-
};
|
|
254
|
-
|
|
255
|
-
function memoryAdaptiveCacheLimit(): number {
|
|
256
|
-
const total = getSystemTotalMb();
|
|
257
|
-
if (total < 4096) return 32;
|
|
258
|
-
if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 64;
|
|
259
|
-
return DEFAULT_CONFIG.frameDataUriCacheLimit;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
function memoryAdaptiveCacheBytesMb(): number {
|
|
263
|
-
const total = getSystemTotalMb();
|
|
264
|
-
if (total < 4096) return 128;
|
|
265
|
-
if (total <= LOW_MEMORY_TOTAL_MB_THRESHOLD) return 256;
|
|
266
|
-
return DEFAULT_CONFIG.frameDataUriCacheBytesLimitMb;
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
/**
|
|
270
|
-
* Resolve configuration by merging: defaults ← env vars ← explicit overrides.
|
|
271
|
-
* Env vars provide backward compatibility during migration; explicit config
|
|
272
|
-
* takes precedence over everything.
|
|
273
|
-
*/
|
|
274
|
-
export function resolveConfig(overrides?: Partial<EngineConfig>): EngineConfig {
|
|
275
|
-
const env = (key: string): string | undefined => process.env[key];
|
|
276
|
-
const envNum = (key: string, fallback: number): number => {
|
|
277
|
-
const raw = env(key);
|
|
278
|
-
if (raw === undefined || raw === "") return fallback;
|
|
279
|
-
const n = Number(raw);
|
|
280
|
-
return Number.isFinite(n) ? n : fallback;
|
|
281
|
-
};
|
|
282
|
-
const envBool = (key: string, fallback: boolean): boolean => {
|
|
283
|
-
const raw = env(key);
|
|
284
|
-
if (raw === undefined) return fallback;
|
|
285
|
-
return raw === "true";
|
|
286
|
-
};
|
|
287
|
-
const envVp9CpuUsed = (): number => {
|
|
288
|
-
const raw = env("PRODUCER_VP9_CPU_USED");
|
|
289
|
-
if (raw === undefined || raw === "") return DEFAULT_CONFIG.vp9CpuUsed;
|
|
290
|
-
return normalizeVp9CpuUsed(Number(raw));
|
|
291
|
-
};
|
|
292
|
-
const envBrowserGpuMode = (): EngineConfig["browserGpuMode"] => {
|
|
293
|
-
const raw = env("PRODUCER_BROWSER_GPU_MODE");
|
|
294
|
-
if (raw === "hardware" || raw === "software" || raw === "auto") return raw;
|
|
295
|
-
return DEFAULT_CONFIG.browserGpuMode;
|
|
296
|
-
};
|
|
297
|
-
// Tri-state: explicit on/off via env, otherwise auto-detect from total RAM.
|
|
298
|
-
const resolveLowMemoryMode = (): boolean => {
|
|
299
|
-
const raw = env("PRODUCER_LOW_MEMORY_MODE")?.toLowerCase();
|
|
300
|
-
if (raw === "true" || raw === "on" || raw === "1") return true;
|
|
301
|
-
if (raw === "false" || raw === "off" || raw === "0") return false;
|
|
302
|
-
return isLowMemorySystem();
|
|
303
|
-
};
|
|
304
|
-
// Opt-OUT: default ON, disabled only by an explicit falsey value.
|
|
305
|
-
const resolveStaticFrameDedup = (): boolean => {
|
|
306
|
-
const raw = env("HF_STATIC_DEDUP")?.trim().toLowerCase();
|
|
307
|
-
return !(raw === "false" || raw === "off" || raw === "0");
|
|
308
|
-
};
|
|
309
|
-
|
|
310
|
-
// Env-var layer (backward compat)
|
|
311
|
-
const fromEnv: Partial<EngineConfig> = {
|
|
312
|
-
concurrency: env("PRODUCER_MAX_WORKERS") ? Number(env("PRODUCER_MAX_WORKERS")) : undefined,
|
|
313
|
-
coresPerWorker: envNum("PRODUCER_CORES_PER_WORKER", DEFAULT_CONFIG.coresPerWorker),
|
|
314
|
-
minParallelFrames: envNum("PRODUCER_MIN_PARALLEL_FRAMES", DEFAULT_CONFIG.minParallelFrames),
|
|
315
|
-
largeRenderThreshold: envNum(
|
|
316
|
-
"PRODUCER_LARGE_RENDER_THRESHOLD",
|
|
317
|
-
DEFAULT_CONFIG.largeRenderThreshold,
|
|
318
|
-
),
|
|
319
|
-
|
|
320
|
-
chromePath: env("PRODUCER_HEADLESS_SHELL_PATH"),
|
|
321
|
-
disableGpu: envBool("PRODUCER_DISABLE_GPU", DEFAULT_CONFIG.disableGpu),
|
|
322
|
-
browserGpuMode: envBrowserGpuMode(),
|
|
323
|
-
enableBrowserPool: envBool("PRODUCER_ENABLE_BROWSER_POOL", DEFAULT_CONFIG.enableBrowserPool),
|
|
324
|
-
browserTimeout: envNum("PRODUCER_PUPPETEER_LAUNCH_TIMEOUT_MS", DEFAULT_CONFIG.browserTimeout),
|
|
325
|
-
protocolTimeout: envNum(
|
|
326
|
-
"PRODUCER_PUPPETEER_PROTOCOL_TIMEOUT_MS",
|
|
327
|
-
DEFAULT_CONFIG.protocolTimeout,
|
|
328
|
-
),
|
|
329
|
-
expectedChromiumMajor: env("PRODUCER_EXPECTED_CHROMIUM_MAJOR")
|
|
330
|
-
? Number(env("PRODUCER_EXPECTED_CHROMIUM_MAJOR"))
|
|
331
|
-
: undefined,
|
|
332
|
-
|
|
333
|
-
forceScreenshot: envBool("PRODUCER_FORCE_SCREENSHOT", DEFAULT_CONFIG.forceScreenshot),
|
|
334
|
-
staticFrameDedup: resolveStaticFrameDedup(),
|
|
335
|
-
lowMemoryMode: resolveLowMemoryMode(),
|
|
336
|
-
enablePageSideCompositing: envBool(
|
|
337
|
-
"HF_PAGE_SIDE_COMPOSITING",
|
|
338
|
-
DEFAULT_CONFIG.enablePageSideCompositing,
|
|
339
|
-
),
|
|
340
|
-
|
|
341
|
-
vp9CpuUsed: envVp9CpuUsed(),
|
|
342
|
-
enableChunkedEncode: envBool(
|
|
343
|
-
"PRODUCER_ENABLE_CHUNKED_ENCODE",
|
|
344
|
-
DEFAULT_CONFIG.enableChunkedEncode,
|
|
345
|
-
),
|
|
346
|
-
chunkSizeFrames: Math.max(
|
|
347
|
-
120,
|
|
348
|
-
envNum("PRODUCER_CHUNK_SIZE_FRAMES", DEFAULT_CONFIG.chunkSizeFrames),
|
|
349
|
-
),
|
|
350
|
-
enableStreamingEncode: envBool(
|
|
351
|
-
"PRODUCER_ENABLE_STREAMING_ENCODE",
|
|
352
|
-
DEFAULT_CONFIG.enableStreamingEncode,
|
|
353
|
-
),
|
|
354
|
-
streamingEncodeMaxDurationSeconds: Math.max(
|
|
355
|
-
0,
|
|
356
|
-
envNum(
|
|
357
|
-
"PRODUCER_STREAMING_ENCODE_MAX_DURATION_SECONDS",
|
|
358
|
-
DEFAULT_CONFIG.streamingEncodeMaxDurationSeconds,
|
|
359
|
-
),
|
|
360
|
-
),
|
|
361
|
-
|
|
362
|
-
ffmpegEncodeTimeout: envNum("FFMPEG_ENCODE_TIMEOUT_MS", DEFAULT_CONFIG.ffmpegEncodeTimeout),
|
|
363
|
-
ffmpegProcessTimeout: envNum("FFMPEG_PROCESS_TIMEOUT_MS", DEFAULT_CONFIG.ffmpegProcessTimeout),
|
|
364
|
-
ffmpegStreamingTimeout: envNum(
|
|
365
|
-
"FFMPEG_STREAMING_TIMEOUT_MS",
|
|
366
|
-
DEFAULT_CONFIG.ffmpegStreamingTimeout,
|
|
367
|
-
),
|
|
368
|
-
|
|
369
|
-
hdr: (() => {
|
|
370
|
-
const raw = env("PRODUCER_HDR_TRANSFER");
|
|
371
|
-
if (raw === "hlg" || raw === "pq") return { transfer: raw };
|
|
372
|
-
return false;
|
|
373
|
-
})(),
|
|
374
|
-
hdrAutoDetect: envBool("PRODUCER_HDR_AUTO_DETECT", DEFAULT_CONFIG.hdrAutoDetect),
|
|
375
|
-
|
|
376
|
-
audioGain: envNum("PRODUCER_AUDIO_GAIN", DEFAULT_CONFIG.audioGain),
|
|
377
|
-
frameDataUriCacheLimit: Math.max(
|
|
378
|
-
32,
|
|
379
|
-
envNum("PRODUCER_FRAME_DATA_URI_CACHE_LIMIT", memoryAdaptiveCacheLimit()),
|
|
380
|
-
),
|
|
381
|
-
frameDataUriCacheBytesLimitMb: Math.max(
|
|
382
|
-
64,
|
|
383
|
-
envNum("PRODUCER_FRAME_DATA_URI_CACHE_BYTES_MB", memoryAdaptiveCacheBytesMb()),
|
|
384
|
-
),
|
|
385
|
-
|
|
386
|
-
playerReadyTimeout: envNum(
|
|
387
|
-
"PRODUCER_PLAYER_READY_TIMEOUT_MS",
|
|
388
|
-
DEFAULT_CONFIG.playerReadyTimeout,
|
|
389
|
-
),
|
|
390
|
-
renderReadyTimeout: envNum(
|
|
391
|
-
"PRODUCER_RENDER_READY_TIMEOUT_MS",
|
|
392
|
-
DEFAULT_CONFIG.renderReadyTimeout,
|
|
393
|
-
),
|
|
394
|
-
pageNavigationTimeout: envNum(
|
|
395
|
-
"PRODUCER_PAGE_NAVIGATION_TIMEOUT_MS",
|
|
396
|
-
DEFAULT_CONFIG.pageNavigationTimeout,
|
|
397
|
-
),
|
|
398
|
-
|
|
399
|
-
verifyRuntime: env("PRODUCER_VERIFY_HYPERFRAME_RUNTIME") !== "false",
|
|
400
|
-
runtimeManifestPath: env("PRODUCER_HYPERFRAME_MANIFEST_PATH"),
|
|
401
|
-
|
|
402
|
-
extractCacheDir: env("HYPERFRAMES_EXTRACT_CACHE_DIR"),
|
|
403
|
-
};
|
|
404
|
-
|
|
405
|
-
// Remove undefined values so they don't override defaults
|
|
406
|
-
const cleanEnv = Object.fromEntries(Object.entries(fromEnv).filter(([, v]) => v !== undefined));
|
|
407
|
-
|
|
408
|
-
const merged = {
|
|
409
|
-
...DEFAULT_CONFIG,
|
|
410
|
-
...cleanEnv,
|
|
411
|
-
...overrides,
|
|
412
|
-
};
|
|
413
|
-
return {
|
|
414
|
-
...merged,
|
|
415
|
-
vp9CpuUsed: normalizeVp9CpuUsed(merged.vp9CpuUsed),
|
|
416
|
-
};
|
|
417
|
-
}
|
package/src/index.ts
DELETED
|
@@ -1,273 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* @hyperframes/engine
|
|
3
|
-
*
|
|
4
|
-
* Seekable web page to video rendering engine.
|
|
5
|
-
* Framework-agnostic: works with GSAP, Lottie, Three.js, CSS animations,
|
|
6
|
-
* or any web content that implements the window.__hf seek protocol.
|
|
7
|
-
*
|
|
8
|
-
* ## Error Convention
|
|
9
|
-
*
|
|
10
|
-
* Engine services use three error strategies depending on the operation type:
|
|
11
|
-
*
|
|
12
|
-
* - **Orchestration services throw on failure.** Browser launch, session init,
|
|
13
|
-
* frame capture, and CDP operations propagate errors as thrown exceptions.
|
|
14
|
-
* Callers are expected to catch and handle (e.g. frameCapture, browserManager,
|
|
15
|
-
* screenshotService, videoFrameExtractor.extractVideoFramesRange).
|
|
16
|
-
*
|
|
17
|
-
* - **FFmpeg process wrappers return `{ success, error? }` result objects.**
|
|
18
|
-
* Encoding, muxing, audio mixing, and streaming encode operations never reject.
|
|
19
|
-
* They resolve with a result that includes `success: boolean` and an optional
|
|
20
|
-
* `error` string (e.g. chunkEncoder, audioMixer, streamingEncoder).
|
|
21
|
-
*
|
|
22
|
-
* - **Cleanup and teardown functions never throw.** Browser close, session close,
|
|
23
|
-
* temp directory removal, and resource release swallow errors via `.catch(() => {})`
|
|
24
|
-
* to avoid masking the original failure (e.g. releaseBrowser, closeCaptureSession,
|
|
25
|
-
* FrameLookupTable.cleanup).
|
|
26
|
-
*
|
|
27
|
-
* - **Optional lookups return `T | undefined` or `T | null`.**
|
|
28
|
-
* Functions that may legitimately find nothing (resolveHeadlessShellPath,
|
|
29
|
-
* getFrameAtTime, detectGpuEncoder) return a nullable value instead of throwing.
|
|
30
|
-
*
|
|
31
|
-
*/
|
|
32
|
-
|
|
33
|
-
// ── Protocol types ─────────────────────────────────────────────────────────────
|
|
34
|
-
export type {
|
|
35
|
-
HfProtocol,
|
|
36
|
-
HfMediaElement,
|
|
37
|
-
HfTransitionMeta,
|
|
38
|
-
CaptureOptions,
|
|
39
|
-
CaptureVideoMetadataHint,
|
|
40
|
-
CaptureResult,
|
|
41
|
-
CaptureBufferResult,
|
|
42
|
-
CapturePerfSummary,
|
|
43
|
-
} from "./types.js";
|
|
44
|
-
|
|
45
|
-
// ── Configuration ──────────────────────────────────────────────────────────────
|
|
46
|
-
export { resolveConfig, DEFAULT_CONFIG, type EngineConfig } from "./config.js";
|
|
47
|
-
export {
|
|
48
|
-
DEFAULT_VP9_CPU_USED,
|
|
49
|
-
MAX_VP9_CPU_USED,
|
|
50
|
-
MIN_VP9_CPU_USED,
|
|
51
|
-
normalizeVp9CpuUsed,
|
|
52
|
-
} from "./services/vp9Options.js";
|
|
53
|
-
export {
|
|
54
|
-
getSystemTotalMb,
|
|
55
|
-
isLowMemorySystem,
|
|
56
|
-
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
57
|
-
} from "./services/systemMemory.js";
|
|
58
|
-
|
|
59
|
-
// ── Browser management ─────────────────────────────────────────────────────────
|
|
60
|
-
export {
|
|
61
|
-
acquireBrowser,
|
|
62
|
-
releaseBrowser,
|
|
63
|
-
drainBrowserPool,
|
|
64
|
-
resolveHeadlessShellPath,
|
|
65
|
-
resolveBrowserGpuMode,
|
|
66
|
-
buildChromeArgs,
|
|
67
|
-
ENABLE_BROWSER_POOL,
|
|
68
|
-
type BuildChromeArgsOptions,
|
|
69
|
-
type CaptureMode,
|
|
70
|
-
type AcquiredBrowser,
|
|
71
|
-
} from "./services/browserManager.js";
|
|
72
|
-
|
|
73
|
-
// ── Frame capture pipeline ──────────────────────────────────────────────────────
|
|
74
|
-
export {
|
|
75
|
-
createCaptureSession,
|
|
76
|
-
initializeSession,
|
|
77
|
-
closeCaptureSession,
|
|
78
|
-
captureFrame,
|
|
79
|
-
captureFrameToBuffer,
|
|
80
|
-
discardWarmupCapture,
|
|
81
|
-
getCompositionDuration,
|
|
82
|
-
getCapturePerfSummary,
|
|
83
|
-
prepareCaptureSessionForReuse,
|
|
84
|
-
type CaptureSession,
|
|
85
|
-
type BeforeCaptureHook,
|
|
86
|
-
type DiscardWarmupInnerCapture,
|
|
87
|
-
} from "./services/frameCapture.js";
|
|
88
|
-
|
|
89
|
-
// ── Screenshot (BeginFrame) ─────────────────────────────────────────────────────
|
|
90
|
-
export {
|
|
91
|
-
beginFrameCapture,
|
|
92
|
-
pageScreenshotCapture,
|
|
93
|
-
getCdpSession,
|
|
94
|
-
injectVideoFramesBatch,
|
|
95
|
-
syncVideoFrameVisibility,
|
|
96
|
-
cdpSessionCache,
|
|
97
|
-
initTransparentBackground,
|
|
98
|
-
captureAlphaPng,
|
|
99
|
-
applyDomLayerMask,
|
|
100
|
-
removeDomLayerMask,
|
|
101
|
-
DOM_LAYER_MASK_STYLE_ID,
|
|
102
|
-
type BeginFrameResult,
|
|
103
|
-
} from "./services/screenshotService.js";
|
|
104
|
-
|
|
105
|
-
// ── Encoding ───────────────────────────────────────────────────────────────────
|
|
106
|
-
export {
|
|
107
|
-
buildEncoderArgs,
|
|
108
|
-
encodeFramesFromDir,
|
|
109
|
-
encodeFramesChunkedConcat,
|
|
110
|
-
muxVideoWithAudio,
|
|
111
|
-
applyFaststart,
|
|
112
|
-
detectGpuEncoder,
|
|
113
|
-
ENCODER_PRESETS,
|
|
114
|
-
getEncoderPreset,
|
|
115
|
-
type GpuEncoder,
|
|
116
|
-
} from "./services/chunkEncoder.js";
|
|
117
|
-
export type { EncoderOptions, EncodeResult, MuxResult } from "./services/chunkEncoder.types.js";
|
|
118
|
-
|
|
119
|
-
export {
|
|
120
|
-
spawnStreamingEncoder,
|
|
121
|
-
createFrameReorderBuffer,
|
|
122
|
-
type StreamingEncoder,
|
|
123
|
-
type StreamingEncoderOptions,
|
|
124
|
-
type StreamingEncoderResult,
|
|
125
|
-
type FrameReorderBuffer,
|
|
126
|
-
} from "./services/streamingEncoder.js";
|
|
127
|
-
|
|
128
|
-
// ── Media processing ───────────────────────────────────────────────────────────
|
|
129
|
-
export {
|
|
130
|
-
parseVideoElements,
|
|
131
|
-
parseImageElements,
|
|
132
|
-
extractVideoFramesRange,
|
|
133
|
-
extractAllVideoFrames,
|
|
134
|
-
resolveProjectRelativeSrc,
|
|
135
|
-
getFrameAtTime,
|
|
136
|
-
createFrameLookupTable,
|
|
137
|
-
FrameLookupTable,
|
|
138
|
-
type VideoElement,
|
|
139
|
-
type ImageElement,
|
|
140
|
-
type ExtractedFrames,
|
|
141
|
-
type ExtractionOptions,
|
|
142
|
-
type ExtractionResult,
|
|
143
|
-
type ExtractionPhaseBreakdown,
|
|
144
|
-
type VideoFrameFormat,
|
|
145
|
-
VIDEO_FRAME_FORMATS,
|
|
146
|
-
isVideoFrameFormat,
|
|
147
|
-
} from "./services/videoFrameExtractor.js";
|
|
148
|
-
|
|
149
|
-
export { createVideoFrameInjector } from "./services/videoFrameInjector.js";
|
|
150
|
-
|
|
151
|
-
export { parseAudioElements, processCompositionAudio } from "./services/audioMixer.js";
|
|
152
|
-
export type {
|
|
153
|
-
AudioElement,
|
|
154
|
-
AudioTrack,
|
|
155
|
-
AudioVolumeKeyframe,
|
|
156
|
-
MixResult,
|
|
157
|
-
} from "./services/audioMixer.types.js";
|
|
158
|
-
|
|
159
|
-
// ── Parallel rendering ─────────────────────────────────────────────────────────
|
|
160
|
-
export {
|
|
161
|
-
calculateOptimalWorkers,
|
|
162
|
-
distributeFrames,
|
|
163
|
-
executeParallelCapture,
|
|
164
|
-
mergeWorkerFrames,
|
|
165
|
-
getSystemResources,
|
|
166
|
-
type WorkerTask,
|
|
167
|
-
type WorkerResult,
|
|
168
|
-
type ParallelProgress,
|
|
169
|
-
} from "./services/parallelCoordinator.js";
|
|
170
|
-
|
|
171
|
-
// ── File server ────────────────────────────────────────────────────────────────
|
|
172
|
-
export {
|
|
173
|
-
createFileServer,
|
|
174
|
-
type FileServerOptions,
|
|
175
|
-
type FileServerHandle,
|
|
176
|
-
} from "./services/fileServer.js";
|
|
177
|
-
|
|
178
|
-
// ── Utilities ──────────────────────────────────────────────────────────────────
|
|
179
|
-
export { quantizeTimeToFrame, MEDIA_VISUAL_STYLE_PROPERTIES } from "@hyperframes/core";
|
|
180
|
-
|
|
181
|
-
export {
|
|
182
|
-
assertSwiftShader,
|
|
183
|
-
readWebGlVendorInfo,
|
|
184
|
-
SwiftShaderAssertionError,
|
|
185
|
-
BROWSER_GPU_NOT_SOFTWARE,
|
|
186
|
-
} from "./utils/assertSwiftShader.js";
|
|
187
|
-
|
|
188
|
-
export { readWebGlVendorInfoFromCanvas } from "./utils/readWebGlVendorInfoFromCanvas.js";
|
|
189
|
-
|
|
190
|
-
export {
|
|
191
|
-
extractMediaMetadata,
|
|
192
|
-
extractVideoMetadata,
|
|
193
|
-
extractAudioMetadata,
|
|
194
|
-
analyzeKeyframeIntervals,
|
|
195
|
-
type VideoMetadata,
|
|
196
|
-
type AudioMetadata,
|
|
197
|
-
type KeyframeAnalysis,
|
|
198
|
-
} from "./utils/ffprobe.js";
|
|
199
|
-
|
|
200
|
-
export { assertPublicHttpsUrl, downloadToTemp, isHttpUrl } from "./utils/urlDownloader.js";
|
|
201
|
-
export {
|
|
202
|
-
runFfmpeg,
|
|
203
|
-
formatFfmpegError,
|
|
204
|
-
type RunFfmpegOptions,
|
|
205
|
-
type RunFfmpegResult,
|
|
206
|
-
} from "./utils/runFfmpeg.js";
|
|
207
|
-
export {
|
|
208
|
-
assertConfiguredFfmpegBinariesExist,
|
|
209
|
-
getFfmpegBinary,
|
|
210
|
-
getFfprobeBinary,
|
|
211
|
-
FFMPEG_PATH_ENV,
|
|
212
|
-
FFPROBE_PATH_ENV,
|
|
213
|
-
} from "./utils/ffmpegBinaries.js";
|
|
214
|
-
|
|
215
|
-
export { trackChildProcess, killTrackedProcesses } from "./utils/processTracker.js";
|
|
216
|
-
|
|
217
|
-
export {
|
|
218
|
-
decodePng,
|
|
219
|
-
decodePngToRgb48le,
|
|
220
|
-
blitRgba8OverRgb48le,
|
|
221
|
-
blitRgb48leRegion,
|
|
222
|
-
blitRgb48leAffine,
|
|
223
|
-
parseTransformMatrix,
|
|
224
|
-
roundedRectAlpha,
|
|
225
|
-
resampleRgb48leObjectFit,
|
|
226
|
-
normalizeObjectFit,
|
|
227
|
-
type ObjectFit,
|
|
228
|
-
} from "./utils/alphaBlit.js";
|
|
229
|
-
|
|
230
|
-
export { groupIntoLayers, type CompositeLayer } from "./utils/layerCompositor.js";
|
|
231
|
-
|
|
232
|
-
// ── Shader transitions ────────────────────────────────────────────────────────
|
|
233
|
-
export {
|
|
234
|
-
type TransitionFn,
|
|
235
|
-
TRANSITIONS,
|
|
236
|
-
crossfade,
|
|
237
|
-
sampleRgb48le,
|
|
238
|
-
hdrToLinear,
|
|
239
|
-
linearToHdr,
|
|
240
|
-
convertTransfer,
|
|
241
|
-
} from "./utils/shaderTransitions.js";
|
|
242
|
-
|
|
243
|
-
export {
|
|
244
|
-
initHdrReadback,
|
|
245
|
-
uploadAndReadbackHdrFrame,
|
|
246
|
-
float16ToPqRgb,
|
|
247
|
-
buildHdrChromeArgs,
|
|
248
|
-
launchHdrBrowser,
|
|
249
|
-
} from "./services/hdrCapture.js";
|
|
250
|
-
|
|
251
|
-
export { captureScreenshotWithAlpha } from "./services/screenshotService.js";
|
|
252
|
-
|
|
253
|
-
export {
|
|
254
|
-
hideVideoElements,
|
|
255
|
-
showVideoElements,
|
|
256
|
-
queryVideoElementBounds,
|
|
257
|
-
queryElementStacking,
|
|
258
|
-
type VideoElementBounds,
|
|
259
|
-
type ElementStackingInfo,
|
|
260
|
-
} from "./services/videoFrameInjector.js";
|
|
261
|
-
|
|
262
|
-
export {
|
|
263
|
-
isHdrColorSpace,
|
|
264
|
-
detectTransfer,
|
|
265
|
-
getHdrEncoderColorParams,
|
|
266
|
-
analyzeCompositionHdr,
|
|
267
|
-
DEFAULT_HDR10_MASTERING,
|
|
268
|
-
type HdrTransfer,
|
|
269
|
-
type HdrEncoderColorParams,
|
|
270
|
-
type CompositionHdrInfo,
|
|
271
|
-
type HdrMasteringMetadata,
|
|
272
|
-
} from "./utils/hdr.js";
|
|
273
|
-
export type { VideoColorSpace } from "./utils/ffprobe.js";
|