@hyperframes/producer 0.4.15 → 0.4.17
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/benchmark.d.ts +9 -2
- package/dist/benchmark.d.ts.map +1 -1
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +4 -4
- package/dist/index.js +364 -199
- package/dist/index.js.map +3 -3
- package/dist/logger.d.ts +19 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/public-server.js +364 -199
- package/dist/public-server.js.map +3 -3
- package/dist/services/frameDirCache.d.ts +76 -0
- package/dist/services/frameDirCache.d.ts.map +1 -0
- package/dist/services/renderOrchestrator.d.ts +17 -0
- package/dist/services/renderOrchestrator.d.ts.map +1 -1
- package/dist/utils/ffprobe.d.ts +1 -1
- package/dist/utils/ffprobe.d.ts.map +1 -1
- package/package.json +4 -3
package/dist/public-server.js
CHANGED
|
@@ -57866,7 +57866,7 @@ var require_util2 = __commonJS({
|
|
|
57866
57866
|
}
|
|
57867
57867
|
path12 = url.path;
|
|
57868
57868
|
}
|
|
57869
|
-
var
|
|
57869
|
+
var isAbsolute5 = exports.isAbsolute(path12);
|
|
57870
57870
|
var parts = path12.split(/\/+/);
|
|
57871
57871
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57872
57872
|
part = parts[i];
|
|
@@ -57886,7 +57886,7 @@ var require_util2 = __commonJS({
|
|
|
57886
57886
|
}
|
|
57887
57887
|
path12 = parts.join("/");
|
|
57888
57888
|
if (path12 === "") {
|
|
57889
|
-
path12 =
|
|
57889
|
+
path12 = isAbsolute5 ? "/" : ".";
|
|
57890
57890
|
}
|
|
57891
57891
|
if (url) {
|
|
57892
57892
|
url.path = path12;
|
|
@@ -104407,6 +104407,34 @@ function getGpuEncoderName(encoder, codec) {
|
|
|
104407
104407
|
return codec === "h264" ? "libx264" : "libx265";
|
|
104408
104408
|
}
|
|
104409
104409
|
}
|
|
104410
|
+
var NVENC_PRESET_MAP = {
|
|
104411
|
+
ultrafast: "p1",
|
|
104412
|
+
superfast: "p1",
|
|
104413
|
+
veryfast: "p2",
|
|
104414
|
+
faster: "p3",
|
|
104415
|
+
fast: "p4",
|
|
104416
|
+
medium: "p4",
|
|
104417
|
+
slow: "p5",
|
|
104418
|
+
slower: "p6",
|
|
104419
|
+
veryslow: "p7",
|
|
104420
|
+
placebo: "p7"
|
|
104421
|
+
};
|
|
104422
|
+
var QSV_PRESET_MAP = {
|
|
104423
|
+
ultrafast: "veryfast",
|
|
104424
|
+
superfast: "veryfast",
|
|
104425
|
+
placebo: "veryslow"
|
|
104426
|
+
};
|
|
104427
|
+
function mapPresetForGpuEncoder(encoder, preset) {
|
|
104428
|
+
switch (encoder) {
|
|
104429
|
+
case "nvenc":
|
|
104430
|
+
if (/^p[1-7]$/.test(preset)) return preset;
|
|
104431
|
+
return NVENC_PRESET_MAP[preset] ?? "p4";
|
|
104432
|
+
case "qsv":
|
|
104433
|
+
return QSV_PRESET_MAP[preset] ?? preset;
|
|
104434
|
+
default:
|
|
104435
|
+
return preset;
|
|
104436
|
+
}
|
|
104437
|
+
}
|
|
104410
104438
|
|
|
104411
104439
|
// ../engine/src/utils/hdr.ts
|
|
104412
104440
|
function isHdrColorSpace(cs) {
|
|
@@ -104450,6 +104478,16 @@ function analyzeCompositionHdr(colorSpaces) {
|
|
|
104450
104478
|
// ../engine/src/utils/runFfmpeg.ts
|
|
104451
104479
|
import { spawn as spawn4 } from "child_process";
|
|
104452
104480
|
var DEFAULT_TIMEOUT2 = 3e5;
|
|
104481
|
+
var DEFAULT_STDERR_TAIL_LINES = 15;
|
|
104482
|
+
function formatFfmpegError(exitCode, stderr, tailLines = DEFAULT_STDERR_TAIL_LINES) {
|
|
104483
|
+
const tail = (stderr ?? "").split(/\r?\n/).filter((line) => line.length > 0).slice(-tailLines).join("\n");
|
|
104484
|
+
if (exitCode === null) {
|
|
104485
|
+
return tail ? `[FFmpeg] ${tail}` : "[FFmpeg] process error";
|
|
104486
|
+
}
|
|
104487
|
+
return tail ? `FFmpeg exited with code ${exitCode}
|
|
104488
|
+
ffmpeg stderr (tail):
|
|
104489
|
+
${tail}` : `FFmpeg exited with code ${exitCode}`;
|
|
104490
|
+
}
|
|
104453
104491
|
async function runFfmpeg(args, opts) {
|
|
104454
104492
|
const startMs = Date.now();
|
|
104455
104493
|
const signal = opts?.signal;
|
|
@@ -104560,7 +104598,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
104560
104598
|
args.push("-c:v", encoderName);
|
|
104561
104599
|
switch (gpuEncoder) {
|
|
104562
104600
|
case "nvenc":
|
|
104563
|
-
args.push("-preset", preset);
|
|
104601
|
+
args.push("-preset", mapPresetForGpuEncoder("nvenc", preset));
|
|
104564
104602
|
if (bitrate) args.push("-b:v", bitrate);
|
|
104565
104603
|
else args.push("-cq", String(quality));
|
|
104566
104604
|
break;
|
|
@@ -104579,7 +104617,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
104579
104617
|
else args.push("-qp", String(quality));
|
|
104580
104618
|
break;
|
|
104581
104619
|
case "qsv":
|
|
104582
|
-
args.push("-preset", preset);
|
|
104620
|
+
args.push("-preset", mapPresetForGpuEncoder("qsv", preset));
|
|
104583
104621
|
if (bitrate) args.push("-b:v", bitrate);
|
|
104584
104622
|
else args.push("-global_quality", String(quality));
|
|
104585
104623
|
break;
|
|
@@ -104719,7 +104757,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
104719
104757
|
durationMs,
|
|
104720
104758
|
framesEncoded: 0,
|
|
104721
104759
|
fileSize: 0,
|
|
104722
|
-
error:
|
|
104760
|
+
error: formatFfmpegError(code, stderr)
|
|
104723
104761
|
});
|
|
104724
104762
|
return;
|
|
104725
104763
|
}
|
|
@@ -104889,7 +104927,7 @@ async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, confi
|
|
|
104889
104927
|
success: result.success,
|
|
104890
104928
|
outputPath,
|
|
104891
104929
|
durationMs: result.durationMs,
|
|
104892
|
-
error: !result.success ? result.exitCode
|
|
104930
|
+
error: !result.success ? formatFfmpegError(result.exitCode, result.stderr) : void 0
|
|
104893
104931
|
};
|
|
104894
104932
|
}
|
|
104895
104933
|
async function applyFaststart(inputPath, outputPath, signal, config2) {
|
|
@@ -104912,7 +104950,7 @@ async function applyFaststart(inputPath, outputPath, signal, config2) {
|
|
|
104912
104950
|
success: result.success,
|
|
104913
104951
|
outputPath,
|
|
104914
104952
|
durationMs: result.durationMs,
|
|
104915
|
-
error: !result.success ? result.exitCode
|
|
104953
|
+
error: !result.success ? formatFfmpegError(result.exitCode, result.stderr) : void 0
|
|
104916
104954
|
};
|
|
104917
104955
|
}
|
|
104918
104956
|
|
|
@@ -105005,7 +105043,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
105005
105043
|
args.push("-c:v", encoderName);
|
|
105006
105044
|
switch (gpuEncoder) {
|
|
105007
105045
|
case "nvenc":
|
|
105008
|
-
args.push("-preset", preset);
|
|
105046
|
+
args.push("-preset", mapPresetForGpuEncoder("nvenc", preset));
|
|
105009
105047
|
if (bitrate) args.push("-b:v", bitrate);
|
|
105010
105048
|
else args.push("-cq", String(quality));
|
|
105011
105049
|
break;
|
|
@@ -105024,7 +105062,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
105024
105062
|
else args.push("-qp", String(quality));
|
|
105025
105063
|
break;
|
|
105026
105064
|
case "qsv":
|
|
105027
|
-
args.push("-preset", preset);
|
|
105065
|
+
args.push("-preset", mapPresetForGpuEncoder("qsv", preset));
|
|
105028
105066
|
if (bitrate) args.push("-b:v", bitrate);
|
|
105029
105067
|
else args.push("-global_quality", String(quality));
|
|
105030
105068
|
break;
|
|
@@ -105180,7 +105218,7 @@ Process error: ${err.message}`;
|
|
|
105180
105218
|
success: false,
|
|
105181
105219
|
durationMs,
|
|
105182
105220
|
fileSize: 0,
|
|
105183
|
-
error:
|
|
105221
|
+
error: formatFfmpegError(exitCode, stderr)
|
|
105184
105222
|
};
|
|
105185
105223
|
}
|
|
105186
105224
|
const fileSize = existsSync6(outputPath) ? statSync4(outputPath).size : 0;
|
|
@@ -105194,7 +105232,7 @@ Process error: ${err.message}`;
|
|
|
105194
105232
|
// ../engine/src/services/videoFrameExtractor.ts
|
|
105195
105233
|
import { spawn as spawn8 } from "child_process";
|
|
105196
105234
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync4, rmSync } from "fs";
|
|
105197
|
-
import { join as join8 } from "path";
|
|
105235
|
+
import { isAbsolute as isAbsolute2, join as join8 } from "path";
|
|
105198
105236
|
|
|
105199
105237
|
// ../engine/src/utils/ffprobe.ts
|
|
105200
105238
|
import { spawn as spawn7 } from "child_process";
|
|
@@ -105309,7 +105347,7 @@ function parseFrameRate(frameRateStr) {
|
|
|
105309
105347
|
}
|
|
105310
105348
|
return parseFloat(frameRateStr) || 0;
|
|
105311
105349
|
}
|
|
105312
|
-
async function
|
|
105350
|
+
async function extractMediaMetadata(filePath) {
|
|
105313
105351
|
const cached = videoMetadataCache.get(filePath);
|
|
105314
105352
|
if (cached) return cached;
|
|
105315
105353
|
const probePromise = (async () => {
|
|
@@ -105595,7 +105633,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
105595
105633
|
const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
|
|
105596
105634
|
const videoOutputDir = join8(outputDir, videoId);
|
|
105597
105635
|
if (!existsSync8(videoOutputDir)) mkdirSync5(videoOutputDir, { recursive: true });
|
|
105598
|
-
const metadata = await
|
|
105636
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
105599
105637
|
const framePattern = `frame_%05d.${format3}`;
|
|
105600
105638
|
const outputPattern = join8(videoOutputDir, framePattern);
|
|
105601
105639
|
const isHdr = isHdrColorSpace(metadata.colorSpace);
|
|
@@ -105744,7 +105782,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
105744
105782
|
if (signal?.aborted) break;
|
|
105745
105783
|
try {
|
|
105746
105784
|
let videoPath = video.src;
|
|
105747
|
-
if (!videoPath
|
|
105785
|
+
if (!isAbsolute2(videoPath) && !isHttpUrl(videoPath)) {
|
|
105748
105786
|
const fromCompiled = compiledDir ? join8(compiledDir, videoPath) : null;
|
|
105749
105787
|
videoPath = fromCompiled && existsSync8(fromCompiled) ? fromCompiled : join8(baseDir, videoPath);
|
|
105750
105788
|
}
|
|
@@ -105764,7 +105802,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
105764
105802
|
}
|
|
105765
105803
|
const videoColorSpaces = await Promise.all(
|
|
105766
105804
|
resolvedVideos.map(async ({ videoPath }) => {
|
|
105767
|
-
const metadata = await
|
|
105805
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
105768
105806
|
return metadata.colorSpace;
|
|
105769
105807
|
})
|
|
105770
105808
|
);
|
|
@@ -105797,7 +105835,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
105797
105835
|
if (signal?.aborted) break;
|
|
105798
105836
|
const entry = resolvedVideos[i];
|
|
105799
105837
|
if (!entry) continue;
|
|
105800
|
-
const metadata = await
|
|
105838
|
+
const metadata = await extractMediaMetadata(entry.videoPath);
|
|
105801
105839
|
if (!metadata.isVFR) continue;
|
|
105802
105840
|
let segDuration = entry.video.end - entry.video.start;
|
|
105803
105841
|
if (!Number.isFinite(segDuration) || segDuration <= 0) {
|
|
@@ -105833,7 +105871,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
105833
105871
|
try {
|
|
105834
105872
|
let videoDuration = video.end - video.start;
|
|
105835
105873
|
if (!Number.isFinite(videoDuration) || videoDuration <= 0) {
|
|
105836
|
-
const metadata = await
|
|
105874
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
105837
105875
|
const sourceDuration = metadata.durationSeconds - video.mediaStart;
|
|
105838
105876
|
videoDuration = sourceDuration > 0 ? sourceDuration : metadata.durationSeconds;
|
|
105839
105877
|
video.end = video.start + videoDuration;
|
|
@@ -106208,7 +106246,7 @@ async function queryElementStacking(page, nativeHdrIds) {
|
|
|
106208
106246
|
|
|
106209
106247
|
// ../engine/src/services/audioMixer.ts
|
|
106210
106248
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
|
|
106211
|
-
import { join as join9, dirname as dirname7 } from "path";
|
|
106249
|
+
import { isAbsolute as isAbsolute3, join as join9, dirname as dirname7 } from "path";
|
|
106212
106250
|
function parseAudioElements(html) {
|
|
106213
106251
|
const elements = [];
|
|
106214
106252
|
const { document: document2 } = parseHTML(html);
|
|
@@ -106435,7 +106473,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
106435
106473
|
}
|
|
106436
106474
|
try {
|
|
106437
106475
|
let srcPath = element.src;
|
|
106438
|
-
if (!srcPath
|
|
106476
|
+
if (!isAbsolute3(srcPath) && !isHttpUrl(srcPath)) {
|
|
106439
106477
|
const fromCompiled = compiledDir ? join9(compiledDir, srcPath) : null;
|
|
106440
106478
|
srcPath = fromCompiled && existsSync9(fromCompiled) ? fromCompiled : join9(baseDir, srcPath);
|
|
106441
106479
|
}
|
|
@@ -107161,13 +107199,51 @@ function normalizeObjectFit(value) {
|
|
|
107161
107199
|
}
|
|
107162
107200
|
function parseTransformMatrix(css) {
|
|
107163
107201
|
if (!css || css === "none") return null;
|
|
107164
|
-
const
|
|
107202
|
+
const match2d = css.match(
|
|
107165
107203
|
/^matrix\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,)]+)\s*\)$/
|
|
107166
107204
|
);
|
|
107167
|
-
if (
|
|
107168
|
-
|
|
107169
|
-
|
|
107170
|
-
|
|
107205
|
+
if (match2d) {
|
|
107206
|
+
const values = match2d.slice(1, 7).map(Number);
|
|
107207
|
+
if (!values.every(Number.isFinite)) return null;
|
|
107208
|
+
return values;
|
|
107209
|
+
}
|
|
107210
|
+
const match3d = css.match(/^matrix3d\(\s*([^)]+)\)$/);
|
|
107211
|
+
if (match3d) {
|
|
107212
|
+
const raw2 = match3d[1];
|
|
107213
|
+
if (!raw2) return null;
|
|
107214
|
+
const parts = raw2.split(",").map((s) => Number(s.trim()));
|
|
107215
|
+
if (parts.length !== 16 || !parts.every(Number.isFinite)) return null;
|
|
107216
|
+
warnIfZSignificant(parts);
|
|
107217
|
+
return [
|
|
107218
|
+
parts[0],
|
|
107219
|
+
parts[1],
|
|
107220
|
+
parts[4],
|
|
107221
|
+
parts[5],
|
|
107222
|
+
parts[12],
|
|
107223
|
+
parts[13]
|
|
107224
|
+
];
|
|
107225
|
+
}
|
|
107226
|
+
return null;
|
|
107227
|
+
}
|
|
107228
|
+
var warnedZSignificant = false;
|
|
107229
|
+
var Z_EPSILON = 1e-6;
|
|
107230
|
+
function warnIfZSignificant(parts) {
|
|
107231
|
+
if (warnedZSignificant) return;
|
|
107232
|
+
const a3 = parts[8] ?? 0;
|
|
107233
|
+
const b3 = parts[9] ?? 0;
|
|
107234
|
+
const c1 = parts[2] ?? 0;
|
|
107235
|
+
const c2 = parts[6] ?? 0;
|
|
107236
|
+
const c3 = parts[10] ?? 1;
|
|
107237
|
+
const d1 = parts[3] ?? 0;
|
|
107238
|
+
const d2 = parts[7] ?? 0;
|
|
107239
|
+
const d3 = parts[11] ?? 0;
|
|
107240
|
+
const d4 = parts[15] ?? 1;
|
|
107241
|
+
if (Math.abs(a3) > Z_EPSILON || Math.abs(b3) > Z_EPSILON || Math.abs(c1) > Z_EPSILON || Math.abs(c2) > Z_EPSILON || Math.abs(c3 - 1) > Z_EPSILON || Math.abs(d1) > Z_EPSILON || Math.abs(d2) > Z_EPSILON || Math.abs(d3) > Z_EPSILON || Math.abs(d4 - 1) > Z_EPSILON) {
|
|
107242
|
+
warnedZSignificant = true;
|
|
107243
|
+
console.warn(
|
|
107244
|
+
`[alphaBlit] parseTransformMatrix received a matrix3d with non-trivial 3D components (a3=${a3}, b3=${b3}, c1=${c1}, c2=${c2}, c3=${c3}, d1=${d1}, d2=${d2}, d3=${d3}, d4=${d4}). The engine projects 3D transforms to 2D (m11, m12, m21, m22, m41, m42) and silently discards perspective and out-of-plane rotation. If your composition uses real 3D (rotateX/Y, perspective), the rendered output will not match the studio preview. Z translation (translateZ) is dropped by design and does not trigger this warning. This warning is emitted once per process.`
|
|
107245
|
+
);
|
|
107246
|
+
}
|
|
107171
107247
|
}
|
|
107172
107248
|
|
|
107173
107249
|
// ../engine/src/utils/layerCompositor.ts
|
|
@@ -108371,14 +108447,14 @@ import { join as join14, dirname as dirname9, resolve as resolve10 } from "path"
|
|
|
108371
108447
|
import postcss from "postcss";
|
|
108372
108448
|
|
|
108373
108449
|
// src/utils/paths.ts
|
|
108374
|
-
import { resolve as resolve9, basename as basename2, join as join12, relative as relative2, isAbsolute as
|
|
108450
|
+
import { resolve as resolve9, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute4 } from "node:path";
|
|
108375
108451
|
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve9(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108376
108452
|
function isPathInside2(childPath, parentPath) {
|
|
108377
108453
|
const absChild = resolve9(childPath);
|
|
108378
108454
|
const absParent = resolve9(parentPath);
|
|
108379
108455
|
if (absChild === absParent) return true;
|
|
108380
108456
|
const rel = relative2(absParent, absChild);
|
|
108381
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
108457
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute4(rel);
|
|
108382
108458
|
}
|
|
108383
108459
|
function toExternalAssetKey(absPath) {
|
|
108384
108460
|
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
@@ -108841,7 +108917,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
108841
108917
|
if (!existsSync14(filePath)) {
|
|
108842
108918
|
return { duration: 0, resolvedPath: filePath };
|
|
108843
108919
|
}
|
|
108844
|
-
const metadata = tagName19 === "video" ? await
|
|
108920
|
+
const metadata = tagName19 === "video" ? await extractMediaMetadata(filePath) : await extractAudioMetadata(filePath);
|
|
108845
108921
|
const fileDuration = metadata.durationSeconds;
|
|
108846
108922
|
const effectiveDuration = fileDuration - mediaStart;
|
|
108847
108923
|
const duration = effectiveDuration > 0 ? effectiveDuration : fileDuration;
|
|
@@ -109424,7 +109500,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
109424
109500
|
if (isHttpUrl(video.src)) continue;
|
|
109425
109501
|
const videoPath = resolve10(projectDir, video.src);
|
|
109426
109502
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
109427
|
-
Promise.all([analyzeKeyframeIntervals(videoPath),
|
|
109503
|
+
Promise.all([analyzeKeyframeIntervals(videoPath), extractMediaMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
109428
109504
|
if (analysis.isProblematic) {
|
|
109429
109505
|
console.warn(
|
|
109430
109506
|
`[Compiler] WARNING: Video "${video.id}" has sparse keyframes (max interval: ${analysis.maxIntervalSeconds}s). This causes seek failures and frame freezing. Re-encode with: ${reencode}`
|
|
@@ -109590,6 +109666,9 @@ function createConsoleLogger(level = "info") {
|
|
|
109590
109666
|
if (shouldLog("debug")) {
|
|
109591
109667
|
console.log(`[DEBUG] ${message}${formatMeta(meta)}`);
|
|
109592
109668
|
}
|
|
109669
|
+
},
|
|
109670
|
+
isLevelEnabled(msgLevel) {
|
|
109671
|
+
return shouldLog(msgLevel);
|
|
109593
109672
|
}
|
|
109594
109673
|
};
|
|
109595
109674
|
}
|
|
@@ -109623,6 +109702,21 @@ function getMaxFrameIndex(frameDir) {
|
|
|
109623
109702
|
frameDirMaxIndexCache.set(frameDir, max);
|
|
109624
109703
|
return max;
|
|
109625
109704
|
}
|
|
109705
|
+
function countNonZeroAlpha(rgba) {
|
|
109706
|
+
let n = 0;
|
|
109707
|
+
for (let p = 3; p < rgba.length; p += 4) {
|
|
109708
|
+
if (rgba[p] !== 0) n++;
|
|
109709
|
+
}
|
|
109710
|
+
return n;
|
|
109711
|
+
}
|
|
109712
|
+
function countNonZeroRgb48(buf) {
|
|
109713
|
+
let n = 0;
|
|
109714
|
+
for (let p = 0; p < buf.length; p += 6) {
|
|
109715
|
+
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0 || buf[p + 3] !== 0 || buf[p + 4] !== 0 || buf[p + 5] !== 0)
|
|
109716
|
+
n++;
|
|
109717
|
+
}
|
|
109718
|
+
return n;
|
|
109719
|
+
}
|
|
109626
109720
|
var RenderCancelledError = class extends Error {
|
|
109627
109721
|
reason;
|
|
109628
109722
|
constructor(message = "render_cancelled", reason = "aborted") {
|
|
@@ -109830,6 +109924,165 @@ function blitHdrImageLayer(canvas, el, hdrImageBuffers, width, height, log, sour
|
|
|
109830
109924
|
}
|
|
109831
109925
|
}
|
|
109832
109926
|
}
|
|
109927
|
+
async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
|
|
109928
|
+
const {
|
|
109929
|
+
log,
|
|
109930
|
+
domSession,
|
|
109931
|
+
beforeCaptureHook,
|
|
109932
|
+
width,
|
|
109933
|
+
height,
|
|
109934
|
+
fps,
|
|
109935
|
+
effectiveHdr,
|
|
109936
|
+
nativeHdrImageIds,
|
|
109937
|
+
hdrImageBuffers,
|
|
109938
|
+
hdrFrameDirs,
|
|
109939
|
+
hdrVideoStartTimes,
|
|
109940
|
+
imageTransfers,
|
|
109941
|
+
videoTransfers,
|
|
109942
|
+
debugDumpEnabled,
|
|
109943
|
+
debugDumpDir
|
|
109944
|
+
} = ctx;
|
|
109945
|
+
const filteredStacking = elementFilter ? fullStacking.filter((e) => elementFilter.has(e.id)) : fullStacking;
|
|
109946
|
+
const layers = groupIntoLayers(filteredStacking);
|
|
109947
|
+
const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
|
|
109948
|
+
if (shouldLog) {
|
|
109949
|
+
log.info("[diag] compositeToBuffer plan", {
|
|
109950
|
+
frame: debugFrameIndex,
|
|
109951
|
+
time: time.toFixed(3),
|
|
109952
|
+
filterSize: elementFilter?.size,
|
|
109953
|
+
fullStackingCount: fullStacking.length,
|
|
109954
|
+
filteredCount: filteredStacking.length,
|
|
109955
|
+
layerCount: layers.length,
|
|
109956
|
+
layers: layers.map(
|
|
109957
|
+
(l) => l.type === "hdr" ? {
|
|
109958
|
+
type: "hdr",
|
|
109959
|
+
id: l.element.id,
|
|
109960
|
+
z: l.element.zIndex,
|
|
109961
|
+
visible: l.element.visible,
|
|
109962
|
+
opacity: l.element.opacity,
|
|
109963
|
+
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
109964
|
+
} : { type: "dom", ids: l.elementIds }
|
|
109965
|
+
)
|
|
109966
|
+
});
|
|
109967
|
+
}
|
|
109968
|
+
for (const [layerIdx, layer] of layers.entries()) {
|
|
109969
|
+
if (layer.type === "hdr") {
|
|
109970
|
+
const before2 = shouldLog ? countNonZeroRgb48(canvas) : 0;
|
|
109971
|
+
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
109972
|
+
if (isHdrImage) {
|
|
109973
|
+
blitHdrImageLayer(
|
|
109974
|
+
canvas,
|
|
109975
|
+
layer.element,
|
|
109976
|
+
hdrImageBuffers,
|
|
109977
|
+
width,
|
|
109978
|
+
height,
|
|
109979
|
+
log,
|
|
109980
|
+
imageTransfers.get(layer.element.id),
|
|
109981
|
+
effectiveHdr.transfer
|
|
109982
|
+
);
|
|
109983
|
+
} else {
|
|
109984
|
+
blitHdrVideoLayer(
|
|
109985
|
+
canvas,
|
|
109986
|
+
layer.element,
|
|
109987
|
+
time,
|
|
109988
|
+
fps,
|
|
109989
|
+
hdrFrameDirs,
|
|
109990
|
+
hdrVideoStartTimes,
|
|
109991
|
+
width,
|
|
109992
|
+
height,
|
|
109993
|
+
log,
|
|
109994
|
+
videoTransfers.get(layer.element.id),
|
|
109995
|
+
effectiveHdr.transfer
|
|
109996
|
+
);
|
|
109997
|
+
}
|
|
109998
|
+
if (shouldLog) {
|
|
109999
|
+
const after2 = countNonZeroRgb48(canvas);
|
|
110000
|
+
if (isHdrImage) {
|
|
110001
|
+
const buf = hdrImageBuffers.get(layer.element.id);
|
|
110002
|
+
log.info("[diag] hdr layer blit", {
|
|
110003
|
+
frame: debugFrameIndex,
|
|
110004
|
+
layerIdx,
|
|
110005
|
+
id: layer.element.id,
|
|
110006
|
+
kind: "image",
|
|
110007
|
+
pixelsAdded: after2 - before2,
|
|
110008
|
+
totalNonZero: after2,
|
|
110009
|
+
bufferDecoded: !!buf,
|
|
110010
|
+
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
110011
|
+
});
|
|
110012
|
+
} else {
|
|
110013
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
110014
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
110015
|
+
const localTime = time - startTime;
|
|
110016
|
+
const frameNum = Math.floor(localTime * fps) + 1;
|
|
110017
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
110018
|
+
log.info("[diag] hdr layer blit", {
|
|
110019
|
+
frame: debugFrameIndex,
|
|
110020
|
+
layerIdx,
|
|
110021
|
+
id: layer.element.id,
|
|
110022
|
+
kind: "video",
|
|
110023
|
+
pixelsAdded: after2 - before2,
|
|
110024
|
+
totalNonZero: after2,
|
|
110025
|
+
startTime,
|
|
110026
|
+
localTime: localTime.toFixed(3),
|
|
110027
|
+
hdrFrameNum: frameNum,
|
|
110028
|
+
expectedFrame,
|
|
110029
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
110030
|
+
});
|
|
110031
|
+
}
|
|
110032
|
+
}
|
|
110033
|
+
} else {
|
|
110034
|
+
const allElementIds = fullStacking.map((e) => e.id);
|
|
110035
|
+
const layerIds = new Set(layer.elementIds);
|
|
110036
|
+
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
110037
|
+
await domSession.page.evaluate((t) => {
|
|
110038
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
110039
|
+
}, time);
|
|
110040
|
+
if (beforeCaptureHook) {
|
|
110041
|
+
await beforeCaptureHook(domSession.page, time);
|
|
110042
|
+
}
|
|
110043
|
+
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
110044
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
110045
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
110046
|
+
try {
|
|
110047
|
+
const { data: domRgba } = decodePng(domPng);
|
|
110048
|
+
const before2 = shouldLog ? countNonZeroRgb48(canvas) : 0;
|
|
110049
|
+
const alphaPixels = shouldLog ? countNonZeroAlpha(domRgba) : 0;
|
|
110050
|
+
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
110051
|
+
if (shouldLog && debugDumpDir) {
|
|
110052
|
+
const after2 = countNonZeroRgb48(canvas);
|
|
110053
|
+
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
110054
|
+
const dumpPath = join15(debugDumpDir, dumpName);
|
|
110055
|
+
writeFileSync4(dumpPath, domPng);
|
|
110056
|
+
log.info("[diag] dom layer blit", {
|
|
110057
|
+
frame: debugFrameIndex,
|
|
110058
|
+
layerIdx,
|
|
110059
|
+
layerIds: layer.elementIds,
|
|
110060
|
+
hideCount: hideIds.length,
|
|
110061
|
+
pngBytes: domPng.length,
|
|
110062
|
+
alphaPixels,
|
|
110063
|
+
pixelsAdded: after2 - before2,
|
|
110064
|
+
totalNonZero: after2,
|
|
110065
|
+
dumpPath
|
|
110066
|
+
});
|
|
110067
|
+
}
|
|
110068
|
+
} catch (err) {
|
|
110069
|
+
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
110070
|
+
layerIds: layer.elementIds,
|
|
110071
|
+
error: err instanceof Error ? err.message : String(err)
|
|
110072
|
+
});
|
|
110073
|
+
}
|
|
110074
|
+
}
|
|
110075
|
+
}
|
|
110076
|
+
if (shouldLog && debugDumpDir) {
|
|
110077
|
+
const finalNonZero = countNonZeroRgb48(canvas);
|
|
110078
|
+
log.info("[diag] compositeToBuffer end", {
|
|
110079
|
+
frame: debugFrameIndex,
|
|
110080
|
+
finalNonZeroPixels: finalNonZero,
|
|
110081
|
+
totalPixels: width * height,
|
|
110082
|
+
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
110083
|
+
});
|
|
110084
|
+
}
|
|
110085
|
+
}
|
|
109833
110086
|
function createRenderJob(config2) {
|
|
109834
110087
|
return {
|
|
109835
110088
|
id: randomUUID(),
|
|
@@ -109897,6 +110150,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109897
110150
|
const enableChunkedEncode = cfg.enableChunkedEncode;
|
|
109898
110151
|
const chunkedEncodeSize = cfg.chunkSizeFrames;
|
|
109899
110152
|
const enableStreamingEncode = cfg.enableStreamingEncode;
|
|
110153
|
+
let peakRssBytes = 0;
|
|
110154
|
+
let peakHeapUsedBytes = 0;
|
|
110155
|
+
const sampleMemory = () => {
|
|
110156
|
+
try {
|
|
110157
|
+
const m = process.memoryUsage();
|
|
110158
|
+
if (m.rss > peakRssBytes) peakRssBytes = m.rss;
|
|
110159
|
+
if (m.heapUsed > peakHeapUsedBytes) peakHeapUsedBytes = m.heapUsed;
|
|
110160
|
+
} catch {
|
|
110161
|
+
}
|
|
110162
|
+
};
|
|
110163
|
+
sampleMemory();
|
|
110164
|
+
const memSamplerInterval = setInterval(sampleMemory, 250);
|
|
110165
|
+
memSamplerInterval.unref?.();
|
|
109900
110166
|
try {
|
|
109901
110167
|
const assertNotAborted = () => {
|
|
109902
110168
|
if (abortSignal?.aborted) {
|
|
@@ -110174,7 +110440,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110174
110440
|
videoPath = fromCompiled;
|
|
110175
110441
|
}
|
|
110176
110442
|
if (!existsSync15(videoPath)) return;
|
|
110177
|
-
const meta = await
|
|
110443
|
+
const meta = await extractMediaMetadata(videoPath);
|
|
110178
110444
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
110179
110445
|
nativeHdrVideoIds.add(v.id);
|
|
110180
110446
|
videoTransfers.set(v.id, detectTransfer(meta.colorSpace));
|
|
@@ -110195,7 +110461,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110195
110461
|
imgPath = fromCompiled;
|
|
110196
110462
|
}
|
|
110197
110463
|
if (!existsSync15(imgPath)) return null;
|
|
110198
|
-
const meta = await
|
|
110464
|
+
const meta = await extractMediaMetadata(imgPath);
|
|
110199
110465
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
110200
110466
|
nativeHdrImageIds.add(img.id);
|
|
110201
110467
|
imageTransfers.set(img.id, detectTransfer(meta.colorSpace));
|
|
@@ -110307,6 +110573,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110307
110573
|
format: needsAlpha ? "png" : "jpeg",
|
|
110308
110574
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95
|
|
110309
110575
|
};
|
|
110576
|
+
const buildHdrCaptureOptions = () => ({
|
|
110577
|
+
...captureOptions,
|
|
110578
|
+
skipReadinessVideoIds: Array.from(nativeHdrVideoIds)
|
|
110579
|
+
});
|
|
110310
110580
|
const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
|
|
110311
110581
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
110312
110582
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
@@ -110341,7 +110611,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110341
110611
|
const domSession = await createCaptureSession(
|
|
110342
110612
|
fileServer.url,
|
|
110343
110613
|
framesDir,
|
|
110344
|
-
|
|
110614
|
+
buildHdrCaptureOptions(),
|
|
110345
110615
|
createVideoFrameInjector(frameLookup),
|
|
110346
110616
|
cfg
|
|
110347
110617
|
);
|
|
@@ -110437,6 +110707,29 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110437
110707
|
}
|
|
110438
110708
|
}
|
|
110439
110709
|
}
|
|
110710
|
+
for (const [imageId, startTime] of hdrImageStartTimes) {
|
|
110711
|
+
if (hdrExtractionDims.has(imageId)) continue;
|
|
110712
|
+
const img = composition.images.find((i) => i.id === imageId);
|
|
110713
|
+
if (!img) continue;
|
|
110714
|
+
const duration = img.end - img.start;
|
|
110715
|
+
const retryTime = startTime + Math.min(0.5, duration * 0.1);
|
|
110716
|
+
await domSession.page.evaluate((t) => {
|
|
110717
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
110718
|
+
}, retryTime);
|
|
110719
|
+
if (domSession.onBeforeCapture) {
|
|
110720
|
+
await domSession.onBeforeCapture(domSession.page, retryTime);
|
|
110721
|
+
}
|
|
110722
|
+
const retryStacking = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
110723
|
+
for (const el of retryStacking) {
|
|
110724
|
+
if (el.id === imageId && el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0) {
|
|
110725
|
+
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
110726
|
+
if (!hdrImageFitInfo.has(el.id)) {
|
|
110727
|
+
hdrImageFitInfo.set(el.id, { fit: el.objectFit, position: el.objectPosition });
|
|
110728
|
+
}
|
|
110729
|
+
break;
|
|
110730
|
+
}
|
|
110731
|
+
}
|
|
110732
|
+
}
|
|
110440
110733
|
for (const [videoId, srcPath] of hdrVideoSrcPaths) {
|
|
110441
110734
|
const video = composition.videos.find((v) => v.id === videoId);
|
|
110442
110735
|
if (!video) continue;
|
|
@@ -110519,21 +110812,6 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110519
110812
|
}
|
|
110520
110813
|
assertNotAborted();
|
|
110521
110814
|
try {
|
|
110522
|
-
let countNonZeroAlpha2 = function(rgba) {
|
|
110523
|
-
let n = 0;
|
|
110524
|
-
for (let p = 3; p < rgba.length; p += 4) {
|
|
110525
|
-
if (rgba[p] !== 0) n++;
|
|
110526
|
-
}
|
|
110527
|
-
return n;
|
|
110528
|
-
}, countNonZeroRgb482 = function(buf) {
|
|
110529
|
-
let n = 0;
|
|
110530
|
-
for (let p = 0; p < buf.length; p += 6) {
|
|
110531
|
-
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0 || buf[p + 3] !== 0 || buf[p + 4] !== 0 || buf[p + 5] !== 0)
|
|
110532
|
-
n++;
|
|
110533
|
-
}
|
|
110534
|
-
return n;
|
|
110535
|
-
};
|
|
110536
|
-
var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
|
|
110537
110815
|
const beforeCaptureHook = domSession.onBeforeCapture;
|
|
110538
110816
|
const cleanedUpVideos = /* @__PURE__ */ new Set();
|
|
110539
110817
|
const hdrVideoEndTimes = /* @__PURE__ */ new Map();
|
|
@@ -110547,153 +110825,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110547
110825
|
if (debugDumpDir && !existsSync15(debugDumpDir)) {
|
|
110548
110826
|
mkdirSync10(debugDumpDir, { recursive: true });
|
|
110549
110827
|
}
|
|
110550
|
-
|
|
110551
|
-
|
|
110552
|
-
|
|
110553
|
-
|
|
110554
|
-
if (shouldLog) {
|
|
110555
|
-
log.info("[diag] compositeToBuffer plan", {
|
|
110556
|
-
frame: debugFrameIndex,
|
|
110557
|
-
time: time.toFixed(3),
|
|
110558
|
-
filterSize: elementFilter?.size,
|
|
110559
|
-
fullStackingCount: fullStacking.length,
|
|
110560
|
-
filteredCount: filteredStacking.length,
|
|
110561
|
-
layerCount: layers.length,
|
|
110562
|
-
layers: layers.map(
|
|
110563
|
-
(l) => l.type === "hdr" ? {
|
|
110564
|
-
type: "hdr",
|
|
110565
|
-
id: l.element.id,
|
|
110566
|
-
z: l.element.zIndex,
|
|
110567
|
-
visible: l.element.visible,
|
|
110568
|
-
opacity: l.element.opacity,
|
|
110569
|
-
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
110570
|
-
} : { type: "dom", ids: l.elementIds }
|
|
110571
|
-
)
|
|
110572
|
-
});
|
|
110573
|
-
}
|
|
110574
|
-
for (const [layerIdx, layer] of layers.entries()) {
|
|
110575
|
-
if (layer.type === "hdr") {
|
|
110576
|
-
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
110577
|
-
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
110578
|
-
if (isHdrImage) {
|
|
110579
|
-
blitHdrImageLayer(
|
|
110580
|
-
canvas,
|
|
110581
|
-
layer.element,
|
|
110582
|
-
hdrImageBuffers,
|
|
110583
|
-
width,
|
|
110584
|
-
height,
|
|
110585
|
-
log,
|
|
110586
|
-
imageTransfers.get(layer.element.id),
|
|
110587
|
-
effectiveHdr?.transfer
|
|
110588
|
-
);
|
|
110589
|
-
} else {
|
|
110590
|
-
blitHdrVideoLayer(
|
|
110591
|
-
canvas,
|
|
110592
|
-
layer.element,
|
|
110593
|
-
time,
|
|
110594
|
-
job.config.fps,
|
|
110595
|
-
hdrFrameDirs,
|
|
110596
|
-
hdrVideoStartTimes,
|
|
110597
|
-
width,
|
|
110598
|
-
height,
|
|
110599
|
-
log,
|
|
110600
|
-
videoTransfers.get(layer.element.id),
|
|
110601
|
-
effectiveHdr?.transfer
|
|
110602
|
-
);
|
|
110603
|
-
}
|
|
110604
|
-
if (shouldLog) {
|
|
110605
|
-
const after2 = countNonZeroRgb482(canvas);
|
|
110606
|
-
if (isHdrImage) {
|
|
110607
|
-
const buf = hdrImageBuffers.get(layer.element.id);
|
|
110608
|
-
log.info("[diag] hdr layer blit", {
|
|
110609
|
-
frame: debugFrameIndex,
|
|
110610
|
-
layerIdx,
|
|
110611
|
-
id: layer.element.id,
|
|
110612
|
-
kind: "image",
|
|
110613
|
-
pixelsAdded: after2 - before2,
|
|
110614
|
-
totalNonZero: after2,
|
|
110615
|
-
bufferDecoded: !!buf,
|
|
110616
|
-
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
110617
|
-
});
|
|
110618
|
-
} else {
|
|
110619
|
-
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
110620
|
-
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
110621
|
-
const localTime = time - startTime;
|
|
110622
|
-
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
110623
|
-
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
110624
|
-
log.info("[diag] hdr layer blit", {
|
|
110625
|
-
frame: debugFrameIndex,
|
|
110626
|
-
layerIdx,
|
|
110627
|
-
id: layer.element.id,
|
|
110628
|
-
kind: "video",
|
|
110629
|
-
pixelsAdded: after2 - before2,
|
|
110630
|
-
totalNonZero: after2,
|
|
110631
|
-
startTime,
|
|
110632
|
-
localTime: localTime.toFixed(3),
|
|
110633
|
-
hdrFrameNum: frameNum,
|
|
110634
|
-
expectedFrame,
|
|
110635
|
-
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
110636
|
-
});
|
|
110637
|
-
}
|
|
110638
|
-
}
|
|
110639
|
-
} else {
|
|
110640
|
-
const allElementIds = fullStacking.map((e) => e.id);
|
|
110641
|
-
const layerIds = new Set(layer.elementIds);
|
|
110642
|
-
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
110643
|
-
await domSession.page.evaluate((t) => {
|
|
110644
|
-
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
110645
|
-
}, time);
|
|
110646
|
-
if (beforeCaptureHook) {
|
|
110647
|
-
await beforeCaptureHook(domSession.page, time);
|
|
110648
|
-
}
|
|
110649
|
-
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
110650
|
-
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
110651
|
-
await removeDomLayerMask(domSession.page, hideIds);
|
|
110652
|
-
try {
|
|
110653
|
-
const { data: domRgba } = decodePng(domPng);
|
|
110654
|
-
if (!effectiveHdr) {
|
|
110655
|
-
throw new Error(
|
|
110656
|
-
"Invariant violation: effectiveHdr is undefined inside HDR layer branch"
|
|
110657
|
-
);
|
|
110658
|
-
}
|
|
110659
|
-
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
110660
|
-
const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
|
|
110661
|
-
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
110662
|
-
if (shouldLog && debugDumpDir) {
|
|
110663
|
-
const after2 = countNonZeroRgb482(canvas);
|
|
110664
|
-
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
110665
|
-
const dumpPath = join15(debugDumpDir, dumpName);
|
|
110666
|
-
writeFileSync4(dumpPath, domPng);
|
|
110667
|
-
log.info("[diag] dom layer blit", {
|
|
110668
|
-
frame: debugFrameIndex,
|
|
110669
|
-
layerIdx,
|
|
110670
|
-
layerIds: layer.elementIds,
|
|
110671
|
-
hideCount: hideIds.length,
|
|
110672
|
-
pngBytes: domPng.length,
|
|
110673
|
-
alphaPixels,
|
|
110674
|
-
pixelsAdded: after2 - before2,
|
|
110675
|
-
totalNonZero: after2,
|
|
110676
|
-
dumpPath
|
|
110677
|
-
});
|
|
110678
|
-
}
|
|
110679
|
-
} catch (err) {
|
|
110680
|
-
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
110681
|
-
layerIds: layer.elementIds,
|
|
110682
|
-
error: err instanceof Error ? err.message : String(err)
|
|
110683
|
-
});
|
|
110684
|
-
}
|
|
110685
|
-
}
|
|
110686
|
-
}
|
|
110687
|
-
if (shouldLog && debugDumpDir) {
|
|
110688
|
-
const finalNonZero = countNonZeroRgb482(canvas);
|
|
110689
|
-
log.info("[diag] compositeToBuffer end", {
|
|
110690
|
-
frame: debugFrameIndex,
|
|
110691
|
-
finalNonZeroPixels: finalNonZero,
|
|
110692
|
-
totalPixels: width * height,
|
|
110693
|
-
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
110694
|
-
});
|
|
110695
|
-
}
|
|
110828
|
+
if (!effectiveHdr) {
|
|
110829
|
+
throw new Error(
|
|
110830
|
+
"Internal: HDR render path entered without effectiveHdr \u2014 this is a bug."
|
|
110831
|
+
);
|
|
110696
110832
|
}
|
|
110833
|
+
const hdrCompositeCtx = {
|
|
110834
|
+
log,
|
|
110835
|
+
domSession,
|
|
110836
|
+
beforeCaptureHook,
|
|
110837
|
+
width,
|
|
110838
|
+
height,
|
|
110839
|
+
fps: job.config.fps,
|
|
110840
|
+
effectiveHdr,
|
|
110841
|
+
nativeHdrImageIds,
|
|
110842
|
+
hdrImageBuffers,
|
|
110843
|
+
hdrFrameDirs,
|
|
110844
|
+
hdrVideoStartTimes,
|
|
110845
|
+
imageTransfers,
|
|
110846
|
+
videoTransfers,
|
|
110847
|
+
debugDumpEnabled,
|
|
110848
|
+
debugDumpDir
|
|
110849
|
+
};
|
|
110697
110850
|
const bufSize = width * height * 6;
|
|
110698
110851
|
const hasTransitions = transitionRanges.length > 0;
|
|
110699
110852
|
const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
@@ -110713,7 +110866,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110713
110866
|
const activeTransition = transitionRanges.find(
|
|
110714
110867
|
(t) => i >= t.startFrame && i <= t.endFrame
|
|
110715
110868
|
);
|
|
110716
|
-
if (i % 30 === 0) {
|
|
110869
|
+
if (i % 30 === 0 && (log.isLevelEnabled?.("debug") ?? true)) {
|
|
110717
110870
|
const hdrEl = stackingInfo.find((e) => e.isHdr);
|
|
110718
110871
|
log.debug("[Render] HDR layer composite frame", {
|
|
110719
110872
|
frame: i,
|
|
@@ -110801,7 +110954,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110801
110954
|
hdrEncoder.writeFrame(transOutput);
|
|
110802
110955
|
} else {
|
|
110803
110956
|
normalCanvas.fill(0);
|
|
110804
|
-
await
|
|
110957
|
+
await compositeHdrFrame(
|
|
110958
|
+
hdrCompositeCtx,
|
|
110959
|
+
normalCanvas,
|
|
110960
|
+
time,
|
|
110961
|
+
stackingInfo,
|
|
110962
|
+
void 0,
|
|
110963
|
+
i
|
|
110964
|
+
);
|
|
110805
110965
|
if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
|
|
110806
110966
|
const previewPath = join15(
|
|
110807
110967
|
debugDumpDir,
|
|
@@ -110920,7 +111080,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110920
111080
|
fileServer.url,
|
|
110921
111081
|
workDir,
|
|
110922
111082
|
tasks,
|
|
110923
|
-
|
|
111083
|
+
buildHdrCaptureOptions(),
|
|
110924
111084
|
() => createVideoFrameInjector(frameLookup),
|
|
110925
111085
|
abortSignal,
|
|
110926
111086
|
(progress) => {
|
|
@@ -110950,7 +111110,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110950
111110
|
const session = probeSession ?? await createCaptureSession(
|
|
110951
111111
|
fileServer.url,
|
|
110952
111112
|
framesDir,
|
|
110953
|
-
|
|
111113
|
+
buildHdrCaptureOptions(),
|
|
110954
111114
|
videoInjector,
|
|
110955
111115
|
cfg
|
|
110956
111116
|
);
|
|
@@ -111002,7 +111162,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111002
111162
|
fileServer.url,
|
|
111003
111163
|
workDir,
|
|
111004
111164
|
tasks,
|
|
111005
|
-
|
|
111165
|
+
buildHdrCaptureOptions(),
|
|
111006
111166
|
() => createVideoFrameInjector(frameLookup),
|
|
111007
111167
|
abortSignal,
|
|
111008
111168
|
(progress) => {
|
|
@@ -111033,7 +111193,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111033
111193
|
const session = probeSession ?? await createCaptureSession(
|
|
111034
111194
|
fileServer.url,
|
|
111035
111195
|
framesDir,
|
|
111036
|
-
|
|
111196
|
+
buildHdrCaptureOptions(),
|
|
111037
111197
|
videoInjector,
|
|
111038
111198
|
cfg
|
|
111039
111199
|
);
|
|
@@ -111149,6 +111309,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111149
111309
|
job.outputPath = outputPath;
|
|
111150
111310
|
updateJobStatus(job, "complete", "Render complete", 100, onProgress);
|
|
111151
111311
|
const totalElapsed = Date.now() - pipelineStart;
|
|
111312
|
+
sampleMemory();
|
|
111152
111313
|
const perfSummary = {
|
|
111153
111314
|
renderId: job.id,
|
|
111154
111315
|
totalElapsedMs: totalElapsed,
|
|
@@ -111164,7 +111325,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111164
111325
|
audioCount: composition.audios.length,
|
|
111165
111326
|
stages: perfStages,
|
|
111166
111327
|
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0,
|
|
111167
|
-
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
111328
|
+
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0,
|
|
111329
|
+
peakRssMb: Math.round(peakRssBytes / (1024 * 1024)),
|
|
111330
|
+
peakHeapUsedMb: Math.round(peakHeapUsedBytes / (1024 * 1024))
|
|
111168
111331
|
};
|
|
111169
111332
|
job.perfSummary = perfSummary;
|
|
111170
111333
|
if (job.config.debug) {
|
|
@@ -111272,6 +111435,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111272
111435
|
}
|
|
111273
111436
|
if (restoreLogger) restoreLogger();
|
|
111274
111437
|
throw error;
|
|
111438
|
+
} finally {
|
|
111439
|
+
clearInterval(memSamplerInterval);
|
|
111275
111440
|
}
|
|
111276
111441
|
}
|
|
111277
111442
|
|