@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/index.js
CHANGED
|
@@ -57865,7 +57865,7 @@ var require_util2 = __commonJS({
|
|
|
57865
57865
|
}
|
|
57866
57866
|
path12 = url.path;
|
|
57867
57867
|
}
|
|
57868
|
-
var
|
|
57868
|
+
var isAbsolute5 = exports.isAbsolute(path12);
|
|
57869
57869
|
var parts = path12.split(/\/+/);
|
|
57870
57870
|
for (var part, up = 0, i = parts.length - 1; i >= 0; i--) {
|
|
57871
57871
|
part = parts[i];
|
|
@@ -57885,7 +57885,7 @@ var require_util2 = __commonJS({
|
|
|
57885
57885
|
}
|
|
57886
57886
|
path12 = parts.join("/");
|
|
57887
57887
|
if (path12 === "") {
|
|
57888
|
-
path12 =
|
|
57888
|
+
path12 = isAbsolute5 ? "/" : ".";
|
|
57889
57889
|
}
|
|
57890
57890
|
if (url) {
|
|
57891
57891
|
url.path = path12;
|
|
@@ -101618,6 +101618,34 @@ function getGpuEncoderName(encoder, codec) {
|
|
|
101618
101618
|
return codec === "h264" ? "libx264" : "libx265";
|
|
101619
101619
|
}
|
|
101620
101620
|
}
|
|
101621
|
+
var NVENC_PRESET_MAP = {
|
|
101622
|
+
ultrafast: "p1",
|
|
101623
|
+
superfast: "p1",
|
|
101624
|
+
veryfast: "p2",
|
|
101625
|
+
faster: "p3",
|
|
101626
|
+
fast: "p4",
|
|
101627
|
+
medium: "p4",
|
|
101628
|
+
slow: "p5",
|
|
101629
|
+
slower: "p6",
|
|
101630
|
+
veryslow: "p7",
|
|
101631
|
+
placebo: "p7"
|
|
101632
|
+
};
|
|
101633
|
+
var QSV_PRESET_MAP = {
|
|
101634
|
+
ultrafast: "veryfast",
|
|
101635
|
+
superfast: "veryfast",
|
|
101636
|
+
placebo: "veryslow"
|
|
101637
|
+
};
|
|
101638
|
+
function mapPresetForGpuEncoder(encoder, preset) {
|
|
101639
|
+
switch (encoder) {
|
|
101640
|
+
case "nvenc":
|
|
101641
|
+
if (/^p[1-7]$/.test(preset)) return preset;
|
|
101642
|
+
return NVENC_PRESET_MAP[preset] ?? "p4";
|
|
101643
|
+
case "qsv":
|
|
101644
|
+
return QSV_PRESET_MAP[preset] ?? preset;
|
|
101645
|
+
default:
|
|
101646
|
+
return preset;
|
|
101647
|
+
}
|
|
101648
|
+
}
|
|
101621
101649
|
|
|
101622
101650
|
// ../engine/src/utils/hdr.ts
|
|
101623
101651
|
function isHdrColorSpace(cs) {
|
|
@@ -101661,6 +101689,16 @@ function analyzeCompositionHdr(colorSpaces) {
|
|
|
101661
101689
|
// ../engine/src/utils/runFfmpeg.ts
|
|
101662
101690
|
import { spawn as spawn4 } from "child_process";
|
|
101663
101691
|
var DEFAULT_TIMEOUT2 = 3e5;
|
|
101692
|
+
var DEFAULT_STDERR_TAIL_LINES = 15;
|
|
101693
|
+
function formatFfmpegError(exitCode, stderr, tailLines = DEFAULT_STDERR_TAIL_LINES) {
|
|
101694
|
+
const tail = (stderr ?? "").split(/\r?\n/).filter((line) => line.length > 0).slice(-tailLines).join("\n");
|
|
101695
|
+
if (exitCode === null) {
|
|
101696
|
+
return tail ? `[FFmpeg] ${tail}` : "[FFmpeg] process error";
|
|
101697
|
+
}
|
|
101698
|
+
return tail ? `FFmpeg exited with code ${exitCode}
|
|
101699
|
+
ffmpeg stderr (tail):
|
|
101700
|
+
${tail}` : `FFmpeg exited with code ${exitCode}`;
|
|
101701
|
+
}
|
|
101664
101702
|
async function runFfmpeg(args, opts) {
|
|
101665
101703
|
const startMs = Date.now();
|
|
101666
101704
|
const signal = opts?.signal;
|
|
@@ -101771,7 +101809,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
101771
101809
|
args.push("-c:v", encoderName);
|
|
101772
101810
|
switch (gpuEncoder) {
|
|
101773
101811
|
case "nvenc":
|
|
101774
|
-
args.push("-preset", preset);
|
|
101812
|
+
args.push("-preset", mapPresetForGpuEncoder("nvenc", preset));
|
|
101775
101813
|
if (bitrate) args.push("-b:v", bitrate);
|
|
101776
101814
|
else args.push("-cq", String(quality));
|
|
101777
101815
|
break;
|
|
@@ -101790,7 +101828,7 @@ function buildEncoderArgs(options, inputArgs, outputPath, gpuEncoder = null) {
|
|
|
101790
101828
|
else args.push("-qp", String(quality));
|
|
101791
101829
|
break;
|
|
101792
101830
|
case "qsv":
|
|
101793
|
-
args.push("-preset", preset);
|
|
101831
|
+
args.push("-preset", mapPresetForGpuEncoder("qsv", preset));
|
|
101794
101832
|
if (bitrate) args.push("-b:v", bitrate);
|
|
101795
101833
|
else args.push("-global_quality", String(quality));
|
|
101796
101834
|
break;
|
|
@@ -101930,7 +101968,7 @@ async function encodeFramesFromDir(framesDir, framePattern, outputPath, options,
|
|
|
101930
101968
|
durationMs,
|
|
101931
101969
|
framesEncoded: 0,
|
|
101932
101970
|
fileSize: 0,
|
|
101933
|
-
error:
|
|
101971
|
+
error: formatFfmpegError(code, stderr)
|
|
101934
101972
|
});
|
|
101935
101973
|
return;
|
|
101936
101974
|
}
|
|
@@ -102100,7 +102138,7 @@ async function muxVideoWithAudio(videoPath, audioPath, outputPath, signal, confi
|
|
|
102100
102138
|
success: result.success,
|
|
102101
102139
|
outputPath,
|
|
102102
102140
|
durationMs: result.durationMs,
|
|
102103
|
-
error: !result.success ? result.exitCode
|
|
102141
|
+
error: !result.success ? formatFfmpegError(result.exitCode, result.stderr) : void 0
|
|
102104
102142
|
};
|
|
102105
102143
|
}
|
|
102106
102144
|
async function applyFaststart(inputPath, outputPath, signal, config2) {
|
|
@@ -102123,7 +102161,7 @@ async function applyFaststart(inputPath, outputPath, signal, config2) {
|
|
|
102123
102161
|
success: result.success,
|
|
102124
102162
|
outputPath,
|
|
102125
102163
|
durationMs: result.durationMs,
|
|
102126
|
-
error: !result.success ? result.exitCode
|
|
102164
|
+
error: !result.success ? formatFfmpegError(result.exitCode, result.stderr) : void 0
|
|
102127
102165
|
};
|
|
102128
102166
|
}
|
|
102129
102167
|
|
|
@@ -102216,7 +102254,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
102216
102254
|
args.push("-c:v", encoderName);
|
|
102217
102255
|
switch (gpuEncoder) {
|
|
102218
102256
|
case "nvenc":
|
|
102219
|
-
args.push("-preset", preset);
|
|
102257
|
+
args.push("-preset", mapPresetForGpuEncoder("nvenc", preset));
|
|
102220
102258
|
if (bitrate) args.push("-b:v", bitrate);
|
|
102221
102259
|
else args.push("-cq", String(quality));
|
|
102222
102260
|
break;
|
|
@@ -102235,7 +102273,7 @@ function buildStreamingArgs(options, outputPath, gpuEncoder = null) {
|
|
|
102235
102273
|
else args.push("-qp", String(quality));
|
|
102236
102274
|
break;
|
|
102237
102275
|
case "qsv":
|
|
102238
|
-
args.push("-preset", preset);
|
|
102276
|
+
args.push("-preset", mapPresetForGpuEncoder("qsv", preset));
|
|
102239
102277
|
if (bitrate) args.push("-b:v", bitrate);
|
|
102240
102278
|
else args.push("-global_quality", String(quality));
|
|
102241
102279
|
break;
|
|
@@ -102391,7 +102429,7 @@ Process error: ${err.message}`;
|
|
|
102391
102429
|
success: false,
|
|
102392
102430
|
durationMs,
|
|
102393
102431
|
fileSize: 0,
|
|
102394
|
-
error:
|
|
102432
|
+
error: formatFfmpegError(exitCode, stderr)
|
|
102395
102433
|
};
|
|
102396
102434
|
}
|
|
102397
102435
|
const fileSize = existsSync6(outputPath) ? statSync4(outputPath).size : 0;
|
|
@@ -102405,7 +102443,7 @@ Process error: ${err.message}`;
|
|
|
102405
102443
|
// ../engine/src/services/videoFrameExtractor.ts
|
|
102406
102444
|
import { spawn as spawn8 } from "child_process";
|
|
102407
102445
|
import { existsSync as existsSync8, mkdirSync as mkdirSync5, readdirSync as readdirSync4, rmSync } from "fs";
|
|
102408
|
-
import { join as join8 } from "path";
|
|
102446
|
+
import { isAbsolute as isAbsolute2, join as join8 } from "path";
|
|
102409
102447
|
|
|
102410
102448
|
// ../engine/src/utils/ffprobe.ts
|
|
102411
102449
|
import { spawn as spawn7 } from "child_process";
|
|
@@ -102520,7 +102558,7 @@ function parseFrameRate(frameRateStr) {
|
|
|
102520
102558
|
}
|
|
102521
102559
|
return parseFloat(frameRateStr) || 0;
|
|
102522
102560
|
}
|
|
102523
|
-
async function
|
|
102561
|
+
async function extractMediaMetadata(filePath) {
|
|
102524
102562
|
const cached = videoMetadataCache.get(filePath);
|
|
102525
102563
|
if (cached) return cached;
|
|
102526
102564
|
const probePromise = (async () => {
|
|
@@ -102806,7 +102844,7 @@ async function extractVideoFramesRange(videoPath, videoId, startTime, duration,
|
|
|
102806
102844
|
const { fps, outputDir, quality = 95, format: format3 = "jpg" } = options;
|
|
102807
102845
|
const videoOutputDir = join8(outputDir, videoId);
|
|
102808
102846
|
if (!existsSync8(videoOutputDir)) mkdirSync5(videoOutputDir, { recursive: true });
|
|
102809
|
-
const metadata = await
|
|
102847
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
102810
102848
|
const framePattern = `frame_%05d.${format3}`;
|
|
102811
102849
|
const outputPattern = join8(videoOutputDir, framePattern);
|
|
102812
102850
|
const isHdr = isHdrColorSpace(metadata.colorSpace);
|
|
@@ -102955,7 +102993,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
102955
102993
|
if (signal?.aborted) break;
|
|
102956
102994
|
try {
|
|
102957
102995
|
let videoPath = video.src;
|
|
102958
|
-
if (!videoPath
|
|
102996
|
+
if (!isAbsolute2(videoPath) && !isHttpUrl(videoPath)) {
|
|
102959
102997
|
const fromCompiled = compiledDir ? join8(compiledDir, videoPath) : null;
|
|
102960
102998
|
videoPath = fromCompiled && existsSync8(fromCompiled) ? fromCompiled : join8(baseDir, videoPath);
|
|
102961
102999
|
}
|
|
@@ -102975,7 +103013,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
102975
103013
|
}
|
|
102976
103014
|
const videoColorSpaces = await Promise.all(
|
|
102977
103015
|
resolvedVideos.map(async ({ videoPath }) => {
|
|
102978
|
-
const metadata = await
|
|
103016
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
102979
103017
|
return metadata.colorSpace;
|
|
102980
103018
|
})
|
|
102981
103019
|
);
|
|
@@ -103008,7 +103046,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103008
103046
|
if (signal?.aborted) break;
|
|
103009
103047
|
const entry = resolvedVideos[i];
|
|
103010
103048
|
if (!entry) continue;
|
|
103011
|
-
const metadata = await
|
|
103049
|
+
const metadata = await extractMediaMetadata(entry.videoPath);
|
|
103012
103050
|
if (!metadata.isVFR) continue;
|
|
103013
103051
|
let segDuration = entry.video.end - entry.video.start;
|
|
103014
103052
|
if (!Number.isFinite(segDuration) || segDuration <= 0) {
|
|
@@ -103044,7 +103082,7 @@ async function extractAllVideoFrames(videos, baseDir, options, signal, config2,
|
|
|
103044
103082
|
try {
|
|
103045
103083
|
let videoDuration = video.end - video.start;
|
|
103046
103084
|
if (!Number.isFinite(videoDuration) || videoDuration <= 0) {
|
|
103047
|
-
const metadata = await
|
|
103085
|
+
const metadata = await extractMediaMetadata(videoPath);
|
|
103048
103086
|
const sourceDuration = metadata.durationSeconds - video.mediaStart;
|
|
103049
103087
|
videoDuration = sourceDuration > 0 ? sourceDuration : metadata.durationSeconds;
|
|
103050
103088
|
video.end = video.start + videoDuration;
|
|
@@ -103419,7 +103457,7 @@ async function queryElementStacking(page, nativeHdrIds) {
|
|
|
103419
103457
|
|
|
103420
103458
|
// ../engine/src/services/audioMixer.ts
|
|
103421
103459
|
import { existsSync as existsSync9, mkdirSync as mkdirSync6, rmSync as rmSync2 } from "fs";
|
|
103422
|
-
import { join as join9, dirname as dirname7 } from "path";
|
|
103460
|
+
import { isAbsolute as isAbsolute3, join as join9, dirname as dirname7 } from "path";
|
|
103423
103461
|
function parseAudioElements(html) {
|
|
103424
103462
|
const elements = [];
|
|
103425
103463
|
const { document: document2 } = parseHTML(html);
|
|
@@ -103646,7 +103684,7 @@ async function processCompositionAudio(elements, baseDir, workDir, outputPath, t
|
|
|
103646
103684
|
}
|
|
103647
103685
|
try {
|
|
103648
103686
|
let srcPath = element.src;
|
|
103649
|
-
if (!srcPath
|
|
103687
|
+
if (!isAbsolute3(srcPath) && !isHttpUrl(srcPath)) {
|
|
103650
103688
|
const fromCompiled = compiledDir ? join9(compiledDir, srcPath) : null;
|
|
103651
103689
|
srcPath = fromCompiled && existsSync9(fromCompiled) ? fromCompiled : join9(baseDir, srcPath);
|
|
103652
103690
|
}
|
|
@@ -106996,13 +107034,51 @@ function normalizeObjectFit(value) {
|
|
|
106996
107034
|
}
|
|
106997
107035
|
function parseTransformMatrix(css) {
|
|
106998
107036
|
if (!css || css === "none") return null;
|
|
106999
|
-
const
|
|
107037
|
+
const match2d = css.match(
|
|
107000
107038
|
/^matrix\(\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,]+),\s*([^,)]+)\s*\)$/
|
|
107001
107039
|
);
|
|
107002
|
-
if (
|
|
107003
|
-
|
|
107004
|
-
|
|
107005
|
-
|
|
107040
|
+
if (match2d) {
|
|
107041
|
+
const values = match2d.slice(1, 7).map(Number);
|
|
107042
|
+
if (!values.every(Number.isFinite)) return null;
|
|
107043
|
+
return values;
|
|
107044
|
+
}
|
|
107045
|
+
const match3d = css.match(/^matrix3d\(\s*([^)]+)\)$/);
|
|
107046
|
+
if (match3d) {
|
|
107047
|
+
const raw2 = match3d[1];
|
|
107048
|
+
if (!raw2) return null;
|
|
107049
|
+
const parts = raw2.split(",").map((s) => Number(s.trim()));
|
|
107050
|
+
if (parts.length !== 16 || !parts.every(Number.isFinite)) return null;
|
|
107051
|
+
warnIfZSignificant(parts);
|
|
107052
|
+
return [
|
|
107053
|
+
parts[0],
|
|
107054
|
+
parts[1],
|
|
107055
|
+
parts[4],
|
|
107056
|
+
parts[5],
|
|
107057
|
+
parts[12],
|
|
107058
|
+
parts[13]
|
|
107059
|
+
];
|
|
107060
|
+
}
|
|
107061
|
+
return null;
|
|
107062
|
+
}
|
|
107063
|
+
var warnedZSignificant = false;
|
|
107064
|
+
var Z_EPSILON = 1e-6;
|
|
107065
|
+
function warnIfZSignificant(parts) {
|
|
107066
|
+
if (warnedZSignificant) return;
|
|
107067
|
+
const a3 = parts[8] ?? 0;
|
|
107068
|
+
const b3 = parts[9] ?? 0;
|
|
107069
|
+
const c1 = parts[2] ?? 0;
|
|
107070
|
+
const c2 = parts[6] ?? 0;
|
|
107071
|
+
const c3 = parts[10] ?? 1;
|
|
107072
|
+
const d1 = parts[3] ?? 0;
|
|
107073
|
+
const d2 = parts[7] ?? 0;
|
|
107074
|
+
const d3 = parts[11] ?? 0;
|
|
107075
|
+
const d4 = parts[15] ?? 1;
|
|
107076
|
+
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) {
|
|
107077
|
+
warnedZSignificant = true;
|
|
107078
|
+
console.warn(
|
|
107079
|
+
`[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.`
|
|
107080
|
+
);
|
|
107081
|
+
}
|
|
107006
107082
|
}
|
|
107007
107083
|
|
|
107008
107084
|
// ../engine/src/utils/layerCompositor.ts
|
|
@@ -108206,14 +108282,14 @@ import { join as join14, dirname as dirname9, resolve as resolve10 } from "path"
|
|
|
108206
108282
|
import postcss from "postcss";
|
|
108207
108283
|
|
|
108208
108284
|
// src/utils/paths.ts
|
|
108209
|
-
import { resolve as resolve9, basename as basename2, join as join12, relative as relative2, isAbsolute as
|
|
108285
|
+
import { resolve as resolve9, basename as basename2, join as join12, relative as relative2, isAbsolute as isAbsolute4 } from "node:path";
|
|
108210
108286
|
var DEFAULT_RENDERS_DIR = process.env.PRODUCER_RENDERS_DIR ?? resolve9(new URL(import.meta.url).pathname, "../../..", "renders");
|
|
108211
108287
|
function isPathInside2(childPath, parentPath) {
|
|
108212
108288
|
const absChild = resolve9(childPath);
|
|
108213
108289
|
const absParent = resolve9(parentPath);
|
|
108214
108290
|
if (absChild === absParent) return true;
|
|
108215
108291
|
const rel = relative2(absParent, absChild);
|
|
108216
|
-
return rel !== "" && !rel.startsWith("..") && !
|
|
108292
|
+
return rel !== "" && !rel.startsWith("..") && !isAbsolute4(rel);
|
|
108217
108293
|
}
|
|
108218
108294
|
function toExternalAssetKey(absPath) {
|
|
108219
108295
|
if (absPath.startsWith("hf-ext/")) return absPath;
|
|
@@ -108676,7 +108752,7 @@ async function resolveMediaDuration(src, mediaStart, baseDir, downloadDir, tagNa
|
|
|
108676
108752
|
if (!existsSync14(filePath)) {
|
|
108677
108753
|
return { duration: 0, resolvedPath: filePath };
|
|
108678
108754
|
}
|
|
108679
|
-
const metadata = tagName19 === "video" ? await
|
|
108755
|
+
const metadata = tagName19 === "video" ? await extractMediaMetadata(filePath) : await extractAudioMetadata(filePath);
|
|
108680
108756
|
const fileDuration = metadata.durationSeconds;
|
|
108681
108757
|
const effectiveDuration = fileDuration - mediaStart;
|
|
108682
108758
|
const duration = effectiveDuration > 0 ? effectiveDuration : fileDuration;
|
|
@@ -109259,7 +109335,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir) {
|
|
|
109259
109335
|
if (isHttpUrl(video.src)) continue;
|
|
109260
109336
|
const videoPath = resolve10(projectDir, video.src);
|
|
109261
109337
|
const reencode = `ffmpeg -i "${video.src}" -c:v libx264 -r 30 -g 30 -keyint_min 30 -movflags +faststart -c:a copy output.mp4`;
|
|
109262
|
-
Promise.all([analyzeKeyframeIntervals(videoPath),
|
|
109338
|
+
Promise.all([analyzeKeyframeIntervals(videoPath), extractMediaMetadata(videoPath)]).then(([analysis, metadata]) => {
|
|
109263
109339
|
if (analysis.isProblematic) {
|
|
109264
109340
|
console.warn(
|
|
109265
109341
|
`[Compiler] WARNING: Video "${video.id}" has sparse keyframes (max interval: ${analysis.maxIntervalSeconds}s). This causes seek failures and frame freezing. Re-encode with: ${reencode}`
|
|
@@ -109425,6 +109501,9 @@ function createConsoleLogger(level = "info") {
|
|
|
109425
109501
|
if (shouldLog("debug")) {
|
|
109426
109502
|
console.log(`[DEBUG] ${message}${formatMeta(meta)}`);
|
|
109427
109503
|
}
|
|
109504
|
+
},
|
|
109505
|
+
isLevelEnabled(msgLevel) {
|
|
109506
|
+
return shouldLog(msgLevel);
|
|
109428
109507
|
}
|
|
109429
109508
|
};
|
|
109430
109509
|
}
|
|
@@ -109458,6 +109537,21 @@ function getMaxFrameIndex(frameDir) {
|
|
|
109458
109537
|
frameDirMaxIndexCache.set(frameDir, max);
|
|
109459
109538
|
return max;
|
|
109460
109539
|
}
|
|
109540
|
+
function countNonZeroAlpha(rgba) {
|
|
109541
|
+
let n = 0;
|
|
109542
|
+
for (let p = 3; p < rgba.length; p += 4) {
|
|
109543
|
+
if (rgba[p] !== 0) n++;
|
|
109544
|
+
}
|
|
109545
|
+
return n;
|
|
109546
|
+
}
|
|
109547
|
+
function countNonZeroRgb48(buf) {
|
|
109548
|
+
let n = 0;
|
|
109549
|
+
for (let p = 0; p < buf.length; p += 6) {
|
|
109550
|
+
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0 || buf[p + 3] !== 0 || buf[p + 4] !== 0 || buf[p + 5] !== 0)
|
|
109551
|
+
n++;
|
|
109552
|
+
}
|
|
109553
|
+
return n;
|
|
109554
|
+
}
|
|
109461
109555
|
var RenderCancelledError = class extends Error {
|
|
109462
109556
|
reason;
|
|
109463
109557
|
constructor(message = "render_cancelled", reason = "aborted") {
|
|
@@ -109665,6 +109759,165 @@ function blitHdrImageLayer(canvas, el, hdrImageBuffers, width, height, log, sour
|
|
|
109665
109759
|
}
|
|
109666
109760
|
}
|
|
109667
109761
|
}
|
|
109762
|
+
async function compositeHdrFrame(ctx, canvas, time, fullStacking, elementFilter, debugFrameIndex = -1) {
|
|
109763
|
+
const {
|
|
109764
|
+
log,
|
|
109765
|
+
domSession,
|
|
109766
|
+
beforeCaptureHook,
|
|
109767
|
+
width,
|
|
109768
|
+
height,
|
|
109769
|
+
fps,
|
|
109770
|
+
effectiveHdr,
|
|
109771
|
+
nativeHdrImageIds,
|
|
109772
|
+
hdrImageBuffers,
|
|
109773
|
+
hdrFrameDirs,
|
|
109774
|
+
hdrVideoStartTimes,
|
|
109775
|
+
imageTransfers,
|
|
109776
|
+
videoTransfers,
|
|
109777
|
+
debugDumpEnabled,
|
|
109778
|
+
debugDumpDir
|
|
109779
|
+
} = ctx;
|
|
109780
|
+
const filteredStacking = elementFilter ? fullStacking.filter((e) => elementFilter.has(e.id)) : fullStacking;
|
|
109781
|
+
const layers = groupIntoLayers(filteredStacking);
|
|
109782
|
+
const shouldLog = debugDumpEnabled && debugFrameIndex >= 0;
|
|
109783
|
+
if (shouldLog) {
|
|
109784
|
+
log.info("[diag] compositeToBuffer plan", {
|
|
109785
|
+
frame: debugFrameIndex,
|
|
109786
|
+
time: time.toFixed(3),
|
|
109787
|
+
filterSize: elementFilter?.size,
|
|
109788
|
+
fullStackingCount: fullStacking.length,
|
|
109789
|
+
filteredCount: filteredStacking.length,
|
|
109790
|
+
layerCount: layers.length,
|
|
109791
|
+
layers: layers.map(
|
|
109792
|
+
(l) => l.type === "hdr" ? {
|
|
109793
|
+
type: "hdr",
|
|
109794
|
+
id: l.element.id,
|
|
109795
|
+
z: l.element.zIndex,
|
|
109796
|
+
visible: l.element.visible,
|
|
109797
|
+
opacity: l.element.opacity,
|
|
109798
|
+
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
109799
|
+
} : { type: "dom", ids: l.elementIds }
|
|
109800
|
+
)
|
|
109801
|
+
});
|
|
109802
|
+
}
|
|
109803
|
+
for (const [layerIdx, layer] of layers.entries()) {
|
|
109804
|
+
if (layer.type === "hdr") {
|
|
109805
|
+
const before2 = shouldLog ? countNonZeroRgb48(canvas) : 0;
|
|
109806
|
+
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
109807
|
+
if (isHdrImage) {
|
|
109808
|
+
blitHdrImageLayer(
|
|
109809
|
+
canvas,
|
|
109810
|
+
layer.element,
|
|
109811
|
+
hdrImageBuffers,
|
|
109812
|
+
width,
|
|
109813
|
+
height,
|
|
109814
|
+
log,
|
|
109815
|
+
imageTransfers.get(layer.element.id),
|
|
109816
|
+
effectiveHdr.transfer
|
|
109817
|
+
);
|
|
109818
|
+
} else {
|
|
109819
|
+
blitHdrVideoLayer(
|
|
109820
|
+
canvas,
|
|
109821
|
+
layer.element,
|
|
109822
|
+
time,
|
|
109823
|
+
fps,
|
|
109824
|
+
hdrFrameDirs,
|
|
109825
|
+
hdrVideoStartTimes,
|
|
109826
|
+
width,
|
|
109827
|
+
height,
|
|
109828
|
+
log,
|
|
109829
|
+
videoTransfers.get(layer.element.id),
|
|
109830
|
+
effectiveHdr.transfer
|
|
109831
|
+
);
|
|
109832
|
+
}
|
|
109833
|
+
if (shouldLog) {
|
|
109834
|
+
const after2 = countNonZeroRgb48(canvas);
|
|
109835
|
+
if (isHdrImage) {
|
|
109836
|
+
const buf = hdrImageBuffers.get(layer.element.id);
|
|
109837
|
+
log.info("[diag] hdr layer blit", {
|
|
109838
|
+
frame: debugFrameIndex,
|
|
109839
|
+
layerIdx,
|
|
109840
|
+
id: layer.element.id,
|
|
109841
|
+
kind: "image",
|
|
109842
|
+
pixelsAdded: after2 - before2,
|
|
109843
|
+
totalNonZero: after2,
|
|
109844
|
+
bufferDecoded: !!buf,
|
|
109845
|
+
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
109846
|
+
});
|
|
109847
|
+
} else {
|
|
109848
|
+
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
109849
|
+
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
109850
|
+
const localTime = time - startTime;
|
|
109851
|
+
const frameNum = Math.floor(localTime * fps) + 1;
|
|
109852
|
+
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
109853
|
+
log.info("[diag] hdr layer blit", {
|
|
109854
|
+
frame: debugFrameIndex,
|
|
109855
|
+
layerIdx,
|
|
109856
|
+
id: layer.element.id,
|
|
109857
|
+
kind: "video",
|
|
109858
|
+
pixelsAdded: after2 - before2,
|
|
109859
|
+
totalNonZero: after2,
|
|
109860
|
+
startTime,
|
|
109861
|
+
localTime: localTime.toFixed(3),
|
|
109862
|
+
hdrFrameNum: frameNum,
|
|
109863
|
+
expectedFrame,
|
|
109864
|
+
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
109865
|
+
});
|
|
109866
|
+
}
|
|
109867
|
+
}
|
|
109868
|
+
} else {
|
|
109869
|
+
const allElementIds = fullStacking.map((e) => e.id);
|
|
109870
|
+
const layerIds = new Set(layer.elementIds);
|
|
109871
|
+
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
109872
|
+
await domSession.page.evaluate((t) => {
|
|
109873
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
109874
|
+
}, time);
|
|
109875
|
+
if (beforeCaptureHook) {
|
|
109876
|
+
await beforeCaptureHook(domSession.page, time);
|
|
109877
|
+
}
|
|
109878
|
+
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
109879
|
+
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
109880
|
+
await removeDomLayerMask(domSession.page, hideIds);
|
|
109881
|
+
try {
|
|
109882
|
+
const { data: domRgba } = decodePng(domPng);
|
|
109883
|
+
const before2 = shouldLog ? countNonZeroRgb48(canvas) : 0;
|
|
109884
|
+
const alphaPixels = shouldLog ? countNonZeroAlpha(domRgba) : 0;
|
|
109885
|
+
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
109886
|
+
if (shouldLog && debugDumpDir) {
|
|
109887
|
+
const after2 = countNonZeroRgb48(canvas);
|
|
109888
|
+
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
109889
|
+
const dumpPath = join15(debugDumpDir, dumpName);
|
|
109890
|
+
writeFileSync4(dumpPath, domPng);
|
|
109891
|
+
log.info("[diag] dom layer blit", {
|
|
109892
|
+
frame: debugFrameIndex,
|
|
109893
|
+
layerIdx,
|
|
109894
|
+
layerIds: layer.elementIds,
|
|
109895
|
+
hideCount: hideIds.length,
|
|
109896
|
+
pngBytes: domPng.length,
|
|
109897
|
+
alphaPixels,
|
|
109898
|
+
pixelsAdded: after2 - before2,
|
|
109899
|
+
totalNonZero: after2,
|
|
109900
|
+
dumpPath
|
|
109901
|
+
});
|
|
109902
|
+
}
|
|
109903
|
+
} catch (err) {
|
|
109904
|
+
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
109905
|
+
layerIds: layer.elementIds,
|
|
109906
|
+
error: err instanceof Error ? err.message : String(err)
|
|
109907
|
+
});
|
|
109908
|
+
}
|
|
109909
|
+
}
|
|
109910
|
+
}
|
|
109911
|
+
if (shouldLog && debugDumpDir) {
|
|
109912
|
+
const finalNonZero = countNonZeroRgb48(canvas);
|
|
109913
|
+
log.info("[diag] compositeToBuffer end", {
|
|
109914
|
+
frame: debugFrameIndex,
|
|
109915
|
+
finalNonZeroPixels: finalNonZero,
|
|
109916
|
+
totalPixels: width * height,
|
|
109917
|
+
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
109918
|
+
});
|
|
109919
|
+
}
|
|
109920
|
+
}
|
|
109668
109921
|
function createRenderJob(config2) {
|
|
109669
109922
|
return {
|
|
109670
109923
|
id: randomUUID(),
|
|
@@ -109732,6 +109985,19 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
109732
109985
|
const enableChunkedEncode = cfg.enableChunkedEncode;
|
|
109733
109986
|
const chunkedEncodeSize = cfg.chunkSizeFrames;
|
|
109734
109987
|
const enableStreamingEncode = cfg.enableStreamingEncode;
|
|
109988
|
+
let peakRssBytes = 0;
|
|
109989
|
+
let peakHeapUsedBytes = 0;
|
|
109990
|
+
const sampleMemory = () => {
|
|
109991
|
+
try {
|
|
109992
|
+
const m = process.memoryUsage();
|
|
109993
|
+
if (m.rss > peakRssBytes) peakRssBytes = m.rss;
|
|
109994
|
+
if (m.heapUsed > peakHeapUsedBytes) peakHeapUsedBytes = m.heapUsed;
|
|
109995
|
+
} catch {
|
|
109996
|
+
}
|
|
109997
|
+
};
|
|
109998
|
+
sampleMemory();
|
|
109999
|
+
const memSamplerInterval = setInterval(sampleMemory, 250);
|
|
110000
|
+
memSamplerInterval.unref?.();
|
|
109735
110001
|
try {
|
|
109736
110002
|
const assertNotAborted = () => {
|
|
109737
110003
|
if (abortSignal?.aborted) {
|
|
@@ -110009,7 +110275,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110009
110275
|
videoPath = fromCompiled;
|
|
110010
110276
|
}
|
|
110011
110277
|
if (!existsSync15(videoPath)) return;
|
|
110012
|
-
const meta = await
|
|
110278
|
+
const meta = await extractMediaMetadata(videoPath);
|
|
110013
110279
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
110014
110280
|
nativeHdrVideoIds.add(v.id);
|
|
110015
110281
|
videoTransfers.set(v.id, detectTransfer(meta.colorSpace));
|
|
@@ -110030,7 +110296,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110030
110296
|
imgPath = fromCompiled;
|
|
110031
110297
|
}
|
|
110032
110298
|
if (!existsSync15(imgPath)) return null;
|
|
110033
|
-
const meta = await
|
|
110299
|
+
const meta = await extractMediaMetadata(imgPath);
|
|
110034
110300
|
if (isHdrColorSpace(meta.colorSpace)) {
|
|
110035
110301
|
nativeHdrImageIds.add(img.id);
|
|
110036
110302
|
imageTransfers.set(img.id, detectTransfer(meta.colorSpace));
|
|
@@ -110142,6 +110408,10 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110142
110408
|
format: needsAlpha ? "png" : "jpeg",
|
|
110143
110409
|
quality: needsAlpha ? void 0 : job.config.quality === "draft" ? 80 : 95
|
|
110144
110410
|
};
|
|
110411
|
+
const buildHdrCaptureOptions = () => ({
|
|
110412
|
+
...captureOptions,
|
|
110413
|
+
skipReadinessVideoIds: Array.from(nativeHdrVideoIds)
|
|
110414
|
+
});
|
|
110145
110415
|
const workerCount = calculateOptimalWorkers(totalFrames, job.config.workers, cfg);
|
|
110146
110416
|
const FORMAT_EXT = { mp4: ".mp4", webm: ".webm", mov: ".mov" };
|
|
110147
110417
|
const videoExt = FORMAT_EXT[outputFormat] ?? ".mp4";
|
|
@@ -110176,7 +110446,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110176
110446
|
const domSession = await createCaptureSession(
|
|
110177
110447
|
fileServer.url,
|
|
110178
110448
|
framesDir,
|
|
110179
|
-
|
|
110449
|
+
buildHdrCaptureOptions(),
|
|
110180
110450
|
createVideoFrameInjector(frameLookup),
|
|
110181
110451
|
cfg
|
|
110182
110452
|
);
|
|
@@ -110272,6 +110542,29 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110272
110542
|
}
|
|
110273
110543
|
}
|
|
110274
110544
|
}
|
|
110545
|
+
for (const [imageId, startTime] of hdrImageStartTimes) {
|
|
110546
|
+
if (hdrExtractionDims.has(imageId)) continue;
|
|
110547
|
+
const img = composition.images.find((i) => i.id === imageId);
|
|
110548
|
+
if (!img) continue;
|
|
110549
|
+
const duration = img.end - img.start;
|
|
110550
|
+
const retryTime = startTime + Math.min(0.5, duration * 0.1);
|
|
110551
|
+
await domSession.page.evaluate((t) => {
|
|
110552
|
+
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
110553
|
+
}, retryTime);
|
|
110554
|
+
if (domSession.onBeforeCapture) {
|
|
110555
|
+
await domSession.onBeforeCapture(domSession.page, retryTime);
|
|
110556
|
+
}
|
|
110557
|
+
const retryStacking = await queryElementStacking(domSession.page, nativeHdrIds);
|
|
110558
|
+
for (const el of retryStacking) {
|
|
110559
|
+
if (el.id === imageId && el.isHdr && el.layoutWidth > 0 && el.layoutHeight > 0) {
|
|
110560
|
+
hdrExtractionDims.set(el.id, { width: el.layoutWidth, height: el.layoutHeight });
|
|
110561
|
+
if (!hdrImageFitInfo.has(el.id)) {
|
|
110562
|
+
hdrImageFitInfo.set(el.id, { fit: el.objectFit, position: el.objectPosition });
|
|
110563
|
+
}
|
|
110564
|
+
break;
|
|
110565
|
+
}
|
|
110566
|
+
}
|
|
110567
|
+
}
|
|
110275
110568
|
for (const [videoId, srcPath] of hdrVideoSrcPaths) {
|
|
110276
110569
|
const video = composition.videos.find((v) => v.id === videoId);
|
|
110277
110570
|
if (!video) continue;
|
|
@@ -110354,21 +110647,6 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110354
110647
|
}
|
|
110355
110648
|
assertNotAborted();
|
|
110356
110649
|
try {
|
|
110357
|
-
let countNonZeroAlpha2 = function(rgba) {
|
|
110358
|
-
let n = 0;
|
|
110359
|
-
for (let p = 3; p < rgba.length; p += 4) {
|
|
110360
|
-
if (rgba[p] !== 0) n++;
|
|
110361
|
-
}
|
|
110362
|
-
return n;
|
|
110363
|
-
}, countNonZeroRgb482 = function(buf) {
|
|
110364
|
-
let n = 0;
|
|
110365
|
-
for (let p = 0; p < buf.length; p += 6) {
|
|
110366
|
-
if (buf[p] !== 0 || buf[p + 1] !== 0 || buf[p + 2] !== 0 || buf[p + 3] !== 0 || buf[p + 4] !== 0 || buf[p + 5] !== 0)
|
|
110367
|
-
n++;
|
|
110368
|
-
}
|
|
110369
|
-
return n;
|
|
110370
|
-
};
|
|
110371
|
-
var countNonZeroAlpha = countNonZeroAlpha2, countNonZeroRgb48 = countNonZeroRgb482;
|
|
110372
110650
|
const beforeCaptureHook = domSession.onBeforeCapture;
|
|
110373
110651
|
const cleanedUpVideos = /* @__PURE__ */ new Set();
|
|
110374
110652
|
const hdrVideoEndTimes = /* @__PURE__ */ new Map();
|
|
@@ -110382,153 +110660,28 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110382
110660
|
if (debugDumpDir && !existsSync15(debugDumpDir)) {
|
|
110383
110661
|
mkdirSync10(debugDumpDir, { recursive: true });
|
|
110384
110662
|
}
|
|
110385
|
-
|
|
110386
|
-
|
|
110387
|
-
|
|
110388
|
-
|
|
110389
|
-
if (shouldLog) {
|
|
110390
|
-
log.info("[diag] compositeToBuffer plan", {
|
|
110391
|
-
frame: debugFrameIndex,
|
|
110392
|
-
time: time.toFixed(3),
|
|
110393
|
-
filterSize: elementFilter?.size,
|
|
110394
|
-
fullStackingCount: fullStacking.length,
|
|
110395
|
-
filteredCount: filteredStacking.length,
|
|
110396
|
-
layerCount: layers.length,
|
|
110397
|
-
layers: layers.map(
|
|
110398
|
-
(l) => l.type === "hdr" ? {
|
|
110399
|
-
type: "hdr",
|
|
110400
|
-
id: l.element.id,
|
|
110401
|
-
z: l.element.zIndex,
|
|
110402
|
-
visible: l.element.visible,
|
|
110403
|
-
opacity: l.element.opacity,
|
|
110404
|
-
bounds: `${Math.round(l.element.x)},${Math.round(l.element.y)} ${Math.round(l.element.width)}x${Math.round(l.element.height)}`
|
|
110405
|
-
} : { type: "dom", ids: l.elementIds }
|
|
110406
|
-
)
|
|
110407
|
-
});
|
|
110408
|
-
}
|
|
110409
|
-
for (const [layerIdx, layer] of layers.entries()) {
|
|
110410
|
-
if (layer.type === "hdr") {
|
|
110411
|
-
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
110412
|
-
const isHdrImage = nativeHdrImageIds.has(layer.element.id);
|
|
110413
|
-
if (isHdrImage) {
|
|
110414
|
-
blitHdrImageLayer(
|
|
110415
|
-
canvas,
|
|
110416
|
-
layer.element,
|
|
110417
|
-
hdrImageBuffers,
|
|
110418
|
-
width,
|
|
110419
|
-
height,
|
|
110420
|
-
log,
|
|
110421
|
-
imageTransfers.get(layer.element.id),
|
|
110422
|
-
effectiveHdr?.transfer
|
|
110423
|
-
);
|
|
110424
|
-
} else {
|
|
110425
|
-
blitHdrVideoLayer(
|
|
110426
|
-
canvas,
|
|
110427
|
-
layer.element,
|
|
110428
|
-
time,
|
|
110429
|
-
job.config.fps,
|
|
110430
|
-
hdrFrameDirs,
|
|
110431
|
-
hdrVideoStartTimes,
|
|
110432
|
-
width,
|
|
110433
|
-
height,
|
|
110434
|
-
log,
|
|
110435
|
-
videoTransfers.get(layer.element.id),
|
|
110436
|
-
effectiveHdr?.transfer
|
|
110437
|
-
);
|
|
110438
|
-
}
|
|
110439
|
-
if (shouldLog) {
|
|
110440
|
-
const after2 = countNonZeroRgb482(canvas);
|
|
110441
|
-
if (isHdrImage) {
|
|
110442
|
-
const buf = hdrImageBuffers.get(layer.element.id);
|
|
110443
|
-
log.info("[diag] hdr layer blit", {
|
|
110444
|
-
frame: debugFrameIndex,
|
|
110445
|
-
layerIdx,
|
|
110446
|
-
id: layer.element.id,
|
|
110447
|
-
kind: "image",
|
|
110448
|
-
pixelsAdded: after2 - before2,
|
|
110449
|
-
totalNonZero: after2,
|
|
110450
|
-
bufferDecoded: !!buf,
|
|
110451
|
-
bufferDims: buf ? `${buf.width}x${buf.height}` : null
|
|
110452
|
-
});
|
|
110453
|
-
} else {
|
|
110454
|
-
const frameDir = hdrFrameDirs.get(layer.element.id);
|
|
110455
|
-
const startTime = hdrVideoStartTimes.get(layer.element.id) ?? 0;
|
|
110456
|
-
const localTime = time - startTime;
|
|
110457
|
-
const frameNum = Math.floor(localTime * job.config.fps) + 1;
|
|
110458
|
-
const expectedFrame = frameDir ? join15(frameDir, `frame_${String(frameNum).padStart(4, "0")}.png`) : null;
|
|
110459
|
-
log.info("[diag] hdr layer blit", {
|
|
110460
|
-
frame: debugFrameIndex,
|
|
110461
|
-
layerIdx,
|
|
110462
|
-
id: layer.element.id,
|
|
110463
|
-
kind: "video",
|
|
110464
|
-
pixelsAdded: after2 - before2,
|
|
110465
|
-
totalNonZero: after2,
|
|
110466
|
-
startTime,
|
|
110467
|
-
localTime: localTime.toFixed(3),
|
|
110468
|
-
hdrFrameNum: frameNum,
|
|
110469
|
-
expectedFrame,
|
|
110470
|
-
expectedFrameExists: expectedFrame ? existsSync15(expectedFrame) : false
|
|
110471
|
-
});
|
|
110472
|
-
}
|
|
110473
|
-
}
|
|
110474
|
-
} else {
|
|
110475
|
-
const allElementIds = fullStacking.map((e) => e.id);
|
|
110476
|
-
const layerIds = new Set(layer.elementIds);
|
|
110477
|
-
const hideIds = allElementIds.filter((id) => !layerIds.has(id));
|
|
110478
|
-
await domSession.page.evaluate((t) => {
|
|
110479
|
-
if (window.__hf && typeof window.__hf.seek === "function") window.__hf.seek(t);
|
|
110480
|
-
}, time);
|
|
110481
|
-
if (beforeCaptureHook) {
|
|
110482
|
-
await beforeCaptureHook(domSession.page, time);
|
|
110483
|
-
}
|
|
110484
|
-
await applyDomLayerMask(domSession.page, layer.elementIds, hideIds);
|
|
110485
|
-
const domPng = await captureAlphaPng(domSession.page, width, height);
|
|
110486
|
-
await removeDomLayerMask(domSession.page, hideIds);
|
|
110487
|
-
try {
|
|
110488
|
-
const { data: domRgba } = decodePng(domPng);
|
|
110489
|
-
if (!effectiveHdr) {
|
|
110490
|
-
throw new Error(
|
|
110491
|
-
"Invariant violation: effectiveHdr is undefined inside HDR layer branch"
|
|
110492
|
-
);
|
|
110493
|
-
}
|
|
110494
|
-
const before2 = shouldLog ? countNonZeroRgb482(canvas) : 0;
|
|
110495
|
-
const alphaPixels = shouldLog ? countNonZeroAlpha2(domRgba) : 0;
|
|
110496
|
-
blitRgba8OverRgb48le(domRgba, canvas, width, height, effectiveHdr.transfer);
|
|
110497
|
-
if (shouldLog && debugDumpDir) {
|
|
110498
|
-
const after2 = countNonZeroRgb482(canvas);
|
|
110499
|
-
const dumpName = `frame_${String(debugFrameIndex).padStart(4, "0")}_layer_${String(layerIdx).padStart(2, "0")}_dom.png`;
|
|
110500
|
-
const dumpPath = join15(debugDumpDir, dumpName);
|
|
110501
|
-
writeFileSync4(dumpPath, domPng);
|
|
110502
|
-
log.info("[diag] dom layer blit", {
|
|
110503
|
-
frame: debugFrameIndex,
|
|
110504
|
-
layerIdx,
|
|
110505
|
-
layerIds: layer.elementIds,
|
|
110506
|
-
hideCount: hideIds.length,
|
|
110507
|
-
pngBytes: domPng.length,
|
|
110508
|
-
alphaPixels,
|
|
110509
|
-
pixelsAdded: after2 - before2,
|
|
110510
|
-
totalNonZero: after2,
|
|
110511
|
-
dumpPath
|
|
110512
|
-
});
|
|
110513
|
-
}
|
|
110514
|
-
} catch (err) {
|
|
110515
|
-
log.warn("DOM layer decode/blit failed; skipping overlay", {
|
|
110516
|
-
layerIds: layer.elementIds,
|
|
110517
|
-
error: err instanceof Error ? err.message : String(err)
|
|
110518
|
-
});
|
|
110519
|
-
}
|
|
110520
|
-
}
|
|
110521
|
-
}
|
|
110522
|
-
if (shouldLog && debugDumpDir) {
|
|
110523
|
-
const finalNonZero = countNonZeroRgb482(canvas);
|
|
110524
|
-
log.info("[diag] compositeToBuffer end", {
|
|
110525
|
-
frame: debugFrameIndex,
|
|
110526
|
-
finalNonZeroPixels: finalNonZero,
|
|
110527
|
-
totalPixels: width * height,
|
|
110528
|
-
coverage: (finalNonZero / (width * height) * 100).toFixed(1) + "%"
|
|
110529
|
-
});
|
|
110530
|
-
}
|
|
110663
|
+
if (!effectiveHdr) {
|
|
110664
|
+
throw new Error(
|
|
110665
|
+
"Internal: HDR render path entered without effectiveHdr \u2014 this is a bug."
|
|
110666
|
+
);
|
|
110531
110667
|
}
|
|
110668
|
+
const hdrCompositeCtx = {
|
|
110669
|
+
log,
|
|
110670
|
+
domSession,
|
|
110671
|
+
beforeCaptureHook,
|
|
110672
|
+
width,
|
|
110673
|
+
height,
|
|
110674
|
+
fps: job.config.fps,
|
|
110675
|
+
effectiveHdr,
|
|
110676
|
+
nativeHdrImageIds,
|
|
110677
|
+
hdrImageBuffers,
|
|
110678
|
+
hdrFrameDirs,
|
|
110679
|
+
hdrVideoStartTimes,
|
|
110680
|
+
imageTransfers,
|
|
110681
|
+
videoTransfers,
|
|
110682
|
+
debugDumpEnabled,
|
|
110683
|
+
debugDumpDir
|
|
110684
|
+
};
|
|
110532
110685
|
const bufSize = width * height * 6;
|
|
110533
110686
|
const hasTransitions = transitionRanges.length > 0;
|
|
110534
110687
|
const transBufferA = hasTransitions ? Buffer.alloc(bufSize) : null;
|
|
@@ -110548,7 +110701,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110548
110701
|
const activeTransition = transitionRanges.find(
|
|
110549
110702
|
(t) => i >= t.startFrame && i <= t.endFrame
|
|
110550
110703
|
);
|
|
110551
|
-
if (i % 30 === 0) {
|
|
110704
|
+
if (i % 30 === 0 && (log.isLevelEnabled?.("debug") ?? true)) {
|
|
110552
110705
|
const hdrEl = stackingInfo.find((e) => e.isHdr);
|
|
110553
110706
|
log.debug("[Render] HDR layer composite frame", {
|
|
110554
110707
|
frame: i,
|
|
@@ -110636,7 +110789,14 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110636
110789
|
hdrEncoder.writeFrame(transOutput);
|
|
110637
110790
|
} else {
|
|
110638
110791
|
normalCanvas.fill(0);
|
|
110639
|
-
await
|
|
110792
|
+
await compositeHdrFrame(
|
|
110793
|
+
hdrCompositeCtx,
|
|
110794
|
+
normalCanvas,
|
|
110795
|
+
time,
|
|
110796
|
+
stackingInfo,
|
|
110797
|
+
void 0,
|
|
110798
|
+
i
|
|
110799
|
+
);
|
|
110640
110800
|
if (debugDumpEnabled && debugDumpDir && i % 30 === 0) {
|
|
110641
110801
|
const previewPath = join15(
|
|
110642
110802
|
debugDumpDir,
|
|
@@ -110755,7 +110915,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110755
110915
|
fileServer.url,
|
|
110756
110916
|
workDir,
|
|
110757
110917
|
tasks,
|
|
110758
|
-
|
|
110918
|
+
buildHdrCaptureOptions(),
|
|
110759
110919
|
() => createVideoFrameInjector(frameLookup),
|
|
110760
110920
|
abortSignal,
|
|
110761
110921
|
(progress) => {
|
|
@@ -110785,7 +110945,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110785
110945
|
const session = probeSession ?? await createCaptureSession(
|
|
110786
110946
|
fileServer.url,
|
|
110787
110947
|
framesDir,
|
|
110788
|
-
|
|
110948
|
+
buildHdrCaptureOptions(),
|
|
110789
110949
|
videoInjector,
|
|
110790
110950
|
cfg
|
|
110791
110951
|
);
|
|
@@ -110837,7 +110997,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110837
110997
|
fileServer.url,
|
|
110838
110998
|
workDir,
|
|
110839
110999
|
tasks,
|
|
110840
|
-
|
|
111000
|
+
buildHdrCaptureOptions(),
|
|
110841
111001
|
() => createVideoFrameInjector(frameLookup),
|
|
110842
111002
|
abortSignal,
|
|
110843
111003
|
(progress) => {
|
|
@@ -110868,7 +111028,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110868
111028
|
const session = probeSession ?? await createCaptureSession(
|
|
110869
111029
|
fileServer.url,
|
|
110870
111030
|
framesDir,
|
|
110871
|
-
|
|
111031
|
+
buildHdrCaptureOptions(),
|
|
110872
111032
|
videoInjector,
|
|
110873
111033
|
cfg
|
|
110874
111034
|
);
|
|
@@ -110984,6 +111144,7 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110984
111144
|
job.outputPath = outputPath;
|
|
110985
111145
|
updateJobStatus(job, "complete", "Render complete", 100, onProgress);
|
|
110986
111146
|
const totalElapsed = Date.now() - pipelineStart;
|
|
111147
|
+
sampleMemory();
|
|
110987
111148
|
const perfSummary = {
|
|
110988
111149
|
renderId: job.id,
|
|
110989
111150
|
totalElapsedMs: totalElapsed,
|
|
@@ -110999,7 +111160,9 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
110999
111160
|
audioCount: composition.audios.length,
|
|
111000
111161
|
stages: perfStages,
|
|
111001
111162
|
hdrDiagnostics: hdrDiagnostics.videoExtractionFailures > 0 || hdrDiagnostics.imageDecodeFailures > 0 ? { ...hdrDiagnostics } : void 0,
|
|
111002
|
-
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0
|
|
111163
|
+
captureAvgMs: totalFrames > 0 ? Math.round((perfStages.captureMs ?? 0) / totalFrames) : void 0,
|
|
111164
|
+
peakRssMb: Math.round(peakRssBytes / (1024 * 1024)),
|
|
111165
|
+
peakHeapUsedMb: Math.round(peakHeapUsedBytes / (1024 * 1024))
|
|
111003
111166
|
};
|
|
111004
111167
|
job.perfSummary = perfSummary;
|
|
111005
111168
|
if (job.config.debug) {
|
|
@@ -111107,6 +111270,8 @@ async function executeRenderJob(job, projectDir, outputPath, onProgress, abortSi
|
|
|
111107
111270
|
}
|
|
111108
111271
|
if (restoreLogger) restoreLogger();
|
|
111109
111272
|
throw error;
|
|
111273
|
+
} finally {
|
|
111274
|
+
clearInterval(memSamplerInterval);
|
|
111110
111275
|
}
|
|
111111
111276
|
}
|
|
111112
111277
|
|