hyperframes 0.7.43 → 0.7.44
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/cli.js +302 -87
- package/dist/studio/assets/{index-Drb3FuD6.js → index-8c83yScV.js} +1 -1
- package/dist/studio/assets/{index-Dqugm4lQ.js → index-BiZvHXPu.js} +1 -1
- package/dist/studio/assets/{index-C-0DP25T.js → index-BtAysyap.js} +3 -3
- package/dist/studio/index.html +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -50,7 +50,7 @@ var VERSION;
|
|
|
50
50
|
var init_version = __esm({
|
|
51
51
|
"src/version.ts"() {
|
|
52
52
|
"use strict";
|
|
53
|
-
VERSION = true ? "0.7.
|
|
53
|
+
VERSION = true ? "0.7.44" : "0.0.0-dev";
|
|
54
54
|
}
|
|
55
55
|
});
|
|
56
56
|
|
|
@@ -62953,6 +62953,7 @@ async function createCaptureSession(serverUrl, outputDir, options, onBeforeCaptu
|
|
|
62953
62953
|
onBeforeCapture,
|
|
62954
62954
|
isInitialized: false,
|
|
62955
62955
|
browserConsoleBuffer: [],
|
|
62956
|
+
scriptLoadFailures: [],
|
|
62956
62957
|
capturePerf: {
|
|
62957
62958
|
frames: 0,
|
|
62958
62959
|
seekMs: 0,
|
|
@@ -62993,15 +62994,6 @@ function formatConsoleDiagnostic(type, text2, locationUrl) {
|
|
|
62993
62994
|
const prefix = isResourceLoadError ? "[non-blocking]" : type === "error" ? "[Browser:ERROR]" : type === "warn" ? "[Browser:WARN]" : "[Browser]";
|
|
62994
62995
|
return { text: `${prefix} ${text2}`, suppressHostLog: false };
|
|
62995
62996
|
}
|
|
62996
|
-
async function pollPageExpression(page, expression, timeoutMs, intervalMs = 100) {
|
|
62997
|
-
const deadline = Date.now() + timeoutMs;
|
|
62998
|
-
while (Date.now() < deadline) {
|
|
62999
|
-
const ready = Boolean(await page.evaluate(expression));
|
|
63000
|
-
if (ready) return true;
|
|
63001
|
-
await new Promise((resolve62) => setTimeout(resolve62, intervalMs));
|
|
63002
|
-
}
|
|
63003
|
-
return Boolean(await page.evaluate(expression));
|
|
63004
|
-
}
|
|
63005
62997
|
function buildZeroDurationDiagnostic(diag) {
|
|
63006
62998
|
const hints = [];
|
|
63007
62999
|
if (!diag.hasPlayer) {
|
|
@@ -63058,7 +63050,7 @@ async function pollHfReady(page, timeoutMs, intervalMs = 100) {
|
|
|
63058
63050
|
State: __hf=${diag.hasHf}, seek=${diag.hasSeek}, player=${diag.hasPlayer}, renderReady=${diag.renderReady}, duration=${diag.duration}`
|
|
63059
63051
|
);
|
|
63060
63052
|
}
|
|
63061
|
-
async function pollSubCompositionTimelines(page, timeoutMs, intervalMs = 150) {
|
|
63053
|
+
async function pollSubCompositionTimelines(page, timeoutMs, intervalMs = 150, getScriptLoadFailures, scriptFailureGraceMs = 2e3) {
|
|
63062
63054
|
const expression = `(function() {
|
|
63063
63055
|
var hosts = document.querySelectorAll("[data-composition-id]");
|
|
63064
63056
|
if (hosts.length === 0) return true;
|
|
@@ -63071,30 +63063,52 @@ async function pollSubCompositionTimelines(page, timeoutMs, intervalMs = 150) {
|
|
|
63071
63063
|
}
|
|
63072
63064
|
return true;
|
|
63073
63065
|
})()`;
|
|
63074
|
-
const
|
|
63066
|
+
const start = Date.now();
|
|
63067
|
+
const deadline = start + timeoutMs;
|
|
63068
|
+
let ready = false;
|
|
63069
|
+
let scriptFailureBail = false;
|
|
63070
|
+
for (; ; ) {
|
|
63071
|
+
ready = Boolean(await page.evaluate(expression));
|
|
63072
|
+
if (ready) break;
|
|
63073
|
+
const now = Date.now();
|
|
63074
|
+
if (now >= deadline) break;
|
|
63075
|
+
const failures = getScriptLoadFailures?.() ?? [];
|
|
63076
|
+
if (failures.length > 0 && now - start >= scriptFailureGraceMs) {
|
|
63077
|
+
scriptFailureBail = true;
|
|
63078
|
+
console.warn(
|
|
63079
|
+
`[FrameCapture] Sub-composition timeline wait cut short after ${now - start}ms: script resource(s) failed to load (${failures.join(", ")}) \u2014 the timeline registration they carry can never arrive. Fix the script reference; the render proceeds without those animations.`
|
|
63080
|
+
);
|
|
63081
|
+
break;
|
|
63082
|
+
}
|
|
63083
|
+
await new Promise((resolve62) => setTimeout(resolve62, intervalMs));
|
|
63084
|
+
}
|
|
63075
63085
|
if (ready) {
|
|
63076
63086
|
await page.evaluate(`(function() {
|
|
63077
63087
|
if (typeof window.__hfForceTimelineRebind === "function") {
|
|
63078
63088
|
window.__hfForceTimelineRebind();
|
|
63079
63089
|
}
|
|
63080
63090
|
})()`);
|
|
63091
|
+
return "ready";
|
|
63081
63092
|
}
|
|
63082
|
-
|
|
63083
|
-
|
|
63084
|
-
|
|
63085
|
-
|
|
63086
|
-
|
|
63087
|
-
|
|
63088
|
-
|
|
63089
|
-
|
|
63090
|
-
|
|
63091
|
-
|
|
63092
|
-
|
|
63093
|
-
|
|
63093
|
+
const missing = await page.evaluate(`(function() {
|
|
63094
|
+
var hosts = document.querySelectorAll("[data-composition-id]");
|
|
63095
|
+
var timelines = window.__timelines || {};
|
|
63096
|
+
var m = [];
|
|
63097
|
+
for (var i = 0; i < hosts.length; i++) {
|
|
63098
|
+
if (hosts[i].hasAttribute("data-no-timeline")) continue;
|
|
63099
|
+
var id = hosts[i].getAttribute("data-composition-id");
|
|
63100
|
+
if (id && !timelines[id]) m.push(id);
|
|
63101
|
+
}
|
|
63102
|
+
return m.join(", ");
|
|
63103
|
+
})()`);
|
|
63104
|
+
if (scriptFailureBail) {
|
|
63105
|
+
console.warn(`[FrameCapture] Composition(s) still waiting on the failed script: ${missing}.`);
|
|
63106
|
+
} else {
|
|
63094
63107
|
console.warn(
|
|
63095
63108
|
`[FrameCapture] Sub-composition timelines not registered after ${timeoutMs}ms: ${missing}. Compositions that load data asynchronously (e.g. fetch) must register window.__timelines[id] after setup completes. Compositions intentionally driven without GSAP timelines (CSS animations / rAF) can mark the host with data-no-timeline to skip this wait.`
|
|
63096
63109
|
);
|
|
63097
63110
|
}
|
|
63111
|
+
return scriptFailureBail ? "script_failure" : "timeout";
|
|
63098
63112
|
}
|
|
63099
63113
|
async function pollVideosReady(page, skipIds, timeoutMs, intervalMs = 100) {
|
|
63100
63114
|
const check = async () => {
|
|
@@ -63193,6 +63207,11 @@ async function waitForOptionalTailwindReady(page, timeoutMs) {
|
|
|
63193
63207
|
);
|
|
63194
63208
|
}
|
|
63195
63209
|
}
|
|
63210
|
+
function recordScriptLoadFailure(session, url) {
|
|
63211
|
+
if (!session.scriptLoadFailures.includes(url)) {
|
|
63212
|
+
session.scriptLoadFailures.push(url);
|
|
63213
|
+
}
|
|
63214
|
+
}
|
|
63196
63215
|
async function initializeSession(session) {
|
|
63197
63216
|
const { page, serverUrl } = session;
|
|
63198
63217
|
page.on("console", (msg) => {
|
|
@@ -63213,6 +63232,9 @@ async function initializeSession(session) {
|
|
|
63213
63232
|
appendBrowserDiagnostic(session, text2);
|
|
63214
63233
|
});
|
|
63215
63234
|
page.on("requestfailed", (request) => {
|
|
63235
|
+
if (request.resourceType() === "script") {
|
|
63236
|
+
recordScriptLoadFailure(session, request.url());
|
|
63237
|
+
}
|
|
63216
63238
|
appendBrowserDiagnostic(
|
|
63217
63239
|
session,
|
|
63218
63240
|
formatRequestFailureDiagnostic({
|
|
@@ -63227,6 +63249,9 @@ async function initializeSession(session) {
|
|
|
63227
63249
|
const status = response.status();
|
|
63228
63250
|
if (status < 400) return;
|
|
63229
63251
|
const request = response.request();
|
|
63252
|
+
if (request.resourceType() === "script") {
|
|
63253
|
+
recordScriptLoadFailure(session, response.url());
|
|
63254
|
+
}
|
|
63230
63255
|
appendBrowserDiagnostic(
|
|
63231
63256
|
session,
|
|
63232
63257
|
formatHttpErrorDiagnostic({
|
|
@@ -63278,8 +63303,13 @@ async function initializeSession(session) {
|
|
|
63278
63303
|
const pageReadyTimeout2 = session.config?.playerReadyTimeout ?? DEFAULT_CONFIG2.playerReadyTimeout;
|
|
63279
63304
|
await pollHfReady(page, pageReadyTimeout2);
|
|
63280
63305
|
logInitPhase("pollHfReady complete");
|
|
63281
|
-
await pollSubCompositionTimelines(
|
|
63282
|
-
|
|
63306
|
+
session.subTimelineWaitOutcome = await pollSubCompositionTimelines(
|
|
63307
|
+
page,
|
|
63308
|
+
pageReadyTimeout2,
|
|
63309
|
+
void 0,
|
|
63310
|
+
() => session.scriptLoadFailures
|
|
63311
|
+
);
|
|
63312
|
+
logInitPhase(`pollSubCompositionTimelines complete (${session.subTimelineWaitOutcome})`);
|
|
63283
63313
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
63284
63314
|
logInitPhase("applyVideoMetadataHints complete");
|
|
63285
63315
|
const skipVideoIds = session.options.skipReadinessVideoIds ?? [];
|
|
@@ -63371,8 +63401,13 @@ async function initializeSession(session) {
|
|
|
63371
63401
|
warmupState.running = false;
|
|
63372
63402
|
throw err;
|
|
63373
63403
|
}
|
|
63374
|
-
await pollSubCompositionTimelines(
|
|
63375
|
-
|
|
63404
|
+
session.subTimelineWaitOutcome = await pollSubCompositionTimelines(
|
|
63405
|
+
page,
|
|
63406
|
+
pageReadyTimeout,
|
|
63407
|
+
void 0,
|
|
63408
|
+
() => session.scriptLoadFailures
|
|
63409
|
+
);
|
|
63410
|
+
logInitPhase(`pollSubCompositionTimelines complete (${session.subTimelineWaitOutcome})`);
|
|
63376
63411
|
await applyVideoMetadataHints(page, session.options.videoMetadataHints);
|
|
63377
63412
|
logInitPhase("applyVideoMetadataHints complete");
|
|
63378
63413
|
const bfSkipVideoIds = session.options.skipReadinessVideoIds ?? [];
|
|
@@ -63899,9 +63934,20 @@ async function captureFrameToBufferPipelined(session, frameIndex, time) {
|
|
|
63899
63934
|
const { page, options } = session;
|
|
63900
63935
|
const startTime = Date.now();
|
|
63901
63936
|
if (session.staticFrames?.has(frameIndex) && session.lastEncodeResult) {
|
|
63902
|
-
|
|
63903
|
-
|
|
63904
|
-
|
|
63937
|
+
const lastIdx = session.lastEncodeResultFrame ?? frameIndex - 1;
|
|
63938
|
+
let gapStatic = true;
|
|
63939
|
+
for (let j3 = lastIdx + 1; j3 <= frameIndex; j3++) {
|
|
63940
|
+
if (!session.staticFrames.has(j3)) {
|
|
63941
|
+
gapStatic = false;
|
|
63942
|
+
break;
|
|
63943
|
+
}
|
|
63944
|
+
}
|
|
63945
|
+
if (gapStatic) {
|
|
63946
|
+
session.staticDedupCount = (session.staticDedupCount ?? 0) + 1;
|
|
63947
|
+
session.capturePerf.frames += 1;
|
|
63948
|
+
session.lastEncodeResultFrame = frameIndex;
|
|
63949
|
+
return { encodeResult: session.lastEncodeResult, captureTimeMs: Date.now() - startTime };
|
|
63950
|
+
}
|
|
63905
63951
|
}
|
|
63906
63952
|
try {
|
|
63907
63953
|
const { quantizedTime, seekMs, beforeCaptureMs } = await prepareFrameForCapture(
|
|
@@ -63921,7 +63967,10 @@ async function captureFrameToBufferPipelined(session, frameIndex, time) {
|
|
|
63921
63967
|
session.capturePerf.frameMs.push(boundaryMs);
|
|
63922
63968
|
}
|
|
63923
63969
|
const boundaryResult = Promise.resolve(buffer);
|
|
63924
|
-
if (session.staticFrames)
|
|
63970
|
+
if (session.staticFrames) {
|
|
63971
|
+
session.lastEncodeResult = boundaryResult;
|
|
63972
|
+
session.lastEncodeResultFrame = frameIndex;
|
|
63973
|
+
}
|
|
63925
63974
|
return { encodeResult: boundaryResult, captureTimeMs: Date.now() - startTime };
|
|
63926
63975
|
}
|
|
63927
63976
|
const { encodeResult } = await produceDrawElementFrame(
|
|
@@ -63938,7 +63987,10 @@ async function captureFrameToBufferPipelined(session, frameIndex, time) {
|
|
|
63938
63987
|
session.capturePerf.screenshotMs += captureTimeMs - seekMs - beforeCaptureMs;
|
|
63939
63988
|
session.capturePerf.totalMs += captureTimeMs;
|
|
63940
63989
|
session.capturePerf.frameMs.push(captureTimeMs);
|
|
63941
|
-
if (session.staticFrames)
|
|
63990
|
+
if (session.staticFrames) {
|
|
63991
|
+
session.lastEncodeResult = encodeResult;
|
|
63992
|
+
session.lastEncodeResultFrame = frameIndex;
|
|
63993
|
+
}
|
|
63942
63994
|
return { encodeResult, captureTimeMs };
|
|
63943
63995
|
} catch (captureError) {
|
|
63944
63996
|
if (isNoCachedPaintRecordError(captureError)) {
|
|
@@ -64164,6 +64216,7 @@ function getCapturePerfSummary(session) {
|
|
|
64164
64216
|
avgBeforeCaptureMs: Math.round(session.capturePerf.beforeCaptureMs / frames),
|
|
64165
64217
|
avgScreenshotMs: Math.round(session.capturePerf.screenshotMs / frames),
|
|
64166
64218
|
p50TotalMs: medianOf(session.capturePerf.frameMs),
|
|
64219
|
+
subTimelineWaitOutcome: session.subTimelineWaitOutcome,
|
|
64167
64220
|
staticDedupReused: session.staticDedupCount ?? 0,
|
|
64168
64221
|
staticDedupEnabled: session.staticDedupEnabled ?? false,
|
|
64169
64222
|
// armed ⟺ a non-empty static set survived verification; predicted === its size.
|
|
@@ -65634,40 +65687,57 @@ import { existsSync as existsSync7, mkdirSync as mkdirSync4, statSync as statSyn
|
|
|
65634
65687
|
import { dirname as dirname5 } from "path";
|
|
65635
65688
|
function createFrameReorderBuffer(startFrame, endFrame) {
|
|
65636
65689
|
let cursor = startFrame;
|
|
65690
|
+
let aborted = null;
|
|
65637
65691
|
const pending = /* @__PURE__ */ new Map();
|
|
65638
|
-
const enqueueAt = (frame, resolve62) => {
|
|
65692
|
+
const enqueueAt = (frame, resolve62, reject) => {
|
|
65639
65693
|
const list = pending.get(frame);
|
|
65640
65694
|
if (list === void 0) {
|
|
65641
|
-
pending.set(frame, [resolve62]);
|
|
65695
|
+
pending.set(frame, [{ resolve: resolve62, reject }]);
|
|
65642
65696
|
} else {
|
|
65643
|
-
list.push(resolve62);
|
|
65697
|
+
list.push({ resolve: resolve62, reject });
|
|
65644
65698
|
}
|
|
65645
65699
|
};
|
|
65646
65700
|
const flushAt = (frame) => {
|
|
65647
65701
|
const list = pending.get(frame);
|
|
65648
65702
|
if (list === void 0) return;
|
|
65649
65703
|
pending.delete(frame);
|
|
65650
|
-
for (const
|
|
65704
|
+
for (const waiter of list) waiter.resolve();
|
|
65651
65705
|
};
|
|
65652
|
-
const waitForFrame = (frame) => new Promise((resolve62) => {
|
|
65706
|
+
const waitForFrame = (frame) => new Promise((resolve62, reject) => {
|
|
65707
|
+
if (aborted) {
|
|
65708
|
+
reject(aborted);
|
|
65709
|
+
return;
|
|
65710
|
+
}
|
|
65653
65711
|
if (frame === cursor) {
|
|
65654
65712
|
resolve62();
|
|
65655
65713
|
return;
|
|
65656
65714
|
}
|
|
65657
|
-
enqueueAt(frame, resolve62);
|
|
65715
|
+
enqueueAt(frame, resolve62, reject);
|
|
65658
65716
|
});
|
|
65659
65717
|
const advanceTo = (frame) => {
|
|
65660
65718
|
cursor = frame;
|
|
65661
65719
|
flushAt(frame);
|
|
65662
65720
|
};
|
|
65663
|
-
const waitForAllDone = () => new Promise((resolve62) => {
|
|
65721
|
+
const waitForAllDone = () => new Promise((resolve62, reject) => {
|
|
65722
|
+
if (aborted) {
|
|
65723
|
+
reject(aborted);
|
|
65724
|
+
return;
|
|
65725
|
+
}
|
|
65664
65726
|
if (cursor >= endFrame) {
|
|
65665
65727
|
resolve62();
|
|
65666
65728
|
return;
|
|
65667
65729
|
}
|
|
65668
|
-
enqueueAt(endFrame, resolve62);
|
|
65730
|
+
enqueueAt(endFrame, resolve62, reject);
|
|
65669
65731
|
});
|
|
65670
|
-
|
|
65732
|
+
const abort = (err) => {
|
|
65733
|
+
if (aborted) return;
|
|
65734
|
+
aborted = err;
|
|
65735
|
+
for (const [frame, list] of pending) {
|
|
65736
|
+
pending.delete(frame);
|
|
65737
|
+
for (const waiter of list) waiter.reject(err);
|
|
65738
|
+
}
|
|
65739
|
+
};
|
|
65740
|
+
return { waitForFrame, advanceTo, waitForAllDone, abort };
|
|
65671
65741
|
}
|
|
65672
65742
|
function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
65673
65743
|
const {
|
|
@@ -76185,19 +76255,79 @@ function distributeFrames(totalFrames, workerCount, workDir, rangeStart = 0) {
|
|
|
76185
76255
|
}
|
|
76186
76256
|
return tasks;
|
|
76187
76257
|
}
|
|
76258
|
+
function distributeFramesInterleaved(totalFrames, workerCount, workDir, rangeStart = 0) {
|
|
76259
|
+
const tasks = [];
|
|
76260
|
+
for (let i2 = 0; i2 < workerCount && i2 < totalFrames; i2++) {
|
|
76261
|
+
tasks.push({
|
|
76262
|
+
workerId: i2,
|
|
76263
|
+
startFrame: rangeStart + i2,
|
|
76264
|
+
endFrame: rangeStart + totalFrames,
|
|
76265
|
+
frameStride: workerCount,
|
|
76266
|
+
outputDir: join15(workDir, `worker-${i2}`),
|
|
76267
|
+
outputFrameOffset: rangeStart
|
|
76268
|
+
});
|
|
76269
|
+
}
|
|
76270
|
+
return tasks;
|
|
76271
|
+
}
|
|
76188
76272
|
function shouldVerifyWorkerGpu(workerId, config) {
|
|
76189
76273
|
return config?.browserGpuMode === "software" && workerId === 0;
|
|
76190
76274
|
}
|
|
76191
76275
|
async function captureFrameRange(session, task, captureOptions, signal, onFrameCaptured, onFrameBuffer) {
|
|
76192
76276
|
let framesCaptured = 0;
|
|
76193
76277
|
const outputOffset = task.outputFrameOffset ?? 0;
|
|
76194
|
-
|
|
76278
|
+
const stride = task.frameStride ?? 1;
|
|
76279
|
+
if (onFrameBuffer && session.workerEncodeEnabled) {
|
|
76280
|
+
const dbg = process.env.HF_DE_PAR_DEBUG === "1";
|
|
76281
|
+
const dbgT0 = Date.now();
|
|
76282
|
+
const dbgWin = 40 * stride;
|
|
76283
|
+
let prev = null;
|
|
76284
|
+
for (let i2 = task.startFrame; i2 < task.endFrame; i2 += stride) {
|
|
76285
|
+
if (signal?.aborted) throw new Error("Parallel worker cancelled");
|
|
76286
|
+
const time = i2 * captureOptions.fps.den / captureOptions.fps.num;
|
|
76287
|
+
if (dbg && i2 < task.startFrame + dbgWin) {
|
|
76288
|
+
console.log(`[par:w${task.workerId}] +${Date.now() - dbgT0}ms produce ${i2} start`);
|
|
76289
|
+
}
|
|
76290
|
+
const { encodeResult } = await captureFrameToBufferPipelined(session, i2 - outputOffset, time);
|
|
76291
|
+
encodeResult.catch(() => {
|
|
76292
|
+
});
|
|
76293
|
+
if (dbg && i2 < task.startFrame + dbgWin) {
|
|
76294
|
+
console.log(`[par:w${task.workerId}] +${Date.now() - dbgT0}ms produce ${i2} kicked`);
|
|
76295
|
+
}
|
|
76296
|
+
if (prev) {
|
|
76297
|
+
if (dbg && prev.idx < task.startFrame + dbgWin) {
|
|
76298
|
+
console.log(
|
|
76299
|
+
`[par:w${task.workerId}] +${Date.now() - dbgT0}ms drain ${prev.idx} await-encode`
|
|
76300
|
+
);
|
|
76301
|
+
}
|
|
76302
|
+
const buf = await prev.encodeResult;
|
|
76303
|
+
if (dbg && prev.idx < task.startFrame + dbgWin) {
|
|
76304
|
+
console.log(
|
|
76305
|
+
`[par:w${task.workerId}] +${Date.now() - dbgT0}ms drain ${prev.idx} encoded ${buf.length}B`
|
|
76306
|
+
);
|
|
76307
|
+
}
|
|
76308
|
+
await onFrameBuffer(prev.idx, buf, session);
|
|
76309
|
+
if (dbg && prev.idx < task.startFrame + dbgWin) {
|
|
76310
|
+
console.log(`[par:w${task.workerId}] +${Date.now() - dbgT0}ms drain ${prev.idx} written`);
|
|
76311
|
+
}
|
|
76312
|
+
framesCaptured++;
|
|
76313
|
+
if (onFrameCaptured) onFrameCaptured(task.workerId, prev.idx);
|
|
76314
|
+
}
|
|
76315
|
+
prev = { idx: i2, encodeResult };
|
|
76316
|
+
}
|
|
76317
|
+
if (prev) {
|
|
76318
|
+
await onFrameBuffer(prev.idx, await prev.encodeResult, session);
|
|
76319
|
+
framesCaptured++;
|
|
76320
|
+
if (onFrameCaptured) onFrameCaptured(task.workerId, prev.idx);
|
|
76321
|
+
}
|
|
76322
|
+
return framesCaptured;
|
|
76323
|
+
}
|
|
76324
|
+
for (let i2 = task.startFrame; i2 < task.endFrame; i2 += stride) {
|
|
76195
76325
|
if (signal?.aborted) throw new Error("Parallel worker cancelled");
|
|
76196
76326
|
const time = i2 * captureOptions.fps.den / captureOptions.fps.num;
|
|
76197
76327
|
const fileFrameIdx = i2 - outputOffset;
|
|
76198
76328
|
if (onFrameBuffer) {
|
|
76199
76329
|
const { buffer } = await captureFrameToBuffer(session, fileFrameIdx, time);
|
|
76200
|
-
await onFrameBuffer(i2, buffer);
|
|
76330
|
+
await onFrameBuffer(i2, buffer, session);
|
|
76201
76331
|
} else {
|
|
76202
76332
|
await captureFrame(session, fileFrameIdx, time);
|
|
76203
76333
|
}
|
|
@@ -76228,10 +76358,18 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
|
|
|
76228
76358
|
createBeforeCaptureHook(),
|
|
76229
76359
|
workerConfig
|
|
76230
76360
|
);
|
|
76361
|
+
if (process.env.HF_DE_PAR_DEBUG === "1") {
|
|
76362
|
+
console.log(`[par:w${task.workerId}] session created`);
|
|
76363
|
+
}
|
|
76231
76364
|
if (shouldVerifyWorkerGpu(task.workerId, workerConfig)) {
|
|
76232
76365
|
await assertSwiftShader(session.page, readWebGlVendorInfoFromCanvas);
|
|
76233
76366
|
}
|
|
76234
76367
|
await initializeSession(session);
|
|
76368
|
+
if (process.env.HF_DE_PAR_DEBUG === "1") {
|
|
76369
|
+
console.log(
|
|
76370
|
+
`[par:w${task.workerId}] init done (mode=${session.captureMode} workerEncode=${session.workerEncodeEnabled === true})`
|
|
76371
|
+
);
|
|
76372
|
+
}
|
|
76235
76373
|
framesCaptured = await captureFrameRange(
|
|
76236
76374
|
session,
|
|
76237
76375
|
task,
|
|
@@ -76268,7 +76406,10 @@ async function executeWorkerTask(task, serverUrl, captureOptions, createBeforeCa
|
|
|
76268
76406
|
}
|
|
76269
76407
|
}
|
|
76270
76408
|
async function executeParallelCapture(serverUrl, workDir, tasks, captureOptions, createBeforeCaptureHook, signal, onProgress, onFrameBuffer, config) {
|
|
76271
|
-
const totalFrames = tasks.reduce(
|
|
76409
|
+
const totalFrames = tasks.reduce(
|
|
76410
|
+
(sum, t2) => sum + Math.ceil((t2.endFrame - t2.startFrame) / (t2.frameStride ?? 1)),
|
|
76411
|
+
0
|
|
76412
|
+
);
|
|
76272
76413
|
const workerProgress = /* @__PURE__ */ new Map();
|
|
76273
76414
|
for (const task of tasks) workerProgress.set(task.workerId, 0);
|
|
76274
76415
|
const onFrameCaptured = (workerId, _frameIndex) => {
|
|
@@ -77960,6 +78101,7 @@ __export(src_exports, {
|
|
|
77960
78101
|
detectTransfer: () => detectTransfer,
|
|
77961
78102
|
discardWarmupCapture: () => discardWarmupCapture,
|
|
77962
78103
|
distributeFrames: () => distributeFrames,
|
|
78104
|
+
distributeFramesInterleaved: () => distributeFramesInterleaved,
|
|
77963
78105
|
downloadToTemp: () => downloadToTemp,
|
|
77964
78106
|
drainBrowserPool: () => drainBrowserPool,
|
|
77965
78107
|
encodeFramesChunkedConcat: () => encodeFramesChunkedConcat,
|
|
@@ -78634,6 +78776,7 @@ __export(events_exports, {
|
|
|
78634
78776
|
});
|
|
78635
78777
|
function renderObservabilityEventProperties(props) {
|
|
78636
78778
|
return {
|
|
78779
|
+
sub_timeline_wait: props.subTimelineWait,
|
|
78637
78780
|
observability_render_job_id: props.observabilityRenderJobId,
|
|
78638
78781
|
observability_composition_hash: props.observabilityCompositionHash,
|
|
78639
78782
|
observability_event_count: props.observabilityEventCount,
|
|
@@ -83465,6 +83608,7 @@ var init_skills = __esm({
|
|
|
83465
83608
|
var transcribe_exports = {};
|
|
83466
83609
|
__export(transcribe_exports, {
|
|
83467
83610
|
detectSpeechOnset: () => detectSpeechOnset,
|
|
83611
|
+
dtwPresetForModel: () => dtwPresetForModel,
|
|
83468
83612
|
transcribe: () => transcribe
|
|
83469
83613
|
});
|
|
83470
83614
|
import { execFileSync as execFileSync5 } from "child_process";
|
|
@@ -83598,6 +83742,9 @@ function prepareAudio(audioPath) {
|
|
|
83598
83742
|
);
|
|
83599
83743
|
return wavPath;
|
|
83600
83744
|
}
|
|
83745
|
+
function dtwPresetForModel(model) {
|
|
83746
|
+
return model.replace(/-/g, ".");
|
|
83747
|
+
}
|
|
83601
83748
|
async function transcribe(inputPath, outputDir, options) {
|
|
83602
83749
|
const model = options?.model ?? DEFAULT_MODEL;
|
|
83603
83750
|
options?.onProgress?.("Checking whisper...");
|
|
@@ -83649,7 +83796,7 @@ async function transcribe(inputPath, outputDir, options) {
|
|
|
83649
83796
|
"--output-file",
|
|
83650
83797
|
outputBase,
|
|
83651
83798
|
"--dtw",
|
|
83652
|
-
effectiveModel,
|
|
83799
|
+
dtwPresetForModel(effectiveModel),
|
|
83653
83800
|
"--suppress-nst"
|
|
83654
83801
|
];
|
|
83655
83802
|
if (detectedLanguage) {
|
|
@@ -84619,9 +84766,12 @@ function renderObservabilityTelemetryPayload(observability) {
|
|
|
84619
84766
|
};
|
|
84620
84767
|
}
|
|
84621
84768
|
function renderJobObservabilityTelemetryPayload(job) {
|
|
84622
|
-
return
|
|
84623
|
-
|
|
84624
|
-
|
|
84769
|
+
return {
|
|
84770
|
+
...renderObservabilityTelemetryPayload(
|
|
84771
|
+
job?.errorDetails?.observability ?? job?.perfSummary?.observability
|
|
84772
|
+
),
|
|
84773
|
+
subTimelineWait: job?.errorDetails?.subTimelineWait ?? job?.perfSummary?.subTimelineWait
|
|
84774
|
+
};
|
|
84625
84775
|
}
|
|
84626
84776
|
var init_renderObservability = __esm({
|
|
84627
84777
|
"src/telemetry/renderObservability.ts"() {
|
|
@@ -99988,7 +100138,8 @@ function buildRenderErrorDetails(input2) {
|
|
|
99988
100138
|
browserConsoleTail: input2.lastBrowserConsole.length > 0 ? input2.lastBrowserConsole.slice(-30) : void 0,
|
|
99989
100139
|
perfStages: Object.keys(input2.perfStages).length > 0 ? { ...input2.perfStages } : void 0,
|
|
99990
100140
|
hdrDiagnostics: input2.hdrDiagnostics.videoExtractionFailures > 0 || input2.hdrDiagnostics.imageDecodeFailures > 0 ? { ...input2.hdrDiagnostics } : void 0,
|
|
99991
|
-
observability: input2.observability
|
|
100141
|
+
observability: input2.observability,
|
|
100142
|
+
subTimelineWait: input2.subTimelineWait
|
|
99992
100143
|
};
|
|
99993
100144
|
}
|
|
99994
100145
|
var init_cleanup = __esm({
|
|
@@ -100168,6 +100319,13 @@ var init_hdrPerf = __esm({
|
|
|
100168
100319
|
});
|
|
100169
100320
|
|
|
100170
100321
|
// ../producer/src/services/render/perfSummary.ts
|
|
100322
|
+
function worstSubTimelineWaitOutcome(perfs) {
|
|
100323
|
+
const outcomes = perfs.map((p2) => p2.subTimelineWaitOutcome).filter((o) => !!o);
|
|
100324
|
+
if (outcomes.length === 0) return void 0;
|
|
100325
|
+
if (outcomes.includes("script_failure")) return "script_failure";
|
|
100326
|
+
if (outcomes.includes("timeout")) return "timeout";
|
|
100327
|
+
return "ready";
|
|
100328
|
+
}
|
|
100171
100329
|
function pushWorkerDedupPerfs(results, sink) {
|
|
100172
100330
|
for (const r2 of results) {
|
|
100173
100331
|
if (r2.perf) sink.push(r2.perf);
|
|
@@ -100249,6 +100407,7 @@ function buildRenderPerfSummary(input2) {
|
|
|
100249
100407
|
captureAvgMs: input2.totalFrames > 0 ? Math.round(
|
|
100250
100408
|
(input2.perfStages.captureFrameMs ?? input2.perfStages.captureMs ?? 0) / input2.totalFrames
|
|
100251
100409
|
) : void 0,
|
|
100410
|
+
subTimelineWait: worstSubTimelineWaitOutcome(input2.dedupPerfs),
|
|
100252
100411
|
captureP50Ms: (() => {
|
|
100253
100412
|
const withSamples = input2.dedupPerfs.filter((p2) => (p2.p50TotalMs ?? 0) > 0);
|
|
100254
100413
|
if (withSamples.length === 0) return void 0;
|
|
@@ -108231,9 +108390,8 @@ async function psnrDb(a, b2) {
|
|
|
108231
108390
|
});
|
|
108232
108391
|
}
|
|
108233
108392
|
}
|
|
108234
|
-
|
|
108235
|
-
|
|
108236
|
-
const frameTime = (i2) => i2 * job.config.fps.den / job.config.fps.num;
|
|
108393
|
+
function createDrainFrameGuard(args) {
|
|
108394
|
+
const { log: log2, stats, frameTime } = args;
|
|
108237
108395
|
const verifyMinDbRaw = Number(process.env.HF_DE_VERIFY_MIN_DB ?? "32");
|
|
108238
108396
|
const verifyMinDb = Number.isFinite(verifyMinDbRaw) && verifyMinDbRaw >= 10 && verifyMinDbRaw <= 60 ? verifyMinDbRaw : 32;
|
|
108239
108397
|
if (process.env.HF_DE_VERIFY_MIN_DB !== void 0 && verifyMinDb !== verifyMinDbRaw) {
|
|
@@ -108250,7 +108408,7 @@ async function runWorkerEncodePipelineLoop(session, totalFrames, job, currentEnc
|
|
|
108250
108408
|
return Math.max(absFloor, median * 0.12);
|
|
108251
108409
|
};
|
|
108252
108410
|
let acceptedSmall = null;
|
|
108253
|
-
|
|
108411
|
+
return async (session, idx, buf) => {
|
|
108254
108412
|
if (process.env.HF_FORCE_DRAWELEMENT !== "1") {
|
|
108255
108413
|
const floor = blankFloor();
|
|
108256
108414
|
if (floor > 0 && buf.length < floor && acceptedSmall?.equals(buf)) {
|
|
@@ -108325,6 +108483,12 @@ async function runWorkerEncodePipelineLoop(session, totalFrames, job, currentEnc
|
|
|
108325
108483
|
}
|
|
108326
108484
|
return buf;
|
|
108327
108485
|
};
|
|
108486
|
+
}
|
|
108487
|
+
async function runWorkerEncodePipelineLoop(session, totalFrames, job, currentEncoder, reorderBuffer, assertNotAborted, onProgress, log2, stats) {
|
|
108488
|
+
let prev = null;
|
|
108489
|
+
const frameTime = (i2) => i2 * job.config.fps.den / job.config.fps.num;
|
|
108490
|
+
const guard = createDrainFrameGuard({ log: log2, stats, frameTime });
|
|
108491
|
+
const guardFrame = (idx, buf) => guard(session, idx, buf);
|
|
108328
108492
|
const drainPrev = async () => {
|
|
108329
108493
|
if (!prev) return;
|
|
108330
108494
|
assertNotAborted();
|
|
@@ -108451,37 +108615,81 @@ async function runCaptureStreamingStage(input2) {
|
|
|
108451
108615
|
try {
|
|
108452
108616
|
const reorderBuffer = createFrameReorderBuffer(0, totalFrames);
|
|
108453
108617
|
if (workerCount > 1) {
|
|
108454
|
-
const
|
|
108455
|
-
const
|
|
108456
|
-
|
|
108457
|
-
|
|
108458
|
-
|
|
108618
|
+
const deParallelStream = process.env.HF_DE_PARALLEL_STREAM === "true";
|
|
108619
|
+
const tasks = deParallelStream ? distributeFramesInterleaved(totalFrames, workerCount, workDir) : distributeFrames(totalFrames, workerCount, workDir);
|
|
108620
|
+
const parallelStats = {
|
|
108621
|
+
verifyChecked: 0,
|
|
108622
|
+
blankSuspects: 0,
|
|
108623
|
+
blankDeterministicAccepts: 0,
|
|
108624
|
+
blankRecaptures: 0
|
|
108459
108625
|
};
|
|
108460
|
-
const
|
|
108461
|
-
|
|
108462
|
-
|
|
108463
|
-
|
|
108464
|
-
|
|
108465
|
-
|
|
108466
|
-
|
|
108467
|
-
|
|
108468
|
-
|
|
108469
|
-
|
|
108470
|
-
|
|
108471
|
-
|
|
108472
|
-
updateJobStatus(
|
|
108473
|
-
job,
|
|
108474
|
-
"rendering",
|
|
108475
|
-
`Streaming frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
|
|
108476
|
-
Math.round(progressPct),
|
|
108477
|
-
onProgress
|
|
108478
|
-
);
|
|
108626
|
+
const parallelGuard = createDrainFrameGuard({
|
|
108627
|
+
log: log2,
|
|
108628
|
+
stats: parallelStats,
|
|
108629
|
+
frameTime: (i2) => i2 * job.config.fps.den / job.config.fps.num
|
|
108630
|
+
});
|
|
108631
|
+
let parallelGuardRan = false;
|
|
108632
|
+
let parallelDrainError = null;
|
|
108633
|
+
const onFrameBuffer = async (frameIndex, buffer, workerSession) => {
|
|
108634
|
+
try {
|
|
108635
|
+
if (deParallelStream && workerSession.captureMode === "drawelement") {
|
|
108636
|
+
parallelGuardRan = true;
|
|
108637
|
+
buffer = await parallelGuard(workerSession, frameIndex, buffer);
|
|
108479
108638
|
}
|
|
108480
|
-
|
|
108481
|
-
|
|
108482
|
-
|
|
108483
|
-
|
|
108639
|
+
await reorderBuffer.waitForFrame(frameIndex);
|
|
108640
|
+
ensureFrameWritten(await currentEncoder.writeFrame(buffer), frameIndex, currentEncoder);
|
|
108641
|
+
reorderBuffer.advanceTo(frameIndex + 1);
|
|
108642
|
+
} catch (err) {
|
|
108643
|
+
const e3 = err instanceof Error ? err : new Error(String(err));
|
|
108644
|
+
if (!parallelDrainError) {
|
|
108645
|
+
parallelDrainError = e3;
|
|
108646
|
+
reorderBuffer.abort(e3);
|
|
108647
|
+
}
|
|
108648
|
+
throw e3;
|
|
108649
|
+
}
|
|
108650
|
+
};
|
|
108651
|
+
let workerResults;
|
|
108652
|
+
try {
|
|
108653
|
+
workerResults = await executeParallelCapture(
|
|
108654
|
+
fileServer.url,
|
|
108655
|
+
workDir,
|
|
108656
|
+
tasks,
|
|
108657
|
+
buildCaptureOptions(),
|
|
108658
|
+
createRenderVideoFrameInjector,
|
|
108659
|
+
abortSignal,
|
|
108660
|
+
(progress) => {
|
|
108661
|
+
job.framesRendered = progress.capturedFrames;
|
|
108662
|
+
const frameProgress = progress.capturedFrames / progress.totalFrames;
|
|
108663
|
+
const progressPct = 25 + frameProgress * 55;
|
|
108664
|
+
if (progress.capturedFrames % 30 === 0 || progress.capturedFrames === progress.totalFrames) {
|
|
108665
|
+
updateJobStatus(
|
|
108666
|
+
job,
|
|
108667
|
+
"rendering",
|
|
108668
|
+
`Streaming frame ${progress.capturedFrames}/${progress.totalFrames} (${workerCount} workers)`,
|
|
108669
|
+
Math.round(progressPct),
|
|
108670
|
+
onProgress
|
|
108671
|
+
);
|
|
108672
|
+
}
|
|
108673
|
+
},
|
|
108674
|
+
onFrameBuffer,
|
|
108675
|
+
// Interleaved DE workers each need their own browser PROCESS:
|
|
108676
|
+
// pages co-tenant in one browser share one compositor, whose
|
|
108677
|
+
// internal frame scheduling deprioritizes non-active pages — their
|
|
108678
|
+
// canvas `paint` events starve and the drawElement paint-wait slows
|
|
108679
|
+
// ~3x (measured: 86s vs 30s on a 3,245-frame rAF comp). This is
|
|
108680
|
+
// Chromium's internal frame-production scheduling on ALL platforms,
|
|
108681
|
+
// NOT the Linux-only HeadlessExperimental.beginFrame capture mode.
|
|
108682
|
+
deParallelStream ? { ...captureCfg, enableBrowserPool: false } : captureCfg
|
|
108683
|
+
);
|
|
108684
|
+
} catch (err) {
|
|
108685
|
+
if (parallelDrainError) throw parallelDrainError;
|
|
108686
|
+
throw err;
|
|
108687
|
+
}
|
|
108688
|
+
if (parallelDrainError) throw parallelDrainError;
|
|
108484
108689
|
pushWorkerDedupPerfs(workerResults, dedupPerfs);
|
|
108690
|
+
if (parallelGuardRan) {
|
|
108691
|
+
deDrainStats = parallelStats;
|
|
108692
|
+
}
|
|
108485
108693
|
if (probeSession) {
|
|
108486
108694
|
captureBeyondViewport = probeSession.options.captureBeyondViewport;
|
|
108487
108695
|
lastBrowserConsole = probeSession.browserConsoleBuffer;
|
|
@@ -110435,6 +110643,7 @@ function shouldUseStreamingEncode(cfg, outputFormat, workerCount, durationSecond
|
|
|
110435
110643
|
if (outputFormat === "gif") return false;
|
|
110436
110644
|
if (!Number.isFinite(durationSeconds) || durationSeconds <= 0) return false;
|
|
110437
110645
|
if (durationSeconds > cfg.streamingEncodeMaxDurationSeconds) return false;
|
|
110646
|
+
if (process.env.HF_DE_PARALLEL_STREAM === "true") return true;
|
|
110438
110647
|
return workerCount === 1;
|
|
110439
110648
|
}
|
|
110440
110649
|
function shouldPreferSingleWorkerDrawElement(args) {
|
|
@@ -110529,6 +110738,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110529
110738
|
captureObservability.captureMode = captureObservability.forceScreenshot ? "screenshot" : "beginframe";
|
|
110530
110739
|
};
|
|
110531
110740
|
const captureAttempts = [];
|
|
110741
|
+
const dedupPerfs = [];
|
|
110532
110742
|
const recordTransientRetryObservability = () => {
|
|
110533
110743
|
const count = captureAttempts.filter((a) => a.reason === "transient-retry").length;
|
|
110534
110744
|
if (count > 0) updateCaptureObservability({ transientRetries: count });
|
|
@@ -110883,7 +111093,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110883
111093
|
layeredOrEffectRoute: hasHdrContent || compiled.hasShaderTransitions,
|
|
110884
111094
|
supersampling: deviceScaleFactor > 1,
|
|
110885
111095
|
probeDeGated: probeSession !== null && probeSession.captureMode !== "drawelement" && !probeSession.deInitDeferred,
|
|
110886
|
-
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true"
|
|
111096
|
+
experimentalParallelDeOptIn: process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE === "true" || // Verified parallel DE streaming (opt-in) wants its parallelism kept.
|
|
111097
|
+
process.env.HF_DE_PARALLEL_STREAM === "true"
|
|
110887
111098
|
});
|
|
110888
111099
|
if (job.config.workers === void 0 && totalFrames >= 60 && !htmlInCanvasDetected && !cfg.lowMemoryMode && !deInversionEligible) {
|
|
110889
111100
|
const outcome = await observeRenderStage(
|
|
@@ -110960,7 +111171,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110960
111171
|
durationSeconds: job.duration,
|
|
110961
111172
|
maxDurationSeconds: cfg.streamingEncodeMaxDurationSeconds
|
|
110962
111173
|
});
|
|
110963
|
-
|
|
111174
|
+
const deParallelStreamVerified = process.env.HF_DE_PARALLEL_STREAM === "true" && useStreamingEncode && workerCount > 1;
|
|
111175
|
+
if (cfg.useDrawElement && process.env.PRODUCER_EXPERIMENTAL_FAST_CAPTURE !== "true" && (!useStreamingEncode || workerCount > 1) && !deParallelStreamVerified) {
|
|
110964
111176
|
cfg.useDrawElement = false;
|
|
110965
111177
|
deClampReason = workerCount > 1 ? "parallel" : "disk_path";
|
|
110966
111178
|
log2.info(
|
|
@@ -110971,7 +111183,6 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110971
111183
|
probeSession = null;
|
|
110972
111184
|
}
|
|
110973
111185
|
}
|
|
110974
|
-
const dedupPerfs = [];
|
|
110975
111186
|
const FORMAT_EXT3 = {
|
|
110976
111187
|
mp4: ".mp4",
|
|
110977
111188
|
webm: ".webm",
|
|
@@ -111437,7 +111648,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111437
111648
|
lastBrowserConsole,
|
|
111438
111649
|
perfStages,
|
|
111439
111650
|
hdrDiagnostics,
|
|
111440
|
-
observability: observabilitySummary
|
|
111651
|
+
observability: observabilitySummary,
|
|
111652
|
+
subTimelineWait: worstSubTimelineWaitOutcome(dedupPerfs)
|
|
111441
111653
|
});
|
|
111442
111654
|
log2.info("[Render] Failure summary", {
|
|
111443
111655
|
failedStage: job.currentStage,
|
|
@@ -114313,7 +114525,9 @@ async function findFromHyperframesCache() {
|
|
|
114313
114525
|
);
|
|
114314
114526
|
installed = [];
|
|
114315
114527
|
}
|
|
114316
|
-
const match = installed.find(
|
|
114528
|
+
const match = installed.find(
|
|
114529
|
+
(b2) => b2.browser === Browser.CHROMEHEADLESSSHELL && b2.buildId === CHROME_VERSION
|
|
114530
|
+
);
|
|
114317
114531
|
if (match && existsSync53(match.executablePath)) {
|
|
114318
114532
|
return { result: { executablePath: match.executablePath, source: "cache" } };
|
|
114319
114533
|
}
|
|
@@ -120525,6 +120739,7 @@ function trackRenderMetrics(job, elapsedMs, options, docker) {
|
|
|
120525
120739
|
speedRatio,
|
|
120526
120740
|
captureAvgMs: perf?.captureAvgMs,
|
|
120527
120741
|
captureP50Ms: perf?.captureP50Ms,
|
|
120742
|
+
subTimelineWait: perf?.subTimelineWait,
|
|
120528
120743
|
videoCount: perf?.videoCount,
|
|
120529
120744
|
capturePeakMs: perf?.capturePeakMs,
|
|
120530
120745
|
tmpPeakBytes: perf?.tmpPeakBytes,
|