@hyperframes/engine 0.7.56 → 0.7.58
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/config.d.ts +51 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +86 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/services/audioMixer.d.ts.map +1 -1
- package/dist/services/audioMixer.js +26 -7
- package/dist/services/audioMixer.js.map +1 -1
- package/dist/services/chunkEncoder.d.ts.map +1 -1
- package/dist/services/chunkEncoder.js +2 -2
- package/dist/services/chunkEncoder.js.map +1 -1
- package/dist/services/frameCapture.d.ts +5 -1
- package/dist/services/frameCapture.d.ts.map +1 -1
- package/dist/services/frameCapture.js +113 -4
- package/dist/services/frameCapture.js.map +1 -1
- package/dist/services/parallelCoordinator.js +3 -3
- package/dist/services/parallelCoordinator.js.map +1 -1
- package/dist/services/streamingEncoder.d.ts.map +1 -1
- package/dist/services/streamingEncoder.js +2 -2
- package/dist/services/streamingEncoder.js.map +1 -1
- package/dist/services/videoFrameExtractor.d.ts.map +1 -1
- package/dist/services/videoFrameExtractor.js +6 -5
- package/dist/services/videoFrameExtractor.js.map +1 -1
- package/dist/types.d.ts +13 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/utils/evenDimensions.d.ts +5 -3
- package/dist/utils/evenDimensions.d.ts.map +1 -1
- package/dist/utils/evenDimensions.js +8 -3
- package/dist/utils/evenDimensions.js.map +1 -1
- package/dist/utils/hdr.d.ts.map +1 -1
- package/dist/utils/hdr.js +4 -4
- package/dist/utils/hdr.js.map +1 -1
- package/dist/utils/runFfmpeg.d.ts.map +1 -1
- package/dist/utils/runFfmpeg.js +6 -0
- package/dist/utils/runFfmpeg.js.map +1 -1
- package/package.json +2 -2
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { type Browser, type Page } from "puppeteer-core";
|
|
10
10
|
import { type CaptureMode } from "./browserManager.js";
|
|
11
11
|
import { type EngineConfig } from "../config.js";
|
|
12
|
-
import type { CaptureOptions, CaptureResult, CaptureBufferResult, CapturePerfSummary, SubTimelineWaitOutcome } from "../types.js";
|
|
12
|
+
import type { CaptureOptions, CaptureResult, CaptureBufferResult, CapturePerfSummary, CaptureWarning, SubTimelineWaitOutcome } from "../types.js";
|
|
13
13
|
export type { CaptureOptions, CaptureResult, CaptureBufferResult, CapturePerfSummary };
|
|
14
14
|
/** Called after seeking, before screenshot. Use for video frame injection or other pre-capture work. */
|
|
15
15
|
export type BeforeCaptureHook = (page: Page, time: number) => Promise<void>;
|
|
@@ -53,6 +53,8 @@ export interface CaptureSession {
|
|
|
53
53
|
scriptLoadFailures: string[];
|
|
54
54
|
/** Outcome of the sub-composition timeline wait: ready | timeout | script_failure. */
|
|
55
55
|
subTimelineWaitOutcome?: SubTimelineWaitOutcome;
|
|
56
|
+
/** Structured readiness warnings surfaced to the producer's render policy. */
|
|
57
|
+
warnings: CaptureWarning[];
|
|
56
58
|
initTelemetry?: {
|
|
57
59
|
initDurationMs: number;
|
|
58
60
|
tweenCount: number;
|
|
@@ -245,6 +247,8 @@ export declare function formatConsoleDiagnostic(type: string, text: string, loca
|
|
|
245
247
|
export declare function pollSubCompositionTimelines(page: Page, timeoutMs: number, intervalMs?: number, getScriptLoadFailures?: () => readonly string[], scriptFailureGraceMs?: number): Promise<SubTimelineWaitOutcome>;
|
|
246
248
|
/** @internal exported for unit testing only */
|
|
247
249
|
export declare function pollImagesReady(page: Page, timeoutMs: number, intervalMs?: number): Promise<boolean>;
|
|
250
|
+
/** @internal exported for contract testing. */
|
|
251
|
+
export declare function collectMediaReadinessWarnings(page: Page, skipIds: readonly string[], timeoutMs: number): Promise<CaptureWarning[]>;
|
|
248
252
|
export declare function initializeSession(session: CaptureSession): Promise<void>;
|
|
249
253
|
/**
|
|
250
254
|
* Predict the dedupable (static) frame set from window.__timelines. A frame f (f>0) is
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"frameCapture.d.ts","sourceRoot":"","sources":["../../src/services/frameCapture.ts"],"names":[],"mappings":"AACA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,OAAO,EAAE,KAAK,IAAI,EAAsC,MAAM,gBAAgB,CAAC;AAM7F,OAAO,EAOL,KAAK,WAAW,EACjB,MAAM,qBAAqB,CAAC;AAqB7B,OAAO,
|
|
1
|
+
{"version":3,"file":"frameCapture.d.ts","sourceRoot":"","sources":["../../src/services/frameCapture.ts"],"names":[],"mappings":"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"}
|
|
@@ -15,7 +15,7 @@ import { acquireBrowser, releaseBrowser, forceReleaseBrowser, buildChromeArgs, r
|
|
|
15
15
|
import { beginFrameCapture, ensureRenderFrameSiblings, getCdpSession, pageScreenshotCapture, initTransparentBackground, shouldDefaultCaptureBeyondViewport, } from "./screenshotService.js";
|
|
16
16
|
import { detectSwiftShader, injectDrawElementCanvas, captureDrawElementFrame, resolveDrawElementCaptureMode, instrumentAcceleratedCanvases, initDrawElementWorkerEncode, cleanupDrawElementWorkerEncode, produceDrawElementFrame, produceDrawElementFrameBatch, } from "./drawElementService.js";
|
|
17
17
|
import { initThreeDProjection, detectCssEffectRisk } from "./threeDProjection.js";
|
|
18
|
-
import { DEFAULT_CONFIG } from "../config.js";
|
|
18
|
+
import { DEFAULT_CONFIG, applyConcreteGpuScreenshotClamp } from "../config.js";
|
|
19
19
|
/**
|
|
20
20
|
* drawElement self-verification failure — a captured DE frame diverged from its
|
|
21
21
|
* pre-injection screenshot ground truth (or a blank frame survived a retry).
|
|
@@ -508,14 +508,28 @@ export async function createCaptureSession(serverUrl, outputDir, options, onBefo
|
|
|
508
508
|
// need explicit clip+scale on `Page.captureScreenshot`, so fall back to
|
|
509
509
|
// the screenshot path for any DPR > 1.
|
|
510
510
|
const supersampling = (options.deviceScaleFactor ?? 1) > 1;
|
|
511
|
-
const preMode = headlessShell && isLinux && !forceScreenshot && !supersampling && !drawElementTransparent
|
|
512
|
-
? "beginframe"
|
|
513
|
-
: "screenshot";
|
|
514
511
|
const requestedGpuMode = config?.browserGpuMode ?? DEFAULT_CONFIG.browserGpuMode;
|
|
515
512
|
const resolvedGpuMode = await resolveBrowserGpuMode(requestedGpuMode, {
|
|
516
513
|
chromePath: headlessShell ?? undefined,
|
|
517
514
|
browserTimeout: config?.browserTimeout,
|
|
518
515
|
});
|
|
516
|
+
// Apply the software-GPU→screenshot invariant at the concrete-resolved
|
|
517
|
+
// point too — `resolveConfig` can only see the pre-resolve `browserGpuMode`
|
|
518
|
+
// string, so `"auto"` that probes to software would otherwise slip through
|
|
519
|
+
// and launch BeginFrame + SwiftShader (the exact combination the invariant
|
|
520
|
+
// is meant to prevent). Both env and programmatic opt-outs preserved via
|
|
521
|
+
// `applyConcreteGpuScreenshotClamp` (the programmatic one carried on the
|
|
522
|
+
// config as `forceScreenshotExplicitlyOptedOut`, since at this point the
|
|
523
|
+
// boolean `forceScreenshot === false` is otherwise ambiguous between
|
|
524
|
+
// default and explicit opt-out).
|
|
525
|
+
const effectiveForceScreenshot = applyConcreteGpuScreenshotClamp(forceScreenshot, resolvedGpuMode, config);
|
|
526
|
+
const preMode = headlessShell &&
|
|
527
|
+
isLinux &&
|
|
528
|
+
!effectiveForceScreenshot &&
|
|
529
|
+
!supersampling &&
|
|
530
|
+
!drawElementTransparent
|
|
531
|
+
? "beginframe"
|
|
532
|
+
: "screenshot";
|
|
519
533
|
const chromeArgs = buildChromeArgs({ width: options.width, height: options.height, captureMode: preMode }, { ...config, browserGpuMode: resolvedGpuMode });
|
|
520
534
|
const { browser, captureMode } = await acquireBrowser(chromeArgs, config);
|
|
521
535
|
const page = await browser.newPage();
|
|
@@ -627,6 +641,7 @@ export async function createCaptureSession(serverUrl, outputDir, options, onBefo
|
|
|
627
641
|
isInitialized: false,
|
|
628
642
|
browserConsoleBuffer: [],
|
|
629
643
|
scriptLoadFailures: [],
|
|
644
|
+
warnings: [],
|
|
630
645
|
capturePerf: {
|
|
631
646
|
frames: 0,
|
|
632
647
|
seekMs: 0,
|
|
@@ -944,6 +959,87 @@ export async function pollImagesReady(page, timeoutMs, intervalMs = 100) {
|
|
|
944
959
|
}
|
|
945
960
|
return check();
|
|
946
961
|
}
|
|
962
|
+
/** @internal exported for contract testing. */
|
|
963
|
+
export async function collectMediaReadinessWarnings(page, skipIds, timeoutMs) {
|
|
964
|
+
const snapshot = await page.evaluate((skipIdList) => {
|
|
965
|
+
const skipped = new Set(skipIdList);
|
|
966
|
+
const result = {
|
|
967
|
+
pendingImages: [],
|
|
968
|
+
failedImages: [],
|
|
969
|
+
pendingVideos: [],
|
|
970
|
+
failedVideos: [],
|
|
971
|
+
};
|
|
972
|
+
for (const img of document.querySelectorAll("img")) {
|
|
973
|
+
const src = img.getAttribute("src") || "";
|
|
974
|
+
if (!src || src.startsWith("data:"))
|
|
975
|
+
continue;
|
|
976
|
+
if (!img.complete)
|
|
977
|
+
result.pendingImages.push(img.src || src);
|
|
978
|
+
else if (img.naturalWidth <= 0)
|
|
979
|
+
result.failedImages.push(img.src || src);
|
|
980
|
+
}
|
|
981
|
+
// Browser media readiness is a frame-capture requirement only for video.
|
|
982
|
+
// Audio is extracted and mixed out of band by the producer, so an idle
|
|
983
|
+
// DOM <audio> element can legitimately remain at HAVE_NOTHING here. The
|
|
984
|
+
// producer reports actual extraction/mix failures as audio_processing_failed.
|
|
985
|
+
for (const media of document.querySelectorAll("video")) {
|
|
986
|
+
const mediaElement = media;
|
|
987
|
+
if (skipped.has(mediaElement.id))
|
|
988
|
+
continue;
|
|
989
|
+
const src = mediaElement.currentSrc || mediaElement.getAttribute("src") || "(no src)";
|
|
990
|
+
const failed = Boolean(mediaElement.error) ||
|
|
991
|
+
mediaElement.networkState === HTMLMediaElement.NETWORK_NO_SOURCE;
|
|
992
|
+
const pending = !failed && mediaElement.readyState < HTMLMediaElement.HAVE_CURRENT_DATA;
|
|
993
|
+
if (failed)
|
|
994
|
+
result.failedVideos.push(src);
|
|
995
|
+
else if (pending)
|
|
996
|
+
result.pendingVideos.push(src);
|
|
997
|
+
}
|
|
998
|
+
return result;
|
|
999
|
+
}, skipIds);
|
|
1000
|
+
const warnings = [];
|
|
1001
|
+
const append = (code, mediaType, sources) => {
|
|
1002
|
+
if (sources.length === 0)
|
|
1003
|
+
return;
|
|
1004
|
+
const timedOut = code === "media_readiness_timeout";
|
|
1005
|
+
warnings.push({
|
|
1006
|
+
code,
|
|
1007
|
+
message: timedOut
|
|
1008
|
+
? `${mediaType} media did not become capture-ready within ${timeoutMs}ms`
|
|
1009
|
+
: `${mediaType} media failed to load before capture`,
|
|
1010
|
+
details: { mediaType, sources: [...new Set(sources)].sort(), timeoutMs },
|
|
1011
|
+
});
|
|
1012
|
+
};
|
|
1013
|
+
append("media_readiness_timeout", "image", snapshot.pendingImages);
|
|
1014
|
+
append("media_load_failed", "image", snapshot.failedImages);
|
|
1015
|
+
append("media_readiness_timeout", "video", snapshot.pendingVideos);
|
|
1016
|
+
append("media_load_failed", "video", snapshot.failedVideos);
|
|
1017
|
+
return warnings;
|
|
1018
|
+
}
|
|
1019
|
+
function recordCaptureWarnings(session, warnings) {
|
|
1020
|
+
for (const warning of warnings) {
|
|
1021
|
+
const key = `${warning.code}:${JSON.stringify(warning.details ?? {})}`;
|
|
1022
|
+
if (session.warnings.some((existing) => `${existing.code}:${JSON.stringify(existing.details ?? {})}` === key)) {
|
|
1023
|
+
continue;
|
|
1024
|
+
}
|
|
1025
|
+
session.warnings.push(warning);
|
|
1026
|
+
console.warn(`[FrameCapture:${warning.code}] ${warning.message}`, warning.details ?? {});
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
function recordSubTimelineWarning(session, timeoutMs) {
|
|
1030
|
+
if (session.subTimelineWaitOutcome === "ready" || !session.subTimelineWaitOutcome)
|
|
1031
|
+
return;
|
|
1032
|
+
const scriptFailure = session.subTimelineWaitOutcome === "script_failure";
|
|
1033
|
+
recordCaptureWarnings(session, [
|
|
1034
|
+
{
|
|
1035
|
+
code: scriptFailure ? "sub_timeline_script_failure" : "sub_timeline_readiness_timeout",
|
|
1036
|
+
message: scriptFailure
|
|
1037
|
+
? "A sub-composition timeline script failed to load"
|
|
1038
|
+
: `Sub-composition timelines did not become ready within ${timeoutMs}ms`,
|
|
1039
|
+
details: { timeoutMs },
|
|
1040
|
+
},
|
|
1041
|
+
]);
|
|
1042
|
+
}
|
|
947
1043
|
// Force every successfully-loaded `<img>` to be GPU-uploaded before the first
|
|
948
1044
|
// frame capture. `naturalWidth > 0` means the bitmap has been decoded into
|
|
949
1045
|
// CPU memory, but compositor-side GPU upload can still happen lazily on first
|
|
@@ -1122,6 +1218,7 @@ export async function initializeSession(session) {
|
|
|
1122
1218
|
logInitPhase("pollHfReady complete");
|
|
1123
1219
|
session.subTimelineWaitOutcome = await pollSubCompositionTimelines(page, pageReadyTimeout, undefined, () => session.scriptLoadFailures);
|
|
1124
1220
|
logInitPhase(`pollSubCompositionTimelines complete (${session.subTimelineWaitOutcome})`);
|
|
1221
|
+
recordSubTimelineWarning(session, pageReadyTimeout);
|
|
1125
1222
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
1126
1223
|
logInitPhase("applyVideoMetadataHints complete");
|
|
1127
1224
|
// Run independent readiness checks in parallel — videos, images, fonts,
|
|
@@ -1165,6 +1262,7 @@ export async function initializeSession(session) {
|
|
|
1165
1262
|
console.warn(`[FrameCapture] Some video elements did not decode within ${pageReadyTimeout}ms: ${failedVideos}. ` +
|
|
1166
1263
|
`Continuing render — affected videos will appear as blank/black frames.`);
|
|
1167
1264
|
}
|
|
1265
|
+
recordCaptureWarnings(session, await collectMediaReadinessWarnings(page, skipVideoIds, pageReadyTimeout));
|
|
1168
1266
|
await recordSessionInitTelemetry(session, initStart);
|
|
1169
1267
|
// drawElement or transparent-background init — runs after page is fully ready.
|
|
1170
1268
|
await initDrawElementOrTransparentBackground(session, page, logInitPhase);
|
|
@@ -1240,6 +1338,7 @@ export async function initializeSession(session) {
|
|
|
1240
1338
|
}
|
|
1241
1339
|
session.subTimelineWaitOutcome = await pollSubCompositionTimelines(page, pageReadyTimeout, undefined, () => session.scriptLoadFailures);
|
|
1242
1340
|
logInitPhase(`pollSubCompositionTimelines complete (${session.subTimelineWaitOutcome})`);
|
|
1341
|
+
recordSubTimelineWarning(session, pageReadyTimeout);
|
|
1243
1342
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
1244
1343
|
logInitPhase("applyVideoMetadataHints complete");
|
|
1245
1344
|
// Run independent readiness checks in parallel — videos, images, fonts,
|
|
@@ -1283,6 +1382,7 @@ export async function initializeSession(session) {
|
|
|
1283
1382
|
console.warn(`[FrameCapture] Some video elements did not decode within ${pageReadyTimeout}ms: ${failedVideos}. ` +
|
|
1284
1383
|
`Continuing render — affected videos will appear as blank/black frames.`);
|
|
1285
1384
|
}
|
|
1385
|
+
recordCaptureWarnings(session, await collectMediaReadinessWarnings(page, bfSkipVideoIds, pageReadyTimeout));
|
|
1286
1386
|
await recordSessionInitTelemetry(session, initStart);
|
|
1287
1387
|
// Stop warmup, then drain the loop in BOTH modes before any further
|
|
1288
1388
|
// BeginFrame on this session (drawElement init, the render-frame commit tick
|
|
@@ -2516,6 +2616,15 @@ export function getCapturePerfSummary(session) {
|
|
|
2516
2616
|
avgScreenshotMs: Math.round(session.capturePerf.screenshotMs / frames),
|
|
2517
2617
|
p50TotalMs: medianOf(session.capturePerf.frameMs),
|
|
2518
2618
|
subTimelineWaitOutcome: session.subTimelineWaitOutcome,
|
|
2619
|
+
warnings: session.warnings.map((warning) => ({
|
|
2620
|
+
...warning,
|
|
2621
|
+
details: warning.details
|
|
2622
|
+
? {
|
|
2623
|
+
...warning.details,
|
|
2624
|
+
sources: warning.details.sources ? [...warning.details.sources] : undefined,
|
|
2625
|
+
}
|
|
2626
|
+
: undefined,
|
|
2627
|
+
})),
|
|
2519
2628
|
staticDedupReused: session.staticDedupCount ?? 0,
|
|
2520
2629
|
staticDedupEnabled: session.staticDedupEnabled ?? false,
|
|
2521
2630
|
// armed ⟺ a non-empty static set survived verification; predicted === its size.
|