@hyperframes/producer 0.9.15 → 0.9.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/distributed.js +489 -396
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +68 -68
- package/dist/index.js +1045 -671
- package/dist/public-server.js +739 -329
- package/dist/services/distributed/chunkFrames.d.ts +1 -2
- package/dist/services/render/deferredVideoFrames.d.ts +42 -0
- package/dist/services/render/observability.d.ts +2 -0
- package/dist/services/render/segmentVideoFrames.d.ts +41 -0
- package/dist/services/render/stages/captureSegmentedStage.d.ts +5 -2
- package/dist/services/render/stages/captureStreamingStage.d.ts +7 -0
- package/dist/services/render/stages/compileStage.d.ts +12 -3
- package/dist/services/render/videoFrameWindow.d.ts +12 -0
- package/dist/services/renderOrchestrator.d.ts +2 -5
- package/package.json +7 -7
|
@@ -38,8 +38,7 @@ export declare function buildChunkCaptureOptions(input: {
|
|
|
38
38
|
skipReadinessVideoIds?: string[];
|
|
39
39
|
videoMetadataHints?: CaptureOptions["videoMetadataHints"];
|
|
40
40
|
}): CaptureOptions;
|
|
41
|
-
|
|
42
|
-
export declare function shownDeferredFrameIndexes(planVideos: PlanVideosJson, frames: Iterable<number>, fps: {
|
|
41
|
+
export declare function shownPlanFrameIndexes(planVideos: PlanVideosJson, frames: Iterable<number>, fps: {
|
|
43
42
|
num: number;
|
|
44
43
|
den: number;
|
|
45
44
|
}): Map<string, Set<number>>;
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { type EngineConfig, type ExtractedFrames, type ShownBox, type VideoElement } from "@hyperframes/engine";
|
|
2
|
+
/** The frame indexes each deferred video shows across `frames`, by video id. */
|
|
3
|
+
export declare function shownDeferredFrameIndexes(source: {
|
|
4
|
+
videos: VideoElement[];
|
|
5
|
+
extracted: ExtractedFrames[];
|
|
6
|
+
}, frames: Iterable<number>, fps: {
|
|
7
|
+
num: number;
|
|
8
|
+
den: number;
|
|
9
|
+
}): Map<string, Set<number>>;
|
|
10
|
+
/** Extracts the given frames of deferred videos under the names a full extraction gives them. */
|
|
11
|
+
export declare function extractDeferredFrames(input: {
|
|
12
|
+
videos: VideoElement[];
|
|
13
|
+
extracted: ExtractedFrames[];
|
|
14
|
+
frames: Iterable<number>;
|
|
15
|
+
fps: {
|
|
16
|
+
num: number;
|
|
17
|
+
den: number;
|
|
18
|
+
};
|
|
19
|
+
outputRoot: string;
|
|
20
|
+
cfg: Pick<EngineConfig, "ffmpegProcessTimeout">;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
/** Where the video's source is read from: a local path or a URL. May throw. */
|
|
23
|
+
sourceOf: (video: ExtractedFrames) => string;
|
|
24
|
+
shownBoxes?: ReadonlyMap<string, ShownBox>;
|
|
25
|
+
/** The error to throw when the extractor returns no frame for an index the video shows. */
|
|
26
|
+
onMissingFrame: (video: ExtractedFrames, index: number) => Error;
|
|
27
|
+
}): Promise<ExtractedFrames[]>;
|
|
28
|
+
/**
|
|
29
|
+
* Fills every deferred video in place with the frames a full extraction writes, into the folder it
|
|
30
|
+
* already has. For a route that cannot read frames per segment.
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractAllDeferredFrames(extracted: ExtractedFrames[], input: {
|
|
33
|
+
fps: {
|
|
34
|
+
num: number;
|
|
35
|
+
den: number;
|
|
36
|
+
};
|
|
37
|
+
cfg: Pick<EngineConfig, "ffmpegProcessTimeout">;
|
|
38
|
+
signal?: AbortSignal;
|
|
39
|
+
sourceOf?: (video: ExtractedFrames) => string;
|
|
40
|
+
maxTransientRetries?: number;
|
|
41
|
+
onProgress?: (framesDone: number, framesTotal: number) => void;
|
|
42
|
+
}): Promise<void>;
|
|
@@ -200,6 +200,8 @@ export interface RenderCaptureObservability {
|
|
|
200
200
|
/** Segmented capture only (Phase 2): current segment and retries so far. */
|
|
201
201
|
segmentIndex?: number;
|
|
202
202
|
segmentRetries?: number;
|
|
203
|
+
videoFrameWindow?: "on" | "off";
|
|
204
|
+
videoFrameWindowPeakBytes?: number;
|
|
203
205
|
}
|
|
204
206
|
export interface RenderExtractionObservability {
|
|
205
207
|
videoCount: number;
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { createVideoFrameInjector, type BeforeCaptureHook, type EngineConfig, type ExtractedFrames, type VideoElement } from "@hyperframes/engine";
|
|
2
|
+
import { extractDeferredFrames } from "./deferredVideoFrames.js";
|
|
3
|
+
import type { SegmentSlice } from "./segmentPlan.js";
|
|
4
|
+
export interface SegmentWorkerFrames {
|
|
5
|
+
/**
|
|
6
|
+
* One hook for the worker's whole life, so a recycled session keeps it. Inside a
|
|
7
|
+
* prepared window it injects from the window; outside one it extracts the frames
|
|
8
|
+
* it is asked for and removes them again.
|
|
9
|
+
*/
|
|
10
|
+
hook: BeforeCaptureHook;
|
|
11
|
+
/** Extracts the frames `segment` shows and points the hook at them. */
|
|
12
|
+
prepare(segment: SegmentSlice): Promise<void>;
|
|
13
|
+
/** Deletes the segment's frames. Safe to call again. */
|
|
14
|
+
release(): void;
|
|
15
|
+
}
|
|
16
|
+
export interface SegmentVideoFrames {
|
|
17
|
+
forWorker(): SegmentWorkerFrames;
|
|
18
|
+
/** Extracts the given output frames into `segment-frames/<name>/` ahead of time; `release()` is idempotent. */
|
|
19
|
+
forFrames(frames: readonly number[], name: string): Promise<{
|
|
20
|
+
injector(): BeforeCaptureHook | null;
|
|
21
|
+
release(): void;
|
|
22
|
+
}>;
|
|
23
|
+
}
|
|
24
|
+
type FrameExtractor = typeof extractDeferredFrames;
|
|
25
|
+
/** Each worker reads only the video frames its current segment shows, and deletes them when the segment closes. */
|
|
26
|
+
export declare function createSegmentVideoFrames(input: {
|
|
27
|
+
videos: VideoElement[];
|
|
28
|
+
extracted: ExtractedFrames[];
|
|
29
|
+
fps: {
|
|
30
|
+
num: number;
|
|
31
|
+
den: number;
|
|
32
|
+
};
|
|
33
|
+
/** The render's work dir; frames go under `segment-frames/segment_NNNNN/`. */
|
|
34
|
+
rootDir: string;
|
|
35
|
+
cfg: EngineConfig;
|
|
36
|
+
injectorOptions: Parameters<typeof createVideoFrameInjector>[1];
|
|
37
|
+
abortSignal?: AbortSignal;
|
|
38
|
+
sourceOf?: (video: ExtractedFrames) => string;
|
|
39
|
+
extractFrames?: FrameExtractor;
|
|
40
|
+
}): SegmentVideoFrames;
|
|
41
|
+
export {};
|
|
@@ -3,6 +3,7 @@ import type { FileServerHandle } from "../../fileServer.js";
|
|
|
3
3
|
import type { ProducerLogger } from "../../../logger.js";
|
|
4
4
|
import type { ProgressCallback, RenderJob } from "../../renderOrchestrator.js";
|
|
5
5
|
import type { SdrSegmentedCapturePlan } from "../capturePlan.js";
|
|
6
|
+
import type { SegmentVideoFrames } from "../segmentVideoFrames.js";
|
|
6
7
|
import { type StreamingEncoderOptions } from "./captureStreamingStage.js";
|
|
7
8
|
export interface SegmentedStageDeps {
|
|
8
9
|
spawnEncoder: typeof spawnStreamingEncoder;
|
|
@@ -12,9 +13,9 @@ export interface SegmentedStageDeps {
|
|
|
12
13
|
/** Delete a partial segment so a retry cannot leave a stale file behind. */
|
|
13
14
|
removeFile: (path: string) => void;
|
|
14
15
|
}
|
|
15
|
-
/** Opens a fresh, initialized capture session with the video injector attached. */
|
|
16
|
+
/** Opens a fresh, initialized capture session with the video injector attached; a custom factory may ignore the override. */
|
|
16
17
|
export interface SessionFactory {
|
|
17
|
-
create: () => Promise<CaptureSession>;
|
|
18
|
+
create: (injectorOverride?: () => BeforeCaptureHook | null) => Promise<CaptureSession>;
|
|
18
19
|
}
|
|
19
20
|
export interface CaptureSegmentedStageInput {
|
|
20
21
|
fileServer: FileServerHandle;
|
|
@@ -32,6 +33,8 @@ export interface CaptureSegmentedStageInput {
|
|
|
32
33
|
streamingEncoderOptions: StreamingEncoderOptions;
|
|
33
34
|
buildCaptureOptions: () => CaptureOptions;
|
|
34
35
|
createRenderVideoFrameInjector: () => BeforeCaptureHook | null;
|
|
36
|
+
/** Windowed frames: extracted per segment, deleted when it closes; segment files are deleted once joined. */
|
|
37
|
+
segmentVideoFrames?: SegmentVideoFrames;
|
|
35
38
|
abortSignal: AbortSignal | undefined;
|
|
36
39
|
assertNotAborted: () => void;
|
|
37
40
|
onProgress?: ProgressCallback;
|
|
@@ -127,5 +127,12 @@ export type CaptureStreamingStageResult = {
|
|
|
127
127
|
/** Spawn failed (non-abort) — sequencer should fall back to the disk path. */
|
|
128
128
|
success: false;
|
|
129
129
|
};
|
|
130
|
+
/** At an armed sample index, a frame below the PSNR floor vs its pre-injection screenshot throws. */
|
|
131
|
+
export declare function verifyDrawElementSample(session: CaptureSession, idx: number, buf: Buffer, ctx: {
|
|
132
|
+
log: CaptureStreamingStageInput["log"];
|
|
133
|
+
/** Telemetry counters; the stages that report none pass nothing. */
|
|
134
|
+
stats?: Pick<DeDrainStats, "verifyChecked" | "verifyMinDb">;
|
|
135
|
+
verifyMinDb: number;
|
|
136
|
+
}): Promise<void>;
|
|
130
137
|
export declare function runCaptureStreamingStage(input: CaptureStreamingStageInput): Promise<CaptureStreamingStageResult>;
|
|
131
138
|
export {};
|
|
@@ -42,9 +42,7 @@ import type { RenderJob } from "../../renderOrchestrator.js";
|
|
|
42
42
|
export interface CompileStageInput {
|
|
43
43
|
projectDir: string;
|
|
44
44
|
workDir: string;
|
|
45
|
-
/**
|
|
46
|
-
htmlPath: string;
|
|
47
|
-
/** The relative `entryFile` string, used only for log payloads. */
|
|
45
|
+
/** Entry HTML relative to `projectDir`; a `<template>` sub-composition is isolated inside the index shell. */
|
|
48
46
|
entryFile: string;
|
|
49
47
|
job: RenderJob;
|
|
50
48
|
/**
|
|
@@ -104,4 +102,15 @@ export interface CompileStageResult {
|
|
|
104
102
|
* `3d` | `ancestor_background_image` | `shader_transitions`. Undefined when none fired. */
|
|
105
103
|
deCompileGate?: string;
|
|
106
104
|
}
|
|
105
|
+
/**
|
|
106
|
+
* The HTML file to compile for `entryFile`. A `<template>`-wrapped
|
|
107
|
+
* sub-composition has no live root, timeline or duration of its own, so it is
|
|
108
|
+
* rendered through the project's index.html shell with only its mount host kept.
|
|
109
|
+
*/
|
|
110
|
+
export declare function resolveEntryHtmlPath(input: {
|
|
111
|
+
projectDir: string;
|
|
112
|
+
workDir: string;
|
|
113
|
+
entryFile: string;
|
|
114
|
+
log: ProducerLogger;
|
|
115
|
+
}): string;
|
|
107
116
|
export declare function runCompileStage(input: CompileStageInput): Promise<CompileStageResult>;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { SegmentVideoFrames } from "./segmentVideoFrames.js";
|
|
2
|
+
/**
|
|
3
|
+
* Whether source-video frames are read one capture segment at a time. Off unless
|
|
4
|
+
* `HF_VIDEO_FRAME_WINDOW` reads `true`, and only for a render that segments, because only
|
|
5
|
+
* the segmented stage knows which frames a segment shows and when it is done with them.
|
|
6
|
+
*/
|
|
7
|
+
export declare function shouldWindowVideoFrames(args: {
|
|
8
|
+
env: Readonly<Record<string, string | undefined>>;
|
|
9
|
+
segmented: boolean;
|
|
10
|
+
}): boolean;
|
|
11
|
+
/** Reports the most bytes `segment-frames` has held at once, sampled each time a segment's frames land. */
|
|
12
|
+
export declare function trackSegmentFramePeak(frames: SegmentVideoFrames, rootDir: string, onPeak: (bytes: number) => void): SegmentVideoFrames;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type CanvasResolution, type Fps, type FpsInput, type HfVfxCapture } from "@hyperframes/core";
|
|
2
|
-
import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, explainDrawElementDisabled, type CaptureFailureKind, type MotionBlurOptions } from "@hyperframes/engine";
|
|
2
|
+
import { type EngineConfig, type ExtractionPhaseBreakdown, type VideoFrameFormat, type CaptureOptions, type CaptureVideoMetadataHint, type CaptureSession, type BeforeCaptureHook, type ProresProfile, type ParallelProgress, type WorkerTask, type CapturePerfSummary, type CaptureWarning, type SubTimelineWaitOutcome, type WorkerSizing, type StaticVerificationOutcome, explainDrawElementDisabled, type CaptureFailureKind, displaySize, type MotionBlurOptions } from "@hyperframes/engine";
|
|
3
3
|
import { type ReferenceBackgroundResult } from "@hyperframes/engine";
|
|
4
4
|
import { type ProducerLogger } from "../logger.js";
|
|
5
5
|
import { type RenderOutputFormat } from "./render/renderFormat.js";
|
|
@@ -480,10 +480,7 @@ export declare function createRenderFileLogger(logPath: string, base?: ProducerL
|
|
|
480
480
|
export declare function collectVideoReadinessSkipIds(nativeHdrVideoIds: ReadonlySet<string>, extractedVideos: readonly ExtractedVideoReadinessInput[]): string[];
|
|
481
481
|
interface ExtractedVideoReadinessInput {
|
|
482
482
|
videoId: string;
|
|
483
|
-
metadata:
|
|
484
|
-
width: number;
|
|
485
|
-
height: number;
|
|
486
|
-
};
|
|
483
|
+
metadata: Parameters<typeof displaySize>[0];
|
|
487
484
|
}
|
|
488
485
|
export declare function collectVideoMetadataHints(extractedVideos: readonly ExtractedVideoReadinessInput[]): CaptureVideoMetadataHint[];
|
|
489
486
|
export declare function findMissingFrameRanges(totalFrames: number, framesDir: string, frameExt: "jpg" | "png"): FrameRange[];
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.17",
|
|
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/lint": "0.9.
|
|
41
|
-
"@hyperframes/parsers": "0.9.
|
|
42
|
-
"@hyperframes/
|
|
38
|
+
"@hyperframes/engine": "0.9.17",
|
|
39
|
+
"@hyperframes/studio-server": "0.9.17",
|
|
40
|
+
"@hyperframes/lint": "0.9.17",
|
|
41
|
+
"@hyperframes/parsers": "0.9.17",
|
|
42
|
+
"@hyperframes/core": "0.9.17"
|
|
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.9.
|
|
51
|
+
"@hyperframes/aws-lambda": "0.9.17"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|