@hyperframes/producer 0.8.221 → 0.8.223
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/distributed.js +40 -6
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +72 -72
- package/dist/index.d.ts +1 -0
- package/dist/index.js +4649 -4506
- package/dist/public-server.js +81 -16
- package/dist/services/distributed/renderSpan.d.ts +19 -0
- package/dist/services/render/observability.d.ts +3 -1
- package/dist/services/render/shared.d.ts +4 -0
- package/dist/services/render/stages/captureHdrStage.d.ts +1 -0
- package/dist/services/render/stages/captureSegmentedStage.d.ts +1 -0
- package/dist/services/render/stages/captureStreamingStage.d.ts +1 -0
- package/dist/services/render/stages/extractVideosStage.d.ts +2 -0
- package/dist/services/renderOrchestrator.d.ts +12 -1
- package/package.json +7 -7
package/dist/public-server.js
CHANGED
|
@@ -1103,6 +1103,21 @@ function reportFrameProgress(job, stage, progress, onProgress, done, total) {
|
|
|
1103
1103
|
total
|
|
1104
1104
|
});
|
|
1105
1105
|
}
|
|
1106
|
+
var lastExtractReportAt = /* @__PURE__ */ new WeakMap();
|
|
1107
|
+
function reportExtractProgress(job, done, total, onProgress) {
|
|
1108
|
+
if (total <= 0) return;
|
|
1109
|
+
const frames = Math.min(done, total);
|
|
1110
|
+
reportThrottled(
|
|
1111
|
+
lastExtractReportAt,
|
|
1112
|
+
job,
|
|
1113
|
+
"Extracting video frames",
|
|
1114
|
+
10 + 10 * frames / total,
|
|
1115
|
+
onProgress,
|
|
1116
|
+
frames === total,
|
|
1117
|
+
{ code: "extract_video", done: frames, total },
|
|
1118
|
+
"preprocessing"
|
|
1119
|
+
);
|
|
1120
|
+
}
|
|
1106
1121
|
var lastEncodeReportAt = /* @__PURE__ */ new WeakMap();
|
|
1107
1122
|
function reportEncodeProgress(job, done, total, onProgress, from) {
|
|
1108
1123
|
if (total <= 0) return;
|
|
@@ -1134,6 +1149,14 @@ function reportAssembleProgress(job, done, total, onProgress) {
|
|
|
1134
1149
|
);
|
|
1135
1150
|
}
|
|
1136
1151
|
var workerPhasesByJob = /* @__PURE__ */ new WeakMap();
|
|
1152
|
+
function forgetWorkerPhases(job) {
|
|
1153
|
+
workerPhasesByJob.delete(job);
|
|
1154
|
+
}
|
|
1155
|
+
function describeWorkerPhases(job) {
|
|
1156
|
+
const phases = workerPhasesByJob.get(job);
|
|
1157
|
+
if (!phases?.size) return void 0;
|
|
1158
|
+
return `Last phase per worker: ${[...phases].map(([id, phase]) => `worker ${id} ${phase}`).join(", ")}.`;
|
|
1159
|
+
}
|
|
1137
1160
|
function reportWorkerStartup(job, progress, onProgress) {
|
|
1138
1161
|
const phase = progress.latestWorkerPhase;
|
|
1139
1162
|
if (!phase) return;
|
|
@@ -2215,6 +2238,11 @@ function aggregateChromeMemory(perfs) {
|
|
|
2215
2238
|
samples: sampled.reduce((sum, p) => sum + (p.chromeMemorySamples ?? 0), 0)
|
|
2216
2239
|
};
|
|
2217
2240
|
}
|
|
2241
|
+
function frameWeightedAvgMs(perfs, avgOf) {
|
|
2242
|
+
const frames = perfs.reduce((sum, p) => sum + p.frames, 0);
|
|
2243
|
+
if (frames === 0) return void 0;
|
|
2244
|
+
return Math.round(perfs.reduce((sum, p) => sum + avgOf(p) * p.frames, 0) / frames);
|
|
2245
|
+
}
|
|
2218
2246
|
function aggregateDedup(perfs) {
|
|
2219
2247
|
if (perfs.length === 0) return void 0;
|
|
2220
2248
|
const armed = perfs.some((p) => p.staticDedupArmed);
|
|
@@ -2313,6 +2341,10 @@ function buildRenderPerfSummary(input) {
|
|
|
2313
2341
|
if (withSamples.length === 0) return void 0;
|
|
2314
2342
|
return withSamples.reduce((a, b) => b.frames > a.frames ? b : a).p50TotalMs;
|
|
2315
2343
|
})(),
|
|
2344
|
+
captureSeekAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgSeekMs),
|
|
2345
|
+
captureBeforeCaptureAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgBeforeCaptureMs),
|
|
2346
|
+
captureScreenshotAvgMs: frameWeightedAvgMs(input.dedupPerfs, (p) => p.avgScreenshotMs),
|
|
2347
|
+
encoderWaitAvgMs: input.perfStages.encoderDrainWaitMs !== void 0 && input.totalFrames > 0 ? Math.round(input.perfStages.encoderDrainWaitMs / input.totalFrames) : void 0,
|
|
2316
2348
|
peakRssMb: Math.round(input.peakRssBytes / (1024 * 1024)),
|
|
2317
2349
|
peakHeapUsedMb: Math.round(input.peakHeapUsedBytes / (1024 * 1024)),
|
|
2318
2350
|
staticDedup: aggregateDedup(input.dedupPerfs),
|
|
@@ -4338,6 +4370,7 @@ async function runCaptureStreamingStage(input) {
|
|
|
4338
4370
|
return {
|
|
4339
4371
|
success: true,
|
|
4340
4372
|
encodeMs: encodeResult.durationMs,
|
|
4373
|
+
encoderDrainWaitMs: encodeResult.drainWaitMs,
|
|
4341
4374
|
probeSession,
|
|
4342
4375
|
lastBrowserConsole,
|
|
4343
4376
|
workerCount,
|
|
@@ -4437,7 +4470,7 @@ async function captureSegment(ctx, segment) {
|
|
|
4437
4470
|
// finished; absent only in unit tests, whose fake encoder writes none.
|
|
4438
4471
|
bytes: existsSync6(segmentPath) ? statSync3(segmentPath).size : 0
|
|
4439
4472
|
});
|
|
4440
|
-
return encodeResult
|
|
4473
|
+
return encodeResult;
|
|
4441
4474
|
} finally {
|
|
4442
4475
|
if (!encoderClosed) {
|
|
4443
4476
|
await encoder.close().catch(() => {
|
|
@@ -4579,7 +4612,11 @@ async function retryAfterTargetLoss(run, worker, err, segment, segmentPath) {
|
|
|
4579
4612
|
);
|
|
4580
4613
|
run.deps.removeFile(segmentPath);
|
|
4581
4614
|
await recycleWorkerSession(run, worker, "retry");
|
|
4582
|
-
run.totals
|
|
4615
|
+
addSegmentEncode(run.totals, await captureSegment(worker.ctx, segment));
|
|
4616
|
+
}
|
|
4617
|
+
function addSegmentEncode(totals, result) {
|
|
4618
|
+
totals.encodeMs += result.durationMs;
|
|
4619
|
+
totals.encoderDrainWaitMs += result.drainWaitMs ?? 0;
|
|
4583
4620
|
}
|
|
4584
4621
|
async function runOneSegment(run, worker, segment) {
|
|
4585
4622
|
const segmentPath = segmentOutputPath(run.segmentDir, segment.index);
|
|
@@ -4591,7 +4628,7 @@ async function runOneSegment(run, worker, segment) {
|
|
|
4591
4628
|
segmentIndex: segment.index
|
|
4592
4629
|
});
|
|
4593
4630
|
try {
|
|
4594
|
-
run.totals
|
|
4631
|
+
addSegmentEncode(run.totals, await captureSegment(worker.ctx, segment));
|
|
4595
4632
|
} catch (err) {
|
|
4596
4633
|
if (err instanceof SegmentEncoderSpawnError) return onSegmentSpawnFailure(run, err, segment);
|
|
4597
4634
|
await retryAfterTargetLoss(run, worker, err, segment, segmentPath);
|
|
@@ -4634,7 +4671,7 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4634
4671
|
const run = {
|
|
4635
4672
|
input,
|
|
4636
4673
|
deps,
|
|
4637
|
-
totals: { encodeMs: 0, segmentRetries: 0, browserRecycles: 0 },
|
|
4674
|
+
totals: { encodeMs: 0, encoderDrainWaitMs: 0, segmentRetries: 0, browserRecycles: 0 },
|
|
4638
4675
|
segments,
|
|
4639
4676
|
pending,
|
|
4640
4677
|
segmentDir,
|
|
@@ -4687,6 +4724,7 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4687
4724
|
return {
|
|
4688
4725
|
success: true,
|
|
4689
4726
|
encodeMs: run.totals.encodeMs,
|
|
4727
|
+
encoderDrainWaitMs: run.totals.encoderDrainWaitMs,
|
|
4690
4728
|
probeSession: null,
|
|
4691
4729
|
lastBrowserConsole,
|
|
4692
4730
|
workerCount: run.workerCount,
|
|
@@ -5498,16 +5536,17 @@ var RenderStageStalledError = class extends CaptureFailure2 {
|
|
|
5498
5536
|
code = "RENDER_STAGE_STALLED";
|
|
5499
5537
|
owner = "system";
|
|
5500
5538
|
retryable = false;
|
|
5501
|
-
constructor(phase, silentMs, progress) {
|
|
5539
|
+
constructor(phase, silentMs, progress, detail) {
|
|
5502
5540
|
super({
|
|
5503
5541
|
kind: "protocol_timeout",
|
|
5504
|
-
message: `[Render] ${phase} stalled: no progress for ${silentMs}ms (stuck at ${progress})
|
|
5542
|
+
message: `[Render] ${phase} stalled: no progress for ${silentMs}ms (stuck at ${progress}).${detail ? ` ${detail}` : ""}`
|
|
5505
5543
|
});
|
|
5506
5544
|
this.name = "RenderStageStalledError";
|
|
5507
5545
|
}
|
|
5508
5546
|
};
|
|
5509
5547
|
var STALL_POLL_MS = 5e3;
|
|
5510
5548
|
function watchStall(phase, rule) {
|
|
5549
|
+
const detail = rule.detail ?? (() => void 0);
|
|
5511
5550
|
let last = rule.progress();
|
|
5512
5551
|
let budgetMs = rule.firstProgressMs;
|
|
5513
5552
|
let lastChangeAt = Date.now();
|
|
@@ -5529,7 +5568,7 @@ function watchStall(phase, rule) {
|
|
|
5529
5568
|
}
|
|
5530
5569
|
if (current !== last) return restartWindow(rule.noProgressMs);
|
|
5531
5570
|
if (Date.now() - lastChangeAt < budgetMs) return;
|
|
5532
|
-
const error = new RenderStageStalledError(phase, budgetMs, current);
|
|
5571
|
+
const error = new RenderStageStalledError(phase, budgetMs, current, detail());
|
|
5533
5572
|
if (attempt && !attempt.signal.aborted) {
|
|
5534
5573
|
attempt.abort(error);
|
|
5535
5574
|
return restartWindow(rule.noProgressMs);
|
|
@@ -5543,6 +5582,7 @@ function watchStall(phase, rule) {
|
|
|
5543
5582
|
const openAttempt = (parent) => {
|
|
5544
5583
|
attempt = new AbortController();
|
|
5545
5584
|
inTail = false;
|
|
5585
|
+
rule.attemptOpened?.();
|
|
5546
5586
|
restartWindow(rule.firstProgressMs);
|
|
5547
5587
|
return parent ? AbortSignal.any([parent, attempt.signal]) : attempt.signal;
|
|
5548
5588
|
};
|
|
@@ -7849,7 +7889,7 @@ function rebaseDirectEntryAssetPaths(html, projectDir, htmlPath) {
|
|
|
7849
7889
|
const { document: document2 } = parseHTML5(html);
|
|
7850
7890
|
const assetExists = (path) => existsSync10(resolve7(projectDir, path));
|
|
7851
7891
|
rewriteAssetPaths(
|
|
7852
|
-
document2.querySelectorAll("[src], [href]"),
|
|
7892
|
+
document2.querySelectorAll("[src], [href], [srcset]"),
|
|
7853
7893
|
entryPath,
|
|
7854
7894
|
(el, attr) => el.getAttribute(attr),
|
|
7855
7895
|
(el, attr, value) => el.setAttribute(attr, value),
|
|
@@ -9531,6 +9571,8 @@ async function runExtractVideosStage(input) {
|
|
|
9531
9571
|
safeVideoExtractionSourceLogMetadata(v.src)
|
|
9532
9572
|
);
|
|
9533
9573
|
}
|
|
9574
|
+
let framesPlanned = 0;
|
|
9575
|
+
let framesDone = 0;
|
|
9534
9576
|
extractionResult = await extractAllVideoFrames(
|
|
9535
9577
|
composition.videos,
|
|
9536
9578
|
projectDir,
|
|
@@ -9547,7 +9589,12 @@ async function runExtractVideosStage(input) {
|
|
|
9547
9589
|
collectProbeFailures: extractionPolicy.failureMode === "enforce",
|
|
9548
9590
|
deferRangeExtraction,
|
|
9549
9591
|
contentKeyedDirs: [join18(compiledDir, REMOTE_MEDIA_SUBDIR)],
|
|
9550
|
-
urlByAbsentLocalPath
|
|
9592
|
+
urlByAbsentLocalPath,
|
|
9593
|
+
onProgress: ({ planned = 0, done = 0 }) => {
|
|
9594
|
+
framesPlanned += planned;
|
|
9595
|
+
framesDone += done;
|
|
9596
|
+
reportExtractProgress(job, framesDone, framesPlanned, input.onProgress);
|
|
9597
|
+
}
|
|
9551
9598
|
},
|
|
9552
9599
|
abortSignal,
|
|
9553
9600
|
cfg,
|
|
@@ -11294,6 +11341,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11294
11341
|
let lastBrowserConsole = [];
|
|
11295
11342
|
let captureDurationMs = 0;
|
|
11296
11343
|
let encodeMs = 0;
|
|
11344
|
+
let encoderDrainWaitMs;
|
|
11297
11345
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11298
11346
|
log.info(
|
|
11299
11347
|
hasHdrContent ? "[Render] HDR layered composite: z-ordered DOM + native HDR video/image layers" : "[Render] Shader transition composite: z-ordered SDR DOM layers"
|
|
@@ -11531,6 +11579,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11531
11579
|
reportEncodeProgress(job, totalFrames, totalFrames, onProgress, encodeFrom);
|
|
11532
11580
|
captureDurationMs = Date.now() - stageStart;
|
|
11533
11581
|
encodeMs = hdrEncodeResult.durationMs;
|
|
11582
|
+
encoderDrainWaitMs = hdrEncodeResult.drainWaitMs;
|
|
11534
11583
|
} catch (error) {
|
|
11535
11584
|
lastBrowserConsole = domSession.browserConsoleBuffer;
|
|
11536
11585
|
throw wrapCaptureStageError(error, lastBrowserConsole);
|
|
@@ -11563,6 +11612,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11563
11612
|
hdrPerf,
|
|
11564
11613
|
captureDurationMs,
|
|
11565
11614
|
encodeMs,
|
|
11615
|
+
encoderDrainWaitMs,
|
|
11566
11616
|
warnings: cloneCaptureWarnings2(domSession.warnings)
|
|
11567
11617
|
};
|
|
11568
11618
|
}
|
|
@@ -12355,7 +12405,9 @@ function frameStallRule(job, totalFrames) {
|
|
|
12355
12405
|
noProgressMs,
|
|
12356
12406
|
firstProgressMs: Math.max(FIRST_FRAME_STALL_MS, noProgressMs),
|
|
12357
12407
|
complete: () => (job.framesRendered ?? 0) >= totalFrames,
|
|
12358
|
-
tailMs: Math.max(TAIL_STALL_MS, noProgressMs)
|
|
12408
|
+
tailMs: Math.max(TAIL_STALL_MS, noProgressMs),
|
|
12409
|
+
detail: () => describeWorkerPhases(job),
|
|
12410
|
+
attemptOpened: () => forgetWorkerPhases(job)
|
|
12359
12411
|
};
|
|
12360
12412
|
}
|
|
12361
12413
|
function isRecoverableParallelCaptureError(error) {
|
|
@@ -12881,6 +12933,11 @@ function resolveDeSingleMinFrames(env) {
|
|
|
12881
12933
|
function shouldPreferSingleWorkerDrawElement(args) {
|
|
12882
12934
|
return args.workerCount > 1 && args.useDrawElement && !args.deCompileGate && !args.forceScreenshot && outputUsesH264Pipeline(args.outputFormat) && args.minFrames > 0 && args.totalFrames >= args.minFrames && args.singleWorkerStreamingOk && !args.layeredOrEffectRoute && !args.supersampling && !args.probeDeGated && !args.experimentalParallelDeOptIn;
|
|
12883
12935
|
}
|
|
12936
|
+
function initialDeClampReason(args) {
|
|
12937
|
+
if (args.useDrawElement) return void 0;
|
|
12938
|
+
if (args.deCompileGate) return "compile_gate";
|
|
12939
|
+
return explainDrawElementDisabled(args.config);
|
|
12940
|
+
}
|
|
12884
12941
|
function probeNeedsScreenshotFrames(session) {
|
|
12885
12942
|
return (session?.deRiskFrames?.size ?? 0) > 0;
|
|
12886
12943
|
}
|
|
@@ -13270,11 +13327,15 @@ async function executeRenderPipeline(input) {
|
|
|
13270
13327
|
perfStages.compileOnlyMs = compileResult.compileOnlyMs;
|
|
13271
13328
|
let captureForceScreenshot = compileResult.forceScreenshot;
|
|
13272
13329
|
const deCompileGate = compileResult.deCompileGate;
|
|
13273
|
-
let deClampReason =
|
|
13274
|
-
|
|
13275
|
-
|
|
13276
|
-
|
|
13277
|
-
|
|
13330
|
+
let deClampReason = initialDeClampReason({
|
|
13331
|
+
useDrawElement: cfg.useDrawElement,
|
|
13332
|
+
deCompileGate,
|
|
13333
|
+
config: {
|
|
13334
|
+
platform: process.platform,
|
|
13335
|
+
browserGpuMode: cfg.browserGpuMode,
|
|
13336
|
+
workerEncode: cfg.enableDrawElementWorkerEncode,
|
|
13337
|
+
chromeCeiling: chromeMajorCeiling()
|
|
13338
|
+
}
|
|
13278
13339
|
});
|
|
13279
13340
|
let deWorkerInversion;
|
|
13280
13341
|
let deParallelStreamForced = false;
|
|
@@ -13400,7 +13461,8 @@ async function executeRenderPipeline(input) {
|
|
|
13400
13461
|
abortSignal: executionSignal,
|
|
13401
13462
|
assertNotAborted,
|
|
13402
13463
|
// Local staging can use links; distributed plan() alone requires real copies.
|
|
13403
|
-
materializeSymlinks: false
|
|
13464
|
+
materializeSymlinks: false,
|
|
13465
|
+
onProgress
|
|
13404
13466
|
})
|
|
13405
13467
|
);
|
|
13406
13468
|
const {
|
|
@@ -14264,6 +14326,7 @@ async function executeRenderPipeline(input) {
|
|
|
14264
14326
|
perfStages.captureFrameMs = hdrRes.captureDurationMs;
|
|
14265
14327
|
perfStages.captureSetupMs = Math.max(0, Date.now() - stage4Start - hdrRes.captureDurationMs);
|
|
14266
14328
|
perfStages.encodeMs = hdrRes.encodeMs;
|
|
14329
|
+
perfStages.encoderDrainWaitMs = hdrRes.encoderDrainWaitMs ?? 0;
|
|
14267
14330
|
} else {
|
|
14268
14331
|
let streamingHandled = false;
|
|
14269
14332
|
if (capturePlan.kind === "sdr_segmented") {
|
|
@@ -14443,6 +14506,7 @@ async function executeRenderPipeline(input) {
|
|
|
14443
14506
|
perfStages.captureFrameMs = Date.now() - captureFrameStart;
|
|
14444
14507
|
perfStages.captureSetupMs = Math.max(0, perfStages.captureMs - perfStages.captureFrameMs);
|
|
14445
14508
|
perfStages.encodeMs = segmentedRes.encodeMs;
|
|
14509
|
+
perfStages.encoderDrainWaitMs = segmentedRes.encoderDrainWaitMs ?? 0;
|
|
14446
14510
|
log.info(
|
|
14447
14511
|
`[Render] Segmented capture complete: ${segmentedRes.segments} segment(s) concatenated.`,
|
|
14448
14512
|
{
|
|
@@ -14620,6 +14684,7 @@ async function executeRenderPipeline(input) {
|
|
|
14620
14684
|
perfStages.captureFrameMs = captureFrameMs;
|
|
14621
14685
|
perfStages.captureSetupMs = Math.max(0, perfStages.captureMs - captureFrameMs);
|
|
14622
14686
|
perfStages.encodeMs = streamingRes.encodeMs;
|
|
14687
|
+
perfStages.encoderDrainWaitMs = streamingRes.encoderDrainWaitMs ?? 0;
|
|
14623
14688
|
} else {
|
|
14624
14689
|
if (capturePlan.kind === "sdr_streaming") {
|
|
14625
14690
|
capturePlan = replanAfterFailure(capturePlan, { kind: "streaming_unavailable" });
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { type DistributedRenderConfig } from "./plan.js";
|
|
2
|
+
export interface RenderSpanResult {
|
|
3
|
+
startFrame: number;
|
|
4
|
+
endFrame: number;
|
|
5
|
+
framesEncoded: number;
|
|
6
|
+
}
|
|
7
|
+
export declare class RenderSpanUnsupportedError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/** The frames `[startFrame, endFrame)` of a `totalFrames` timeline that `[startSeconds, endSeconds)` covers. */
|
|
11
|
+
export declare function spanFrameRange(startSeconds: number, endSeconds: number | undefined, fps: number, totalFrames: number): {
|
|
12
|
+
startFrame: number;
|
|
13
|
+
endFrame: number;
|
|
14
|
+
};
|
|
15
|
+
/** Renders `[startSeconds, endSeconds)` as a standalone mp4 from 0, with that span's audio, by chunk sub-ranges. */
|
|
16
|
+
export declare function renderSpan(projectDir: string, config: DistributedRenderConfig, span: {
|
|
17
|
+
startSeconds: number;
|
|
18
|
+
endSeconds?: number;
|
|
19
|
+
}, outputPath: string): Promise<RenderSpanResult>;
|
|
@@ -337,6 +337,8 @@ export interface StageStallRule {
|
|
|
337
337
|
complete?: () => boolean;
|
|
338
338
|
/** Allowed silence once `complete()` holds; defaults to `noProgressMs`. */
|
|
339
339
|
tailMs?: number;
|
|
340
|
+
detail?: () => string | undefined;
|
|
341
|
+
attemptOpened?: () => void;
|
|
340
342
|
}
|
|
341
343
|
/**
|
|
342
344
|
* Classified like the per-call protocol timeout it replaces, so the capture retry ladder retries it.
|
|
@@ -346,7 +348,7 @@ export declare class RenderStageStalledError extends CaptureFailure {
|
|
|
346
348
|
readonly code = "RENDER_STAGE_STALLED";
|
|
347
349
|
readonly owner: "system";
|
|
348
350
|
readonly retryable: false;
|
|
349
|
-
constructor(phase: string, silentMs: number, progress: number);
|
|
351
|
+
constructor(phase: string, silentMs: number, progress: number, detail?: string);
|
|
350
352
|
}
|
|
351
353
|
/** Opens a capture attempt: a fresh no-progress window, and a signal the rule aborts when that window runs out. */
|
|
352
354
|
export type OpenStallAttempt = (parent?: AbortSignal) => AbortSignal;
|
|
@@ -106,10 +106,14 @@ export declare function applyRenderModeHints(alreadyForced: boolean, compiled: C
|
|
|
106
106
|
export declare function updateJobStatus(job: RenderJob, status: RenderStatus, stage: string, progress: number, onProgress?: ProgressCallback, stageProgress?: RenderStageProgress): void;
|
|
107
107
|
/** Capture-loop progress: the first frame, the last frame, and at most four reports a second between. */
|
|
108
108
|
export declare function reportFrameProgress(job: RenderJob, stage: string, progress: number, onProgress: ProgressCallback | undefined, done: number, total: number): void;
|
|
109
|
+
/** Frames ffmpeg has written for the source videos, 10% to 20%. */
|
|
110
|
+
export declare function reportExtractProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined): void;
|
|
109
111
|
/** Frames ffmpeg has encoded, from where capture left the bar up to 90%; same cadence as capture. */
|
|
110
112
|
export declare function reportEncodeProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined, from: number): void;
|
|
111
113
|
/** Seconds of the final file written, 90% to 99%: only a complete file reaches 100. */
|
|
112
114
|
export declare function reportAssembleProgress(job: RenderJob, done: number, total: number, onProgress: ProgressCallback | undefined): void;
|
|
115
|
+
export declare function forgetWorkerPhases(job: object): void;
|
|
116
|
+
export declare function describeWorkerPhases(job: object): string | undefined;
|
|
113
117
|
/** Browser warm-up before the first frame, from the parallel workers' phase events. */
|
|
114
118
|
export declare function reportWorkerStartup(job: RenderJob, progress: ParallelProgress, onProgress: ProgressCallback | undefined): void;
|
|
115
119
|
/**
|
|
@@ -84,6 +84,7 @@ export interface CaptureHdrStageResult {
|
|
|
84
84
|
captureDurationMs: number;
|
|
85
85
|
/** ffmpeg-reported encode duration; overlapped with capture. */
|
|
86
86
|
encodeMs: number;
|
|
87
|
+
encoderDrainWaitMs?: number;
|
|
87
88
|
warnings: CaptureWarning[];
|
|
88
89
|
}
|
|
89
90
|
export declare function runCaptureHdrStage(input: CaptureHdrStageInput): Promise<CaptureHdrStageResult>;
|
|
@@ -112,6 +112,7 @@ export type CaptureStreamingStageResult = {
|
|
|
112
112
|
success: true;
|
|
113
113
|
/** Wall-clock ms for the encode phase (overlapped with capture; from the encoder's own report). */
|
|
114
114
|
encodeMs: number;
|
|
115
|
+
encoderDrainWaitMs?: number;
|
|
115
116
|
probeSession: CaptureSession | null;
|
|
116
117
|
lastBrowserConsole: string[];
|
|
117
118
|
workerCount: number;
|
|
@@ -30,6 +30,7 @@
|
|
|
30
30
|
import { type CaptureVideoMetadataHint, type EngineConfig, type ExtractionResult, type FrameLookupTable, type HdrTransfer, type VideoExtractionFailureKind, type VideoColorSpace, classifyVideoExtractionError, extractAllVideoFrames } from "@hyperframes/engine";
|
|
31
31
|
import { type RenderJob } from "../../renderOrchestrator.js";
|
|
32
32
|
import { type CompositionMetadata } from "../shared.js";
|
|
33
|
+
import type { ProgressCallback } from "../../renderOrchestrator.js";
|
|
33
34
|
import type { ProducerLogger } from "../../../logger.js";
|
|
34
35
|
import { type ExtractionFailureMetadataV1 } from "../extractionFailureMetadata.js";
|
|
35
36
|
export interface ExtractVideosStageInput {
|
|
@@ -52,6 +53,7 @@ export interface ExtractVideosStageInput {
|
|
|
52
53
|
materializeSymlinks?: boolean;
|
|
53
54
|
deferRangeExtraction?: boolean;
|
|
54
55
|
urlByAbsentLocalPath?: ReadonlyMap<string, string>;
|
|
56
|
+
onProgress?: ProgressCallback;
|
|
55
57
|
}
|
|
56
58
|
export interface ExtractVideosStageResult {
|
|
57
59
|
/** Result of `extractAllVideoFrames`, or `null` if the composition has no videos. */
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CanvasResolution, type Fps, type FpsInput, type HfVfxCapture } from "@hyperframes/core";
|
|
2
|
-
import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
|
|
2
|
+
import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, explainDrawElementDisabled, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
|
|
3
3
|
import { type ProducerLogger } from "../logger.js";
|
|
4
4
|
import { type RenderOutputFormat } from "./render/renderFormat.js";
|
|
5
5
|
import { type RenderCaptureObservability, type RenderObservabilitySummary, type OpenStallAttempt, type StageStallRule } from "./render/observability.js";
|
|
@@ -200,6 +200,11 @@ export interface RenderPerfSummary {
|
|
|
200
200
|
* captured the most frames when parallel workers report separately.
|
|
201
201
|
*/
|
|
202
202
|
captureP50Ms?: number;
|
|
203
|
+
/** Per-frame capture phases, frame-weighted across sessions; encoder wait is FFmpeg back-pressure. */
|
|
204
|
+
captureSeekAvgMs?: number;
|
|
205
|
+
captureBeforeCaptureAvgMs?: number;
|
|
206
|
+
captureScreenshotAvgMs?: number;
|
|
207
|
+
encoderWaitAvgMs?: number;
|
|
203
208
|
/** Worst sub-composition timeline wait outcome across sessions. */
|
|
204
209
|
subTimelineWait?: SubTimelineWaitOutcome;
|
|
205
210
|
capturePeakMs?: number;
|
|
@@ -875,6 +880,12 @@ export declare function shouldPreferSingleWorkerDrawElement(args: {
|
|
|
875
880
|
*/
|
|
876
881
|
experimentalParallelDeOptIn: boolean;
|
|
877
882
|
}): boolean;
|
|
883
|
+
/** Why drawElement is off before capture; the compile stage's content gates are not config refusals. */
|
|
884
|
+
export declare function initialDeClampReason(args: {
|
|
885
|
+
useDrawElement: boolean;
|
|
886
|
+
deCompileGate: string | undefined;
|
|
887
|
+
config: Parameters<typeof explainDrawElementDisabled>[0];
|
|
888
|
+
}): string | undefined;
|
|
878
889
|
/**
|
|
879
890
|
* Plan the self-verify retry for an inverted render: the inversion bet on
|
|
880
891
|
* drawElement and lost, so the re-render returns to the pre-inversion parallel
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.223",
|
|
4
4
|
"description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"postcss": "^8.4.0",
|
|
36
36
|
"puppeteer": "~25.11.0",
|
|
37
37
|
"puppeteer-core": "^25.11.0",
|
|
38
|
-
"@hyperframes/
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/
|
|
42
|
-
"@hyperframes/
|
|
38
|
+
"@hyperframes/core": "0.8.223",
|
|
39
|
+
"@hyperframes/engine": "0.8.223",
|
|
40
|
+
"@hyperframes/lint": "0.8.223",
|
|
41
|
+
"@hyperframes/parsers": "0.8.223",
|
|
42
|
+
"@hyperframes/studio-server": "0.8.223"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^25.0.10",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"tsx": "^4.21.0",
|
|
49
49
|
"typescript": "^5.7.2",
|
|
50
50
|
"vitest": "^4.1.11",
|
|
51
|
-
"@hyperframes/aws-lambda": "0.8.
|
|
51
|
+
"@hyperframes/aws-lambda": "0.8.223"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|