@hyperframes/producer 0.8.181 → 0.8.184
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.d.ts +2 -2
- package/dist/distributed.js +451 -246
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +59 -59
- package/dist/index.d.ts +1 -0
- package/dist/index.js +601 -292
- package/dist/public-server.js +311 -158
- package/dist/services/distributed/assemble.d.ts +2 -1
- package/dist/services/distributed/chunkFrames.d.ts +6 -1
- package/dist/services/distributed/mp4Stitch.d.ts +4 -4
- package/dist/services/distributed/plan.d.ts +11 -0
- package/dist/services/distributed/planV2.d.ts +1 -0
- package/dist/services/distributed/projectHash.d.ts +1 -4
- package/dist/services/distributed/renderChunk.d.ts +9 -2
- package/dist/services/render/artifactTransaction.d.ts +7 -0
- package/dist/services/render/audioPadTrim.d.ts +20 -15
- package/dist/services/render/audioTruePeak.d.ts +1 -5
- package/dist/services/render/perfSummary.d.ts +2 -0
- package/dist/services/render/stages/audioStage.d.ts +2 -0
- package/dist/services/render/stages/captureStage.d.ts +11 -4
- package/dist/services/render/stages/encodeStage.d.ts +26 -2
- package/dist/services/render/stages/freezePlan.d.ts +1 -0
- package/dist/services/renderOrchestrator.d.ts +2 -2
- package/package.json +7 -7
|
@@ -68,6 +68,7 @@ export declare function assemble(planDir: string, chunkOutputs: AssembleChunkPat
|
|
|
68
68
|
*/
|
|
69
69
|
cfr?: boolean;
|
|
70
70
|
}): Promise<AssembleResult>;
|
|
71
|
-
/** Chunks
|
|
71
|
+
/** Chunks carrying audio, or with it as a separate file, stitch under one index like S3's. */
|
|
72
72
|
export declare function chunksAreStitchedMp4(planDir: string, cfr: boolean): boolean;
|
|
73
|
+
export declare function stitchesSeparateAudio(planDir: string): boolean;
|
|
73
74
|
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BeforeCaptureHook, BROWSER_GPU_NOT_SOFTWARE, type CaptureOptions, type EngineConfig, type ExtractedFrames, type FrameLookupTable } from "@hyperframes/engine";
|
|
1
|
+
import { type BeforeCaptureHook, BROWSER_GPU_NOT_SOFTWARE, type CaptureOptions, type EngineConfig, type ExtractedFrames, type FrameLookupTable, type ShownBox } from "@hyperframes/engine";
|
|
2
2
|
import type { LockedRenderConfig } from "../render/stages/freezePlan.js";
|
|
3
3
|
import type { PlanV2RemoteSources } from "./planV2.js";
|
|
4
4
|
import { type DistributedFormat, INVALID_VIDEO_METADATA, type PlanVideosJson } from "./shared.js";
|
|
@@ -39,6 +39,10 @@ export declare function buildChunkCaptureOptions(input: {
|
|
|
39
39
|
videoMetadataHints?: CaptureOptions["videoMetadataHints"];
|
|
40
40
|
}): CaptureOptions;
|
|
41
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: {
|
|
43
|
+
num: number;
|
|
44
|
+
den: number;
|
|
45
|
+
}): Map<string, Set<number>>;
|
|
42
46
|
export declare function extractDeferredVideoFramesForChunk(input: {
|
|
43
47
|
planDir: string;
|
|
44
48
|
planVideos: PlanVideosJson;
|
|
@@ -50,4 +54,5 @@ export declare function extractDeferredVideoFramesForChunk(input: {
|
|
|
50
54
|
outputRoot: string;
|
|
51
55
|
cfg: Pick<EngineConfig, "ffmpegProcessTimeout">;
|
|
52
56
|
remoteSources?: PlanV2RemoteSources;
|
|
57
|
+
shownBoxes?: ReadonlyMap<string, ShownBox>;
|
|
53
58
|
}): Promise<ExtractedFrames[]>;
|
|
@@ -31,9 +31,9 @@ export interface TrackTable {
|
|
|
31
31
|
}
|
|
32
32
|
/** Each track's sample tables, expanded to one entry per sample (and per chunk). */
|
|
33
33
|
export declare function readTracks(moov: Buffer): TrackTable[];
|
|
34
|
-
export declare function buildStitchedHeader(layouts: readonly Mp4Layout[]): Buffer;
|
|
34
|
+
export declare function buildStitchedHeader(layouts: readonly Mp4Layout[], audio?: Mp4Layout): Buffer;
|
|
35
35
|
export declare function fileRange(path: string): ReadRange;
|
|
36
|
-
/** Local join: the
|
|
37
|
-
*
|
|
38
|
-
export declare function writeStitchedMp4(chunkPaths: readonly string[], outputPath: string): Promise<void>;
|
|
36
|
+
/** Local join: the header, then `audioPath`'s and each chunk's payload. Like the ffmpeg join, it
|
|
37
|
+
* writes in a work folder beside `outputPath` and renames only a finished file there. */
|
|
38
|
+
export declare function writeStitchedMp4(chunkPaths: readonly string[], outputPath: string, audioPath?: string): Promise<void>;
|
|
39
39
|
export {};
|
|
@@ -211,6 +211,8 @@ export interface BuildLocalExecutionPlanOptions {
|
|
|
211
211
|
readonly chunksCarryAudio?: boolean;
|
|
212
212
|
/** With `chunksCarryAudio`, also write each chunk's audio packets to their own file. Plan v2 only. */
|
|
213
213
|
readonly sliceChunkAudio?: boolean;
|
|
214
|
+
/** Leave the audio to {@link buildPlanAudio}; chunks render video only. mp4 without `cfr` only. */
|
|
215
|
+
readonly deferAudio?: boolean;
|
|
214
216
|
}
|
|
215
217
|
export interface RemoteProjectFile {
|
|
216
218
|
readonly url: string;
|
|
@@ -401,7 +403,16 @@ export declare function resolveDistributedEngineConfig(config: DistributedRender
|
|
|
401
403
|
* Build the shared local execution representation used by both transport
|
|
402
404
|
* protocols. See the module docstring for the directory layout.
|
|
403
405
|
*/
|
|
406
|
+
/** Whether the plan leaves its audio to {@link buildPlanAudio}. */
|
|
407
|
+
export declare function plansSeparateAudio(config: Pick<DistributedRenderConfig, "format" | "cfr">, options: Pick<BuildLocalExecutionPlanOptions, "deferAudio">): boolean;
|
|
404
408
|
export declare function buildLocalExecutionPlan(projectDir: string, config: DistributedRenderConfig, executionPlanDir: string, options?: Readonly<BuildLocalExecutionPlanOptions>): Promise<LocalExecutionPlan>;
|
|
409
|
+
/**
|
|
410
|
+
* The audio of a plan made with `deferAudio`: the mix and true-peak hold that plan would have
|
|
411
|
+
* made, written to `outputPath` (on `workRoot`'s filesystem) at exactly the video's length.
|
|
412
|
+
*/
|
|
413
|
+
export declare function buildPlanAudio(projectDir: string, config: DistributedRenderConfig, workRoot: string, outputPath: string, options?: Pick<BuildLocalExecutionPlanOptions, "remoteFiles">): Promise<{
|
|
414
|
+
hasAudio: boolean;
|
|
415
|
+
}>;
|
|
405
416
|
/**
|
|
406
417
|
* Legacy v1 transport wrapper around {@link buildLocalExecutionPlan}.
|
|
407
418
|
*
|
|
@@ -91,6 +91,7 @@ export interface PlanV2WithPublisherOptions {
|
|
|
91
91
|
/** See {@link BuildLocalExecutionPlanOptions.remoteFiles}; needs a publisher with `referenceStoredBlob`. */
|
|
92
92
|
readonly remoteFiles?: BuildLocalExecutionPlanOptions["remoteFiles"];
|
|
93
93
|
readonly chunksCarryAudio?: boolean;
|
|
94
|
+
readonly deferAudio?: boolean;
|
|
94
95
|
}
|
|
95
96
|
export interface PlanV2MaterializationResult {
|
|
96
97
|
readonly planDir: string;
|
|
@@ -22,9 +22,6 @@ export declare function listSiteFiles(projectDir: string): string[];
|
|
|
22
22
|
* same-bytes rename still yields a fresh id. We trim to 16 chars because the
|
|
23
23
|
* full 64 isn't useful in an object key for legibility. Pass `files` when the
|
|
24
24
|
* caller already listed them, so the hashed set is the shipped set.
|
|
25
|
-
*
|
|
26
|
-
* Reads are synchronous: project trees are typically tens of MB at most
|
|
27
|
-
* (HTML/CSS/JS plus a few composition assets), so the simpler shape wins over
|
|
28
|
-
* a streaming pipeline.
|
|
25
|
+
* Files are read in fixed-size chunks, so no file is ever held whole in memory.
|
|
29
26
|
*/
|
|
30
27
|
export declare function hashProjectDir(projectDir: string, files?: readonly string[]): string;
|
|
@@ -73,7 +73,7 @@ export interface ChunkResult {
|
|
|
73
73
|
sessionBootMs: number;
|
|
74
74
|
captureStageMs: number;
|
|
75
75
|
encodeStageMs: number;
|
|
76
|
-
/** Capture workers used for this chunk (`
|
|
76
|
+
/** Capture workers used for this chunk (`resolveChunkCaptureWorkers` result). */
|
|
77
77
|
workers: number;
|
|
78
78
|
/**
|
|
79
79
|
* Effective engine mode used by every worker, after any browser fallback.
|
|
@@ -110,11 +110,18 @@ export interface RenderChunkOptions {
|
|
|
110
110
|
* whole slice.
|
|
111
111
|
*/
|
|
112
112
|
frameRange?: ChunkFrameRange;
|
|
113
|
+
/**
|
|
114
|
+
* Capture browsers the runtime can host. Raises the machine-wide sizing up to
|
|
115
|
+
* this many, one browser per 20 frames; never lowers it.
|
|
116
|
+
*/
|
|
117
|
+
maxCaptureWorkers?: number;
|
|
113
118
|
}
|
|
119
|
+
/** Capture browsers for a chunk: the machine-wide sizing, raised by the runtime's budget. */
|
|
120
|
+
export declare function resolveChunkCaptureWorkers(framesInChunk: number, machineSized: number, maxCaptureWorkers: number | undefined): number;
|
|
114
121
|
/** The frames a chunk renders: its slice, or a validated sub-range of it. */
|
|
115
122
|
export declare function resolveChunkFrameRange(slice: ChunkSliceJson, chunkIndex: number, frameRange: ChunkFrameRange | undefined): ChunkFrameRange;
|
|
116
123
|
/** Compatibility-safe adapter seam for built-in or injected chunk renderers. */
|
|
117
|
-
export type ChunkRenderer = (planDir: string, chunkIndex: number, outputChunkPath: string) => Promise<ChunkResult>;
|
|
124
|
+
export type ChunkRenderer = (planDir: string, chunkIndex: number, outputChunkPath: string, options?: RenderChunkOptions) => Promise<ChunkResult>;
|
|
118
125
|
interface DistributedCaptureSessionDependencies {
|
|
119
126
|
createCaptureSession: typeof createCaptureSession;
|
|
120
127
|
assertSwiftShader: typeof assertSwiftShader;
|
|
@@ -22,6 +22,8 @@ export interface ArtifactTransactionFileSystem {
|
|
|
22
22
|
export interface ArtifactDurationProbeResult {
|
|
23
23
|
durationSeconds: number;
|
|
24
24
|
frames?: number;
|
|
25
|
+
width?: number;
|
|
26
|
+
height?: number;
|
|
25
27
|
}
|
|
26
28
|
/**
|
|
27
29
|
* Pluggable probe used by `ArtifactTransaction.validate()` when the caller
|
|
@@ -60,6 +62,9 @@ export interface ArtifactValidationExpectation {
|
|
|
60
62
|
expectedDurationSeconds: number;
|
|
61
63
|
fps?: number;
|
|
62
64
|
expectedFrames?: number;
|
|
65
|
+
/** The output size the render was asked for; a route that ignores it must not publish. */
|
|
66
|
+
expectedWidth?: number;
|
|
67
|
+
expectedHeight?: number;
|
|
63
68
|
toleranceSeconds?: number;
|
|
64
69
|
/** Path relative to the staging directory to run the duration probe against. */
|
|
65
70
|
probeTarget?: string;
|
|
@@ -84,6 +89,8 @@ export declare function buildArtifactExpectation(input: {
|
|
|
84
89
|
durationSeconds: number;
|
|
85
90
|
fps: number;
|
|
86
91
|
expectedFrames: number | undefined;
|
|
92
|
+
width?: number;
|
|
93
|
+
height?: number;
|
|
87
94
|
}): ArtifactValidationExpectation | undefined;
|
|
88
95
|
/**
|
|
89
96
|
* Stages a render beside its final destination and promotes only a validated
|
|
@@ -54,12 +54,16 @@ export interface PadTrimAudioInput {
|
|
|
54
54
|
probeVideoFrameInfo?: (videoPath: string) => Promise<ProbeVideoFrameInfo>;
|
|
55
55
|
probeAudioInfo?: (audioPath: string, signal?: AbortSignal) => Promise<AudioProbeInfo>;
|
|
56
56
|
probeAudioTruePeakDbfs?: (audioPath: string, signal?: AbortSignal) => Promise<number>;
|
|
57
|
-
runFfmpeg?: (args: string[]) => Promise<
|
|
58
|
-
|
|
59
|
-
error?: string;
|
|
60
|
-
failureReason?: "external_interruption";
|
|
61
|
-
}>;
|
|
57
|
+
runFfmpeg?: (args: string[]) => Promise<StepResult>;
|
|
58
|
+
encodeAac?: AacEncoder;
|
|
62
59
|
}
|
|
60
|
+
interface StepResult {
|
|
61
|
+
success: boolean;
|
|
62
|
+
error?: string;
|
|
63
|
+
failureReason?: "external_interruption";
|
|
64
|
+
}
|
|
65
|
+
/** Encodes `filter` applied to `inputPath` as AAC of exactly `durationSeconds`. */
|
|
66
|
+
type AacEncoder = (inputPath: string, outputPath: string, durationSeconds: number, filter: string) => Promise<StepResult>;
|
|
63
67
|
export type PadTrimOperation = "pad" | "trim" | "copy";
|
|
64
68
|
export interface PadTrimAudioResult {
|
|
65
69
|
success: boolean;
|
|
@@ -77,19 +81,21 @@ export interface PadTrimAudioResult {
|
|
|
77
81
|
/** dB the true-peak limiter lowered the whole mix by; absent when it did not engage. */
|
|
78
82
|
audioLoweredDb?: number;
|
|
79
83
|
}
|
|
80
|
-
export type
|
|
81
|
-
|
|
82
|
-
kind: PadTrimAudioStepKind;
|
|
84
|
+
export type PadTrimAudioStep = {
|
|
85
|
+
kind: "copy";
|
|
83
86
|
args: string[];
|
|
84
|
-
}
|
|
87
|
+
} | {
|
|
88
|
+
kind: "trim" | "normalize";
|
|
89
|
+
filter: string;
|
|
90
|
+
};
|
|
85
91
|
export interface PadTrimAudioPlan {
|
|
86
92
|
operation: PadTrimOperation;
|
|
87
93
|
steps: PadTrimAudioStep[];
|
|
88
94
|
cleanupPaths: string[];
|
|
89
95
|
}
|
|
90
96
|
/**
|
|
91
|
-
* Pure helper: decide the pad/trim operation and
|
|
92
|
-
*
|
|
97
|
+
* Pure helper: decide the pad/trim operation and the steps that
|
|
98
|
+
* materialize it. Exported separately so unit tests can pin
|
|
93
99
|
* every branch without spawning ffmpeg.
|
|
94
100
|
*
|
|
95
101
|
* - `sourceDuration < targetDuration` → pad with `apad` to the exact target
|
|
@@ -102,10 +108,6 @@ export interface PadTrimAudioPlan {
|
|
|
102
108
|
* run ffmpeg with `-c:a copy` to materialize the output path.
|
|
103
109
|
*/
|
|
104
110
|
export declare function buildPadTrimAudioPlan(audioPath: string, outputPath: string, sourceDurationSeconds: number, targetDurationSeconds: number): PadTrimAudioPlan;
|
|
105
|
-
export declare function buildPadTrimAudioArgs(audioPath: string, outputPath: string, sourceDurationSeconds: number, targetDurationSeconds: number): {
|
|
106
|
-
args: string[];
|
|
107
|
-
operation: PadTrimOperation;
|
|
108
|
-
};
|
|
109
111
|
/**
|
|
110
112
|
* Pad or trim the mixed audio so its exact duration matches `frameCount / fps`
|
|
111
113
|
* for the assembled video.
|
|
@@ -117,6 +119,8 @@ export declare function padOrTrimAudioToVideoFrameCount(input: PadTrimAudioInput
|
|
|
117
119
|
*/
|
|
118
120
|
export declare function constrainAacTruePeak(input: {
|
|
119
121
|
audioPath: string;
|
|
122
|
+
/** The PCM `audioPath` was encoded from: a correction re-encodes it instead of decoding the AAC. */
|
|
123
|
+
sourcePath?: string;
|
|
120
124
|
targetDurationSeconds: number;
|
|
121
125
|
signal?: AbortSignal;
|
|
122
126
|
timeoutMs?: number;
|
|
@@ -128,3 +132,4 @@ export declare function constrainAacTruePeak(input: {
|
|
|
128
132
|
}>;
|
|
129
133
|
export declare function defaultProbeVideoFrameInfo(videoPath: string, signal?: AbortSignal): Promise<ProbeVideoFrameInfo>;
|
|
130
134
|
export declare function runFfprobeJson<T>(args: string[], signal?: AbortSignal): Promise<T>;
|
|
135
|
+
export {};
|
|
@@ -1,12 +1,8 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* The true peak one `ebur128=peak=true` pass over the whole file reports, measured in parallel
|
|
3
|
-
* segments when the
|
|
3
|
+
* segments when the file is 48 kHz with a known length: the same digit, not an estimate.
|
|
4
4
|
*/
|
|
5
5
|
export declare function measureTruePeakDbfs(audioPath: string, options: {
|
|
6
6
|
timeoutMs: number;
|
|
7
7
|
signal?: AbortSignal;
|
|
8
|
-
segments?: {
|
|
9
|
-
durationSeconds: number;
|
|
10
|
-
sampleRate: number;
|
|
11
|
-
};
|
|
12
8
|
}): Promise<number>;
|
|
@@ -50,6 +50,8 @@ export declare function roundDb(value: number | undefined): number | undefined;
|
|
|
50
50
|
export interface DrawElementPerfInput {
|
|
51
51
|
compileGate?: string;
|
|
52
52
|
clampReason?: string;
|
|
53
|
+
/** Engine init-time gate the pre-capture probe hit; its session may be closed before capture. */
|
|
54
|
+
probeGateReason?: string;
|
|
53
55
|
workerInversion?: "inverted" | "reverted";
|
|
54
56
|
/** Auto-resolved worker count before the inversion pinned it to 1 (set only when the inversion fired). */
|
|
55
57
|
preInversionWorkers?: number;
|
|
@@ -34,6 +34,8 @@ export interface AudioStageInput {
|
|
|
34
34
|
audios: CompositionMetadata["audios"];
|
|
35
35
|
masterFxChain?: string;
|
|
36
36
|
urlByAbsentLocalPath?: ReadonlyMap<string, string>;
|
|
37
|
+
/** Keep the float mix the AAC was encoded from here, for a later re-encode from it. */
|
|
38
|
+
keepEncoderInputAt?: string;
|
|
37
39
|
abortSignal: AbortSignal | undefined;
|
|
38
40
|
assertNotAborted: () => void;
|
|
39
41
|
/** Where a per-track failure's detail goes. Optional so tests need not pass one. */
|
|
@@ -34,10 +34,10 @@
|
|
|
34
34
|
* `safeCleanup`, `sampleDirectoryBytes`, etc.) into a shared module so
|
|
35
35
|
* the stages can import them without reaching back into the orchestrator.
|
|
36
36
|
*/
|
|
37
|
-
import { type BeforeCaptureHook, type CaptureOptions, type CapturePerfSummary, type CaptureSession, type EngineConfig } from "@hyperframes/engine";
|
|
37
|
+
import { type BeforeCaptureHook, type CaptureOptions, type CapturePerfSummary, type CaptureSession, type EngineConfig, type LandedFrame } from "@hyperframes/engine";
|
|
38
38
|
import type { FileServerHandle } from "../../fileServer.js";
|
|
39
39
|
import type { ProducerLogger } from "../../../logger.js";
|
|
40
|
-
import { type CaptureAttemptSummary, type ProgressCallback, type RenderJob } from "../../renderOrchestrator.js";
|
|
40
|
+
import { type CaptureAttemptSummary, type ProgressCallback, type RenderConfig, type RenderJob } from "../../renderOrchestrator.js";
|
|
41
41
|
import type { SdrDiskCapturePlan } from "../capturePlan.js";
|
|
42
42
|
export interface CaptureStageInput {
|
|
43
43
|
fileServer: FileServerHandle;
|
|
@@ -87,6 +87,7 @@ export interface CaptureStageInput {
|
|
|
87
87
|
startFrame: number;
|
|
88
88
|
endFrame: number;
|
|
89
89
|
};
|
|
90
|
+
onFrameLanded?: (frame: LandedFrame) => void;
|
|
90
91
|
}
|
|
91
92
|
export interface CaptureStageResult {
|
|
92
93
|
/** Final worker count after any adaptive retry. */
|
|
@@ -121,8 +122,13 @@ export type DiskCaptureHeadroom = {
|
|
|
121
122
|
};
|
|
122
123
|
/** Shared 90% disk gate used by both fallback planning and disk execution. */
|
|
123
124
|
export declare function inspectDiskCaptureHeadroom(framesDir: string, totalFrames: number, captureOptions: CaptureOptions, freeDiskBytes?: (path: string) => number | null): DiskCaptureHeadroom;
|
|
124
|
-
|
|
125
|
-
|
|
125
|
+
/**
|
|
126
|
+
* Why this render stores frames and what would take it off disk. `--workers 1`
|
|
127
|
+
* is offered only when a one-worker run of the same render would stream.
|
|
128
|
+
*/
|
|
129
|
+
export declare function diskCaptureRemedy(cfg: EngineConfig, outputFormat: NonNullable<RenderConfig["format"]>, durationSeconds: number, workerCount: number): string;
|
|
130
|
+
export declare function diskCaptureShortfallError(needBytes: number, freeBytes: number, framesDir: string, basis: "estimate" | "measured", remedy: string): Error;
|
|
131
|
+
export declare function assertDiskCaptureHeadroom(framesDir: string, totalFrames: number, captureOptions: CaptureOptions, remedy: string, freeDiskBytes?: (path: string) => number | null): void;
|
|
126
132
|
/** Frame bytes written so far: the merged frames dir plus every capture attempt's worker dirs. */
|
|
127
133
|
export declare function measureCaptureFrameBytes(workDir: string, framesDir: string): number;
|
|
128
134
|
/** Per-frame callback: after the sample frames, throws if the projected remainder exceeds 90% of free space. */
|
|
@@ -130,6 +136,7 @@ export declare function createDiskCaptureProjection(input: {
|
|
|
130
136
|
framesDir: string;
|
|
131
137
|
totalFrames: number;
|
|
132
138
|
measureBytes: () => number;
|
|
139
|
+
remedy: string;
|
|
133
140
|
freeDiskBytes?: (path: string) => number | null;
|
|
134
141
|
}): (capturedFrames: number) => void;
|
|
135
142
|
export declare function runCaptureStage(input: CaptureStageInput): Promise<CaptureStageResult>;
|
|
@@ -26,8 +26,12 @@
|
|
|
26
26
|
* branch + same args.
|
|
27
27
|
* - `Encoding failed: <err>` throws on the encoder's
|
|
28
28
|
* `success: false`.
|
|
29
|
+
*
|
|
30
|
+
* `encodeWhileCapturing` runs the same mp4 encode during multi-worker disk
|
|
31
|
+
* capture, feeding frames in order as they land, and falls back to this
|
|
32
|
+
* stage's encode if it fails.
|
|
29
33
|
*/
|
|
30
|
-
import { getEncoderPreset, type EngineConfig } from "@hyperframes/engine";
|
|
34
|
+
import { getEncoderPreset, type EngineConfig, type LandedFrame } from "@hyperframes/engine";
|
|
31
35
|
import type { ProducerLogger } from "../../../logger.js";
|
|
32
36
|
import type { ProgressCallback, RenderJob } from "../../renderOrchestrator.js";
|
|
33
37
|
export interface EncodeStageInput {
|
|
@@ -71,7 +75,7 @@ export interface EncodeStageInput {
|
|
|
71
75
|
enableChunkedEncode: boolean;
|
|
72
76
|
chunkedEncodeSize: number;
|
|
73
77
|
/** Already-resolved engine config from the orchestrator; direct callers fall back below. */
|
|
74
|
-
engineConfig?: Pick<EngineConfig, "ffmpegEncodeTimeout" | "vp9CpuUsed"
|
|
78
|
+
engineConfig?: Pick<EngineConfig, "ffmpegEncodeTimeout" | "vp9CpuUsed"> & Partial<Pick<EngineConfig, "ffmpegStreamingTimeout">>;
|
|
75
79
|
abortSignal: AbortSignal | undefined;
|
|
76
80
|
assertNotAborted: () => void;
|
|
77
81
|
onProgress?: ProgressCallback;
|
|
@@ -97,4 +101,24 @@ export interface EncodeStageResult {
|
|
|
97
101
|
/** Wall-clock ms for the encode (or png-copy) phase. */
|
|
98
102
|
encodeMs: number;
|
|
99
103
|
}
|
|
104
|
+
/**
|
|
105
|
+
* Software libx264 from JPEG only: the streaming encoder then runs the disk encoder's
|
|
106
|
+
* arguments (same bytes). Needs a core the capture workers leave free.
|
|
107
|
+
*/
|
|
108
|
+
export declare function canEncodeWhileCapturing(input: EncodeStageInput, workerCount: number, cpuCount: number): boolean;
|
|
109
|
+
export interface EncodeWhileCapturing {
|
|
110
|
+
/** A worker finished writing this frame. */
|
|
111
|
+
onFrameLanded: (frame: LandedFrame) => void;
|
|
112
|
+
/** Capture succeeded and every frame is in `framesDir`: encode the rest. */
|
|
113
|
+
finish: () => Promise<EncodeStageResult>;
|
|
114
|
+
/** Capture failed: stop the encoder and wait for it to exit. */
|
|
115
|
+
abort: () => Promise<void>;
|
|
116
|
+
/** Frames handed to the encoder so far. */
|
|
117
|
+
readonly framesFed: number;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Feeds frames 0, 1, 2… to the encoder as each lands; capture never waits on it.
|
|
121
|
+
* On failure `finish` re-runs `runEncodeStage` on the same frames.
|
|
122
|
+
*/
|
|
123
|
+
export declare function encodeWhileCapturing(input: EncodeStageInput, totalFrames: number): EncodeWhileCapturing;
|
|
100
124
|
export declare function runEncodeStage(input: EncodeStageInput): Promise<EncodeStageResult>;
|
|
@@ -1152,8 +1152,8 @@ export declare function closeOrphanedProbeForRetry(probe: CaptureSession, closer
|
|
|
1152
1152
|
*/
|
|
1153
1153
|
export declare function resolveParallelCaptureMode(args: {
|
|
1154
1154
|
platform: NodeJS.Platform;
|
|
1155
|
-
/**
|
|
1156
|
-
|
|
1155
|
+
/** The chrome-headless-shell binary resolved for this render, if any. */
|
|
1156
|
+
headlessShellPath: string | undefined;
|
|
1157
1157
|
forceScreenshot: boolean;
|
|
1158
1158
|
deviceScaleFactor?: number;
|
|
1159
1159
|
}): "screenshot" | "beginframe";
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.184",
|
|
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.2.1",
|
|
37
37
|
"puppeteer-core": "^25.2.1",
|
|
38
|
-
"@hyperframes/core": "0.8.
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/parsers": "0.8.
|
|
42
|
-
"@hyperframes/studio-server": "0.8.
|
|
38
|
+
"@hyperframes/core": "0.8.184",
|
|
39
|
+
"@hyperframes/engine": "0.8.184",
|
|
40
|
+
"@hyperframes/lint": "0.8.184",
|
|
41
|
+
"@hyperframes/parsers": "0.8.184",
|
|
42
|
+
"@hyperframes/studio-server": "0.8.184"
|
|
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.184"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|