@hyperframes/producer 0.8.192 → 0.8.194
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.d.ts +1 -0
- package/dist/distributed.js +321 -122
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +71 -65
- package/dist/index.js +580 -456
- package/dist/public-server.js +435 -323
- package/dist/services/distributed/plan.d.ts +2 -0
- package/dist/services/distributed/probeFacts.d.ts +4 -0
- package/dist/services/htmlCompiler.d.ts +2 -1
- package/dist/services/render/artifactTransaction.d.ts +3 -1
- package/dist/services/render/perfSummary.d.ts +6 -0
- package/dist/services/render/stages/audioStage.d.ts +3 -1
- package/dist/services/renderOrchestrator.d.ts +6 -2
- package/package.json +7 -7
package/dist/public-server.js
CHANGED
|
@@ -1384,18 +1384,9 @@ var RenderExecutionContext = class {
|
|
|
1384
1384
|
};
|
|
1385
1385
|
|
|
1386
1386
|
// src/services/render/artifactTransaction.ts
|
|
1387
|
-
import {
|
|
1388
|
-
closeSync as closeSync2,
|
|
1389
|
-
existsSync as existsSync5,
|
|
1390
|
-
fstatSync as fstatSync2,
|
|
1391
|
-
openSync as openSync2,
|
|
1392
|
-
readSync,
|
|
1393
|
-
readdirSync as readdirSync2,
|
|
1394
|
-
renameSync,
|
|
1395
|
-
rmSync as rmSync3
|
|
1396
|
-
} from "node:fs";
|
|
1387
|
+
import { closeSync as closeSync2, existsSync as existsSync5, fstatSync as fstatSync2, openSync as openSync2, readSync, readdirSync as readdirSync2, rmSync as rmSync3 } from "node:fs";
|
|
1397
1388
|
import { basename as basename3, dirname as dirname4, extname as extname2, join as join5, resolve as resolve4 } from "node:path";
|
|
1398
|
-
import { HLS_MASTER_PLAYLIST, HLS_VIDEO_PLAYLIST } from "@hyperframes/engine";
|
|
1389
|
+
import { HLS_MASTER_PLAYLIST, HLS_VIDEO_PLAYLIST, renameWithRetry } from "@hyperframes/engine";
|
|
1399
1390
|
|
|
1400
1391
|
// src/utils/ffprobe.ts
|
|
1401
1392
|
import {
|
|
@@ -1514,7 +1505,7 @@ function createRenderWorkDir(prefix, outputDir) {
|
|
|
1514
1505
|
// src/services/render/artifactTransaction.ts
|
|
1515
1506
|
var defaultFileSystem = {
|
|
1516
1507
|
existsSync: existsSync5,
|
|
1517
|
-
renameSync,
|
|
1508
|
+
renameSync: (source, destination) => renameWithRetry(source, destination),
|
|
1518
1509
|
rmSync: rmSync3
|
|
1519
1510
|
};
|
|
1520
1511
|
async function defaultArtifactDurationProbe(path) {
|
|
@@ -1592,8 +1583,11 @@ function assertDurationWithinTolerance(expectedSeconds, probedSeconds, tolerance
|
|
|
1592
1583
|
`Render artifact is truncated: expected ${expectedSeconds.toFixed(3)}s, probed ${probedSeconds.toFixed(3)}s (deficit ${deficit.toFixed(3)}s exceeds tolerance ${toleranceSeconds.toFixed(3)}s). Artifact: ${stagingPath}`
|
|
1593
1584
|
);
|
|
1594
1585
|
}
|
|
1586
|
+
function hasUsableFrameCount(frames) {
|
|
1587
|
+
return frames !== void 0 && Number.isFinite(frames) && frames > 0;
|
|
1588
|
+
}
|
|
1595
1589
|
function assertFrameCountWithinTolerance(expectedFrames, probedFrames, stagingPath, toleranceFrames = 1) {
|
|
1596
|
-
if (
|
|
1590
|
+
if (!hasUsableFrameCount(probedFrames)) {
|
|
1597
1591
|
return;
|
|
1598
1592
|
}
|
|
1599
1593
|
const shortfall = expectedFrames - probedFrames;
|
|
@@ -1613,9 +1607,10 @@ function assertSizeMatches(expected, probed, stagingPath) {
|
|
|
1613
1607
|
);
|
|
1614
1608
|
}
|
|
1615
1609
|
var ArtifactTransaction = class {
|
|
1616
|
-
constructor(destinationPath, kind, fileSystem = defaultFileSystem, durationProbe = defaultArtifactDurationProbe) {
|
|
1610
|
+
constructor(destinationPath, kind, fileSystem = defaultFileSystem, durationProbe = defaultArtifactDurationProbe, logger = defaultLogger) {
|
|
1617
1611
|
this.kind = kind;
|
|
1618
1612
|
this.fileSystem = fileSystem;
|
|
1613
|
+
this.logger = logger;
|
|
1619
1614
|
this.destinationPath = resolve4(destinationPath);
|
|
1620
1615
|
this.transactionDirectory = createSiblingTransactionDirectory(this.destinationPath);
|
|
1621
1616
|
this.stagingPath = join5(this.transactionDirectory, basename3(this.destinationPath));
|
|
@@ -1698,6 +1693,19 @@ var ArtifactTransaction = class {
|
|
|
1698
1693
|
probePath
|
|
1699
1694
|
);
|
|
1700
1695
|
if (expected.expectedFrames !== void 0) {
|
|
1696
|
+
if (!hasUsableFrameCount(probed.frames)) {
|
|
1697
|
+
try {
|
|
1698
|
+
this.logger.debug(
|
|
1699
|
+
"[Render] Frame-count validation skipped: no usable frame count was reported.",
|
|
1700
|
+
{
|
|
1701
|
+
event: "artifact_frame_count_unavailable",
|
|
1702
|
+
artifact: this.destinationPath,
|
|
1703
|
+
expectedFrames: expected.expectedFrames
|
|
1704
|
+
}
|
|
1705
|
+
);
|
|
1706
|
+
} catch {
|
|
1707
|
+
}
|
|
1708
|
+
}
|
|
1701
1709
|
assertFrameCountWithinTolerance(expected.expectedFrames, probed.frames, probePath);
|
|
1702
1710
|
}
|
|
1703
1711
|
assertSizeMatches(expected, probed, probePath);
|
|
@@ -1913,58 +1921,10 @@ import {
|
|
|
1913
1921
|
|
|
1914
1922
|
// src/services/render/captureStageError.ts
|
|
1915
1923
|
import { CaptureFailure, classifyCaptureFailure } from "@hyperframes/engine";
|
|
1916
|
-
var CaptureStageError = class extends CaptureFailure {
|
|
1917
|
-
browserConsole;
|
|
1918
|
-
constructor(input) {
|
|
1919
|
-
const classified = classifyCaptureFailure(input.cause);
|
|
1920
|
-
super({
|
|
1921
|
-
kind: classified.kind,
|
|
1922
|
-
message: normalizeErrorMessage(input.cause),
|
|
1923
|
-
cause: input.cause,
|
|
1924
|
-
workerDiagnostics: classified.workerDiagnostics
|
|
1925
|
-
});
|
|
1926
|
-
this.name = "CaptureStageError";
|
|
1927
|
-
this.browserConsole = input.browserConsole.slice();
|
|
1928
|
-
if (input.cause instanceof Error && input.cause.stack) {
|
|
1929
|
-
this.stack = input.cause.stack;
|
|
1930
|
-
}
|
|
1931
|
-
}
|
|
1932
|
-
};
|
|
1933
|
-
function wrapCaptureStageError(error, browserConsole) {
|
|
1934
|
-
if (error instanceof CaptureStageError || error instanceof EncoderInterruptedError) return error;
|
|
1935
|
-
return new CaptureStageError({ cause: error, browserConsole });
|
|
1936
|
-
}
|
|
1937
|
-
function getCaptureStageBrowserConsole(error) {
|
|
1938
|
-
if (error instanceof CaptureStageError) return error.browserConsole;
|
|
1939
|
-
return [];
|
|
1940
|
-
}
|
|
1941
1924
|
|
|
1942
|
-
// src/services/render/
|
|
1943
|
-
import {
|
|
1944
|
-
|
|
1945
|
-
blitRgba8OverRgb48le as blitRgba8OverRgb48le2,
|
|
1946
|
-
captureAlphaPng as captureAlphaPng2,
|
|
1947
|
-
decodePng as decodePng2,
|
|
1948
|
-
queryElementStacking as queryElementStacking2,
|
|
1949
|
-
removeDomLayerMask as removeDomLayerMask2
|
|
1950
|
-
} from "@hyperframes/engine";
|
|
1951
|
-
|
|
1952
|
-
// src/services/hdrCompositor.ts
|
|
1953
|
-
import { readSync as readSync2, closeSync as closeSync3 } from "fs";
|
|
1954
|
-
import { join as join6 } from "path";
|
|
1955
|
-
import {
|
|
1956
|
-
captureAlphaPng,
|
|
1957
|
-
applyDomLayerMask,
|
|
1958
|
-
removeDomLayerMask,
|
|
1959
|
-
decodePng,
|
|
1960
|
-
blitRgba8OverRgb48le,
|
|
1961
|
-
blitRgb48leRegion,
|
|
1962
|
-
groupIntoLayers,
|
|
1963
|
-
blitRgb48leAffine,
|
|
1964
|
-
parseTransformMatrix,
|
|
1965
|
-
convertTransfer,
|
|
1966
|
-
isVideoHiddenBeforeStreamStart
|
|
1967
|
-
} from "@hyperframes/engine";
|
|
1925
|
+
// src/services/render/perfSummary.ts
|
|
1926
|
+
import { arch, cpus, platform, totalmem } from "node:os";
|
|
1927
|
+
import { fpsToNumber as fpsToNumber3 } from "@hyperframes/core";
|
|
1968
1928
|
|
|
1969
1929
|
// src/services/render/hdrPerf.ts
|
|
1970
1930
|
function createHdrPerfCollector() {
|
|
@@ -2070,7 +2030,280 @@ function finalizeHdrPerf(perf) {
|
|
|
2070
2030
|
};
|
|
2071
2031
|
}
|
|
2072
2032
|
|
|
2033
|
+
// src/services/render/perfSummary.ts
|
|
2034
|
+
function worstSubTimelineWaitOutcome(perfs) {
|
|
2035
|
+
const outcomes = perfs.map((p) => p.subTimelineWaitOutcome).filter((o) => !!o);
|
|
2036
|
+
if (outcomes.length === 0) return void 0;
|
|
2037
|
+
if (outcomes.includes("script_failure")) return "script_failure";
|
|
2038
|
+
if (outcomes.includes("timeout")) return "timeout";
|
|
2039
|
+
return "ready";
|
|
2040
|
+
}
|
|
2041
|
+
function pushWorkerDedupPerfs(results, sink) {
|
|
2042
|
+
for (const r of results) {
|
|
2043
|
+
if (r.perf) sink.push(r.perf);
|
|
2044
|
+
}
|
|
2045
|
+
}
|
|
2046
|
+
function pushWorkerPageErrors(results, sink) {
|
|
2047
|
+
for (const result of results) {
|
|
2048
|
+
for (const line of result.pageErrorLines ?? []) if (!sink.includes(line)) sink.push(line);
|
|
2049
|
+
}
|
|
2050
|
+
}
|
|
2051
|
+
function withWorkerPageErrors(consoleLines, workerLines) {
|
|
2052
|
+
return [...consoleLines, ...workerLines.filter((line) => !consoleLines.includes(line))];
|
|
2053
|
+
}
|
|
2054
|
+
function roundDb(value) {
|
|
2055
|
+
return value === void 0 ? void 0 : Math.round(Math.min(value, 999) * 10) / 10;
|
|
2056
|
+
}
|
|
2057
|
+
function aggregateDrawElement(perfs, de) {
|
|
2058
|
+
if (perfs.length === 0) return void 0;
|
|
2059
|
+
const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
|
|
2060
|
+
const gateReasons = [
|
|
2061
|
+
...new Set(
|
|
2062
|
+
[de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
|
|
2063
|
+
)
|
|
2064
|
+
].sort();
|
|
2065
|
+
const gpuRenderers = [
|
|
2066
|
+
...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
|
|
2067
|
+
].sort();
|
|
2068
|
+
const drain = de.drainStats;
|
|
2069
|
+
return {
|
|
2070
|
+
mode: modes.join("|") || "unknown",
|
|
2071
|
+
compileGate: de.compileGate,
|
|
2072
|
+
clampReason: de.clampReason,
|
|
2073
|
+
workerInversion: de.workerInversion ?? "none",
|
|
2074
|
+
preInversionWorkers: de.preInversionWorkers,
|
|
2075
|
+
compositionElementCount: de.compositionElementCount,
|
|
2076
|
+
compositionElementCountSource: de.compositionElementCountSource,
|
|
2077
|
+
compositionElementTags: de.compositionElementTags,
|
|
2078
|
+
arollVideoCount: de.arollVideoCount,
|
|
2079
|
+
heygenVideoCount: de.heygenVideoCount,
|
|
2080
|
+
adaptersUsed: de.adaptersUsed,
|
|
2081
|
+
audioCount: de.audioCount,
|
|
2082
|
+
imageCount: de.imageCount,
|
|
2083
|
+
subCompositionCount: de.subCompositionCount,
|
|
2084
|
+
audioGroupCount: de.audioGroupCount,
|
|
2085
|
+
colorGradingCount: de.colorGradingCount,
|
|
2086
|
+
hasLut: de.hasLut,
|
|
2087
|
+
rootBodyMismatch: de.rootBodyMismatch,
|
|
2088
|
+
rootBodyDeltaPxBucket: de.rootBodyDeltaPxBucket,
|
|
2089
|
+
vfxHostCount: de.vfxHostCount,
|
|
2090
|
+
vfxCapture: de.vfxCapture,
|
|
2091
|
+
vfxTypes: de.vfxTypes,
|
|
2092
|
+
shortBand: de.shortBand,
|
|
2093
|
+
parallelRouter: de.parallelRouter ?? "none",
|
|
2094
|
+
preRouterWorkers: de.preRouterWorkers,
|
|
2095
|
+
gateReason: gateReasons.length > 0 ? gateReasons.join("|") : void 0,
|
|
2096
|
+
gpuRenderer: gpuRenderers.length > 0 ? gpuRenderers.join("|") : void 0,
|
|
2097
|
+
workerEncode: perfs.some((p) => p.deWorkerEncode),
|
|
2098
|
+
verifyArmed: perfs.reduce((sum, p) => sum + (p.deVerifyArmed ?? 0), 0),
|
|
2099
|
+
verifyChecked: drain?.verifyChecked ?? 0,
|
|
2100
|
+
verifyMinDb: roundDb(drain?.verifyMinDb),
|
|
2101
|
+
verifyInitMs: perfs.reduce((sum, p) => sum + (p.deVerifyInitMs ?? 0), 0),
|
|
2102
|
+
selfVerifyFallback: de.selfVerifyFallback,
|
|
2103
|
+
fallbackReason: de.fallbackReason,
|
|
2104
|
+
fallbackFailedDb: roundDb(de.fallbackFailedDb),
|
|
2105
|
+
fallbackFrameIndex: de.fallbackFrameIndex,
|
|
2106
|
+
fallbackThresholdDb: roundDb(de.fallbackThresholdDb),
|
|
2107
|
+
blankSuspects: drain?.blankSuspects ?? 0,
|
|
2108
|
+
blankDeterministicAccepts: drain?.blankDeterministicAccepts ?? 0,
|
|
2109
|
+
blankRecaptures: drain?.blankRecaptures ?? 0,
|
|
2110
|
+
boundaryFrames: perfs.reduce((sum, p) => sum + (p.deBoundaryFrames ?? 0), 0),
|
|
2111
|
+
ncprFallbacks: perfs.reduce((sum, p) => sum + (p.deNcprFallbacks ?? 0), 0),
|
|
2112
|
+
frameTimeouts: perfs.reduce((sum, p) => sum + (p.deFrameTimeouts ?? 0), 0)
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
function maxDefined(values) {
|
|
2116
|
+
const present = values.filter((v) => typeof v === "number");
|
|
2117
|
+
return present.length > 0 ? Math.max(...present) : void 0;
|
|
2118
|
+
}
|
|
2119
|
+
function aggregateChromeMemory(perfs) {
|
|
2120
|
+
const sampled = perfs.filter((p) => (p.chromeMemorySamples ?? 0) > 0);
|
|
2121
|
+
if (sampled.length === 0) return void 0;
|
|
2122
|
+
return {
|
|
2123
|
+
browserRssPeakMb: maxDefined(sampled.map((p) => p.chromeBrowserRssPeakMb)),
|
|
2124
|
+
rendererRssPeakMb: maxDefined(sampled.map((p) => p.chromeRendererRssPeakMb)),
|
|
2125
|
+
// Last samples are per session; summing approximates the whole fleet's
|
|
2126
|
+
// footprint at the end of capture (workers run concurrently).
|
|
2127
|
+
rssLastMb: sampled.reduce((sum, p) => sum + (p.chromeRssLastMb ?? 0), 0),
|
|
2128
|
+
gpuProcessSeenLastSample: sampled.some((p) => p.chromeGpuProcessSeenLastSample === true),
|
|
2129
|
+
samples: sampled.reduce((sum, p) => sum + (p.chromeMemorySamples ?? 0), 0)
|
|
2130
|
+
};
|
|
2131
|
+
}
|
|
2132
|
+
function aggregateDedup(perfs) {
|
|
2133
|
+
if (perfs.length === 0) return void 0;
|
|
2134
|
+
const armed = perfs.some((p) => p.staticDedupArmed);
|
|
2135
|
+
const skipReasons = armed ? [] : [
|
|
2136
|
+
...new Set(perfs.map((p) => p.staticDedupSkipReason).filter((r) => !!r))
|
|
2137
|
+
].sort();
|
|
2138
|
+
const verificationPerfs = perfs.filter((perf) => perf.staticDedupVerificationOutcome);
|
|
2139
|
+
const verificationOutcomes = [
|
|
2140
|
+
...new Set(
|
|
2141
|
+
verificationPerfs.map((perf) => perf.staticDedupVerificationOutcome).filter((outcome) => outcome != null)
|
|
2142
|
+
)
|
|
2143
|
+
].sort();
|
|
2144
|
+
return {
|
|
2145
|
+
enabled: perfs.some((p) => p.staticDedupEnabled),
|
|
2146
|
+
armed,
|
|
2147
|
+
predictedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupPredicted ?? 0), 0),
|
|
2148
|
+
reusedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupReused ?? 0), 0),
|
|
2149
|
+
skipReason: skipReasons.length > 0 ? skipReasons.join("|") : void 0,
|
|
2150
|
+
...verificationPerfs.length === 0 ? {} : {
|
|
2151
|
+
verifiedFrames: verificationPerfs.reduce(
|
|
2152
|
+
(sum, perf) => sum + (perf.staticDedupVerified ?? 0),
|
|
2153
|
+
0
|
|
2154
|
+
),
|
|
2155
|
+
verificationOutcomes,
|
|
2156
|
+
plannedRuns: verificationPerfs.reduce(
|
|
2157
|
+
(sum, perf) => sum + (perf.staticDedupVerificationPlannedRuns ?? 0),
|
|
2158
|
+
0
|
|
2159
|
+
),
|
|
2160
|
+
completedRuns: verificationPerfs.reduce(
|
|
2161
|
+
(sum, perf) => sum + (perf.staticDedupVerificationCompletedRuns ?? 0),
|
|
2162
|
+
0
|
|
2163
|
+
),
|
|
2164
|
+
screenshots: verificationPerfs.reduce(
|
|
2165
|
+
(sum, perf) => sum + (perf.staticDedupVerificationScreenshots ?? 0),
|
|
2166
|
+
0
|
|
2167
|
+
),
|
|
2168
|
+
seeks: verificationPerfs.reduce(
|
|
2169
|
+
(sum, perf) => sum + (perf.staticDedupVerificationSeeks ?? 0),
|
|
2170
|
+
0
|
|
2171
|
+
),
|
|
2172
|
+
comparisons: verificationPerfs.reduce(
|
|
2173
|
+
(sum, perf) => sum + (perf.staticDedupVerificationComparisons ?? 0),
|
|
2174
|
+
0
|
|
2175
|
+
),
|
|
2176
|
+
verificationElapsedMs: verificationPerfs.reduce(
|
|
2177
|
+
(sum, perf) => sum + (perf.staticDedupVerificationElapsedMs ?? 0),
|
|
2178
|
+
0
|
|
2179
|
+
)
|
|
2180
|
+
}
|
|
2181
|
+
};
|
|
2182
|
+
}
|
|
2183
|
+
function aggregateBeginFrameReuse(perfs) {
|
|
2184
|
+
const noDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameNoDamage ?? 0), 0);
|
|
2185
|
+
const hasDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameHasDamage ?? 0), 0);
|
|
2186
|
+
if (noDamageFrames + hasDamageFrames === 0) return void 0;
|
|
2187
|
+
return { noDamageFrames, hasDamageFrames };
|
|
2188
|
+
}
|
|
2189
|
+
function buildRenderPerfSummary(input) {
|
|
2190
|
+
return {
|
|
2191
|
+
renderId: input.job.id,
|
|
2192
|
+
totalElapsedMs: input.totalElapsedMs,
|
|
2193
|
+
// RenderPerfSummary surfaces fps as a decimal because it lands in JSON
|
|
2194
|
+
// payloads (CLI telemetry, regression-harness reports) where a single
|
|
2195
|
+
// number is friendlier than `{num,den}`. Callers needing the rational
|
|
2196
|
+
// back can read `job.config.fps`.
|
|
2197
|
+
fps: fpsToNumber3(input.job.config.fps),
|
|
2198
|
+
quality: input.job.config.quality,
|
|
2199
|
+
workers: input.workerCount,
|
|
2200
|
+
workerSizing: input.workerSizing,
|
|
2201
|
+
chunkedEncode: input.enableChunkedEncode,
|
|
2202
|
+
chunkSizeFrames: input.enableChunkedEncode ? input.chunkedEncodeSize : null,
|
|
2203
|
+
compositionDurationSeconds: input.compositionDurationSeconds,
|
|
2204
|
+
totalFrames: input.totalFrames,
|
|
2205
|
+
resolution: { width: input.outputWidth, height: input.outputHeight },
|
|
2206
|
+
videoCount: input.videoCount,
|
|
2207
|
+
audioCount: input.audioCount,
|
|
2208
|
+
stages: input.perfStages,
|
|
2209
|
+
videoExtractBreakdown: input.videoExtractBreakdown,
|
|
2210
|
+
tmpPeakBytes: input.tmpPeakBytes,
|
|
2211
|
+
captureCalibration: input.captureCalibration ? {
|
|
2212
|
+
sampledFrames: input.captureCalibration.samples.map((sample) => sample.frameIndex),
|
|
2213
|
+
p95Ms: input.captureCalibration.estimate.p95Ms,
|
|
2214
|
+
multiplier: input.captureCalibration.estimate.multiplier,
|
|
2215
|
+
reasons: input.captureCalibration.estimate.reasons
|
|
2216
|
+
} : void 0,
|
|
2217
|
+
captureAttempts: input.captureAttempts.length > 0 ? input.captureAttempts : void 0,
|
|
2218
|
+
hdrDiagnostics: input.hdrDiagnostics.videoExtractionFailures > 0 || input.hdrDiagnostics.imageDecodeFailures > 0 ? { ...input.hdrDiagnostics } : void 0,
|
|
2219
|
+
hdrPerf: input.hdrPerf ? finalizeHdrPerf(input.hdrPerf) : void 0,
|
|
2220
|
+
observability: input.observability,
|
|
2221
|
+
captureAvgMs: input.totalFrames > 0 ? Math.round(
|
|
2222
|
+
(input.perfStages.captureFrameMs ?? input.perfStages.captureMs ?? 0) / input.totalFrames
|
|
2223
|
+
) : void 0,
|
|
2224
|
+
subTimelineWait: worstSubTimelineWaitOutcome(input.dedupPerfs),
|
|
2225
|
+
captureP50Ms: (() => {
|
|
2226
|
+
const withSamples = input.dedupPerfs.filter((p) => (p.p50TotalMs ?? 0) > 0);
|
|
2227
|
+
if (withSamples.length === 0) return void 0;
|
|
2228
|
+
return withSamples.reduce((a, b) => b.frames > a.frames ? b : a).p50TotalMs;
|
|
2229
|
+
})(),
|
|
2230
|
+
peakRssMb: Math.round(input.peakRssBytes / (1024 * 1024)),
|
|
2231
|
+
peakHeapUsedMb: Math.round(input.peakHeapUsedBytes / (1024 * 1024)),
|
|
2232
|
+
staticDedup: aggregateDedup(input.dedupPerfs),
|
|
2233
|
+
chromeMemory: aggregateChromeMemory(input.dedupPerfs),
|
|
2234
|
+
beginFrameReuse: aggregateBeginFrameReuse(input.dedupPerfs),
|
|
2235
|
+
drawElement: aggregateDrawElement(
|
|
2236
|
+
input.dedupPerfs,
|
|
2237
|
+
input.drawElement ?? { selfVerifyFallback: false }
|
|
2238
|
+
),
|
|
2239
|
+
host: {
|
|
2240
|
+
platform: platform(),
|
|
2241
|
+
arch: arch(),
|
|
2242
|
+
cpuCount: cpus().length,
|
|
2243
|
+
totalMemMb: Math.round(totalmem() / (1024 * 1024)),
|
|
2244
|
+
nodeVersion: process.version,
|
|
2245
|
+
gpuDisabled: input.gpuDisabled
|
|
2246
|
+
}
|
|
2247
|
+
};
|
|
2248
|
+
}
|
|
2249
|
+
|
|
2250
|
+
// src/services/render/captureStageError.ts
|
|
2251
|
+
var CaptureStageError = class extends CaptureFailure {
|
|
2252
|
+
browserConsole;
|
|
2253
|
+
constructor(input) {
|
|
2254
|
+
const classified = classifyCaptureFailure(input.cause);
|
|
2255
|
+
super({
|
|
2256
|
+
kind: classified.kind,
|
|
2257
|
+
message: normalizeErrorMessage(input.cause),
|
|
2258
|
+
cause: input.cause,
|
|
2259
|
+
workerDiagnostics: classified.workerDiagnostics,
|
|
2260
|
+
pageErrorLines: classified.pageErrorLines
|
|
2261
|
+
});
|
|
2262
|
+
this.name = "CaptureStageError";
|
|
2263
|
+
this.browserConsole = withWorkerPageErrors(input.browserConsole, [
|
|
2264
|
+
...classified.pageErrorLines
|
|
2265
|
+
]);
|
|
2266
|
+
if (input.cause instanceof Error && input.cause.stack) {
|
|
2267
|
+
this.stack = input.cause.stack;
|
|
2268
|
+
}
|
|
2269
|
+
}
|
|
2270
|
+
};
|
|
2271
|
+
function wrapCaptureStageError(error, browserConsole) {
|
|
2272
|
+
if (error instanceof CaptureStageError || error instanceof EncoderInterruptedError) return error;
|
|
2273
|
+
return new CaptureStageError({ cause: error, browserConsole });
|
|
2274
|
+
}
|
|
2275
|
+
function getCaptureStageBrowserConsole(error) {
|
|
2276
|
+
if (error instanceof CaptureStageError) return error.browserConsole;
|
|
2277
|
+
if (error instanceof CaptureFailure) return [...error.pageErrorLines];
|
|
2278
|
+
return [];
|
|
2279
|
+
}
|
|
2280
|
+
|
|
2281
|
+
// src/services/render/stages/captureHdrFrameShared.ts
|
|
2282
|
+
import {
|
|
2283
|
+
applyDomLayerMask as applyDomLayerMask2,
|
|
2284
|
+
blitRgba8OverRgb48le as blitRgba8OverRgb48le2,
|
|
2285
|
+
captureAlphaPng as captureAlphaPng2,
|
|
2286
|
+
decodePng as decodePng2,
|
|
2287
|
+
queryElementStacking as queryElementStacking2,
|
|
2288
|
+
removeDomLayerMask as removeDomLayerMask2
|
|
2289
|
+
} from "@hyperframes/engine";
|
|
2290
|
+
|
|
2073
2291
|
// src/services/hdrCompositor.ts
|
|
2292
|
+
import { readSync as readSync2, closeSync as closeSync3 } from "fs";
|
|
2293
|
+
import { join as join6 } from "path";
|
|
2294
|
+
import {
|
|
2295
|
+
captureAlphaPng,
|
|
2296
|
+
applyDomLayerMask,
|
|
2297
|
+
removeDomLayerMask,
|
|
2298
|
+
decodePng,
|
|
2299
|
+
blitRgba8OverRgb48le,
|
|
2300
|
+
blitRgb48leRegion,
|
|
2301
|
+
groupIntoLayers,
|
|
2302
|
+
blitRgb48leAffine,
|
|
2303
|
+
parseTransformMatrix,
|
|
2304
|
+
convertTransfer,
|
|
2305
|
+
isVideoHiddenBeforeStreamStart
|
|
2306
|
+
} from "@hyperframes/engine";
|
|
2074
2307
|
function countNonZeroAlpha(rgba) {
|
|
2075
2308
|
let n = 0;
|
|
2076
2309
|
for (let p = 3; p < rgba.length; p += 4) {
|
|
@@ -2537,7 +2770,7 @@ import {
|
|
|
2537
2770
|
resolveVideoExtractionWindow,
|
|
2538
2771
|
runFfmpeg
|
|
2539
2772
|
} from "@hyperframes/engine";
|
|
2540
|
-
import { fpsToFfmpegArg, fpsToNumber as
|
|
2773
|
+
import { fpsToFfmpegArg, fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
|
|
2541
2774
|
var NO_FOLLOW_FLAG = constants2.O_NOFOLLOW ?? 0;
|
|
2542
2775
|
function tempDirSafePrefix(id) {
|
|
2543
2776
|
const safe = id.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 80);
|
|
@@ -2773,7 +3006,7 @@ async function extractHdrVideoFrames(args) {
|
|
|
2773
3006
|
const { estimatedBytes, budgetBytes } = assertHdrExtractionDiskHeadroom(
|
|
2774
3007
|
framesDir,
|
|
2775
3008
|
plannedVideos,
|
|
2776
|
-
|
|
3009
|
+
fpsToNumber4(job.config.fps),
|
|
2777
3010
|
log
|
|
2778
3011
|
);
|
|
2779
3012
|
const releaseReservation = reserveHdrExtractionBytes(estimatedBytes, budgetBytes);
|
|
@@ -3226,222 +3459,12 @@ import {
|
|
|
3226
3459
|
prepareCaptureSessionForReuse,
|
|
3227
3460
|
spawnStreamingEncoder
|
|
3228
3461
|
} from "@hyperframes/engine";
|
|
3229
|
-
|
|
3230
|
-
// src/services/render/perfSummary.ts
|
|
3231
|
-
import { arch, cpus, platform, totalmem } from "node:os";
|
|
3232
|
-
import { fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
|
|
3233
|
-
function worstSubTimelineWaitOutcome(perfs) {
|
|
3234
|
-
const outcomes = perfs.map((p) => p.subTimelineWaitOutcome).filter((o) => !!o);
|
|
3235
|
-
if (outcomes.length === 0) return void 0;
|
|
3236
|
-
if (outcomes.includes("script_failure")) return "script_failure";
|
|
3237
|
-
if (outcomes.includes("timeout")) return "timeout";
|
|
3238
|
-
return "ready";
|
|
3239
|
-
}
|
|
3240
|
-
function pushWorkerDedupPerfs(results, sink) {
|
|
3241
|
-
for (const r of results) {
|
|
3242
|
-
if (r.perf) sink.push(r.perf);
|
|
3243
|
-
}
|
|
3244
|
-
}
|
|
3245
|
-
function roundDb(value) {
|
|
3246
|
-
return value === void 0 ? void 0 : Math.round(Math.min(value, 999) * 10) / 10;
|
|
3247
|
-
}
|
|
3248
|
-
function aggregateDrawElement(perfs, de) {
|
|
3249
|
-
if (perfs.length === 0) return void 0;
|
|
3250
|
-
const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
|
|
3251
|
-
const gateReasons = [
|
|
3252
|
-
...new Set(
|
|
3253
|
-
[de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
|
|
3254
|
-
)
|
|
3255
|
-
].sort();
|
|
3256
|
-
const gpuRenderers = [
|
|
3257
|
-
...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
|
|
3258
|
-
].sort();
|
|
3259
|
-
const drain = de.drainStats;
|
|
3260
|
-
return {
|
|
3261
|
-
mode: modes.join("|") || "unknown",
|
|
3262
|
-
compileGate: de.compileGate,
|
|
3263
|
-
clampReason: de.clampReason,
|
|
3264
|
-
workerInversion: de.workerInversion ?? "none",
|
|
3265
|
-
preInversionWorkers: de.preInversionWorkers,
|
|
3266
|
-
compositionElementCount: de.compositionElementCount,
|
|
3267
|
-
compositionElementCountSource: de.compositionElementCountSource,
|
|
3268
|
-
compositionElementTags: de.compositionElementTags,
|
|
3269
|
-
arollVideoCount: de.arollVideoCount,
|
|
3270
|
-
heygenVideoCount: de.heygenVideoCount,
|
|
3271
|
-
adaptersUsed: de.adaptersUsed,
|
|
3272
|
-
audioCount: de.audioCount,
|
|
3273
|
-
imageCount: de.imageCount,
|
|
3274
|
-
subCompositionCount: de.subCompositionCount,
|
|
3275
|
-
audioGroupCount: de.audioGroupCount,
|
|
3276
|
-
colorGradingCount: de.colorGradingCount,
|
|
3277
|
-
hasLut: de.hasLut,
|
|
3278
|
-
rootBodyMismatch: de.rootBodyMismatch,
|
|
3279
|
-
rootBodyDeltaPxBucket: de.rootBodyDeltaPxBucket,
|
|
3280
|
-
vfxHostCount: de.vfxHostCount,
|
|
3281
|
-
vfxCapture: de.vfxCapture,
|
|
3282
|
-
vfxTypes: de.vfxTypes,
|
|
3283
|
-
shortBand: de.shortBand,
|
|
3284
|
-
parallelRouter: de.parallelRouter ?? "none",
|
|
3285
|
-
preRouterWorkers: de.preRouterWorkers,
|
|
3286
|
-
gateReason: gateReasons.length > 0 ? gateReasons.join("|") : void 0,
|
|
3287
|
-
gpuRenderer: gpuRenderers.length > 0 ? gpuRenderers.join("|") : void 0,
|
|
3288
|
-
workerEncode: perfs.some((p) => p.deWorkerEncode),
|
|
3289
|
-
verifyArmed: perfs.reduce((sum, p) => sum + (p.deVerifyArmed ?? 0), 0),
|
|
3290
|
-
verifyChecked: drain?.verifyChecked ?? 0,
|
|
3291
|
-
verifyMinDb: roundDb(drain?.verifyMinDb),
|
|
3292
|
-
verifyInitMs: perfs.reduce((sum, p) => sum + (p.deVerifyInitMs ?? 0), 0),
|
|
3293
|
-
selfVerifyFallback: de.selfVerifyFallback,
|
|
3294
|
-
fallbackReason: de.fallbackReason,
|
|
3295
|
-
fallbackFailedDb: roundDb(de.fallbackFailedDb),
|
|
3296
|
-
fallbackFrameIndex: de.fallbackFrameIndex,
|
|
3297
|
-
fallbackThresholdDb: roundDb(de.fallbackThresholdDb),
|
|
3298
|
-
blankSuspects: drain?.blankSuspects ?? 0,
|
|
3299
|
-
blankDeterministicAccepts: drain?.blankDeterministicAccepts ?? 0,
|
|
3300
|
-
blankRecaptures: drain?.blankRecaptures ?? 0,
|
|
3301
|
-
boundaryFrames: perfs.reduce((sum, p) => sum + (p.deBoundaryFrames ?? 0), 0),
|
|
3302
|
-
ncprFallbacks: perfs.reduce((sum, p) => sum + (p.deNcprFallbacks ?? 0), 0),
|
|
3303
|
-
frameTimeouts: perfs.reduce((sum, p) => sum + (p.deFrameTimeouts ?? 0), 0)
|
|
3304
|
-
};
|
|
3305
|
-
}
|
|
3306
|
-
function maxDefined(values) {
|
|
3307
|
-
const present = values.filter((v) => typeof v === "number");
|
|
3308
|
-
return present.length > 0 ? Math.max(...present) : void 0;
|
|
3309
|
-
}
|
|
3310
|
-
function aggregateChromeMemory(perfs) {
|
|
3311
|
-
const sampled = perfs.filter((p) => (p.chromeMemorySamples ?? 0) > 0);
|
|
3312
|
-
if (sampled.length === 0) return void 0;
|
|
3313
|
-
return {
|
|
3314
|
-
browserRssPeakMb: maxDefined(sampled.map((p) => p.chromeBrowserRssPeakMb)),
|
|
3315
|
-
rendererRssPeakMb: maxDefined(sampled.map((p) => p.chromeRendererRssPeakMb)),
|
|
3316
|
-
// Last samples are per session; summing approximates the whole fleet's
|
|
3317
|
-
// footprint at the end of capture (workers run concurrently).
|
|
3318
|
-
rssLastMb: sampled.reduce((sum, p) => sum + (p.chromeRssLastMb ?? 0), 0),
|
|
3319
|
-
gpuProcessSeenLastSample: sampled.some((p) => p.chromeGpuProcessSeenLastSample === true),
|
|
3320
|
-
samples: sampled.reduce((sum, p) => sum + (p.chromeMemorySamples ?? 0), 0)
|
|
3321
|
-
};
|
|
3322
|
-
}
|
|
3323
|
-
function aggregateDedup(perfs) {
|
|
3324
|
-
if (perfs.length === 0) return void 0;
|
|
3325
|
-
const armed = perfs.some((p) => p.staticDedupArmed);
|
|
3326
|
-
const skipReasons = armed ? [] : [
|
|
3327
|
-
...new Set(perfs.map((p) => p.staticDedupSkipReason).filter((r) => !!r))
|
|
3328
|
-
].sort();
|
|
3329
|
-
const verificationPerfs = perfs.filter((perf) => perf.staticDedupVerificationOutcome);
|
|
3330
|
-
const verificationOutcomes = [
|
|
3331
|
-
...new Set(
|
|
3332
|
-
verificationPerfs.map((perf) => perf.staticDedupVerificationOutcome).filter((outcome) => outcome != null)
|
|
3333
|
-
)
|
|
3334
|
-
].sort();
|
|
3335
|
-
return {
|
|
3336
|
-
enabled: perfs.some((p) => p.staticDedupEnabled),
|
|
3337
|
-
armed,
|
|
3338
|
-
predictedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupPredicted ?? 0), 0),
|
|
3339
|
-
reusedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupReused ?? 0), 0),
|
|
3340
|
-
skipReason: skipReasons.length > 0 ? skipReasons.join("|") : void 0,
|
|
3341
|
-
...verificationPerfs.length === 0 ? {} : {
|
|
3342
|
-
verifiedFrames: verificationPerfs.reduce(
|
|
3343
|
-
(sum, perf) => sum + (perf.staticDedupVerified ?? 0),
|
|
3344
|
-
0
|
|
3345
|
-
),
|
|
3346
|
-
verificationOutcomes,
|
|
3347
|
-
plannedRuns: verificationPerfs.reduce(
|
|
3348
|
-
(sum, perf) => sum + (perf.staticDedupVerificationPlannedRuns ?? 0),
|
|
3349
|
-
0
|
|
3350
|
-
),
|
|
3351
|
-
completedRuns: verificationPerfs.reduce(
|
|
3352
|
-
(sum, perf) => sum + (perf.staticDedupVerificationCompletedRuns ?? 0),
|
|
3353
|
-
0
|
|
3354
|
-
),
|
|
3355
|
-
screenshots: verificationPerfs.reduce(
|
|
3356
|
-
(sum, perf) => sum + (perf.staticDedupVerificationScreenshots ?? 0),
|
|
3357
|
-
0
|
|
3358
|
-
),
|
|
3359
|
-
seeks: verificationPerfs.reduce(
|
|
3360
|
-
(sum, perf) => sum + (perf.staticDedupVerificationSeeks ?? 0),
|
|
3361
|
-
0
|
|
3362
|
-
),
|
|
3363
|
-
comparisons: verificationPerfs.reduce(
|
|
3364
|
-
(sum, perf) => sum + (perf.staticDedupVerificationComparisons ?? 0),
|
|
3365
|
-
0
|
|
3366
|
-
),
|
|
3367
|
-
verificationElapsedMs: verificationPerfs.reduce(
|
|
3368
|
-
(sum, perf) => sum + (perf.staticDedupVerificationElapsedMs ?? 0),
|
|
3369
|
-
0
|
|
3370
|
-
)
|
|
3371
|
-
}
|
|
3372
|
-
};
|
|
3373
|
-
}
|
|
3374
|
-
function aggregateBeginFrameReuse(perfs) {
|
|
3375
|
-
const noDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameNoDamage ?? 0), 0);
|
|
3376
|
-
const hasDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameHasDamage ?? 0), 0);
|
|
3377
|
-
if (noDamageFrames + hasDamageFrames === 0) return void 0;
|
|
3378
|
-
return { noDamageFrames, hasDamageFrames };
|
|
3379
|
-
}
|
|
3380
|
-
function buildRenderPerfSummary(input) {
|
|
3381
|
-
return {
|
|
3382
|
-
renderId: input.job.id,
|
|
3383
|
-
totalElapsedMs: input.totalElapsedMs,
|
|
3384
|
-
// RenderPerfSummary surfaces fps as a decimal because it lands in JSON
|
|
3385
|
-
// payloads (CLI telemetry, regression-harness reports) where a single
|
|
3386
|
-
// number is friendlier than `{num,den}`. Callers needing the rational
|
|
3387
|
-
// back can read `job.config.fps`.
|
|
3388
|
-
fps: fpsToNumber4(input.job.config.fps),
|
|
3389
|
-
quality: input.job.config.quality,
|
|
3390
|
-
workers: input.workerCount,
|
|
3391
|
-
workerSizing: input.workerSizing,
|
|
3392
|
-
chunkedEncode: input.enableChunkedEncode,
|
|
3393
|
-
chunkSizeFrames: input.enableChunkedEncode ? input.chunkedEncodeSize : null,
|
|
3394
|
-
compositionDurationSeconds: input.compositionDurationSeconds,
|
|
3395
|
-
totalFrames: input.totalFrames,
|
|
3396
|
-
resolution: { width: input.outputWidth, height: input.outputHeight },
|
|
3397
|
-
videoCount: input.videoCount,
|
|
3398
|
-
audioCount: input.audioCount,
|
|
3399
|
-
stages: input.perfStages,
|
|
3400
|
-
videoExtractBreakdown: input.videoExtractBreakdown,
|
|
3401
|
-
tmpPeakBytes: input.tmpPeakBytes,
|
|
3402
|
-
captureCalibration: input.captureCalibration ? {
|
|
3403
|
-
sampledFrames: input.captureCalibration.samples.map((sample) => sample.frameIndex),
|
|
3404
|
-
p95Ms: input.captureCalibration.estimate.p95Ms,
|
|
3405
|
-
multiplier: input.captureCalibration.estimate.multiplier,
|
|
3406
|
-
reasons: input.captureCalibration.estimate.reasons
|
|
3407
|
-
} : void 0,
|
|
3408
|
-
captureAttempts: input.captureAttempts.length > 0 ? input.captureAttempts : void 0,
|
|
3409
|
-
hdrDiagnostics: input.hdrDiagnostics.videoExtractionFailures > 0 || input.hdrDiagnostics.imageDecodeFailures > 0 ? { ...input.hdrDiagnostics } : void 0,
|
|
3410
|
-
hdrPerf: input.hdrPerf ? finalizeHdrPerf(input.hdrPerf) : void 0,
|
|
3411
|
-
observability: input.observability,
|
|
3412
|
-
captureAvgMs: input.totalFrames > 0 ? Math.round(
|
|
3413
|
-
(input.perfStages.captureFrameMs ?? input.perfStages.captureMs ?? 0) / input.totalFrames
|
|
3414
|
-
) : void 0,
|
|
3415
|
-
subTimelineWait: worstSubTimelineWaitOutcome(input.dedupPerfs),
|
|
3416
|
-
captureP50Ms: (() => {
|
|
3417
|
-
const withSamples = input.dedupPerfs.filter((p) => (p.p50TotalMs ?? 0) > 0);
|
|
3418
|
-
if (withSamples.length === 0) return void 0;
|
|
3419
|
-
return withSamples.reduce((a, b) => b.frames > a.frames ? b : a).p50TotalMs;
|
|
3420
|
-
})(),
|
|
3421
|
-
peakRssMb: Math.round(input.peakRssBytes / (1024 * 1024)),
|
|
3422
|
-
peakHeapUsedMb: Math.round(input.peakHeapUsedBytes / (1024 * 1024)),
|
|
3423
|
-
staticDedup: aggregateDedup(input.dedupPerfs),
|
|
3424
|
-
chromeMemory: aggregateChromeMemory(input.dedupPerfs),
|
|
3425
|
-
beginFrameReuse: aggregateBeginFrameReuse(input.dedupPerfs),
|
|
3426
|
-
drawElement: aggregateDrawElement(
|
|
3427
|
-
input.dedupPerfs,
|
|
3428
|
-
input.drawElement ?? { selfVerifyFallback: false }
|
|
3429
|
-
),
|
|
3430
|
-
host: {
|
|
3431
|
-
platform: platform(),
|
|
3432
|
-
arch: arch(),
|
|
3433
|
-
cpuCount: cpus().length,
|
|
3434
|
-
totalMemMb: Math.round(totalmem() / (1024 * 1024)),
|
|
3435
|
-
nodeVersion: process.version,
|
|
3436
|
-
gpuDisabled: input.gpuDisabled
|
|
3437
|
-
}
|
|
3438
|
-
};
|
|
3439
|
-
}
|
|
3440
|
-
|
|
3441
|
-
// src/services/render/stages/captureStreamingStage.ts
|
|
3442
3462
|
var DEFAULT_CAPTURE_STALL_MS = 6e4;
|
|
3443
3463
|
var DE_STALL_POLL_MS = 5e3;
|
|
3444
3464
|
var STALL_ADVICE = "Chrome stopped answering. If another app is keeping the GPU or CPU busy (a 3D render, a game, another export), let it finish or render one job at a time, then retry.";
|
|
3465
|
+
function poolFailure(error, probeSession) {
|
|
3466
|
+
return wrapCaptureStageError(error, probeSession?.browserConsoleBuffer ?? []);
|
|
3467
|
+
}
|
|
3445
3468
|
var ParallelCaptureStallError = class extends Error {
|
|
3446
3469
|
variant;
|
|
3447
3470
|
constructor(args) {
|
|
@@ -3888,7 +3911,7 @@ async function runCaptureStreamingStage(input) {
|
|
|
3888
3911
|
}
|
|
3889
3912
|
);
|
|
3890
3913
|
} catch (err) {
|
|
3891
|
-
if (parallelDrainError) throw parallelDrainError;
|
|
3914
|
+
if (parallelDrainError) throw poolFailure(parallelDrainError, probeSession);
|
|
3892
3915
|
if (stalled && abortSignal?.aborted !== true) {
|
|
3893
3916
|
throw new ParallelCaptureStallError({
|
|
3894
3917
|
variant: "pool",
|
|
@@ -3899,13 +3922,15 @@ async function runCaptureStreamingStage(input) {
|
|
|
3899
3922
|
phaseSummary: phaseSummary()
|
|
3900
3923
|
});
|
|
3901
3924
|
}
|
|
3902
|
-
throw err;
|
|
3925
|
+
throw poolFailure(err, probeSession);
|
|
3903
3926
|
} finally {
|
|
3904
3927
|
clearInterval(stallTimer);
|
|
3905
3928
|
abortSignal?.removeEventListener("abort", forwardParentAbort);
|
|
3906
3929
|
}
|
|
3907
|
-
if (parallelDrainError) throw parallelDrainError;
|
|
3930
|
+
if (parallelDrainError) throw poolFailure(parallelDrainError, probeSession);
|
|
3908
3931
|
pushWorkerDedupPerfs(workerResults, dedupPerfs);
|
|
3932
|
+
const workerPageErrors = [];
|
|
3933
|
+
pushWorkerPageErrors(workerResults, workerPageErrors);
|
|
3909
3934
|
if (parallelGuardRan) {
|
|
3910
3935
|
deDrainStats = parallelStats;
|
|
3911
3936
|
}
|
|
@@ -3915,6 +3940,7 @@ async function runCaptureStreamingStage(input) {
|
|
|
3915
3940
|
await closeCaptureSession(probeSession);
|
|
3916
3941
|
probeSession = null;
|
|
3917
3942
|
}
|
|
3943
|
+
lastBrowserConsole = withWorkerPageErrors(lastBrowserConsole, workerPageErrors);
|
|
3918
3944
|
} else {
|
|
3919
3945
|
const videoInjector = createRenderVideoFrameInjector();
|
|
3920
3946
|
const session = probeSession ?? await createCaptureSession(
|
|
@@ -4361,8 +4387,9 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4361
4387
|
|
|
4362
4388
|
// src/services/render/segmentManifest.ts
|
|
4363
4389
|
import { createHash as createHash2 } from "node:crypto";
|
|
4364
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4,
|
|
4390
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
4365
4391
|
import { join as join10 } from "node:path";
|
|
4392
|
+
import { renameWithRetry as renameWithRetry2 } from "@hyperframes/engine";
|
|
4366
4393
|
var MANIFEST_FILENAME = "segments.json";
|
|
4367
4394
|
function computeSegmentPlanHash(input) {
|
|
4368
4395
|
const ordered = [
|
|
@@ -4418,7 +4445,7 @@ function writeSegmentManifest(segmentDir, manifest) {
|
|
|
4418
4445
|
mkdirSync4(segmentDir, { recursive: true });
|
|
4419
4446
|
const tmp = join10(segmentDir, `${MANIFEST_FILENAME}.${process.pid}.tmp`);
|
|
4420
4447
|
writeFileSync3(tmp, JSON.stringify(manifest, null, 2), "utf-8");
|
|
4421
|
-
|
|
4448
|
+
renameWithRetry2(tmp, join10(segmentDir, MANIFEST_FILENAME));
|
|
4422
4449
|
}
|
|
4423
4450
|
async function probeSegmentFrameCount(path, probe) {
|
|
4424
4451
|
try {
|
|
@@ -5266,6 +5293,8 @@ import {
|
|
|
5266
5293
|
rewriteInlineStyleAssetUrls
|
|
5267
5294
|
} from "@hyperframes/core";
|
|
5268
5295
|
import { MAX_AUDIO_GAIN } from "@hyperframes/core/audio-gain";
|
|
5296
|
+
import { readPlaybackRate } from "@hyperframes/parsers/media-duration";
|
|
5297
|
+
import { resolveRateSpec } from "@hyperframes/core/speed-ramp";
|
|
5269
5298
|
import { gsapCdnDist } from "@hyperframes/core/gsap-cdn";
|
|
5270
5299
|
import {
|
|
5271
5300
|
assignBundledRuntimeCompositionIds,
|
|
@@ -5470,19 +5499,11 @@ import {
|
|
|
5470
5499
|
|
|
5471
5500
|
// src/services/animatedGifPrep.ts
|
|
5472
5501
|
import { createHash as createHash4 } from "node:crypto";
|
|
5473
|
-
import {
|
|
5474
|
-
copyFileSync as copyFileSync2,
|
|
5475
|
-
existsSync as existsSync8,
|
|
5476
|
-
mkdirSync as mkdirSync5,
|
|
5477
|
-
readFileSync as readFileSync5,
|
|
5478
|
-
renameSync as renameSync3,
|
|
5479
|
-
rmSync as rmSync6,
|
|
5480
|
-
statSync as statSync4
|
|
5481
|
-
} from "node:fs";
|
|
5502
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync6, statSync as statSync4 } from "node:fs";
|
|
5482
5503
|
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join12, resolve as resolve5 } from "node:path";
|
|
5483
5504
|
import { parseHTML as parseHTML3 } from "linkedom";
|
|
5484
5505
|
import { parseAnimatedGifMetadata } from "@hyperframes/core";
|
|
5485
|
-
import { DEFAULT_VP9_CPU_USED, runFfmpeg as runFfmpeg2 } from "@hyperframes/engine";
|
|
5506
|
+
import { DEFAULT_VP9_CPU_USED, runFfmpeg as runFfmpeg2, renameWithRetry as renameWithRetry3 } from "@hyperframes/engine";
|
|
5486
5507
|
var PREPARED_GIF_SUBDIR = "_animated_gif";
|
|
5487
5508
|
var CACHE_SCHEMA = "hfgif-v1";
|
|
5488
5509
|
function splitUrlSuffix(src) {
|
|
@@ -5661,7 +5682,7 @@ async function ensurePreparedWebm(input) {
|
|
|
5661
5682
|
throw new Error("Animated GIF transcode produced an empty output");
|
|
5662
5683
|
}
|
|
5663
5684
|
if (!isUsableFile(input.cachePath)) {
|
|
5664
|
-
|
|
5685
|
+
renameWithRetry3(tmpPath, input.cachePath);
|
|
5665
5686
|
} else {
|
|
5666
5687
|
rmSync6(tmpPath, { force: true });
|
|
5667
5688
|
}
|
|
@@ -7249,6 +7270,9 @@ async function discoverMediaFromBrowser(page) {
|
|
|
7249
7270
|
const intrinsicDuration = isImage ? 0 : htmlEl.duration;
|
|
7250
7271
|
const playbackStartRaw = htmlEl.getAttribute("data-playback-start");
|
|
7251
7272
|
const mediaStartRaw = htmlEl.getAttribute("data-media-start");
|
|
7273
|
+
const playbackRateRaw = htmlEl.getAttribute("data-playback-rate");
|
|
7274
|
+
const automationRaw = htmlEl.getAttribute("data-automation");
|
|
7275
|
+
const defaultPlaybackRate = isImage ? 1 : htmlEl.defaultPlaybackRate;
|
|
7252
7276
|
const loop = htmlEl.hasAttribute("loop");
|
|
7253
7277
|
const hasAudio = htmlEl.getAttribute("data-has-audio") === "true";
|
|
7254
7278
|
const volume = parseFloat(htmlEl.getAttribute("data-volume") || "1");
|
|
@@ -7264,6 +7288,9 @@ async function discoverMediaFromBrowser(page) {
|
|
|
7264
7288
|
durationInferred,
|
|
7265
7289
|
playbackStartRaw,
|
|
7266
7290
|
mediaStartRaw,
|
|
7291
|
+
playbackRateRaw,
|
|
7292
|
+
automationRaw,
|
|
7293
|
+
defaultPlaybackRate,
|
|
7267
7294
|
loop,
|
|
7268
7295
|
hasAudio,
|
|
7269
7296
|
volume,
|
|
@@ -7273,7 +7300,17 @@ async function discoverMediaFromBrowser(page) {
|
|
|
7273
7300
|
return results;
|
|
7274
7301
|
});
|
|
7275
7302
|
return elements.map(
|
|
7276
|
-
({
|
|
7303
|
+
({
|
|
7304
|
+
endRaw,
|
|
7305
|
+
durationRaw,
|
|
7306
|
+
intrinsicDuration,
|
|
7307
|
+
playbackStartRaw,
|
|
7308
|
+
mediaStartRaw,
|
|
7309
|
+
playbackRateRaw,
|
|
7310
|
+
automationRaw,
|
|
7311
|
+
defaultPlaybackRate,
|
|
7312
|
+
...element
|
|
7313
|
+
}) => ({
|
|
7277
7314
|
...element,
|
|
7278
7315
|
end: parseStrictFiniteTimingNumber(endRaw) ?? 0,
|
|
7279
7316
|
duration: element.durationInferred && Number.isFinite(intrinsicDuration) && intrinsicDuration > 0 ? intrinsicDuration : parseStrictFiniteTimingNumber(durationRaw) ?? 0,
|
|
@@ -7283,7 +7320,14 @@ async function discoverMediaFromBrowser(page) {
|
|
|
7283
7320
|
if (name === "data-media-start") return mediaStartRaw;
|
|
7284
7321
|
return null;
|
|
7285
7322
|
}
|
|
7286
|
-
})
|
|
7323
|
+
}),
|
|
7324
|
+
playbackRate: resolveRateSpec(
|
|
7325
|
+
automationRaw,
|
|
7326
|
+
readPlaybackRate(
|
|
7327
|
+
(name) => name === "data-playback-rate" ? playbackRateRaw : null,
|
|
7328
|
+
defaultPlaybackRate
|
|
7329
|
+
)
|
|
7330
|
+
)
|
|
7287
7331
|
})
|
|
7288
7332
|
);
|
|
7289
7333
|
}
|
|
@@ -7703,9 +7747,18 @@ import {
|
|
|
7703
7747
|
getCompositionDuration,
|
|
7704
7748
|
initializeSession as initializeSession4,
|
|
7705
7749
|
isTransientBrowserError,
|
|
7706
|
-
probeBeginFrameLiveness
|
|
7750
|
+
probeBeginFrameLiveness,
|
|
7751
|
+
videoAudioId
|
|
7707
7752
|
} from "@hyperframes/engine";
|
|
7708
|
-
import {
|
|
7753
|
+
import {
|
|
7754
|
+
MEDIA_RENDER_ID_ATTR as MEDIA_RENDER_ID_ATTR2,
|
|
7755
|
+
fpsToNumber as fpsToNumber7,
|
|
7756
|
+
normalizeRateSpec as normalizeRateSpec3,
|
|
7757
|
+
readMediaStart as readMediaStart2,
|
|
7758
|
+
shiftRateLane as shiftRateLane2,
|
|
7759
|
+
sourceTimeAt as sourceTimeAt3,
|
|
7760
|
+
timeAtSourceTime
|
|
7761
|
+
} from "@hyperframes/core";
|
|
7709
7762
|
import { extractMediaSrcMutations } from "@hyperframes/parsers";
|
|
7710
7763
|
|
|
7711
7764
|
// src/services/render/stages/probeFailures.ts
|
|
@@ -7764,16 +7817,28 @@ function authoredMediaStarts(html) {
|
|
|
7764
7817
|
}
|
|
7765
7818
|
return starts;
|
|
7766
7819
|
}
|
|
7767
|
-
function
|
|
7820
|
+
function isVideoAudio(audio, videoId) {
|
|
7821
|
+
return audio.type === "video" && audio.id === videoAudioId(videoId);
|
|
7822
|
+
}
|
|
7823
|
+
function adoptRuntimeMediaTiming(composition, el, authored) {
|
|
7768
7824
|
const shift = el.mediaStart - authored;
|
|
7769
|
-
if (el.mediaStart <= 0 || Math.abs(shift) <= BROWSER_MEDIA_EPSILON) return;
|
|
7770
7825
|
const entries = el.tagName === "video" ? [
|
|
7771
7826
|
...composition.videos.filter((video) => video.id === el.id),
|
|
7772
|
-
...composition.audios.filter(
|
|
7773
|
-
(audio) => audio.type === "video" && audio.id === `${el.id}-audio`
|
|
7774
|
-
)
|
|
7827
|
+
...composition.audios.filter((audio) => isVideoAudio(audio, el.id))
|
|
7775
7828
|
] : composition.audios.filter((audio) => audio.type !== "video" && audio.id === el.id);
|
|
7776
|
-
for (const entry of entries)
|
|
7829
|
+
for (const entry of entries) {
|
|
7830
|
+
if (typeof entry.playbackRate !== "object") {
|
|
7831
|
+
if (typeof el.playbackRate === "object") {
|
|
7832
|
+
const consumed = Math.max(0, entry.mediaStart - authored);
|
|
7833
|
+
const head = timeAtSourceTime(normalizeRateSpec3(entry.playbackRate), consumed);
|
|
7834
|
+
entry.mediaStart += sourceTimeAt3(el.playbackRate, head) - consumed;
|
|
7835
|
+
entry.playbackRate = shiftRateLane2(el.playbackRate, head);
|
|
7836
|
+
} else {
|
|
7837
|
+
entry.playbackRate = el.playbackRate;
|
|
7838
|
+
}
|
|
7839
|
+
}
|
|
7840
|
+
if (el.mediaStart > 0 && Math.abs(shift) > BROWSER_MEDIA_EPSILON) entry.mediaStart += shift;
|
|
7841
|
+
}
|
|
7777
7842
|
}
|
|
7778
7843
|
function reconcileBrowserMediaEnd(existingEnd, projectedEnd, sourceChanged, durationInferred) {
|
|
7779
7844
|
if (projectedEnd <= 0) return existingEnd;
|
|
@@ -8057,7 +8122,7 @@ async function runProbeStage(input) {
|
|
|
8057
8122
|
sourceChanged,
|
|
8058
8123
|
el.durationInferred
|
|
8059
8124
|
);
|
|
8060
|
-
|
|
8125
|
+
adoptRuntimeMediaTiming(
|
|
8061
8126
|
composition,
|
|
8062
8127
|
el,
|
|
8063
8128
|
authoredStarts.get(el.id) ?? existing.mediaStart
|
|
@@ -8080,6 +8145,7 @@ async function runProbeStage(input) {
|
|
|
8080
8145
|
start: el.start,
|
|
8081
8146
|
end: resolveBrowserMediaEnd(el.start, el.end, el.duration),
|
|
8082
8147
|
mediaStart: el.mediaStart,
|
|
8148
|
+
playbackRate: el.playbackRate,
|
|
8083
8149
|
loop: el.loop,
|
|
8084
8150
|
hasAudio: el.hasAudio && !el.muted
|
|
8085
8151
|
});
|
|
@@ -8104,7 +8170,7 @@ async function runProbeStage(input) {
|
|
|
8104
8170
|
sourceChanged,
|
|
8105
8171
|
el.durationInferred
|
|
8106
8172
|
);
|
|
8107
|
-
|
|
8173
|
+
adoptRuntimeMediaTiming(
|
|
8108
8174
|
composition,
|
|
8109
8175
|
el,
|
|
8110
8176
|
authoredStarts.get(el.id) ?? existing.mediaStart
|
|
@@ -8122,6 +8188,7 @@ async function runProbeStage(input) {
|
|
|
8122
8188
|
end: resolveBrowserMediaEnd(el.start, el.end, el.duration),
|
|
8123
8189
|
mediaStart: el.mediaStart,
|
|
8124
8190
|
loop: el.loop,
|
|
8191
|
+
playbackRate: el.playbackRate,
|
|
8125
8192
|
layer: 0,
|
|
8126
8193
|
volume: el.volume,
|
|
8127
8194
|
type: "audio"
|
|
@@ -8351,7 +8418,8 @@ import {
|
|
|
8351
8418
|
isHttpUrl as isHttpUrl2,
|
|
8352
8419
|
resolveProjectRelativeSrc as resolveProjectRelativeSrc3,
|
|
8353
8420
|
runVideoExtractionWithRetry,
|
|
8354
|
-
safeVideoExtractionSourceIdentity
|
|
8421
|
+
safeVideoExtractionSourceIdentity,
|
|
8422
|
+
videoAudioId as videoAudioId2
|
|
8355
8423
|
} from "@hyperframes/engine";
|
|
8356
8424
|
|
|
8357
8425
|
// src/services/render/extractionFailureMetadata.ts
|
|
@@ -8704,7 +8772,7 @@ function appendAutoDetectedVideoAudio(composition, extracted) {
|
|
|
8704
8772
|
const video = composition.videos.find((v) => v.id === ext.videoId);
|
|
8705
8773
|
if (!video || !video.hasAudio || video.hidden || existingAudioSrcs.has(video.src)) continue;
|
|
8706
8774
|
composition.audios.push({
|
|
8707
|
-
id:
|
|
8775
|
+
id: videoAudioId2(video.id),
|
|
8708
8776
|
src: video.src,
|
|
8709
8777
|
start: video.start,
|
|
8710
8778
|
end: video.end,
|
|
@@ -8730,7 +8798,7 @@ import {
|
|
|
8730
8798
|
|
|
8731
8799
|
// src/services/render/audioPadTrim.ts
|
|
8732
8800
|
import { spawn } from "node:child_process";
|
|
8733
|
-
import { mkdtempSync as mkdtempSync3,
|
|
8801
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync7 } from "node:fs";
|
|
8734
8802
|
import { dirname as dirname7, join as join17 } from "node:path";
|
|
8735
8803
|
import {
|
|
8736
8804
|
DEFAULT_CONFIG,
|
|
@@ -8739,6 +8807,7 @@ import {
|
|
|
8739
8807
|
extractAudioMetadata as extractAudioMetadata3,
|
|
8740
8808
|
getFfprobeBinary,
|
|
8741
8809
|
ManagedChildProcess,
|
|
8810
|
+
renameWithRetry as renameWithRetry4,
|
|
8742
8811
|
runFfmpeg as runFfmpeg4,
|
|
8743
8812
|
trackChildProcess
|
|
8744
8813
|
} from "@hyperframes/engine";
|
|
@@ -8994,7 +9063,7 @@ async function enforceAacTruePeak(input) {
|
|
|
8994
9063
|
}
|
|
8995
9064
|
if (truePeakDbfs <= AAC_DELIVERY_TRUE_PEAK_DBFS) {
|
|
8996
9065
|
if (measuredPath !== correctedPath) return { success: true };
|
|
8997
|
-
|
|
9066
|
+
renameWithRetry4(correctedPath, input.audioPath);
|
|
8998
9067
|
return { success: true, loweredDb: Number((-attenuationDb).toFixed(2)) };
|
|
8999
9068
|
}
|
|
9000
9069
|
if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
|
|
@@ -9184,6 +9253,7 @@ async function runAudioStage(input) {
|
|
|
9184
9253
|
const result = await mixAudioForDelivery(input, duration, pcmSourcePath);
|
|
9185
9254
|
let audioLoweredDb;
|
|
9186
9255
|
if (result.hasAudio) {
|
|
9256
|
+
const guardStart = Date.now();
|
|
9187
9257
|
const peak = await constrainAacTruePeak({
|
|
9188
9258
|
audioPath: result.audioOutputPath,
|
|
9189
9259
|
sourcePath: pcmSourcePath,
|
|
@@ -9193,6 +9263,7 @@ async function runAudioStage(input) {
|
|
|
9193
9263
|
});
|
|
9194
9264
|
if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
|
|
9195
9265
|
audioLoweredDb = peak.loweredDb;
|
|
9266
|
+
input.log?.info("[audio] phases", { ...result.audioPhaseMs, guard: Date.now() - guardStart });
|
|
9196
9267
|
}
|
|
9197
9268
|
return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
|
|
9198
9269
|
} finally {
|
|
@@ -9218,6 +9289,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9218
9289
|
let hasAudio = false;
|
|
9219
9290
|
let audioError;
|
|
9220
9291
|
let audioFailures;
|
|
9292
|
+
let audioPhaseMs;
|
|
9221
9293
|
if (audios.length > 0) {
|
|
9222
9294
|
let audioResult;
|
|
9223
9295
|
try {
|
|
@@ -9267,6 +9339,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9267
9339
|
assertAudioNotInterrupted(audioResult.failures);
|
|
9268
9340
|
hasAudio = audioResult.success;
|
|
9269
9341
|
audioFailures = audioResult.failures;
|
|
9342
|
+
audioPhaseMs = audioResult.phaseMs;
|
|
9270
9343
|
if (!hasAudio) {
|
|
9271
9344
|
audioError = audioResult.error ?? "audio mix failed for an unknown reason";
|
|
9272
9345
|
for (const failure of audioResult.failures ?? []) {
|
|
@@ -9285,7 +9358,8 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9285
9358
|
audioOutputPath,
|
|
9286
9359
|
hasAudio,
|
|
9287
9360
|
audioError,
|
|
9288
|
-
audioFailures
|
|
9361
|
+
audioFailures,
|
|
9362
|
+
audioPhaseMs
|
|
9289
9363
|
};
|
|
9290
9364
|
}
|
|
9291
9365
|
|
|
@@ -9414,6 +9488,7 @@ async function runCaptureStage(input) {
|
|
|
9414
9488
|
let { workerCount } = plan;
|
|
9415
9489
|
const { forceScreenshot } = plan;
|
|
9416
9490
|
let lastBrowserConsole = [];
|
|
9491
|
+
const workerPageErrors = [];
|
|
9417
9492
|
let captureBeyondViewport = probeSession?.options.captureBeyondViewport;
|
|
9418
9493
|
const captureCfg = cfg.forceScreenshot === forceScreenshot ? cfg : { ...cfg, forceScreenshot };
|
|
9419
9494
|
if (frameRange !== void 0) {
|
|
@@ -9451,6 +9526,7 @@ async function runCaptureStage(input) {
|
|
|
9451
9526
|
abortSignal,
|
|
9452
9527
|
frameRangeStart: frameRange?.startFrame,
|
|
9453
9528
|
dedupPerfs,
|
|
9529
|
+
pageErrorLines: workerPageErrors,
|
|
9454
9530
|
onProgress: (progress) => {
|
|
9455
9531
|
if (progress.latestWorkerPhase) {
|
|
9456
9532
|
if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
|
|
@@ -9471,6 +9547,11 @@ async function runCaptureStage(input) {
|
|
|
9471
9547
|
},
|
|
9472
9548
|
cfg: captureCfg,
|
|
9473
9549
|
log
|
|
9550
|
+
}).catch((error) => {
|
|
9551
|
+
throw wrapCaptureStageError(
|
|
9552
|
+
error,
|
|
9553
|
+
withWorkerPageErrors(probeSession?.browserConsoleBuffer ?? [], workerPageErrors)
|
|
9554
|
+
);
|
|
9474
9555
|
});
|
|
9475
9556
|
captureAttempts.push(...attempts);
|
|
9476
9557
|
const lastAttempt = attempts[attempts.length - 1];
|
|
@@ -9483,6 +9564,7 @@ async function runCaptureStage(input) {
|
|
|
9483
9564
|
await closeCaptureSession5(probeSession);
|
|
9484
9565
|
probeSession = null;
|
|
9485
9566
|
}
|
|
9567
|
+
lastBrowserConsole = withWorkerPageErrors(lastBrowserConsole, workerPageErrors);
|
|
9486
9568
|
} else {
|
|
9487
9569
|
const sequential = await runSequentialDiskCapture(
|
|
9488
9570
|
input,
|
|
@@ -10798,7 +10880,7 @@ function videoEncoderOptions(input, engineCfg) {
|
|
|
10798
10880
|
};
|
|
10799
10881
|
}
|
|
10800
10882
|
function canEncodeWhileCapturing(input, workerCount, cpuCount) {
|
|
10801
|
-
return workerCount > 1 && workerCount < cpuCount && !input.isPngSequence && !input.isGif && !input.enableChunkedEncode && input.preset.codec === "h264" && !input.preset.hdr && input.job.config.useGpu !== true && input.captureImageFormat === "jpeg"
|
|
10883
|
+
return workerCount > 1 && workerCount < cpuCount && !input.isPngSequence && !input.isGif && !input.enableChunkedEncode && input.preset.codec === "h264" && !input.preset.hdr && input.job.config.useGpu !== true && input.captureImageFormat === "jpeg";
|
|
10802
10884
|
}
|
|
10803
10885
|
async function readLandedFrame(workerPath, mergedPath) {
|
|
10804
10886
|
if (workerPath !== void 0) {
|
|
@@ -11453,6 +11535,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
|
|
|
11453
11535
|
options.cfg
|
|
11454
11536
|
);
|
|
11455
11537
|
pushWorkerDedupPerfs(workerResults, options.dedupPerfs);
|
|
11538
|
+
if (options.pageErrorLines) pushWorkerPageErrors(workerResults, options.pageErrorLines);
|
|
11456
11539
|
} finally {
|
|
11457
11540
|
await mergeWorkerFrames(attemptWorkDir, tasks, options.framesDir);
|
|
11458
11541
|
}
|
|
@@ -11715,13 +11798,36 @@ function colorGradingValueHasLut(rawAttributeValue) {
|
|
|
11715
11798
|
return false;
|
|
11716
11799
|
}
|
|
11717
11800
|
}
|
|
11718
|
-
|
|
11801
|
+
var PROBE_READ_TIMEOUT_MS = 5e3;
|
|
11802
|
+
async function evaluateWithinBound(page, fn, what, log) {
|
|
11803
|
+
let timer;
|
|
11804
|
+
const timedOut = new Promise((_, reject) => {
|
|
11805
|
+
timer = setTimeout(
|
|
11806
|
+
() => reject(new Error(`no answer within ${PROBE_READ_TIMEOUT_MS} ms (page busy)`)),
|
|
11807
|
+
PROBE_READ_TIMEOUT_MS
|
|
11808
|
+
);
|
|
11809
|
+
});
|
|
11810
|
+
try {
|
|
11811
|
+
return await Promise.race([page.evaluate(fn), timedOut]);
|
|
11812
|
+
} catch (err) {
|
|
11813
|
+
log.warn(`[Render] live ${what} read skipped; using the static answer`, {
|
|
11814
|
+
error: err instanceof Error ? err.message : String(err)
|
|
11815
|
+
});
|
|
11816
|
+
throw err;
|
|
11817
|
+
} finally {
|
|
11818
|
+
clearTimeout(timer);
|
|
11819
|
+
}
|
|
11820
|
+
}
|
|
11821
|
+
async function resolveCompositionElementCount(probeSession, html, log = defaultLogger) {
|
|
11719
11822
|
if (probeSession?.isInitialized) {
|
|
11720
11823
|
try {
|
|
11721
|
-
const liveCount = await
|
|
11824
|
+
const liveCount = await evaluateWithinBound(
|
|
11825
|
+
probeSession.page,
|
|
11722
11826
|
// Live HTMLCollection length — avoids materializing a static NodeList
|
|
11723
11827
|
// on the large-DOM comps this gate exists to catch (review nit).
|
|
11724
|
-
() => document.getElementsByTagName("*").length
|
|
11828
|
+
() => document.getElementsByTagName("*").length,
|
|
11829
|
+
"element count",
|
|
11830
|
+
log
|
|
11725
11831
|
);
|
|
11726
11832
|
if (typeof liveCount === "number" && Number.isFinite(liveCount)) {
|
|
11727
11833
|
return { count: liveCount, source: "live" };
|
|
@@ -11809,11 +11915,11 @@ function probeAdaptersUsed() {
|
|
|
11809
11915
|
}
|
|
11810
11916
|
return used;
|
|
11811
11917
|
}
|
|
11812
|
-
async function resolveAdaptersUsed(probeSession, html) {
|
|
11918
|
+
async function resolveAdaptersUsed(probeSession, html, log = defaultLogger) {
|
|
11813
11919
|
const staticAdapters = detectAdaptersStatic(html);
|
|
11814
11920
|
if (!probeSession?.isInitialized) return staticAdapters;
|
|
11815
11921
|
try {
|
|
11816
|
-
const live = await probeSession.page
|
|
11922
|
+
const live = await evaluateWithinBound(probeSession.page, probeAdaptersUsed, "adapters", log);
|
|
11817
11923
|
if (!Array.isArray(live)) return staticAdapters;
|
|
11818
11924
|
const detected = /* @__PURE__ */ new Set([...staticAdapters, ...live]);
|
|
11819
11925
|
return KNOWN_RUNTIME_ADAPTERS.filter((name) => detected.has(name));
|
|
@@ -12071,7 +12177,10 @@ async function executeRenderPipeline(input) {
|
|
|
12071
12177
|
);
|
|
12072
12178
|
const artifactTransaction = new ArtifactTransaction(
|
|
12073
12179
|
outputPath,
|
|
12074
|
-
isPngSequence || isHls ? "directory" : "file"
|
|
12180
|
+
isPngSequence || isHls ? "directory" : "file",
|
|
12181
|
+
void 0,
|
|
12182
|
+
void 0,
|
|
12183
|
+
log
|
|
12075
12184
|
);
|
|
12076
12185
|
const stagedOutputPath = artifactTransaction.stagingPath;
|
|
12077
12186
|
const needsAlpha = outputNeedsAlpha(outputFormat);
|
|
@@ -12570,8 +12679,8 @@ async function executeRenderPipeline(input) {
|
|
|
12570
12679
|
vfxHostCount,
|
|
12571
12680
|
vfxCapture,
|
|
12572
12681
|
vfxTypes
|
|
12573
|
-
} = await resolveCompositionElementCount(probeSession, compiled.html);
|
|
12574
|
-
const adaptersUsed = await resolveAdaptersUsed(probeSession, compiled.html);
|
|
12682
|
+
} = await resolveCompositionElementCount(probeSession, compiled.html, log);
|
|
12683
|
+
const adaptersUsed = await resolveAdaptersUsed(probeSession, compiled.html, log);
|
|
12575
12684
|
const deShortBandEnabled = deShortBandMaxElements > 0;
|
|
12576
12685
|
const deShortBandOpen = deShortBandEnabled && deShortBandMinFrames > 0 && compositionElementCountSource === "live" && compositionElementCount <= deShortBandMaxElements;
|
|
12577
12686
|
const deShortBandRoute = process.env.HF_DE_SHORT_BAND_ROUTE === "true";
|
|
@@ -14069,7 +14178,9 @@ import {
|
|
|
14069
14178
|
getEncoderPreset as getEncoderPreset4,
|
|
14070
14179
|
normalizeVp9CpuUsed,
|
|
14071
14180
|
resolveConfig as resolveConfig3,
|
|
14072
|
-
declareContentAddressedUrl
|
|
14181
|
+
declareContentAddressedUrl,
|
|
14182
|
+
renameWithRetry as renameWithRetry6,
|
|
14183
|
+
declareProbeFactsUrl
|
|
14073
14184
|
} from "@hyperframes/engine";
|
|
14074
14185
|
|
|
14075
14186
|
// src/services/distributed/planFrameCost.ts
|
|
@@ -14139,6 +14250,7 @@ var FIELD_DELIMITER = Buffer.from([0]);
|
|
|
14139
14250
|
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg6 } from "@hyperframes/engine";
|
|
14140
14251
|
|
|
14141
14252
|
// src/services/distributed/mp4Stitch.ts
|
|
14253
|
+
import { renameWithRetry as renameWithRetry5 } from "@hyperframes/engine";
|
|
14142
14254
|
var SCAN_BYTES = 64 * 1024;
|
|
14143
14255
|
|
|
14144
14256
|
// src/services/distributed/chunkAudio.ts
|