@hyperframes/engine 0.9.16 → 0.9.18
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.
|
@@ -1761,8 +1761,8 @@ export function recordSubTimelineWarning(session, timeoutMs) {
|
|
|
1761
1761
|
`${pendingSuffix} (${sources.join(", ")}). Fix the error; a composition animated by ` +
|
|
1762
1762
|
`CSS or rAF rather than a GSAP timeline must mark its host with data-no-timeline.`
|
|
1763
1763
|
: scriptFailure
|
|
1764
|
-
? `A sub-composition timeline script failed to load
|
|
1765
|
-
|
|
1764
|
+
? `A sub-composition timeline script failed to load${scriptLoadCauseSuffix(loadCauses)} ` +
|
|
1765
|
+
`(${sources.join(", ")})`
|
|
1766
1766
|
: `Sub-composition timelines did not become ready within ${timeoutMs}ms${pendingSuffix}. ` +
|
|
1767
1767
|
`This can be intentional: a composition driven by CSS animations or rAF never registers ` +
|
|
1768
1768
|
`window.__timelines[id], and marking its host with data-no-timeline skips the wait entirely. ` +
|
|
@@ -15,7 +15,7 @@ import { HF_COLOR_GRADING_ATTR } from "@hyperframes/core";
|
|
|
15
15
|
import { isPathInside } from "@hyperframes/parsers/asset-paths";
|
|
16
16
|
import { resolveProjectRelativeSrc } from "@hyperframes/parsers/asset-resolution";
|
|
17
17
|
import { alphaDecoderFor } from "@hyperframes/parsers/media-alpha";
|
|
18
|
-
import { MEDIA_RENDER_ID_ATTR, isAudibleVideoElement, fpsToFfmpegArg, fpsToNumber, MEDIA_DURATION_CLAMP_EPSILON_SECONDS, normalizeRateSpec, readElementRateSpec, shiftRateLane, sourceTimeAt, timeAtSourceTime, exportClipWindow, hasClipStarted, isInClipWindow, mediaElementTime, parseStrictFiniteTimingNumber, readMediaStart, toFps, firstFrameColourArgs, hdrToSdrToneMapFilter, parseFirstFrameColour, } from "@hyperframes/core";
|
|
18
|
+
import { MEDIA_RENDER_ID_ATTR, isAudibleVideoElement, fpsToFfmpegArg, fpsToNumber, MEDIA_DURATION_CLAMP_EPSILON_SECONDS, normalizeRateSpec, readElementRateSpec, shiftRateLane, sourceTimeAt, timeAtSourceTime, exportClipWindow, hasClipStarted, isInClipWindow, mediaElementTime, parseStrictFiniteTimingNumber, readMediaStart, toFps, firstFrameColourArgs, keyframeTransferArgs, parseKeyframeTransfers, hdrToSdrToneMapFilter, parseFirstFrameColour, readsKeyframeTransfers, } from "@hyperframes/core";
|
|
19
19
|
import { resolveReferencedStart } from "./referenceResolver.js";
|
|
20
20
|
import { isKnownInactiveTimelineWindow } from "./mediaTimelineWindow.js";
|
|
21
21
|
import { extractFinalVideoFrameTimestamp, extractMediaMetadata, ffmpegSeekSeconds, formatFfmpegSeconds, keyframeGapSeconds, mediaFileIdentity, readMetadataCache, readStoredFinalFrame, resolvePlayableVideoDuration, videoStartOnMediaTimeline, writeMetadataCache, } from "../utils/ffprobe.js";
|
|
@@ -506,19 +506,32 @@ export function parseImageElements(html) {
|
|
|
506
506
|
return images;
|
|
507
507
|
}
|
|
508
508
|
const firstFrameColourCache = new Map();
|
|
509
|
+
/** A source's SPS transfers, so a PQ or SDR keyframe keeps an HLG one at 100 nits; null when the read failed. */
|
|
510
|
+
function readKeyframeTransfers(videoPath, codec) {
|
|
511
|
+
return inExtractionSlot(() => runFfmpeg([...urlInputArgs(videoPath), ...keyframeTransferArgs(videoPath, codec)])).then((result) => (result.success ? parseKeyframeTransfers(result.stderr) : null));
|
|
512
|
+
}
|
|
509
513
|
/** The first shown frame's colour tags (see {@link firstFrameColourArgs}), probed once per source file. */
|
|
510
|
-
function readFirstFrameColour(videoPath) {
|
|
514
|
+
function readFirstFrameColour(videoPath, codec) {
|
|
511
515
|
const identity = mediaFileIdentity(videoPath);
|
|
512
516
|
const cached = readMetadataCache(firstFrameColourCache, videoPath, identity);
|
|
513
517
|
if (cached)
|
|
514
518
|
return cached;
|
|
515
519
|
// In an extraction slot, so it never adds a decoder; unsignalled, so one cancel cannot cut it short for others.
|
|
516
|
-
const probe = inExtractionSlot(() => runFfmpeg([...urlInputArgs(videoPath), ...firstFrameColourArgs(videoPath)])).then((result) => {
|
|
520
|
+
const probe = inExtractionSlot(() => runFfmpeg([...urlInputArgs(videoPath), ...firstFrameColourArgs(videoPath)])).then(async (result) => {
|
|
521
|
+
const forget = () => {
|
|
522
|
+
if (firstFrameColourCache.get(videoPath)?.promise === probe)
|
|
523
|
+
firstFrameColourCache.delete(videoPath);
|
|
524
|
+
};
|
|
517
525
|
// A failed probe answers this cut only; the next one probes again.
|
|
518
|
-
if (!result.success
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
526
|
+
if (!result.success)
|
|
527
|
+
forget();
|
|
528
|
+
const first = parseFirstFrameColour(result.stderr);
|
|
529
|
+
if (!result.success || !readsKeyframeTransfers(first))
|
|
530
|
+
return first;
|
|
531
|
+
const keyframeTransfers = await readKeyframeTransfers(videoPath, codec);
|
|
532
|
+
if (!keyframeTransfers)
|
|
533
|
+
forget();
|
|
534
|
+
return { ...first, keyframeTransfers: keyframeTransfers ?? [] };
|
|
522
535
|
});
|
|
523
536
|
writeMetadataCache(firstFrameColourCache, videoPath, identity, probe);
|
|
524
537
|
return probe;
|
|
@@ -822,7 +835,9 @@ outputDirOverride) {
|
|
|
822
835
|
args.push("-noaccurate_seek");
|
|
823
836
|
args.push("-ss", formatFfmpegSeconds(ffmpegSeek(startTime)), "-i", videoPath, "-t", formatFfmpegSeconds(duration));
|
|
824
837
|
}
|
|
825
|
-
const frameColour = toneMappedToSdr
|
|
838
|
+
const frameColour = toneMappedToSdr
|
|
839
|
+
? await readFirstFrameColour(videoPath, metadata.videoCodec)
|
|
840
|
+
: undefined;
|
|
826
841
|
const filtersFor = videoFilterChain({
|
|
827
842
|
metadata,
|
|
828
843
|
format,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/engine",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.18",
|
|
4
4
|
"description": "Seekable web page to video rendering engine (Puppeteer + FFmpeg)",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -61,8 +61,8 @@
|
|
|
61
61
|
"puppeteer": "~25.11.0",
|
|
62
62
|
"puppeteer-core": "^25.11.0",
|
|
63
63
|
"undici": "7.25.0",
|
|
64
|
-
"@hyperframes/core": "^0.9.
|
|
65
|
-
"@hyperframes/parsers": "^0.9.
|
|
64
|
+
"@hyperframes/core": "^0.9.18",
|
|
65
|
+
"@hyperframes/parsers": "^0.9.18"
|
|
66
66
|
},
|
|
67
67
|
"devDependencies": {
|
|
68
68
|
"@types/node": "^25.0.10",
|