@hyperframes/producer 0.8.178 → 0.8.180
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 +2237 -2122
- package/dist/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +54 -54
- package/dist/index.js +3499 -3385
- package/dist/public-server.js +13 -1
- package/dist/services/distributed/assemble.d.ts +4 -2
- package/dist/services/distributed/chunkAudio.d.ts +19 -0
- package/dist/services/distributed/chunkFrames.d.ts +2 -1
- package/dist/services/distributed/mp4Stitch.d.ts +1 -0
- package/dist/services/distributed/plan.d.ts +2 -0
- package/dist/services/distributed/planProtocol.d.ts +1 -0
- package/dist/services/distributed/planV2Execution.d.ts +4 -4
- package/dist/services/distributed/renderChunk.d.ts +23 -3
- package/package.json +7 -7
package/dist/public-server.js
CHANGED
|
@@ -13845,12 +13845,24 @@ var DISTRIBUTED_RENDER_CAPABILITIES = Object.freeze({
|
|
|
13845
13845
|
accepts: Object.freeze([PLAN_PROTOCOL_V1, PLAN_PROTOCOL_V2]),
|
|
13846
13846
|
acceptsLegacyV1WithoutDescriptor: true
|
|
13847
13847
|
})
|
|
13848
|
-
})
|
|
13848
|
+
}),
|
|
13849
|
+
chunkFrameRange: true
|
|
13849
13850
|
});
|
|
13850
13851
|
|
|
13851
13852
|
// src/services/render/stages/planHash.ts
|
|
13852
13853
|
var FIELD_DELIMITER = Buffer.from([0]);
|
|
13853
13854
|
|
|
13855
|
+
// src/services/distributed/chunkAudio.ts
|
|
13856
|
+
import { appendRenderProvenanceArgs, describeFfmpegFailure as describeFfmpegFailure2, runFfmpeg as runFfmpeg5 } from "@hyperframes/engine";
|
|
13857
|
+
|
|
13858
|
+
// src/services/distributed/mp4Stitch.ts
|
|
13859
|
+
var SCAN_BYTES = 64 * 1024;
|
|
13860
|
+
|
|
13861
|
+
// src/services/distributed/chunkAudio.ts
|
|
13862
|
+
var SLICE_DIR = "audio-chunks";
|
|
13863
|
+
var SLICE_FRAME = `${SLICE_DIR}/frame.m4a`;
|
|
13864
|
+
var SLICE_LAYOUT = `${SLICE_DIR}/layout.json`;
|
|
13865
|
+
|
|
13854
13866
|
// src/services/distributed/planSize.ts
|
|
13855
13867
|
var PLAN_ROOT_CATEGORY = {
|
|
13856
13868
|
compiled: "compiled",
|
|
@@ -31,6 +31,7 @@ export interface AssembleResult {
|
|
|
31
31
|
framesEncoded: number;
|
|
32
32
|
fileSize: number;
|
|
33
33
|
}
|
|
34
|
+
export type AssembleChunkPaths = readonly (string | readonly string[])[];
|
|
34
35
|
type CfrRateControlSource = Partial<Pick<LockedRenderConfig, "quality" | "crf" | "bitrate">>;
|
|
35
36
|
export declare function cfrRateControlArgs(locked: CfrRateControlSource): string[];
|
|
36
37
|
/**
|
|
@@ -39,7 +40,8 @@ export declare function cfrRateControlArgs(locked: CfrRateControlSource): string
|
|
|
39
40
|
* @param planDir — absolute path to the planDir produced by `plan()`.
|
|
40
41
|
* @param chunkPaths — ordered chunk outputs, length === `chunks.json` length.
|
|
41
42
|
* For mp4/mov each entry is a path to an encoded chunk file; for
|
|
42
|
-
* png-sequence each entry is a path to a directory of frames.
|
|
43
|
+
* png-sequence each entry is a path to a directory of frames. An entry
|
|
44
|
+
* may instead be the ordered parts of that chunk (see {@link AssembleChunkPaths}).
|
|
43
45
|
* @param audioPath — `<planDir>/<MIXED_AUDIO_FILENAME>` for mux'd formats. Pass `null`
|
|
44
46
|
* when the composition has no audio (or `assemble` is being called for a
|
|
45
47
|
* format whose audio is muxed elsewhere). `assemble` always normalizes
|
|
@@ -48,7 +50,7 @@ export declare function cfrRateControlArgs(locked: CfrRateControlSource): string
|
|
|
48
50
|
* @param outputPath — final on-disk output (file for mp4/mov; directory
|
|
49
51
|
* for png-sequence — created if missing).
|
|
50
52
|
*/
|
|
51
|
-
export declare function assemble(planDir: string,
|
|
53
|
+
export declare function assemble(planDir: string, chunkOutputs: AssembleChunkPaths, audioPath: string | null, outputPath: string, options?: {
|
|
52
54
|
logger?: ProducerLogger;
|
|
53
55
|
abortSignal?: AbortSignal;
|
|
54
56
|
/**
|
|
@@ -15,6 +15,25 @@ interface AudioCut {
|
|
|
15
15
|
packetCount: number;
|
|
16
16
|
}
|
|
17
17
|
export declare function audioCutForChunk(grid: AacPacketGrid, chunks: readonly ChunkSliceJson[], index: number, fps: Fps): AudioCut | null;
|
|
18
|
+
/** Chunk `index` split around `range`, so `audioCutForChunk` treats `range` as a chunk. */
|
|
19
|
+
export declare function chunksWithSubRange(chunks: readonly ChunkSliceJson[], index: number, range: {
|
|
20
|
+
startFrame: number;
|
|
21
|
+
endFrame: number;
|
|
22
|
+
}): {
|
|
23
|
+
chunks: ChunkSliceJson[];
|
|
24
|
+
index: number;
|
|
25
|
+
};
|
|
26
|
+
export declare function chunkAudioSlicePath(index: number): string;
|
|
27
|
+
/** Which chunks need a sliced-audio file: `"all"`, one index, or `null` if it is not one. */
|
|
28
|
+
export declare function chunkAudioSliceTarget(path: string): "all" | number | null;
|
|
29
|
+
export declare function writeChunkAudioSlices(input: {
|
|
30
|
+
audioPath: string;
|
|
31
|
+
planDir: string;
|
|
32
|
+
chunks: readonly ChunkSliceJson[];
|
|
33
|
+
fps: Fps;
|
|
34
|
+
}): Promise<void>;
|
|
35
|
+
/** The plan audio for a chunk: the whole file, or one rebuilt at `scratchPath` from its slice. */
|
|
36
|
+
export declare function chunkAudioSource(planDir: string, chunkIndex: number, scratchPath: string): string | null;
|
|
18
37
|
interface MuxInput {
|
|
19
38
|
videoPath: string;
|
|
20
39
|
audioPath: string | null;
|
|
@@ -7,9 +7,10 @@ export declare const FFMPEG_VERSION_MISMATCH = "FFMPEG_VERSION_MISMATCH";
|
|
|
7
7
|
export declare const PLAN_HASH_MISMATCH = "PLAN_HASH_MISMATCH";
|
|
8
8
|
export declare const MISSING_PLAN_ARTIFACT = "MISSING_PLAN_ARTIFACT";
|
|
9
9
|
export declare const CHUNK_INDEX_OUT_OF_RANGE = "CHUNK_INDEX_OUT_OF_RANGE";
|
|
10
|
+
export declare const CHUNK_FRAME_RANGE_INVALID = "CHUNK_FRAME_RANGE_INVALID";
|
|
10
11
|
export declare const MISSING_RUNTIME_ENV_SNAPSHOT = "MISSING_RUNTIME_ENV_SNAPSHOT";
|
|
11
12
|
export { INVALID_VIDEO_METADATA };
|
|
12
|
-
export type RenderChunkValidationCode = typeof FFMPEG_VERSION_MISMATCH | typeof PLAN_HASH_MISMATCH | typeof MISSING_PLAN_ARTIFACT | typeof CHUNK_INDEX_OUT_OF_RANGE | typeof MISSING_RUNTIME_ENV_SNAPSHOT | typeof INVALID_VIDEO_METADATA | typeof BROWSER_GPU_NOT_SOFTWARE;
|
|
13
|
+
export type RenderChunkValidationCode = typeof FFMPEG_VERSION_MISMATCH | typeof PLAN_HASH_MISMATCH | typeof MISSING_PLAN_ARTIFACT | typeof CHUNK_INDEX_OUT_OF_RANGE | typeof CHUNK_FRAME_RANGE_INVALID | typeof MISSING_RUNTIME_ENV_SNAPSHOT | typeof INVALID_VIDEO_METADATA | typeof BROWSER_GPU_NOT_SOFTWARE;
|
|
13
14
|
/** A malformed planDir or a worker that does not match the plan's fingerprint; adapters key retries off `code`. */
|
|
14
15
|
export declare class RenderChunkValidationError extends Error {
|
|
15
16
|
readonly code: RenderChunkValidationCode;
|
|
@@ -32,6 +32,7 @@ export interface TrackTable {
|
|
|
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
34
|
export declare function buildStitchedHeader(layouts: readonly Mp4Layout[]): Buffer;
|
|
35
|
+
export declare function fileRange(path: string): ReadRange;
|
|
35
36
|
/** Local join: the stitched header, then each chunk's mdat payload in order. Like the ffmpeg
|
|
36
37
|
* join, it writes in a work folder beside `outputPath` and renames only a finished file there. */
|
|
37
38
|
export declare function writeStitchedMp4(chunkPaths: readonly string[], outputPath: string): Promise<void>;
|
|
@@ -209,6 +209,8 @@ export interface BuildLocalExecutionPlanOptions {
|
|
|
209
209
|
readonly whileAudioMixes?: () => Promise<void>;
|
|
210
210
|
/** mp4 chunks carry their plan-audio slice unless cfr re-encodes. */
|
|
211
211
|
readonly chunksCarryAudio?: boolean;
|
|
212
|
+
/** With `chunksCarryAudio`, also write each chunk's audio packets to their own file. Plan v2 only. */
|
|
213
|
+
readonly sliceChunkAudio?: boolean;
|
|
212
214
|
}
|
|
213
215
|
export interface RemoteProjectFile {
|
|
214
216
|
readonly url: string;
|
|
@@ -53,6 +53,7 @@ export interface DistributedRenderCapabilities {
|
|
|
53
53
|
chunk: Readonly<PlanProtocolConsumerCapabilities>;
|
|
54
54
|
assembler: Readonly<PlanProtocolConsumerCapabilities>;
|
|
55
55
|
}>;
|
|
56
|
+
readonly chunkFrameRange?: boolean;
|
|
56
57
|
}
|
|
57
58
|
/** Serializable capability payload for fleet rollout and worker handshakes. */
|
|
58
59
|
export declare const DISTRIBUTED_RENDER_CAPABILITIES: Readonly<DistributedRenderCapabilities>;
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import { assemble, type AssembleResult } from "./assemble.js";
|
|
2
|
-
import { type EffectiveChunkResult } from "./renderChunk.js";
|
|
1
|
+
import { assemble, type AssembleChunkPaths, type AssembleResult } from "./assemble.js";
|
|
2
|
+
import { type EffectiveChunkResult, type RenderChunkOptions } from "./renderChunk.js";
|
|
3
3
|
/**
|
|
4
4
|
* Direct v2 chunk-role entry point. Storage adapters may instead download the
|
|
5
5
|
* selected blobs themselves and call `materializePlanV2Target` + `renderChunk`.
|
|
6
6
|
*/
|
|
7
|
-
export declare function renderChunkV2(planV2Dir: string, chunkIndex: number, outputChunkPath: string): Promise<EffectiveChunkResult>;
|
|
7
|
+
export declare function renderChunkV2(planV2Dir: string, chunkIndex: number, outputChunkPath: string, options?: RenderChunkOptions): Promise<EffectiveChunkResult>;
|
|
8
8
|
/**
|
|
9
9
|
* Direct v2 assembler-role entry point. Audio is resolved exclusively from
|
|
10
10
|
* the assembler dependency set and never materialized by chunk workers.
|
|
11
11
|
*/
|
|
12
|
-
export declare function assembleV2(planV2Dir: string, chunkPaths:
|
|
12
|
+
export declare function assembleV2(planV2Dir: string, chunkPaths: AssembleChunkPaths, outputPath: string, options?: Parameters<typeof assemble>[4]): Promise<AssembleResult>;
|
|
@@ -34,9 +34,9 @@
|
|
|
34
34
|
* In-process renders (`executeRenderJob`) leave them off.
|
|
35
35
|
*/
|
|
36
36
|
import { assertSwiftShader, type CaptureOptions, type CaptureMode, type CaptureSession, closeCaptureSession, createCaptureSession, type EngineConfig, initializeSession, probeBeginFrameLiveness, readWebGlVendorInfoFromCanvas } from "@hyperframes/engine";
|
|
37
|
-
import { type LockedRenderConfig } from "../render/stages/freezePlan.js";
|
|
37
|
+
import { type ChunkSliceJson, type LockedRenderConfig } from "../render/stages/freezePlan.js";
|
|
38
38
|
import { type PlanVideosJson } from "./shared.js";
|
|
39
|
-
export { CHUNK_INDEX_OUT_OF_RANGE, createChunkVideoFrameInjectorFactory, extractDeferredVideoFramesForChunk, FFMPEG_VERSION_MISMATCH, INVALID_VIDEO_METADATA, MISSING_PLAN_ARTIFACT, MISSING_RUNTIME_ENV_SNAPSHOT, PLAN_HASH_MISMATCH, rebuildExtractedFramesFromPlanDir, RenderChunkValidationError, } from "./chunkFrames.js";
|
|
39
|
+
export { CHUNK_FRAME_RANGE_INVALID, CHUNK_INDEX_OUT_OF_RANGE, createChunkVideoFrameInjectorFactory, extractDeferredVideoFramesForChunk, FFMPEG_VERSION_MISMATCH, INVALID_VIDEO_METADATA, MISSING_PLAN_ARTIFACT, MISSING_RUNTIME_ENV_SNAPSHOT, PLAN_HASH_MISMATCH, rebuildExtractedFramesFromPlanDir, RenderChunkValidationError, } from "./chunkFrames.js";
|
|
40
40
|
/** Validate the shared video contract before any v1 chunk can inject frames. */
|
|
41
41
|
export declare function validatePlanVideosForChunk(value: unknown): PlanVideosJson;
|
|
42
42
|
/**
|
|
@@ -51,6 +51,7 @@ export interface ChunkResult {
|
|
|
51
51
|
/** `"file"` for mp4/mov; `"frame-dir"` for png-sequence. */
|
|
52
52
|
outputKind: "file" | "frame-dir";
|
|
53
53
|
framesEncoded: number;
|
|
54
|
+
frameRange?: ChunkFrameRange;
|
|
54
55
|
sha256: string;
|
|
55
56
|
durationMs: number;
|
|
56
57
|
/**
|
|
@@ -92,7 +93,26 @@ export interface ChunkResult {
|
|
|
92
93
|
/** Result returned by the built-in renderer, which always observes its mode. */
|
|
93
94
|
export interface EffectiveChunkResult extends ChunkResult {
|
|
94
95
|
captureMode: CaptureMode;
|
|
96
|
+
frameRange: ChunkFrameRange;
|
|
95
97
|
}
|
|
98
|
+
/** Absolute composition frame indices, end exclusive, like a chunk's slice. */
|
|
99
|
+
export interface ChunkFrameRange {
|
|
100
|
+
startFrame: number;
|
|
101
|
+
endFrame: number;
|
|
102
|
+
}
|
|
103
|
+
export interface RenderChunkOptions {
|
|
104
|
+
/**
|
|
105
|
+
* Render only these frames of the chunk, e.g. to retry a slow chunk as
|
|
106
|
+
* parts rendered in parallel. Must be a non-empty range inside the chunk's
|
|
107
|
+
* slice. Each part is a self-contained output (its own IDR keyframe, frame
|
|
108
|
+
* names from zero, the audio packets it owns); pass the parts of a chunk,
|
|
109
|
+
* in order, as one `chunkPaths` entry to `assemble`. Omitted renders the
|
|
110
|
+
* whole slice.
|
|
111
|
+
*/
|
|
112
|
+
frameRange?: ChunkFrameRange;
|
|
113
|
+
}
|
|
114
|
+
/** The frames a chunk renders: its slice, or a validated sub-range of it. */
|
|
115
|
+
export declare function resolveChunkFrameRange(slice: ChunkSliceJson, chunkIndex: number, frameRange: ChunkFrameRange | undefined): ChunkFrameRange;
|
|
96
116
|
/** Compatibility-safe adapter seam for built-in or injected chunk renderers. */
|
|
97
117
|
export type ChunkRenderer = (planDir: string, chunkIndex: number, outputChunkPath: string) => Promise<ChunkResult>;
|
|
98
118
|
interface DistributedCaptureSessionDependencies {
|
|
@@ -159,4 +179,4 @@ export declare function resolveLockedVp9CpuUsed(lockedEncoder: Pick<LockedRender
|
|
|
159
179
|
* outputs — the caller picks the right shape based on `meta/encoder.json`.
|
|
160
180
|
* `renderChunk` enforces the same choice via `outputKind` on the result.
|
|
161
181
|
*/
|
|
162
|
-
export declare function renderChunk(planDir: string, chunkIndex: number, outputChunkPath: string): Promise<EffectiveChunkResult>;
|
|
182
|
+
export declare function renderChunk(planDir: string, chunkIndex: number, outputChunkPath: string, options?: RenderChunkOptions): Promise<EffectiveChunkResult>;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.180",
|
|
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/
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/
|
|
42
|
-
"@hyperframes/studio-server": "0.8.
|
|
38
|
+
"@hyperframes/engine": "0.8.180",
|
|
39
|
+
"@hyperframes/lint": "0.8.180",
|
|
40
|
+
"@hyperframes/parsers": "0.8.180",
|
|
41
|
+
"@hyperframes/core": "0.8.180",
|
|
42
|
+
"@hyperframes/studio-server": "0.8.180"
|
|
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.180"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|