@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.
@@ -38,8 +38,7 @@ export declare function buildChunkCaptureOptions(input: {
38
38
  skipReadinessVideoIds?: string[];
39
39
  videoMetadataHints?: CaptureOptions["videoMetadataHints"];
40
40
  }): CaptureOptions;
41
- /** Extracts the given frames of deferred videos under the names a full extraction gives them. */
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
- /** Absolute path to the entry HTML (already resolved to standalone-entry if needed). */
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.15",
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/core": "0.9.15",
39
- "@hyperframes/engine": "0.9.15",
40
- "@hyperframes/lint": "0.9.15",
41
- "@hyperframes/parsers": "0.9.15",
42
- "@hyperframes/studio-server": "0.9.15"
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.15"
51
+ "@hyperframes/aws-lambda": "0.9.17"
52
52
  },
53
53
  "engines": {
54
54
  "node": ">=22"