@hyperframes/producer 0.8.222 → 0.8.224
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/distributed.js +13 -7
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +70 -70
- package/dist/index.js +36 -10
- package/dist/public-server.js +36 -10
- package/dist/services/htmlCompiler.d.ts +1 -0
- package/dist/services/render/hdrMode.d.ts +4 -1
- package/dist/services/render/shared.d.ts +1 -0
- package/dist/services/render/stages/captureHdrStage.d.ts +1 -0
- package/dist/services/render/stages/extractVideosStage.d.ts +1 -1
- package/dist/services/renderMediaCollector.d.ts +1 -0
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -4884,6 +4884,7 @@ async function validateCompletedSegments(manifest, expectedHash, probeFrames) {
|
|
|
4884
4884
|
import {
|
|
4885
4885
|
analyzeCompositionHdr,
|
|
4886
4886
|
formatHdrAutoPromotionWarning,
|
|
4887
|
+
gradingKeepsSdr,
|
|
4887
4888
|
HDR_AUTO_PROMOTION_PIPELINE,
|
|
4888
4889
|
isHdrColorSpace,
|
|
4889
4890
|
sanitizeHdrAutoPromotionAsset
|
|
@@ -4901,13 +4902,28 @@ function findRenderHdrAutoPromotionTrigger(input) {
|
|
|
4901
4902
|
}
|
|
4902
4903
|
return input.images.find(({ id }) => input.nativeHdrImageIds.has(id))?.src;
|
|
4903
4904
|
}
|
|
4904
|
-
function
|
|
4905
|
+
function logGradingResolution(input, hdrMode, effectiveHdr, hasHdrSource) {
|
|
4906
|
+
const keptSdr = hasHdrSource && gradingKeepsSdr(hdrMode, input.media);
|
|
4907
|
+
if (keptSdr) {
|
|
4908
|
+
input.log.warn(
|
|
4909
|
+
"[Render] HDR source detected, but color grading is SDR-only, so rendering SDR: HDR sources are tone-mapped before the grade. Use --hdr to force HDR output (grades stay SDR)."
|
|
4910
|
+
);
|
|
4911
|
+
} else if (effectiveHdr && [...input.media.videos, ...input.media.images].some((m) => m.graded)) {
|
|
4912
|
+
input.log.warn(
|
|
4913
|
+
"[Render] HDR output with graded media: color grading is SDR-only, so graded elements are graded in SDR and placed in the HDR output."
|
|
4914
|
+
);
|
|
4915
|
+
}
|
|
4916
|
+
return keptSdr;
|
|
4917
|
+
}
|
|
4918
|
+
function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources, hasHdrSource) {
|
|
4919
|
+
const keptSdrForGrading = logGradingResolution(input, hdrMode, effectiveHdr, hasHdrSource);
|
|
4905
4920
|
if (forcedHdrWithoutSources) {
|
|
4906
4921
|
input.log.warn(
|
|
4907
4922
|
"[Render] HDR forced by --hdr flag, but no HDR sources were detected, defaulting to HLG. SDR-only compositions may look perceptually wrong on HDR displays."
|
|
4908
4923
|
);
|
|
4909
4924
|
}
|
|
4910
4925
|
if (!effectiveHdr) {
|
|
4926
|
+
if (keptSdrForGrading) return;
|
|
4911
4927
|
input.log.info(
|
|
4912
4928
|
hdrMode === "force-sdr" ? "[Render] SDR forced by --sdr flag" : "[Render] No HDR sources detected, rendering SDR"
|
|
4913
4929
|
);
|
|
@@ -4932,8 +4948,8 @@ function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources)
|
|
|
4932
4948
|
function formatCarriesHdr(format) {
|
|
4933
4949
|
return format === "mp4";
|
|
4934
4950
|
}
|
|
4935
|
-
function rendersSdrOnly(config) {
|
|
4936
|
-
return config.hdrMode === "force-sdr" || !formatCarriesHdr(config.format ?? "mp4");
|
|
4951
|
+
function rendersSdrOnly(config, media) {
|
|
4952
|
+
return config.hdrMode === "force-sdr" || gradingKeepsSdr(config.hdrMode, media) || !formatCarriesHdr(config.format ?? "mp4");
|
|
4937
4953
|
}
|
|
4938
4954
|
function resolveEffectiveHdrMode(input) {
|
|
4939
4955
|
const hdrMode = input.hdrMode ?? "auto";
|
|
@@ -4944,7 +4960,7 @@ function resolveEffectiveHdrMode(input) {
|
|
|
4944
4960
|
const info = allColorSpaces.length > 0 ? analyzeCompositionHdr(allColorSpaces) : null;
|
|
4945
4961
|
let effectiveHdr;
|
|
4946
4962
|
let forcedHdrWithoutSources = false;
|
|
4947
|
-
if (hdrMode === "force-sdr") {
|
|
4963
|
+
if (hdrMode === "force-sdr" || gradingKeepsSdr(hdrMode, input.media)) {
|
|
4948
4964
|
effectiveHdr = void 0;
|
|
4949
4965
|
} else if (hdrMode === "force-hdr") {
|
|
4950
4966
|
if (info?.hasHdr && info.dominantTransfer) {
|
|
@@ -4960,7 +4976,7 @@ function resolveEffectiveHdrMode(input) {
|
|
|
4960
4976
|
input.log.warn(formatDowngradeWarning(input.outputFormat, forcedHdrWithoutSources));
|
|
4961
4977
|
effectiveHdr = void 0;
|
|
4962
4978
|
}
|
|
4963
|
-
logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources);
|
|
4979
|
+
logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources, info?.hasHdr === true);
|
|
4964
4980
|
return effectiveHdr;
|
|
4965
4981
|
}
|
|
4966
4982
|
|
|
@@ -5825,6 +5841,7 @@ import {
|
|
|
5825
5841
|
} from "@hyperframes/core/media-timing";
|
|
5826
5842
|
import {
|
|
5827
5843
|
parseVideoElements,
|
|
5844
|
+
hasGradedCanvas,
|
|
5828
5845
|
parseImageElements,
|
|
5829
5846
|
parseAudioElements,
|
|
5830
5847
|
isSelfOrAncestorHidden,
|
|
@@ -5959,7 +5976,7 @@ function collectRenderMedia(html) {
|
|
|
5959
5976
|
if (placed) audios.push(placed);
|
|
5960
5977
|
else droppedMediaIds.add(elementId);
|
|
5961
5978
|
}
|
|
5962
|
-
return { videos, audios, images, droppedMediaIds };
|
|
5979
|
+
return { videos, audios, images, droppedMediaIds, gradedCanvas: hasGradedCanvas(html) };
|
|
5963
5980
|
}
|
|
5964
5981
|
function placeAudio(audio, window2) {
|
|
5965
5982
|
const authoredEnd = audio.end > 0 ? audio.end : Infinity;
|
|
@@ -8014,7 +8031,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
|
|
|
8014
8031
|
for (const [relPath, absPath] of preparedHeifAssets) {
|
|
8015
8032
|
externalAssets.set(relPath, absPath);
|
|
8016
8033
|
}
|
|
8017
|
-
const { videos, audios, images, droppedMediaIds } = collectRenderMedia(html);
|
|
8034
|
+
const { videos, audios, images, droppedMediaIds, gradedCanvas } = collectRenderMedia(html);
|
|
8018
8035
|
const masterFxChain = parseMasterFxChain(html);
|
|
8019
8036
|
const advised = /* @__PURE__ */ new Set();
|
|
8020
8037
|
for (const video of videos) {
|
|
@@ -8053,6 +8070,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
|
|
|
8053
8070
|
audios,
|
|
8054
8071
|
images,
|
|
8055
8072
|
droppedMediaIds,
|
|
8073
|
+
gradedCanvas,
|
|
8056
8074
|
...masterFxChain ? { masterFxChain } : {},
|
|
8057
8075
|
unresolvedCompositions,
|
|
8058
8076
|
externalAssets,
|
|
@@ -8506,6 +8524,7 @@ async function runCompileStage(input) {
|
|
|
8506
8524
|
videos: compiled.videos,
|
|
8507
8525
|
audios: compiled.audios,
|
|
8508
8526
|
images: compiled.images,
|
|
8527
|
+
gradedCanvas: compiled.gradedCanvas,
|
|
8509
8528
|
masterFxChain: compiled.masterFxChain,
|
|
8510
8529
|
width: compiled.width,
|
|
8511
8530
|
height: compiled.height
|
|
@@ -9284,6 +9303,7 @@ import {
|
|
|
9284
9303
|
detectTransfer,
|
|
9285
9304
|
extractAllVideoFrames,
|
|
9286
9305
|
extractMediaMetadata as extractMediaMetadata3,
|
|
9306
|
+
gradingKeepsSdr as gradingKeepsSdr2,
|
|
9287
9307
|
isVideoPastTimelineEnd,
|
|
9288
9308
|
isHdrColorSpace as isHdrColorSpace2,
|
|
9289
9309
|
rebaseVideoToWindow,
|
|
@@ -9524,10 +9544,11 @@ async function runExtractVideosStage(input) {
|
|
|
9524
9544
|
let failureToEnforce = null;
|
|
9525
9545
|
let videoReadinessSkipIds = [];
|
|
9526
9546
|
let videoMetadataHints = [];
|
|
9547
|
+
const probesHdr = job.config.hdrMode !== "force-sdr" && !gradingKeepsSdr2(job.config.hdrMode, composition);
|
|
9527
9548
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
9528
9549
|
const videoTransfers = /* @__PURE__ */ new Map();
|
|
9529
9550
|
let hdrProbeTransientRetries = 0;
|
|
9530
|
-
if (
|
|
9551
|
+
if (probesHdr && composition.videos.length > 0) {
|
|
9531
9552
|
log?.info("Probing video color spaces...", { videoCount: composition.videos.length });
|
|
9532
9553
|
const probeFailures = await Promise.all(
|
|
9533
9554
|
composition.videos.map(async (v) => {
|
|
@@ -9566,7 +9587,7 @@ async function runExtractVideosStage(input) {
|
|
|
9566
9587
|
const imageTransfers = /* @__PURE__ */ new Map();
|
|
9567
9588
|
const hdrImageSrcPaths = /* @__PURE__ */ new Map();
|
|
9568
9589
|
const imageColorSpaces = [];
|
|
9569
|
-
if (
|
|
9590
|
+
if (probesHdr && composition.images.length > 0) {
|
|
9570
9591
|
const probed = await Promise.all(
|
|
9571
9592
|
composition.images.map(async (img) => {
|
|
9572
9593
|
const imgPath = resolveProjectRelativeSrc3(img.src, projectDir, compiledDir);
|
|
@@ -9603,7 +9624,7 @@ async function runExtractVideosStage(input) {
|
|
|
9603
9624
|
fps: job.config.fps,
|
|
9604
9625
|
outputDir: join18(compiledDir, "__hyperframes_video_frames"),
|
|
9605
9626
|
format: job.config.videoFrameFormat ?? "auto",
|
|
9606
|
-
toneMapHdrToSdr: rendersSdrOnly(job.config),
|
|
9627
|
+
toneMapHdrToSdr: rendersSdrOnly(job.config, composition),
|
|
9607
9628
|
timelineEnd: composition.duration,
|
|
9608
9629
|
maxTransientRetries: extractionPolicy.maxTransientRetries,
|
|
9609
9630
|
collectProbeFailures: extractionPolicy.failureMode === "enforce",
|
|
@@ -11361,6 +11382,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11361
11382
|
let lastBrowserConsole = [];
|
|
11362
11383
|
let captureDurationMs = 0;
|
|
11363
11384
|
let encodeMs = 0;
|
|
11385
|
+
let encoderDrainWaitMs;
|
|
11364
11386
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11365
11387
|
log.info(
|
|
11366
11388
|
hasHdrContent ? "[Render] HDR layered composite: z-ordered DOM + native HDR video/image layers" : "[Render] Shader transition composite: z-ordered SDR DOM layers"
|
|
@@ -11598,6 +11620,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11598
11620
|
reportEncodeProgress(job, totalFrames, totalFrames, onProgress, encodeFrom);
|
|
11599
11621
|
captureDurationMs = Date.now() - stageStart;
|
|
11600
11622
|
encodeMs = hdrEncodeResult.durationMs;
|
|
11623
|
+
encoderDrainWaitMs = hdrEncodeResult.drainWaitMs;
|
|
11601
11624
|
} catch (error) {
|
|
11602
11625
|
lastBrowserConsole = domSession.browserConsoleBuffer;
|
|
11603
11626
|
throw wrapCaptureStageError(error, lastBrowserConsole);
|
|
@@ -11630,6 +11653,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11630
11653
|
hdrPerf,
|
|
11631
11654
|
captureDurationMs,
|
|
11632
11655
|
encodeMs,
|
|
11656
|
+
encoderDrainWaitMs,
|
|
11633
11657
|
warnings: cloneCaptureWarnings2(domSession.warnings)
|
|
11634
11658
|
};
|
|
11635
11659
|
}
|
|
@@ -13529,6 +13553,7 @@ async function executeRenderPipeline(input) {
|
|
|
13529
13553
|
});
|
|
13530
13554
|
const effectiveHdr = resolveEffectiveHdrMode({
|
|
13531
13555
|
hdrMode: job.config.hdrMode,
|
|
13556
|
+
media: composition,
|
|
13532
13557
|
outputFormat,
|
|
13533
13558
|
extractionResult,
|
|
13534
13559
|
imageColorSpaces,
|
|
@@ -14343,6 +14368,7 @@ async function executeRenderPipeline(input) {
|
|
|
14343
14368
|
perfStages.captureFrameMs = hdrRes.captureDurationMs;
|
|
14344
14369
|
perfStages.captureSetupMs = Math.max(0, Date.now() - stage4Start - hdrRes.captureDurationMs);
|
|
14345
14370
|
perfStages.encodeMs = hdrRes.encodeMs;
|
|
14371
|
+
perfStages.encoderDrainWaitMs = hdrRes.encoderDrainWaitMs ?? 0;
|
|
14346
14372
|
} else {
|
|
14347
14373
|
let streamingHandled = false;
|
|
14348
14374
|
if (capturePlan.kind === "sdr_segmented") {
|
package/dist/public-server.js
CHANGED
|
@@ -4901,6 +4901,7 @@ async function validateCompletedSegments(manifest, expectedHash, probeFrames) {
|
|
|
4901
4901
|
import {
|
|
4902
4902
|
analyzeCompositionHdr,
|
|
4903
4903
|
formatHdrAutoPromotionWarning,
|
|
4904
|
+
gradingKeepsSdr,
|
|
4904
4905
|
HDR_AUTO_PROMOTION_PIPELINE,
|
|
4905
4906
|
isHdrColorSpace,
|
|
4906
4907
|
sanitizeHdrAutoPromotionAsset
|
|
@@ -4918,13 +4919,28 @@ function findRenderHdrAutoPromotionTrigger(input) {
|
|
|
4918
4919
|
}
|
|
4919
4920
|
return input.images.find(({ id }) => input.nativeHdrImageIds.has(id))?.src;
|
|
4920
4921
|
}
|
|
4921
|
-
function
|
|
4922
|
+
function logGradingResolution(input, hdrMode, effectiveHdr, hasHdrSource) {
|
|
4923
|
+
const keptSdr = hasHdrSource && gradingKeepsSdr(hdrMode, input.media);
|
|
4924
|
+
if (keptSdr) {
|
|
4925
|
+
input.log.warn(
|
|
4926
|
+
"[Render] HDR source detected, but color grading is SDR-only, so rendering SDR: HDR sources are tone-mapped before the grade. Use --hdr to force HDR output (grades stay SDR)."
|
|
4927
|
+
);
|
|
4928
|
+
} else if (effectiveHdr && [...input.media.videos, ...input.media.images].some((m) => m.graded)) {
|
|
4929
|
+
input.log.warn(
|
|
4930
|
+
"[Render] HDR output with graded media: color grading is SDR-only, so graded elements are graded in SDR and placed in the HDR output."
|
|
4931
|
+
);
|
|
4932
|
+
}
|
|
4933
|
+
return keptSdr;
|
|
4934
|
+
}
|
|
4935
|
+
function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources, hasHdrSource) {
|
|
4936
|
+
const keptSdrForGrading = logGradingResolution(input, hdrMode, effectiveHdr, hasHdrSource);
|
|
4922
4937
|
if (forcedHdrWithoutSources) {
|
|
4923
4938
|
input.log.warn(
|
|
4924
4939
|
"[Render] HDR forced by --hdr flag, but no HDR sources were detected, defaulting to HLG. SDR-only compositions may look perceptually wrong on HDR displays."
|
|
4925
4940
|
);
|
|
4926
4941
|
}
|
|
4927
4942
|
if (!effectiveHdr) {
|
|
4943
|
+
if (keptSdrForGrading) return;
|
|
4928
4944
|
input.log.info(
|
|
4929
4945
|
hdrMode === "force-sdr" ? "[Render] SDR forced by --sdr flag" : "[Render] No HDR sources detected, rendering SDR"
|
|
4930
4946
|
);
|
|
@@ -4949,8 +4965,8 @@ function logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources)
|
|
|
4949
4965
|
function formatCarriesHdr(format) {
|
|
4950
4966
|
return format === "mp4";
|
|
4951
4967
|
}
|
|
4952
|
-
function rendersSdrOnly(config) {
|
|
4953
|
-
return config.hdrMode === "force-sdr" || !formatCarriesHdr(config.format ?? "mp4");
|
|
4968
|
+
function rendersSdrOnly(config, media) {
|
|
4969
|
+
return config.hdrMode === "force-sdr" || gradingKeepsSdr(config.hdrMode, media) || !formatCarriesHdr(config.format ?? "mp4");
|
|
4954
4970
|
}
|
|
4955
4971
|
function resolveEffectiveHdrMode(input) {
|
|
4956
4972
|
const hdrMode = input.hdrMode ?? "auto";
|
|
@@ -4961,7 +4977,7 @@ function resolveEffectiveHdrMode(input) {
|
|
|
4961
4977
|
const info = allColorSpaces.length > 0 ? analyzeCompositionHdr(allColorSpaces) : null;
|
|
4962
4978
|
let effectiveHdr;
|
|
4963
4979
|
let forcedHdrWithoutSources = false;
|
|
4964
|
-
if (hdrMode === "force-sdr") {
|
|
4980
|
+
if (hdrMode === "force-sdr" || gradingKeepsSdr(hdrMode, input.media)) {
|
|
4965
4981
|
effectiveHdr = void 0;
|
|
4966
4982
|
} else if (hdrMode === "force-hdr") {
|
|
4967
4983
|
if (info?.hasHdr && info.dominantTransfer) {
|
|
@@ -4977,7 +4993,7 @@ function resolveEffectiveHdrMode(input) {
|
|
|
4977
4993
|
input.log.warn(formatDowngradeWarning(input.outputFormat, forcedHdrWithoutSources));
|
|
4978
4994
|
effectiveHdr = void 0;
|
|
4979
4995
|
}
|
|
4980
|
-
logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources);
|
|
4996
|
+
logHdrResolution(input, hdrMode, effectiveHdr, forcedHdrWithoutSources, info?.hasHdr === true);
|
|
4981
4997
|
return effectiveHdr;
|
|
4982
4998
|
}
|
|
4983
4999
|
|
|
@@ -5842,6 +5858,7 @@ import {
|
|
|
5842
5858
|
} from "@hyperframes/core/media-timing";
|
|
5843
5859
|
import {
|
|
5844
5860
|
parseVideoElements,
|
|
5861
|
+
hasGradedCanvas,
|
|
5845
5862
|
parseImageElements,
|
|
5846
5863
|
parseAudioElements,
|
|
5847
5864
|
isSelfOrAncestorHidden,
|
|
@@ -5976,7 +5993,7 @@ function collectRenderMedia(html) {
|
|
|
5976
5993
|
if (placed) audios.push(placed);
|
|
5977
5994
|
else droppedMediaIds.add(elementId);
|
|
5978
5995
|
}
|
|
5979
|
-
return { videos, audios, images, droppedMediaIds };
|
|
5996
|
+
return { videos, audios, images, droppedMediaIds, gradedCanvas: hasGradedCanvas(html) };
|
|
5980
5997
|
}
|
|
5981
5998
|
function placeAudio(audio, window2) {
|
|
5982
5999
|
const authoredEnd = audio.end > 0 ? audio.end : Infinity;
|
|
@@ -8031,7 +8048,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
|
|
|
8031
8048
|
for (const [relPath, absPath] of preparedHeifAssets) {
|
|
8032
8049
|
externalAssets.set(relPath, absPath);
|
|
8033
8050
|
}
|
|
8034
|
-
const { videos, audios, images, droppedMediaIds } = collectRenderMedia(html);
|
|
8051
|
+
const { videos, audios, images, droppedMediaIds, gradedCanvas } = collectRenderMedia(html);
|
|
8035
8052
|
const masterFxChain = parseMasterFxChain(html);
|
|
8036
8053
|
const advised = /* @__PURE__ */ new Set();
|
|
8037
8054
|
for (const video of videos) {
|
|
@@ -8070,6 +8087,7 @@ async function compileForRender(projectDir, htmlPath, downloadDir, options = {})
|
|
|
8070
8087
|
audios,
|
|
8071
8088
|
images,
|
|
8072
8089
|
droppedMediaIds,
|
|
8090
|
+
gradedCanvas,
|
|
8073
8091
|
...masterFxChain ? { masterFxChain } : {},
|
|
8074
8092
|
unresolvedCompositions,
|
|
8075
8093
|
externalAssets,
|
|
@@ -8523,6 +8541,7 @@ async function runCompileStage(input) {
|
|
|
8523
8541
|
videos: compiled.videos,
|
|
8524
8542
|
audios: compiled.audios,
|
|
8525
8543
|
images: compiled.images,
|
|
8544
|
+
gradedCanvas: compiled.gradedCanvas,
|
|
8526
8545
|
masterFxChain: compiled.masterFxChain,
|
|
8527
8546
|
width: compiled.width,
|
|
8528
8547
|
height: compiled.height
|
|
@@ -9269,6 +9288,7 @@ import {
|
|
|
9269
9288
|
detectTransfer,
|
|
9270
9289
|
extractAllVideoFrames,
|
|
9271
9290
|
extractMediaMetadata as extractMediaMetadata3,
|
|
9291
|
+
gradingKeepsSdr as gradingKeepsSdr2,
|
|
9272
9292
|
isVideoPastTimelineEnd,
|
|
9273
9293
|
isHdrColorSpace as isHdrColorSpace2,
|
|
9274
9294
|
rebaseVideoToWindow,
|
|
@@ -9504,10 +9524,11 @@ async function runExtractVideosStage(input) {
|
|
|
9504
9524
|
let failureToEnforce = null;
|
|
9505
9525
|
let videoReadinessSkipIds = [];
|
|
9506
9526
|
let videoMetadataHints = [];
|
|
9527
|
+
const probesHdr = job.config.hdrMode !== "force-sdr" && !gradingKeepsSdr2(job.config.hdrMode, composition);
|
|
9507
9528
|
const nativeHdrVideoIds = /* @__PURE__ */ new Set();
|
|
9508
9529
|
const videoTransfers = /* @__PURE__ */ new Map();
|
|
9509
9530
|
let hdrProbeTransientRetries = 0;
|
|
9510
|
-
if (
|
|
9531
|
+
if (probesHdr && composition.videos.length > 0) {
|
|
9511
9532
|
log?.info("Probing video color spaces...", { videoCount: composition.videos.length });
|
|
9512
9533
|
const probeFailures = await Promise.all(
|
|
9513
9534
|
composition.videos.map(async (v) => {
|
|
@@ -9546,7 +9567,7 @@ async function runExtractVideosStage(input) {
|
|
|
9546
9567
|
const imageTransfers = /* @__PURE__ */ new Map();
|
|
9547
9568
|
const hdrImageSrcPaths = /* @__PURE__ */ new Map();
|
|
9548
9569
|
const imageColorSpaces = [];
|
|
9549
|
-
if (
|
|
9570
|
+
if (probesHdr && composition.images.length > 0) {
|
|
9550
9571
|
const probed = await Promise.all(
|
|
9551
9572
|
composition.images.map(async (img) => {
|
|
9552
9573
|
const imgPath = resolveProjectRelativeSrc3(img.src, projectDir, compiledDir);
|
|
@@ -9583,7 +9604,7 @@ async function runExtractVideosStage(input) {
|
|
|
9583
9604
|
fps: job.config.fps,
|
|
9584
9605
|
outputDir: join18(compiledDir, "__hyperframes_video_frames"),
|
|
9585
9606
|
format: job.config.videoFrameFormat ?? "auto",
|
|
9586
|
-
toneMapHdrToSdr: rendersSdrOnly(job.config),
|
|
9607
|
+
toneMapHdrToSdr: rendersSdrOnly(job.config, composition),
|
|
9587
9608
|
timelineEnd: composition.duration,
|
|
9588
9609
|
maxTransientRetries: extractionPolicy.maxTransientRetries,
|
|
9589
9610
|
collectProbeFailures: extractionPolicy.failureMode === "enforce",
|
|
@@ -11341,6 +11362,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11341
11362
|
let lastBrowserConsole = [];
|
|
11342
11363
|
let captureDurationMs = 0;
|
|
11343
11364
|
let encodeMs = 0;
|
|
11365
|
+
let encoderDrainWaitMs;
|
|
11344
11366
|
const nativeHdrIds = /* @__PURE__ */ new Set([...nativeHdrVideoIds, ...nativeHdrImageIds]);
|
|
11345
11367
|
log.info(
|
|
11346
11368
|
hasHdrContent ? "[Render] HDR layered composite: z-ordered DOM + native HDR video/image layers" : "[Render] Shader transition composite: z-ordered SDR DOM layers"
|
|
@@ -11578,6 +11600,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11578
11600
|
reportEncodeProgress(job, totalFrames, totalFrames, onProgress, encodeFrom);
|
|
11579
11601
|
captureDurationMs = Date.now() - stageStart;
|
|
11580
11602
|
encodeMs = hdrEncodeResult.durationMs;
|
|
11603
|
+
encoderDrainWaitMs = hdrEncodeResult.drainWaitMs;
|
|
11581
11604
|
} catch (error) {
|
|
11582
11605
|
lastBrowserConsole = domSession.browserConsoleBuffer;
|
|
11583
11606
|
throw wrapCaptureStageError(error, lastBrowserConsole);
|
|
@@ -11610,6 +11633,7 @@ async function runCaptureHdrStage(input) {
|
|
|
11610
11633
|
hdrPerf,
|
|
11611
11634
|
captureDurationMs,
|
|
11612
11635
|
encodeMs,
|
|
11636
|
+
encoderDrainWaitMs,
|
|
11613
11637
|
warnings: cloneCaptureWarnings2(domSession.warnings)
|
|
11614
11638
|
};
|
|
11615
11639
|
}
|
|
@@ -13509,6 +13533,7 @@ async function executeRenderPipeline(input) {
|
|
|
13509
13533
|
});
|
|
13510
13534
|
const effectiveHdr = resolveEffectiveHdrMode({
|
|
13511
13535
|
hdrMode: job.config.hdrMode,
|
|
13536
|
+
media: composition,
|
|
13512
13537
|
outputFormat,
|
|
13513
13538
|
extractionResult,
|
|
13514
13539
|
imageColorSpaces,
|
|
@@ -14323,6 +14348,7 @@ async function executeRenderPipeline(input) {
|
|
|
14323
14348
|
perfStages.captureFrameMs = hdrRes.captureDurationMs;
|
|
14324
14349
|
perfStages.captureSetupMs = Math.max(0, Date.now() - stage4Start - hdrRes.captureDurationMs);
|
|
14325
14350
|
perfStages.encodeMs = hdrRes.encodeMs;
|
|
14351
|
+
perfStages.encoderDrainWaitMs = hdrRes.encoderDrainWaitMs ?? 0;
|
|
14326
14352
|
} else {
|
|
14327
14353
|
let streamingHandled = false;
|
|
14328
14354
|
if (capturePlan.kind === "sdr_segmented") {
|
|
@@ -9,6 +9,7 @@ export interface CompiledComposition {
|
|
|
9
9
|
audios: AudioElement[];
|
|
10
10
|
images: ImageElement[];
|
|
11
11
|
droppedMediaIds: Set<string>;
|
|
12
|
+
gradedCanvas: boolean;
|
|
12
13
|
masterFxChain?: string;
|
|
13
14
|
unresolvedCompositions: UnresolvedElement[];
|
|
14
15
|
/** Assets that resolve outside projectDir. Keys are the path used in HTML, values are absolute filesystem paths. */
|
|
@@ -8,14 +8,17 @@
|
|
|
8
8
|
* SDR) lives here too so the sequencer doesn't need to know which
|
|
9
9
|
* formats can carry an HDR signal.
|
|
10
10
|
*/
|
|
11
|
+
import { gradingKeepsSdr } from "@hyperframes/engine";
|
|
11
12
|
import type { ExtractionResult, HdrTransfer, VideoColorSpace } from "@hyperframes/engine";
|
|
12
13
|
import type { ProducerLogger } from "../../logger.js";
|
|
13
14
|
import type { RenderConfig } from "../renderOrchestrator.js";
|
|
14
15
|
type EffectiveHdr = {
|
|
15
16
|
transfer: HdrTransfer;
|
|
16
17
|
} | undefined;
|
|
18
|
+
type RenderMedia = Parameters<typeof gradingKeepsSdr>[1];
|
|
17
19
|
type HdrModeInput = {
|
|
18
20
|
hdrMode: RenderConfig["hdrMode"];
|
|
21
|
+
media: RenderMedia;
|
|
19
22
|
outputFormat: NonNullable<RenderConfig["format"]>;
|
|
20
23
|
extractionResult: ExtractionResult | null | undefined;
|
|
21
24
|
imageColorSpaces: (VideoColorSpace | null)[];
|
|
@@ -34,6 +37,6 @@ export declare function findRenderHdrAutoPromotionTrigger(input: {
|
|
|
34
37
|
}[];
|
|
35
38
|
nativeHdrImageIds: ReadonlySet<string>;
|
|
36
39
|
}): string | undefined;
|
|
37
|
-
export declare function rendersSdrOnly(config: Pick<RenderConfig, "hdrMode" | "format"
|
|
40
|
+
export declare function rendersSdrOnly(config: Pick<RenderConfig, "hdrMode" | "format">, media: RenderMedia): boolean;
|
|
38
41
|
export declare function resolveEffectiveHdrMode(input: HdrModeInput): EffectiveHdr;
|
|
39
42
|
export {};
|
|
@@ -84,6 +84,7 @@ export interface CaptureHdrStageResult {
|
|
|
84
84
|
captureDurationMs: number;
|
|
85
85
|
/** ffmpeg-reported encode duration; overlapped with capture. */
|
|
86
86
|
encodeMs: number;
|
|
87
|
+
encoderDrainWaitMs?: number;
|
|
87
88
|
warnings: CaptureWarning[];
|
|
88
89
|
}
|
|
89
90
|
export declare function runCaptureHdrStage(input: CaptureHdrStageInput): Promise<CaptureHdrStageResult>;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* - `perfStages.videoExtractMs` is set at the same end-of-stage point.
|
|
17
17
|
* - `materializeExtractedFramesForCompiledDir` is still called once
|
|
18
18
|
* when `extractionResult.extracted` is non-empty.
|
|
19
|
-
* - `force-sdr` mode still
|
|
19
|
+
* - `force-sdr` mode, and auto mode with graded media, still skip ALL ffprobe overhead.
|
|
20
20
|
*
|
|
21
21
|
* New for distributed mode:
|
|
22
22
|
* - `materializeSymlinks` (default `false`) — when `true`, the stage
|
|
@@ -14,6 +14,7 @@ export interface RenderMedia {
|
|
|
14
14
|
images: ImageElement[];
|
|
15
15
|
/** Ids of clips in the document that never play; the browser probe must not add them back. */
|
|
16
16
|
droppedMediaIds: Set<string>;
|
|
17
|
+
gradedCanvas: boolean;
|
|
17
18
|
}
|
|
18
19
|
/**
|
|
19
20
|
* Parse every media element in the inlined render document, with each clip's
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.224",
|
|
4
4
|
"description": "HTML-to-video rendering engine using Chrome's BeginFrame API",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -35,11 +35,11 @@
|
|
|
35
35
|
"postcss": "^8.4.0",
|
|
36
36
|
"puppeteer": "~25.11.0",
|
|
37
37
|
"puppeteer-core": "^25.11.0",
|
|
38
|
-
"@hyperframes/
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/
|
|
42
|
-
"@hyperframes/parsers": "0.8.
|
|
38
|
+
"@hyperframes/lint": "0.8.224",
|
|
39
|
+
"@hyperframes/engine": "0.8.224",
|
|
40
|
+
"@hyperframes/studio-server": "0.8.224",
|
|
41
|
+
"@hyperframes/core": "0.8.224",
|
|
42
|
+
"@hyperframes/parsers": "0.8.224"
|
|
43
43
|
},
|
|
44
44
|
"devDependencies": {
|
|
45
45
|
"@types/node": "^25.0.10",
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"tsx": "^4.21.0",
|
|
49
49
|
"typescript": "^5.7.2",
|
|
50
50
|
"vitest": "^4.1.11",
|
|
51
|
-
"@hyperframes/aws-lambda": "0.8.
|
|
51
|
+
"@hyperframes/aws-lambda": "0.8.224"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|