@hyperframes/producer 0.8.191 → 0.8.193
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 +300 -109
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +62 -62
- package/dist/index.js +503 -456
- package/dist/public-server.js +333 -299
- package/dist/services/distributed/plan.d.ts +2 -0
- package/dist/services/distributed/probeFacts.d.ts +4 -0
- package/dist/services/render/perfSummary.d.ts +6 -0
- package/dist/services/render/stages/audioStage.d.ts +3 -1
- package/dist/services/render/stages/extractVideosStage.d.ts +17 -2
- package/dist/services/renderOrchestrator.d.ts +2 -0
- 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) {
|
|
@@ -1913,58 +1904,10 @@ import {
|
|
|
1913
1904
|
|
|
1914
1905
|
// src/services/render/captureStageError.ts
|
|
1915
1906
|
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
|
-
|
|
1942
|
-
// src/services/render/stages/captureHdrFrameShared.ts
|
|
1943
|
-
import {
|
|
1944
|
-
applyDomLayerMask as applyDomLayerMask2,
|
|
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
1907
|
|
|
1952
|
-
// src/services/
|
|
1953
|
-
import {
|
|
1954
|
-
import {
|
|
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";
|
|
1908
|
+
// src/services/render/perfSummary.ts
|
|
1909
|
+
import { arch, cpus, platform, totalmem } from "node:os";
|
|
1910
|
+
import { fpsToNumber as fpsToNumber3 } from "@hyperframes/core";
|
|
1968
1911
|
|
|
1969
1912
|
// src/services/render/hdrPerf.ts
|
|
1970
1913
|
function createHdrPerfCollector() {
|
|
@@ -2070,7 +2013,280 @@ function finalizeHdrPerf(perf) {
|
|
|
2070
2013
|
};
|
|
2071
2014
|
}
|
|
2072
2015
|
|
|
2016
|
+
// src/services/render/perfSummary.ts
|
|
2017
|
+
function worstSubTimelineWaitOutcome(perfs) {
|
|
2018
|
+
const outcomes = perfs.map((p) => p.subTimelineWaitOutcome).filter((o) => !!o);
|
|
2019
|
+
if (outcomes.length === 0) return void 0;
|
|
2020
|
+
if (outcomes.includes("script_failure")) return "script_failure";
|
|
2021
|
+
if (outcomes.includes("timeout")) return "timeout";
|
|
2022
|
+
return "ready";
|
|
2023
|
+
}
|
|
2024
|
+
function pushWorkerDedupPerfs(results, sink) {
|
|
2025
|
+
for (const r of results) {
|
|
2026
|
+
if (r.perf) sink.push(r.perf);
|
|
2027
|
+
}
|
|
2028
|
+
}
|
|
2029
|
+
function pushWorkerPageErrors(results, sink) {
|
|
2030
|
+
for (const result of results) {
|
|
2031
|
+
for (const line of result.pageErrorLines ?? []) if (!sink.includes(line)) sink.push(line);
|
|
2032
|
+
}
|
|
2033
|
+
}
|
|
2034
|
+
function withWorkerPageErrors(consoleLines, workerLines) {
|
|
2035
|
+
return [...consoleLines, ...workerLines.filter((line) => !consoleLines.includes(line))];
|
|
2036
|
+
}
|
|
2037
|
+
function roundDb(value) {
|
|
2038
|
+
return value === void 0 ? void 0 : Math.round(Math.min(value, 999) * 10) / 10;
|
|
2039
|
+
}
|
|
2040
|
+
function aggregateDrawElement(perfs, de) {
|
|
2041
|
+
if (perfs.length === 0) return void 0;
|
|
2042
|
+
const modes = [...new Set(perfs.map((p) => p.captureMode).filter(Boolean))].sort();
|
|
2043
|
+
const gateReasons = [
|
|
2044
|
+
...new Set(
|
|
2045
|
+
[de.probeGateReason, ...perfs.map((p) => p.deGateReason)].filter((r) => !!r)
|
|
2046
|
+
)
|
|
2047
|
+
].sort();
|
|
2048
|
+
const gpuRenderers = [
|
|
2049
|
+
...new Set(perfs.map((p) => p.gpuRenderer).filter((r) => !!r))
|
|
2050
|
+
].sort();
|
|
2051
|
+
const drain = de.drainStats;
|
|
2052
|
+
return {
|
|
2053
|
+
mode: modes.join("|") || "unknown",
|
|
2054
|
+
compileGate: de.compileGate,
|
|
2055
|
+
clampReason: de.clampReason,
|
|
2056
|
+
workerInversion: de.workerInversion ?? "none",
|
|
2057
|
+
preInversionWorkers: de.preInversionWorkers,
|
|
2058
|
+
compositionElementCount: de.compositionElementCount,
|
|
2059
|
+
compositionElementCountSource: de.compositionElementCountSource,
|
|
2060
|
+
compositionElementTags: de.compositionElementTags,
|
|
2061
|
+
arollVideoCount: de.arollVideoCount,
|
|
2062
|
+
heygenVideoCount: de.heygenVideoCount,
|
|
2063
|
+
adaptersUsed: de.adaptersUsed,
|
|
2064
|
+
audioCount: de.audioCount,
|
|
2065
|
+
imageCount: de.imageCount,
|
|
2066
|
+
subCompositionCount: de.subCompositionCount,
|
|
2067
|
+
audioGroupCount: de.audioGroupCount,
|
|
2068
|
+
colorGradingCount: de.colorGradingCount,
|
|
2069
|
+
hasLut: de.hasLut,
|
|
2070
|
+
rootBodyMismatch: de.rootBodyMismatch,
|
|
2071
|
+
rootBodyDeltaPxBucket: de.rootBodyDeltaPxBucket,
|
|
2072
|
+
vfxHostCount: de.vfxHostCount,
|
|
2073
|
+
vfxCapture: de.vfxCapture,
|
|
2074
|
+
vfxTypes: de.vfxTypes,
|
|
2075
|
+
shortBand: de.shortBand,
|
|
2076
|
+
parallelRouter: de.parallelRouter ?? "none",
|
|
2077
|
+
preRouterWorkers: de.preRouterWorkers,
|
|
2078
|
+
gateReason: gateReasons.length > 0 ? gateReasons.join("|") : void 0,
|
|
2079
|
+
gpuRenderer: gpuRenderers.length > 0 ? gpuRenderers.join("|") : void 0,
|
|
2080
|
+
workerEncode: perfs.some((p) => p.deWorkerEncode),
|
|
2081
|
+
verifyArmed: perfs.reduce((sum, p) => sum + (p.deVerifyArmed ?? 0), 0),
|
|
2082
|
+
verifyChecked: drain?.verifyChecked ?? 0,
|
|
2083
|
+
verifyMinDb: roundDb(drain?.verifyMinDb),
|
|
2084
|
+
verifyInitMs: perfs.reduce((sum, p) => sum + (p.deVerifyInitMs ?? 0), 0),
|
|
2085
|
+
selfVerifyFallback: de.selfVerifyFallback,
|
|
2086
|
+
fallbackReason: de.fallbackReason,
|
|
2087
|
+
fallbackFailedDb: roundDb(de.fallbackFailedDb),
|
|
2088
|
+
fallbackFrameIndex: de.fallbackFrameIndex,
|
|
2089
|
+
fallbackThresholdDb: roundDb(de.fallbackThresholdDb),
|
|
2090
|
+
blankSuspects: drain?.blankSuspects ?? 0,
|
|
2091
|
+
blankDeterministicAccepts: drain?.blankDeterministicAccepts ?? 0,
|
|
2092
|
+
blankRecaptures: drain?.blankRecaptures ?? 0,
|
|
2093
|
+
boundaryFrames: perfs.reduce((sum, p) => sum + (p.deBoundaryFrames ?? 0), 0),
|
|
2094
|
+
ncprFallbacks: perfs.reduce((sum, p) => sum + (p.deNcprFallbacks ?? 0), 0),
|
|
2095
|
+
frameTimeouts: perfs.reduce((sum, p) => sum + (p.deFrameTimeouts ?? 0), 0)
|
|
2096
|
+
};
|
|
2097
|
+
}
|
|
2098
|
+
function maxDefined(values) {
|
|
2099
|
+
const present = values.filter((v) => typeof v === "number");
|
|
2100
|
+
return present.length > 0 ? Math.max(...present) : void 0;
|
|
2101
|
+
}
|
|
2102
|
+
function aggregateChromeMemory(perfs) {
|
|
2103
|
+
const sampled = perfs.filter((p) => (p.chromeMemorySamples ?? 0) > 0);
|
|
2104
|
+
if (sampled.length === 0) return void 0;
|
|
2105
|
+
return {
|
|
2106
|
+
browserRssPeakMb: maxDefined(sampled.map((p) => p.chromeBrowserRssPeakMb)),
|
|
2107
|
+
rendererRssPeakMb: maxDefined(sampled.map((p) => p.chromeRendererRssPeakMb)),
|
|
2108
|
+
// Last samples are per session; summing approximates the whole fleet's
|
|
2109
|
+
// footprint at the end of capture (workers run concurrently).
|
|
2110
|
+
rssLastMb: sampled.reduce((sum, p) => sum + (p.chromeRssLastMb ?? 0), 0),
|
|
2111
|
+
gpuProcessSeenLastSample: sampled.some((p) => p.chromeGpuProcessSeenLastSample === true),
|
|
2112
|
+
samples: sampled.reduce((sum, p) => sum + (p.chromeMemorySamples ?? 0), 0)
|
|
2113
|
+
};
|
|
2114
|
+
}
|
|
2115
|
+
function aggregateDedup(perfs) {
|
|
2116
|
+
if (perfs.length === 0) return void 0;
|
|
2117
|
+
const armed = perfs.some((p) => p.staticDedupArmed);
|
|
2118
|
+
const skipReasons = armed ? [] : [
|
|
2119
|
+
...new Set(perfs.map((p) => p.staticDedupSkipReason).filter((r) => !!r))
|
|
2120
|
+
].sort();
|
|
2121
|
+
const verificationPerfs = perfs.filter((perf) => perf.staticDedupVerificationOutcome);
|
|
2122
|
+
const verificationOutcomes = [
|
|
2123
|
+
...new Set(
|
|
2124
|
+
verificationPerfs.map((perf) => perf.staticDedupVerificationOutcome).filter((outcome) => outcome != null)
|
|
2125
|
+
)
|
|
2126
|
+
].sort();
|
|
2127
|
+
return {
|
|
2128
|
+
enabled: perfs.some((p) => p.staticDedupEnabled),
|
|
2129
|
+
armed,
|
|
2130
|
+
predictedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupPredicted ?? 0), 0),
|
|
2131
|
+
reusedFrames: perfs.reduce((sum, p) => sum + (p.staticDedupReused ?? 0), 0),
|
|
2132
|
+
skipReason: skipReasons.length > 0 ? skipReasons.join("|") : void 0,
|
|
2133
|
+
...verificationPerfs.length === 0 ? {} : {
|
|
2134
|
+
verifiedFrames: verificationPerfs.reduce(
|
|
2135
|
+
(sum, perf) => sum + (perf.staticDedupVerified ?? 0),
|
|
2136
|
+
0
|
|
2137
|
+
),
|
|
2138
|
+
verificationOutcomes,
|
|
2139
|
+
plannedRuns: verificationPerfs.reduce(
|
|
2140
|
+
(sum, perf) => sum + (perf.staticDedupVerificationPlannedRuns ?? 0),
|
|
2141
|
+
0
|
|
2142
|
+
),
|
|
2143
|
+
completedRuns: verificationPerfs.reduce(
|
|
2144
|
+
(sum, perf) => sum + (perf.staticDedupVerificationCompletedRuns ?? 0),
|
|
2145
|
+
0
|
|
2146
|
+
),
|
|
2147
|
+
screenshots: verificationPerfs.reduce(
|
|
2148
|
+
(sum, perf) => sum + (perf.staticDedupVerificationScreenshots ?? 0),
|
|
2149
|
+
0
|
|
2150
|
+
),
|
|
2151
|
+
seeks: verificationPerfs.reduce(
|
|
2152
|
+
(sum, perf) => sum + (perf.staticDedupVerificationSeeks ?? 0),
|
|
2153
|
+
0
|
|
2154
|
+
),
|
|
2155
|
+
comparisons: verificationPerfs.reduce(
|
|
2156
|
+
(sum, perf) => sum + (perf.staticDedupVerificationComparisons ?? 0),
|
|
2157
|
+
0
|
|
2158
|
+
),
|
|
2159
|
+
verificationElapsedMs: verificationPerfs.reduce(
|
|
2160
|
+
(sum, perf) => sum + (perf.staticDedupVerificationElapsedMs ?? 0),
|
|
2161
|
+
0
|
|
2162
|
+
)
|
|
2163
|
+
}
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
function aggregateBeginFrameReuse(perfs) {
|
|
2167
|
+
const noDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameNoDamage ?? 0), 0);
|
|
2168
|
+
const hasDamageFrames = perfs.reduce((sum, p) => sum + (p.beginFrameHasDamage ?? 0), 0);
|
|
2169
|
+
if (noDamageFrames + hasDamageFrames === 0) return void 0;
|
|
2170
|
+
return { noDamageFrames, hasDamageFrames };
|
|
2171
|
+
}
|
|
2172
|
+
function buildRenderPerfSummary(input) {
|
|
2173
|
+
return {
|
|
2174
|
+
renderId: input.job.id,
|
|
2175
|
+
totalElapsedMs: input.totalElapsedMs,
|
|
2176
|
+
// RenderPerfSummary surfaces fps as a decimal because it lands in JSON
|
|
2177
|
+
// payloads (CLI telemetry, regression-harness reports) where a single
|
|
2178
|
+
// number is friendlier than `{num,den}`. Callers needing the rational
|
|
2179
|
+
// back can read `job.config.fps`.
|
|
2180
|
+
fps: fpsToNumber3(input.job.config.fps),
|
|
2181
|
+
quality: input.job.config.quality,
|
|
2182
|
+
workers: input.workerCount,
|
|
2183
|
+
workerSizing: input.workerSizing,
|
|
2184
|
+
chunkedEncode: input.enableChunkedEncode,
|
|
2185
|
+
chunkSizeFrames: input.enableChunkedEncode ? input.chunkedEncodeSize : null,
|
|
2186
|
+
compositionDurationSeconds: input.compositionDurationSeconds,
|
|
2187
|
+
totalFrames: input.totalFrames,
|
|
2188
|
+
resolution: { width: input.outputWidth, height: input.outputHeight },
|
|
2189
|
+
videoCount: input.videoCount,
|
|
2190
|
+
audioCount: input.audioCount,
|
|
2191
|
+
stages: input.perfStages,
|
|
2192
|
+
videoExtractBreakdown: input.videoExtractBreakdown,
|
|
2193
|
+
tmpPeakBytes: input.tmpPeakBytes,
|
|
2194
|
+
captureCalibration: input.captureCalibration ? {
|
|
2195
|
+
sampledFrames: input.captureCalibration.samples.map((sample) => sample.frameIndex),
|
|
2196
|
+
p95Ms: input.captureCalibration.estimate.p95Ms,
|
|
2197
|
+
multiplier: input.captureCalibration.estimate.multiplier,
|
|
2198
|
+
reasons: input.captureCalibration.estimate.reasons
|
|
2199
|
+
} : void 0,
|
|
2200
|
+
captureAttempts: input.captureAttempts.length > 0 ? input.captureAttempts : void 0,
|
|
2201
|
+
hdrDiagnostics: input.hdrDiagnostics.videoExtractionFailures > 0 || input.hdrDiagnostics.imageDecodeFailures > 0 ? { ...input.hdrDiagnostics } : void 0,
|
|
2202
|
+
hdrPerf: input.hdrPerf ? finalizeHdrPerf(input.hdrPerf) : void 0,
|
|
2203
|
+
observability: input.observability,
|
|
2204
|
+
captureAvgMs: input.totalFrames > 0 ? Math.round(
|
|
2205
|
+
(input.perfStages.captureFrameMs ?? input.perfStages.captureMs ?? 0) / input.totalFrames
|
|
2206
|
+
) : void 0,
|
|
2207
|
+
subTimelineWait: worstSubTimelineWaitOutcome(input.dedupPerfs),
|
|
2208
|
+
captureP50Ms: (() => {
|
|
2209
|
+
const withSamples = input.dedupPerfs.filter((p) => (p.p50TotalMs ?? 0) > 0);
|
|
2210
|
+
if (withSamples.length === 0) return void 0;
|
|
2211
|
+
return withSamples.reduce((a, b) => b.frames > a.frames ? b : a).p50TotalMs;
|
|
2212
|
+
})(),
|
|
2213
|
+
peakRssMb: Math.round(input.peakRssBytes / (1024 * 1024)),
|
|
2214
|
+
peakHeapUsedMb: Math.round(input.peakHeapUsedBytes / (1024 * 1024)),
|
|
2215
|
+
staticDedup: aggregateDedup(input.dedupPerfs),
|
|
2216
|
+
chromeMemory: aggregateChromeMemory(input.dedupPerfs),
|
|
2217
|
+
beginFrameReuse: aggregateBeginFrameReuse(input.dedupPerfs),
|
|
2218
|
+
drawElement: aggregateDrawElement(
|
|
2219
|
+
input.dedupPerfs,
|
|
2220
|
+
input.drawElement ?? { selfVerifyFallback: false }
|
|
2221
|
+
),
|
|
2222
|
+
host: {
|
|
2223
|
+
platform: platform(),
|
|
2224
|
+
arch: arch(),
|
|
2225
|
+
cpuCount: cpus().length,
|
|
2226
|
+
totalMemMb: Math.round(totalmem() / (1024 * 1024)),
|
|
2227
|
+
nodeVersion: process.version,
|
|
2228
|
+
gpuDisabled: input.gpuDisabled
|
|
2229
|
+
}
|
|
2230
|
+
};
|
|
2231
|
+
}
|
|
2232
|
+
|
|
2233
|
+
// src/services/render/captureStageError.ts
|
|
2234
|
+
var CaptureStageError = class extends CaptureFailure {
|
|
2235
|
+
browserConsole;
|
|
2236
|
+
constructor(input) {
|
|
2237
|
+
const classified = classifyCaptureFailure(input.cause);
|
|
2238
|
+
super({
|
|
2239
|
+
kind: classified.kind,
|
|
2240
|
+
message: normalizeErrorMessage(input.cause),
|
|
2241
|
+
cause: input.cause,
|
|
2242
|
+
workerDiagnostics: classified.workerDiagnostics,
|
|
2243
|
+
pageErrorLines: classified.pageErrorLines
|
|
2244
|
+
});
|
|
2245
|
+
this.name = "CaptureStageError";
|
|
2246
|
+
this.browserConsole = withWorkerPageErrors(input.browserConsole, [
|
|
2247
|
+
...classified.pageErrorLines
|
|
2248
|
+
]);
|
|
2249
|
+
if (input.cause instanceof Error && input.cause.stack) {
|
|
2250
|
+
this.stack = input.cause.stack;
|
|
2251
|
+
}
|
|
2252
|
+
}
|
|
2253
|
+
};
|
|
2254
|
+
function wrapCaptureStageError(error, browserConsole) {
|
|
2255
|
+
if (error instanceof CaptureStageError || error instanceof EncoderInterruptedError) return error;
|
|
2256
|
+
return new CaptureStageError({ cause: error, browserConsole });
|
|
2257
|
+
}
|
|
2258
|
+
function getCaptureStageBrowserConsole(error) {
|
|
2259
|
+
if (error instanceof CaptureStageError) return error.browserConsole;
|
|
2260
|
+
if (error instanceof CaptureFailure) return [...error.pageErrorLines];
|
|
2261
|
+
return [];
|
|
2262
|
+
}
|
|
2263
|
+
|
|
2264
|
+
// src/services/render/stages/captureHdrFrameShared.ts
|
|
2265
|
+
import {
|
|
2266
|
+
applyDomLayerMask as applyDomLayerMask2,
|
|
2267
|
+
blitRgba8OverRgb48le as blitRgba8OverRgb48le2,
|
|
2268
|
+
captureAlphaPng as captureAlphaPng2,
|
|
2269
|
+
decodePng as decodePng2,
|
|
2270
|
+
queryElementStacking as queryElementStacking2,
|
|
2271
|
+
removeDomLayerMask as removeDomLayerMask2
|
|
2272
|
+
} from "@hyperframes/engine";
|
|
2273
|
+
|
|
2073
2274
|
// src/services/hdrCompositor.ts
|
|
2275
|
+
import { readSync as readSync2, closeSync as closeSync3 } from "fs";
|
|
2276
|
+
import { join as join6 } from "path";
|
|
2277
|
+
import {
|
|
2278
|
+
captureAlphaPng,
|
|
2279
|
+
applyDomLayerMask,
|
|
2280
|
+
removeDomLayerMask,
|
|
2281
|
+
decodePng,
|
|
2282
|
+
blitRgba8OverRgb48le,
|
|
2283
|
+
blitRgb48leRegion,
|
|
2284
|
+
groupIntoLayers,
|
|
2285
|
+
blitRgb48leAffine,
|
|
2286
|
+
parseTransformMatrix,
|
|
2287
|
+
convertTransfer,
|
|
2288
|
+
isVideoHiddenBeforeStreamStart
|
|
2289
|
+
} from "@hyperframes/engine";
|
|
2074
2290
|
function countNonZeroAlpha(rgba) {
|
|
2075
2291
|
let n = 0;
|
|
2076
2292
|
for (let p = 3; p < rgba.length; p += 4) {
|
|
@@ -2537,7 +2753,7 @@ import {
|
|
|
2537
2753
|
resolveVideoExtractionWindow,
|
|
2538
2754
|
runFfmpeg
|
|
2539
2755
|
} from "@hyperframes/engine";
|
|
2540
|
-
import { fpsToFfmpegArg, fpsToNumber as
|
|
2756
|
+
import { fpsToFfmpegArg, fpsToNumber as fpsToNumber4 } from "@hyperframes/core";
|
|
2541
2757
|
var NO_FOLLOW_FLAG = constants2.O_NOFOLLOW ?? 0;
|
|
2542
2758
|
function tempDirSafePrefix(id) {
|
|
2543
2759
|
const safe = id.replace(/[^A-Za-z0-9_.-]/g, "_").slice(0, 80);
|
|
@@ -2773,7 +2989,7 @@ async function extractHdrVideoFrames(args) {
|
|
|
2773
2989
|
const { estimatedBytes, budgetBytes } = assertHdrExtractionDiskHeadroom(
|
|
2774
2990
|
framesDir,
|
|
2775
2991
|
plannedVideos,
|
|
2776
|
-
|
|
2992
|
+
fpsToNumber4(job.config.fps),
|
|
2777
2993
|
log
|
|
2778
2994
|
);
|
|
2779
2995
|
const releaseReservation = reserveHdrExtractionBytes(estimatedBytes, budgetBytes);
|
|
@@ -3226,222 +3442,12 @@ import {
|
|
|
3226
3442
|
prepareCaptureSessionForReuse,
|
|
3227
3443
|
spawnStreamingEncoder
|
|
3228
3444
|
} 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
3445
|
var DEFAULT_CAPTURE_STALL_MS = 6e4;
|
|
3443
3446
|
var DE_STALL_POLL_MS = 5e3;
|
|
3444
3447
|
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.";
|
|
3448
|
+
function poolFailure(error, probeSession) {
|
|
3449
|
+
return wrapCaptureStageError(error, probeSession?.browserConsoleBuffer ?? []);
|
|
3450
|
+
}
|
|
3445
3451
|
var ParallelCaptureStallError = class extends Error {
|
|
3446
3452
|
variant;
|
|
3447
3453
|
constructor(args) {
|
|
@@ -3888,7 +3894,7 @@ async function runCaptureStreamingStage(input) {
|
|
|
3888
3894
|
}
|
|
3889
3895
|
);
|
|
3890
3896
|
} catch (err) {
|
|
3891
|
-
if (parallelDrainError) throw parallelDrainError;
|
|
3897
|
+
if (parallelDrainError) throw poolFailure(parallelDrainError, probeSession);
|
|
3892
3898
|
if (stalled && abortSignal?.aborted !== true) {
|
|
3893
3899
|
throw new ParallelCaptureStallError({
|
|
3894
3900
|
variant: "pool",
|
|
@@ -3899,13 +3905,15 @@ async function runCaptureStreamingStage(input) {
|
|
|
3899
3905
|
phaseSummary: phaseSummary()
|
|
3900
3906
|
});
|
|
3901
3907
|
}
|
|
3902
|
-
throw err;
|
|
3908
|
+
throw poolFailure(err, probeSession);
|
|
3903
3909
|
} finally {
|
|
3904
3910
|
clearInterval(stallTimer);
|
|
3905
3911
|
abortSignal?.removeEventListener("abort", forwardParentAbort);
|
|
3906
3912
|
}
|
|
3907
|
-
if (parallelDrainError) throw parallelDrainError;
|
|
3913
|
+
if (parallelDrainError) throw poolFailure(parallelDrainError, probeSession);
|
|
3908
3914
|
pushWorkerDedupPerfs(workerResults, dedupPerfs);
|
|
3915
|
+
const workerPageErrors = [];
|
|
3916
|
+
pushWorkerPageErrors(workerResults, workerPageErrors);
|
|
3909
3917
|
if (parallelGuardRan) {
|
|
3910
3918
|
deDrainStats = parallelStats;
|
|
3911
3919
|
}
|
|
@@ -3915,6 +3923,7 @@ async function runCaptureStreamingStage(input) {
|
|
|
3915
3923
|
await closeCaptureSession(probeSession);
|
|
3916
3924
|
probeSession = null;
|
|
3917
3925
|
}
|
|
3926
|
+
lastBrowserConsole = withWorkerPageErrors(lastBrowserConsole, workerPageErrors);
|
|
3918
3927
|
} else {
|
|
3919
3928
|
const videoInjector = createRenderVideoFrameInjector();
|
|
3920
3929
|
const session = probeSession ?? await createCaptureSession(
|
|
@@ -4361,8 +4370,9 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4361
4370
|
|
|
4362
4371
|
// src/services/render/segmentManifest.ts
|
|
4363
4372
|
import { createHash as createHash2 } from "node:crypto";
|
|
4364
|
-
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4,
|
|
4373
|
+
import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync4, statSync as statSync3, writeFileSync as writeFileSync3 } from "node:fs";
|
|
4365
4374
|
import { join as join10 } from "node:path";
|
|
4375
|
+
import { renameWithRetry as renameWithRetry2 } from "@hyperframes/engine";
|
|
4366
4376
|
var MANIFEST_FILENAME = "segments.json";
|
|
4367
4377
|
function computeSegmentPlanHash(input) {
|
|
4368
4378
|
const ordered = [
|
|
@@ -4418,7 +4428,7 @@ function writeSegmentManifest(segmentDir, manifest) {
|
|
|
4418
4428
|
mkdirSync4(segmentDir, { recursive: true });
|
|
4419
4429
|
const tmp = join10(segmentDir, `${MANIFEST_FILENAME}.${process.pid}.tmp`);
|
|
4420
4430
|
writeFileSync3(tmp, JSON.stringify(manifest, null, 2), "utf-8");
|
|
4421
|
-
|
|
4431
|
+
renameWithRetry2(tmp, join10(segmentDir, MANIFEST_FILENAME));
|
|
4422
4432
|
}
|
|
4423
4433
|
async function probeSegmentFrameCount(path, probe) {
|
|
4424
4434
|
try {
|
|
@@ -5470,19 +5480,11 @@ import {
|
|
|
5470
5480
|
|
|
5471
5481
|
// src/services/animatedGifPrep.ts
|
|
5472
5482
|
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";
|
|
5483
|
+
import { copyFileSync as copyFileSync2, existsSync as existsSync8, mkdirSync as mkdirSync5, readFileSync as readFileSync5, rmSync as rmSync6, statSync as statSync4 } from "node:fs";
|
|
5482
5484
|
import { dirname as dirname5, isAbsolute as isAbsolute2, join as join12, resolve as resolve5 } from "node:path";
|
|
5483
5485
|
import { parseHTML as parseHTML3 } from "linkedom";
|
|
5484
5486
|
import { parseAnimatedGifMetadata } from "@hyperframes/core";
|
|
5485
|
-
import { DEFAULT_VP9_CPU_USED, runFfmpeg as runFfmpeg2 } from "@hyperframes/engine";
|
|
5487
|
+
import { DEFAULT_VP9_CPU_USED, runFfmpeg as runFfmpeg2, renameWithRetry as renameWithRetry3 } from "@hyperframes/engine";
|
|
5486
5488
|
var PREPARED_GIF_SUBDIR = "_animated_gif";
|
|
5487
5489
|
var CACHE_SCHEMA = "hfgif-v1";
|
|
5488
5490
|
function splitUrlSuffix(src) {
|
|
@@ -5661,7 +5663,7 @@ async function ensurePreparedWebm(input) {
|
|
|
5661
5663
|
throw new Error("Animated GIF transcode produced an empty output");
|
|
5662
5664
|
}
|
|
5663
5665
|
if (!isUsableFile(input.cachePath)) {
|
|
5664
|
-
|
|
5666
|
+
renameWithRetry3(tmpPath, input.cachePath);
|
|
5665
5667
|
} else {
|
|
5666
5668
|
rmSync6(tmpPath, { force: true });
|
|
5667
5669
|
}
|
|
@@ -8068,6 +8070,10 @@ async function runProbeStage(input) {
|
|
|
8068
8070
|
if (el.loop && !existing.loop) {
|
|
8069
8071
|
existing.loop = true;
|
|
8070
8072
|
}
|
|
8073
|
+
const audio = composition.audios.find(
|
|
8074
|
+
(audio2) => audio2.type === "video" && audio2.id === `${el.id}-audio`
|
|
8075
|
+
);
|
|
8076
|
+
if (audio) audio.loop = existing.loop;
|
|
8071
8077
|
}
|
|
8072
8078
|
} else if (!compiled.droppedMediaIds.has(el.id)) {
|
|
8073
8079
|
composition.videos.push({
|
|
@@ -8105,6 +8111,7 @@ async function runProbeStage(input) {
|
|
|
8105
8111
|
el,
|
|
8106
8112
|
authoredStarts.get(el.id) ?? existing.mediaStart
|
|
8107
8113
|
);
|
|
8114
|
+
existing.loop = el.loop;
|
|
8108
8115
|
if (el.volume > 0 && Math.abs((existing.volume ?? 1) - el.volume) > BROWSER_MEDIA_EPSILON) {
|
|
8109
8116
|
existing.volume = el.volume;
|
|
8110
8117
|
}
|
|
@@ -8116,6 +8123,7 @@ async function runProbeStage(input) {
|
|
|
8116
8123
|
start: el.start,
|
|
8117
8124
|
end: resolveBrowserMediaEnd(el.start, el.end, el.duration),
|
|
8118
8125
|
mediaStart: el.mediaStart,
|
|
8126
|
+
loop: el.loop,
|
|
8119
8127
|
layer: 0,
|
|
8120
8128
|
volume: el.volume,
|
|
8121
8129
|
type: "audio"
|
|
@@ -8339,6 +8347,10 @@ import {
|
|
|
8339
8347
|
extractMediaMetadata as extractMediaMetadata3,
|
|
8340
8348
|
isVideoPastTimelineEnd,
|
|
8341
8349
|
isHdrColorSpace as isHdrColorSpace2,
|
|
8350
|
+
rebaseVideoToWindow,
|
|
8351
|
+
resolveFinalFrameExtractionWindow as resolveFinalFrameExtractionWindow2,
|
|
8352
|
+
resolveVideoExtractionWindow as resolveVideoExtractionWindow2,
|
|
8353
|
+
isHttpUrl as isHttpUrl2,
|
|
8342
8354
|
resolveProjectRelativeSrc as resolveProjectRelativeSrc3,
|
|
8343
8355
|
runVideoExtractionWithRetry,
|
|
8344
8356
|
safeVideoExtractionSourceIdentity
|
|
@@ -8699,6 +8711,8 @@ function appendAutoDetectedVideoAudio(composition, extracted) {
|
|
|
8699
8711
|
start: video.start,
|
|
8700
8712
|
end: video.end,
|
|
8701
8713
|
mediaStart: video.mediaStart,
|
|
8714
|
+
playbackRate: video.playbackRate,
|
|
8715
|
+
loop: video.loop,
|
|
8702
8716
|
layer: 0,
|
|
8703
8717
|
volume: 1,
|
|
8704
8718
|
type: "video"
|
|
@@ -8718,7 +8732,7 @@ import {
|
|
|
8718
8732
|
|
|
8719
8733
|
// src/services/render/audioPadTrim.ts
|
|
8720
8734
|
import { spawn } from "node:child_process";
|
|
8721
|
-
import { mkdtempSync as mkdtempSync3,
|
|
8735
|
+
import { mkdtempSync as mkdtempSync3, rmSync as rmSync7 } from "node:fs";
|
|
8722
8736
|
import { dirname as dirname7, join as join17 } from "node:path";
|
|
8723
8737
|
import {
|
|
8724
8738
|
DEFAULT_CONFIG,
|
|
@@ -8727,6 +8741,7 @@ import {
|
|
|
8727
8741
|
extractAudioMetadata as extractAudioMetadata3,
|
|
8728
8742
|
getFfprobeBinary,
|
|
8729
8743
|
ManagedChildProcess,
|
|
8744
|
+
renameWithRetry as renameWithRetry4,
|
|
8730
8745
|
runFfmpeg as runFfmpeg4,
|
|
8731
8746
|
trackChildProcess
|
|
8732
8747
|
} from "@hyperframes/engine";
|
|
@@ -8982,7 +8997,7 @@ async function enforceAacTruePeak(input) {
|
|
|
8982
8997
|
}
|
|
8983
8998
|
if (truePeakDbfs <= AAC_DELIVERY_TRUE_PEAK_DBFS) {
|
|
8984
8999
|
if (measuredPath !== correctedPath) return { success: true };
|
|
8985
|
-
|
|
9000
|
+
renameWithRetry4(correctedPath, input.audioPath);
|
|
8986
9001
|
return { success: true, loweredDb: Number((-attenuationDb).toFixed(2)) };
|
|
8987
9002
|
}
|
|
8988
9003
|
if (pass === MAX_TRUE_PEAK_CORRECTION_PASSES) break;
|
|
@@ -9172,6 +9187,7 @@ async function runAudioStage(input) {
|
|
|
9172
9187
|
const result = await mixAudioForDelivery(input, duration, pcmSourcePath);
|
|
9173
9188
|
let audioLoweredDb;
|
|
9174
9189
|
if (result.hasAudio) {
|
|
9190
|
+
const guardStart = Date.now();
|
|
9175
9191
|
const peak = await constrainAacTruePeak({
|
|
9176
9192
|
audioPath: result.audioOutputPath,
|
|
9177
9193
|
sourcePath: pcmSourcePath,
|
|
@@ -9181,6 +9197,7 @@ async function runAudioStage(input) {
|
|
|
9181
9197
|
});
|
|
9182
9198
|
if (!peak.success) throw encoderFailureError("Audio true-peak check failed", peak);
|
|
9183
9199
|
audioLoweredDb = peak.loweredDb;
|
|
9200
|
+
input.log?.info("[audio] phases", { ...result.audioPhaseMs, guard: Date.now() - guardStart });
|
|
9184
9201
|
}
|
|
9185
9202
|
return { ...result, audioLoweredDb, audioProcessMs: Date.now() - stageStart };
|
|
9186
9203
|
} finally {
|
|
@@ -9206,6 +9223,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9206
9223
|
let hasAudio = false;
|
|
9207
9224
|
let audioError;
|
|
9208
9225
|
let audioFailures;
|
|
9226
|
+
let audioPhaseMs;
|
|
9209
9227
|
if (audios.length > 0) {
|
|
9210
9228
|
let audioResult;
|
|
9211
9229
|
try {
|
|
@@ -9255,6 +9273,7 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9255
9273
|
assertAudioNotInterrupted(audioResult.failures);
|
|
9256
9274
|
hasAudio = audioResult.success;
|
|
9257
9275
|
audioFailures = audioResult.failures;
|
|
9276
|
+
audioPhaseMs = audioResult.phaseMs;
|
|
9258
9277
|
if (!hasAudio) {
|
|
9259
9278
|
audioError = audioResult.error ?? "audio mix failed for an unknown reason";
|
|
9260
9279
|
for (const failure of audioResult.failures ?? []) {
|
|
@@ -9273,7 +9292,8 @@ async function mixAudioForDelivery(input, duration, pcmSourcePath) {
|
|
|
9273
9292
|
audioOutputPath,
|
|
9274
9293
|
hasAudio,
|
|
9275
9294
|
audioError,
|
|
9276
|
-
audioFailures
|
|
9295
|
+
audioFailures,
|
|
9296
|
+
audioPhaseMs
|
|
9277
9297
|
};
|
|
9278
9298
|
}
|
|
9279
9299
|
|
|
@@ -9402,6 +9422,7 @@ async function runCaptureStage(input) {
|
|
|
9402
9422
|
let { workerCount } = plan;
|
|
9403
9423
|
const { forceScreenshot } = plan;
|
|
9404
9424
|
let lastBrowserConsole = [];
|
|
9425
|
+
const workerPageErrors = [];
|
|
9405
9426
|
let captureBeyondViewport = probeSession?.options.captureBeyondViewport;
|
|
9406
9427
|
const captureCfg = cfg.forceScreenshot === forceScreenshot ? cfg : { ...cfg, forceScreenshot };
|
|
9407
9428
|
if (frameRange !== void 0) {
|
|
@@ -9439,6 +9460,7 @@ async function runCaptureStage(input) {
|
|
|
9439
9460
|
abortSignal,
|
|
9440
9461
|
frameRangeStart: frameRange?.startFrame,
|
|
9441
9462
|
dedupPerfs,
|
|
9463
|
+
pageErrorLines: workerPageErrors,
|
|
9442
9464
|
onProgress: (progress) => {
|
|
9443
9465
|
if (progress.latestWorkerPhase) {
|
|
9444
9466
|
if (progress.capturedFrames === 0) reportWorkerStartup(job, progress, onProgress);
|
|
@@ -9459,6 +9481,11 @@ async function runCaptureStage(input) {
|
|
|
9459
9481
|
},
|
|
9460
9482
|
cfg: captureCfg,
|
|
9461
9483
|
log
|
|
9484
|
+
}).catch((error) => {
|
|
9485
|
+
throw wrapCaptureStageError(
|
|
9486
|
+
error,
|
|
9487
|
+
withWorkerPageErrors(probeSession?.browserConsoleBuffer ?? [], workerPageErrors)
|
|
9488
|
+
);
|
|
9462
9489
|
});
|
|
9463
9490
|
captureAttempts.push(...attempts);
|
|
9464
9491
|
const lastAttempt = attempts[attempts.length - 1];
|
|
@@ -9471,6 +9498,7 @@ async function runCaptureStage(input) {
|
|
|
9471
9498
|
await closeCaptureSession5(probeSession);
|
|
9472
9499
|
probeSession = null;
|
|
9473
9500
|
}
|
|
9501
|
+
lastBrowserConsole = withWorkerPageErrors(lastBrowserConsole, workerPageErrors);
|
|
9474
9502
|
} else {
|
|
9475
9503
|
const sequential = await runSequentialDiskCapture(
|
|
9476
9504
|
input,
|
|
@@ -10405,6 +10433,7 @@ async function runCaptureHdrStage(input) {
|
|
|
10405
10433
|
width,
|
|
10406
10434
|
height,
|
|
10407
10435
|
codec: preset.codec,
|
|
10436
|
+
useGpu: job.config.useGpu,
|
|
10408
10437
|
preset: preset.preset,
|
|
10409
10438
|
quality: effectiveQuality,
|
|
10410
10439
|
bitrate: effectiveBitrate,
|
|
@@ -10785,7 +10814,7 @@ function videoEncoderOptions(input, engineCfg) {
|
|
|
10785
10814
|
};
|
|
10786
10815
|
}
|
|
10787
10816
|
function canEncodeWhileCapturing(input, workerCount, cpuCount) {
|
|
10788
|
-
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"
|
|
10817
|
+
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";
|
|
10789
10818
|
}
|
|
10790
10819
|
async function readLandedFrame(workerPath, mergedPath) {
|
|
10791
10820
|
if (workerPath !== void 0) {
|
|
@@ -11440,6 +11469,7 @@ async function executeDiskCaptureWithAdaptiveRetry(options) {
|
|
|
11440
11469
|
options.cfg
|
|
11441
11470
|
);
|
|
11442
11471
|
pushWorkerDedupPerfs(workerResults, options.dedupPerfs);
|
|
11472
|
+
if (options.pageErrorLines) pushWorkerPageErrors(workerResults, options.pageErrorLines);
|
|
11443
11473
|
} finally {
|
|
11444
11474
|
await mergeWorkerFrames(attemptWorkDir, tasks, options.framesDir);
|
|
11445
11475
|
}
|
|
@@ -14055,7 +14085,10 @@ import {
|
|
|
14055
14085
|
import {
|
|
14056
14086
|
getEncoderPreset as getEncoderPreset4,
|
|
14057
14087
|
normalizeVp9CpuUsed,
|
|
14058
|
-
resolveConfig as resolveConfig3
|
|
14088
|
+
resolveConfig as resolveConfig3,
|
|
14089
|
+
declareContentAddressedUrl,
|
|
14090
|
+
renameWithRetry as renameWithRetry6,
|
|
14091
|
+
declareProbeFactsUrl
|
|
14059
14092
|
} from "@hyperframes/engine";
|
|
14060
14093
|
|
|
14061
14094
|
// src/services/distributed/planFrameCost.ts
|
|
@@ -14125,6 +14158,7 @@ var FIELD_DELIMITER = Buffer.from([0]);
|
|
|
14125
14158
|
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure3, runFfmpeg as runFfmpeg6 } from "@hyperframes/engine";
|
|
14126
14159
|
|
|
14127
14160
|
// src/services/distributed/mp4Stitch.ts
|
|
14161
|
+
import { renameWithRetry as renameWithRetry5 } from "@hyperframes/engine";
|
|
14128
14162
|
var SCAN_BYTES = 64 * 1024;
|
|
14129
14163
|
|
|
14130
14164
|
// src/services/distributed/chunkAudio.ts
|