@hyperframes/producer 0.8.153 → 0.8.155
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 +15 -9
- package/dist/index.js +27 -17
- package/dist/public-server.js +13 -10
- package/dist/server.d.ts +2 -0
- package/dist/services/distributed/assemble.d.ts +5 -1
- package/package.json +7 -7
package/dist/distributed.js
CHANGED
|
@@ -93,7 +93,7 @@ import {
|
|
|
93
93
|
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
94
94
|
assertConfiguredFfmpegBinariesExist,
|
|
95
95
|
resolveBrowserGpuMode,
|
|
96
|
-
resolveHeadlessShellPath
|
|
96
|
+
resolveHeadlessShellPath,
|
|
97
97
|
compositionRequiresWebGpu as compositionRequiresWebGpu2,
|
|
98
98
|
applyConcreteGpuScreenshotClamp,
|
|
99
99
|
explainDrawElementDisabled,
|
|
@@ -1200,7 +1200,6 @@ import {
|
|
|
1200
1200
|
getCapturePerfSummary as getCapturePerfSummary2,
|
|
1201
1201
|
initializeSession as initializeSession2,
|
|
1202
1202
|
prepareCaptureSessionForReuse as prepareCaptureSessionForReuse2,
|
|
1203
|
-
resolveHeadlessShellPath,
|
|
1204
1203
|
shouldDisableBrowserPoolForParallelWorker,
|
|
1205
1204
|
spawnStreamingEncoder as spawnStreamingEncoder2
|
|
1206
1205
|
} from "@hyperframes/engine";
|
|
@@ -8517,12 +8516,20 @@ import {
|
|
|
8517
8516
|
appendRenderProvenanceArgs,
|
|
8518
8517
|
applyFaststart as applyFaststart2,
|
|
8519
8518
|
describeFfmpegFailure as describeFfmpegFailure2,
|
|
8519
|
+
getEncoderPreset as getEncoderPreset5,
|
|
8520
8520
|
MIXED_AUDIO_FILENAME as MIXED_AUDIO_FILENAME4,
|
|
8521
8521
|
muxVideoWithAudio as muxVideoWithAudio2,
|
|
8522
8522
|
resolveConfig as resolveConfig4,
|
|
8523
8523
|
runFfmpeg as runFfmpeg5
|
|
8524
8524
|
} from "@hyperframes/engine";
|
|
8525
8525
|
import { fpsToFfmpegArg as fpsToFfmpegArg3 } from "@hyperframes/core";
|
|
8526
|
+
function cfrRateControlArgs(locked) {
|
|
8527
|
+
const preset = getEncoderPreset5(locked.quality ?? "standard", "mp4");
|
|
8528
|
+
if (locked.crf == null && locked.bitrate) {
|
|
8529
|
+
return ["-preset", preset.preset, "-b:v", locked.bitrate];
|
|
8530
|
+
}
|
|
8531
|
+
return ["-preset", preset.preset, "-crf", String(locked.crf ?? preset.quality)];
|
|
8532
|
+
}
|
|
8526
8533
|
async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
8527
8534
|
const start = Date.now();
|
|
8528
8535
|
const log = options?.logger ?? defaultLogger;
|
|
@@ -8619,7 +8626,9 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
8619
8626
|
if (!existsSync16(encoderJsonPath)) {
|
|
8620
8627
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
8621
8628
|
}
|
|
8622
|
-
const encoderJson = JSON.parse(
|
|
8629
|
+
const encoderJson = JSON.parse(
|
|
8630
|
+
readFileSync10(encoderJsonPath, "utf-8")
|
|
8631
|
+
);
|
|
8623
8632
|
if (encoderJson.encoder === "libx265-software") {
|
|
8624
8633
|
throw new Error(
|
|
8625
8634
|
`[assemble] cfr=true is not yet supported with codec: "h265". The cfr re-encode pass uses libx264 and would silently transcode the h265 chunks. Either disable cfr or render with codec: "h264".`
|
|
@@ -8631,10 +8640,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
8631
8640
|
concatOutputPath,
|
|
8632
8641
|
"-c:v",
|
|
8633
8642
|
"libx264",
|
|
8634
|
-
|
|
8635
|
-
"medium",
|
|
8636
|
-
"-crf",
|
|
8637
|
-
"18",
|
|
8643
|
+
...cfrRateControlArgs(encoderJson),
|
|
8638
8644
|
"-pix_fmt",
|
|
8639
8645
|
"yuv420p",
|
|
8640
8646
|
"-fps_mode",
|
|
@@ -8786,7 +8792,7 @@ import {
|
|
|
8786
8792
|
createVideoFrameInjector as createVideoFrameInjector2,
|
|
8787
8793
|
deriveBeginFrameProbeTimeTicks as deriveBeginFrameProbeTimeTicks2,
|
|
8788
8794
|
extractVideoFramesRange,
|
|
8789
|
-
getEncoderPreset as
|
|
8795
|
+
getEncoderPreset as getEncoderPreset6,
|
|
8790
8796
|
initializeSession as initializeSession8,
|
|
8791
8797
|
probeBeginFrameLiveness as probeBeginFrameLiveness2,
|
|
8792
8798
|
readWebGlVendorInfoFromCanvas,
|
|
@@ -9337,7 +9343,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
9337
9343
|
const isPngSequence = plan2.dimensions.format === "png-sequence";
|
|
9338
9344
|
outputKind = isPngSequence ? "frame-dir" : "file";
|
|
9339
9345
|
const presetFormat = isPngSequence ? "mp4" : plan2.dimensions.format;
|
|
9340
|
-
const basePreset =
|
|
9346
|
+
const basePreset = getEncoderPreset6(job.config.quality, presetFormat, void 0);
|
|
9341
9347
|
const preset = resolvePresetForLockedEncoder(basePreset, encoder.encoder);
|
|
9342
9348
|
const effectiveQuality = encoder.crf ?? preset.quality;
|
|
9343
9349
|
const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
|
package/dist/index.js
CHANGED
|
@@ -36,7 +36,7 @@ import {
|
|
|
36
36
|
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
37
37
|
assertConfiguredFfmpegBinariesExist,
|
|
38
38
|
resolveBrowserGpuMode,
|
|
39
|
-
resolveHeadlessShellPath
|
|
39
|
+
resolveHeadlessShellPath,
|
|
40
40
|
compositionRequiresWebGpu as compositionRequiresWebGpu2,
|
|
41
41
|
applyConcreteGpuScreenshotClamp,
|
|
42
42
|
explainDrawElementDisabled,
|
|
@@ -1837,7 +1837,6 @@ import {
|
|
|
1837
1837
|
getCapturePerfSummary as getCapturePerfSummary2,
|
|
1838
1838
|
initializeSession as initializeSession2,
|
|
1839
1839
|
prepareCaptureSessionForReuse as prepareCaptureSessionForReuse2,
|
|
1840
|
-
resolveHeadlessShellPath,
|
|
1841
1840
|
shouldDisableBrowserPoolForParallelWorker,
|
|
1842
1841
|
spawnStreamingEncoder as spawnStreamingEncoder2
|
|
1843
1842
|
} from "@hyperframes/engine";
|
|
@@ -4081,10 +4080,7 @@ async function openSegmentedSession(input) {
|
|
|
4081
4080
|
const videoInjector = input.createRenderVideoFrameInjector();
|
|
4082
4081
|
const captureOptions = input.buildCaptureOptions();
|
|
4083
4082
|
const ownBrowser = shouldDisableBrowserPoolForParallelWorker({
|
|
4084
|
-
parallel: (input.workerCount ?? 1) > 1
|
|
4085
|
-
platform: process.platform,
|
|
4086
|
-
deviceScaleFactor: captureOptions.deviceScaleFactor,
|
|
4087
|
-
headlessShellPath: resolveHeadlessShellPath(captureCfg)
|
|
4083
|
+
parallel: (input.workerCount ?? 1) > 1
|
|
4088
4084
|
});
|
|
4089
4085
|
return createCaptureSession2(
|
|
4090
4086
|
input.fileServer.url,
|
|
@@ -12209,7 +12205,7 @@ async function executeRenderPipeline(input) {
|
|
|
12209
12205
|
code: "start_browsers"
|
|
12210
12206
|
});
|
|
12211
12207
|
const resolvedBrowserGpuMode = await resolveBrowserGpuMode(cfg.browserGpuMode, {
|
|
12212
|
-
chromePath:
|
|
12208
|
+
chromePath: resolveHeadlessShellPath(cfg),
|
|
12213
12209
|
browserTimeout: cfg.browserTimeout
|
|
12214
12210
|
});
|
|
12215
12211
|
captureForceScreenshot = applyConcreteGpuScreenshotClamp(
|
|
@@ -12554,7 +12550,7 @@ async function executeRenderPipeline(input) {
|
|
|
12554
12550
|
}
|
|
12555
12551
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12556
12552
|
platform: process.platform,
|
|
12557
|
-
headlessShell:
|
|
12553
|
+
headlessShell: resolveHeadlessShellPath(cfg) !== null,
|
|
12558
12554
|
forceScreenshot: captureForceScreenshot,
|
|
12559
12555
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12560
12556
|
});
|
|
@@ -14241,12 +14237,12 @@ function resolveWorkerEntry2() {
|
|
|
14241
14237
|
}
|
|
14242
14238
|
|
|
14243
14239
|
// src/server.ts
|
|
14244
|
-
import { isVideoFrameFormat as isVideoFrameFormat3 } from "@hyperframes/engine";
|
|
14245
14240
|
import {
|
|
14246
14241
|
parseFps,
|
|
14247
14242
|
normalizeResolutionFlag,
|
|
14248
14243
|
isAspectAgnosticResolutionAlias
|
|
14249
14244
|
} from "@hyperframes/core";
|
|
14245
|
+
import { parseEncoderOptions } from "@hyperframes/studio-server/encoder-options";
|
|
14250
14246
|
var DEFAULT_SERVER_FPS = { num: 30, den: 1 };
|
|
14251
14247
|
var SAFE_RENDER_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
14252
14248
|
"ASSET_MEDIA_TYPE_MISMATCH",
|
|
@@ -14320,13 +14316,16 @@ function parseRenderOptions(body) {
|
|
|
14320
14316
|
const entryFile = nonEmptyString(body.entryFile);
|
|
14321
14317
|
const format = parseServerFormat(body.format);
|
|
14322
14318
|
const outputDynamicRange = parseServerOutputDynamicRange(body.outputDynamicRange) ?? fromRenderHdrMode(parseLegacyServerHdrMode(body.hdrMode));
|
|
14323
|
-
const
|
|
14319
|
+
const encoder = parseEncoderOptions(body, format ?? "mp4");
|
|
14320
|
+
const { crf, videoBitrate, videoFrameFormat } = encoder.ok ? encoder.options : {};
|
|
14324
14321
|
const { variables, outputResolution, outputResolutionAspectAgnostic } = parseRenderOverrides(body);
|
|
14325
14322
|
return {
|
|
14326
14323
|
outputPath,
|
|
14327
14324
|
fps,
|
|
14328
14325
|
quality,
|
|
14329
14326
|
workers,
|
|
14327
|
+
crf,
|
|
14328
|
+
videoBitrate,
|
|
14330
14329
|
useGpu,
|
|
14331
14330
|
debug,
|
|
14332
14331
|
strictness,
|
|
@@ -14358,6 +14357,8 @@ function buildRenderJobConfig(input, outputPath, log) {
|
|
|
14358
14357
|
quality: input.quality,
|
|
14359
14358
|
format: input.format ?? "mp4",
|
|
14360
14359
|
workers: input.workers,
|
|
14360
|
+
crf: input.crf,
|
|
14361
|
+
videoBitrate: input.videoBitrate,
|
|
14361
14362
|
useGpu: input.useGpu,
|
|
14362
14363
|
debug: input.debug,
|
|
14363
14364
|
strictness: input.strictness,
|
|
@@ -14379,6 +14380,8 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
|
|
|
14379
14380
|
return { input, cleanupProjectDir, absoluteOutputPath };
|
|
14380
14381
|
}
|
|
14381
14382
|
function validateRenderOverrides(body) {
|
|
14383
|
+
const encoder = parseEncoderOptions(body, parseServerFormat(body.format) ?? "mp4");
|
|
14384
|
+
if (!encoder.ok) return encoder.error;
|
|
14382
14385
|
if (body.variables !== void 0 && !isPlainObject2(body.variables)) {
|
|
14383
14386
|
return 'variables must be a JSON object keyed by variable id (e.g. {"title":"Hello"})';
|
|
14384
14387
|
}
|
|
@@ -17083,12 +17086,20 @@ import {
|
|
|
17083
17086
|
appendRenderProvenanceArgs,
|
|
17084
17087
|
applyFaststart as applyFaststart2,
|
|
17085
17088
|
describeFfmpegFailure as describeFfmpegFailure2,
|
|
17089
|
+
getEncoderPreset as getEncoderPreset5,
|
|
17086
17090
|
MIXED_AUDIO_FILENAME as MIXED_AUDIO_FILENAME4,
|
|
17087
17091
|
muxVideoWithAudio as muxVideoWithAudio2,
|
|
17088
17092
|
resolveConfig as resolveConfig6,
|
|
17089
17093
|
runFfmpeg as runFfmpeg5
|
|
17090
17094
|
} from "@hyperframes/engine";
|
|
17091
17095
|
import { fpsToFfmpegArg as fpsToFfmpegArg3 } from "@hyperframes/core";
|
|
17096
|
+
function cfrRateControlArgs(locked) {
|
|
17097
|
+
const preset = getEncoderPreset5(locked.quality ?? "standard", "mp4");
|
|
17098
|
+
if (locked.crf == null && locked.bitrate) {
|
|
17099
|
+
return ["-preset", preset.preset, "-b:v", locked.bitrate];
|
|
17100
|
+
}
|
|
17101
|
+
return ["-preset", preset.preset, "-crf", String(locked.crf ?? preset.quality)];
|
|
17102
|
+
}
|
|
17092
17103
|
async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
17093
17104
|
const start = Date.now();
|
|
17094
17105
|
const log = options?.logger ?? defaultLogger;
|
|
@@ -17185,7 +17196,9 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
17185
17196
|
if (!existsSync25(encoderJsonPath)) {
|
|
17186
17197
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
17187
17198
|
}
|
|
17188
|
-
const encoderJson = JSON.parse(
|
|
17199
|
+
const encoderJson = JSON.parse(
|
|
17200
|
+
readFileSync13(encoderJsonPath, "utf-8")
|
|
17201
|
+
);
|
|
17189
17202
|
if (encoderJson.encoder === "libx265-software") {
|
|
17190
17203
|
throw new Error(
|
|
17191
17204
|
`[assemble] cfr=true is not yet supported with codec: "h265". The cfr re-encode pass uses libx264 and would silently transcode the h265 chunks. Either disable cfr or render with codec: "h264".`
|
|
@@ -17197,10 +17210,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
17197
17210
|
concatOutputPath,
|
|
17198
17211
|
"-c:v",
|
|
17199
17212
|
"libx264",
|
|
17200
|
-
|
|
17201
|
-
"medium",
|
|
17202
|
-
"-crf",
|
|
17203
|
-
"18",
|
|
17213
|
+
...cfrRateControlArgs(encoderJson),
|
|
17204
17214
|
"-pix_fmt",
|
|
17205
17215
|
"yuv420p",
|
|
17206
17216
|
"-fps_mode",
|
|
@@ -17352,7 +17362,7 @@ import {
|
|
|
17352
17362
|
createVideoFrameInjector as createVideoFrameInjector2,
|
|
17353
17363
|
deriveBeginFrameProbeTimeTicks as deriveBeginFrameProbeTimeTicks2,
|
|
17354
17364
|
extractVideoFramesRange,
|
|
17355
|
-
getEncoderPreset as
|
|
17365
|
+
getEncoderPreset as getEncoderPreset6,
|
|
17356
17366
|
initializeSession as initializeSession9,
|
|
17357
17367
|
probeBeginFrameLiveness as probeBeginFrameLiveness2,
|
|
17358
17368
|
readWebGlVendorInfoFromCanvas,
|
|
@@ -17903,7 +17913,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
17903
17913
|
const isPngSequence = plan2.dimensions.format === "png-sequence";
|
|
17904
17914
|
outputKind = isPngSequence ? "frame-dir" : "file";
|
|
17905
17915
|
const presetFormat = isPngSequence ? "mp4" : plan2.dimensions.format;
|
|
17906
|
-
const basePreset =
|
|
17916
|
+
const basePreset = getEncoderPreset6(job.config.quality, presetFormat, void 0);
|
|
17907
17917
|
const preset = resolvePresetForLockedEncoder(basePreset, encoder.encoder);
|
|
17908
17918
|
const effectiveQuality = encoder.crf ?? preset.quality;
|
|
17909
17919
|
const effectiveBitrate = encoder.crf != null ? void 0 : encoder.bitrate;
|
package/dist/public-server.js
CHANGED
|
@@ -56,7 +56,7 @@ import {
|
|
|
56
56
|
LOW_MEMORY_TOTAL_MB_THRESHOLD,
|
|
57
57
|
assertConfiguredFfmpegBinariesExist,
|
|
58
58
|
resolveBrowserGpuMode,
|
|
59
|
-
resolveHeadlessShellPath
|
|
59
|
+
resolveHeadlessShellPath,
|
|
60
60
|
compositionRequiresWebGpu as compositionRequiresWebGpu2,
|
|
61
61
|
applyConcreteGpuScreenshotClamp,
|
|
62
62
|
explainDrawElementDisabled,
|
|
@@ -1856,7 +1856,6 @@ import {
|
|
|
1856
1856
|
getCapturePerfSummary as getCapturePerfSummary2,
|
|
1857
1857
|
initializeSession as initializeSession2,
|
|
1858
1858
|
prepareCaptureSessionForReuse as prepareCaptureSessionForReuse2,
|
|
1859
|
-
resolveHeadlessShellPath,
|
|
1860
1859
|
shouldDisableBrowserPoolForParallelWorker,
|
|
1861
1860
|
spawnStreamingEncoder as spawnStreamingEncoder2
|
|
1862
1861
|
} from "@hyperframes/engine";
|
|
@@ -4100,10 +4099,7 @@ async function openSegmentedSession(input) {
|
|
|
4100
4099
|
const videoInjector = input.createRenderVideoFrameInjector();
|
|
4101
4100
|
const captureOptions = input.buildCaptureOptions();
|
|
4102
4101
|
const ownBrowser = shouldDisableBrowserPoolForParallelWorker({
|
|
4103
|
-
parallel: (input.workerCount ?? 1) > 1
|
|
4104
|
-
platform: process.platform,
|
|
4105
|
-
deviceScaleFactor: captureOptions.deviceScaleFactor,
|
|
4106
|
-
headlessShellPath: resolveHeadlessShellPath(captureCfg)
|
|
4102
|
+
parallel: (input.workerCount ?? 1) > 1
|
|
4107
4103
|
});
|
|
4108
4104
|
return createCaptureSession2(
|
|
4109
4105
|
input.fileServer.url,
|
|
@@ -12192,7 +12188,7 @@ async function executeRenderPipeline(input) {
|
|
|
12192
12188
|
code: "start_browsers"
|
|
12193
12189
|
});
|
|
12194
12190
|
const resolvedBrowserGpuMode = await resolveBrowserGpuMode(cfg.browserGpuMode, {
|
|
12195
|
-
chromePath:
|
|
12191
|
+
chromePath: resolveHeadlessShellPath(cfg),
|
|
12196
12192
|
browserTimeout: cfg.browserTimeout
|
|
12197
12193
|
});
|
|
12198
12194
|
captureForceScreenshot = applyConcreteGpuScreenshotClamp(
|
|
@@ -12537,7 +12533,7 @@ async function executeRenderPipeline(input) {
|
|
|
12537
12533
|
}
|
|
12538
12534
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12539
12535
|
platform: process.platform,
|
|
12540
|
-
headlessShell:
|
|
12536
|
+
headlessShell: resolveHeadlessShellPath(cfg) !== null,
|
|
12541
12537
|
forceScreenshot: captureForceScreenshot,
|
|
12542
12538
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12543
12539
|
});
|
|
@@ -13703,12 +13699,12 @@ function resolveWorkerEntry2() {
|
|
|
13703
13699
|
}
|
|
13704
13700
|
|
|
13705
13701
|
// src/server.ts
|
|
13706
|
-
import { isVideoFrameFormat as isVideoFrameFormat3 } from "@hyperframes/engine";
|
|
13707
13702
|
import {
|
|
13708
13703
|
parseFps,
|
|
13709
13704
|
normalizeResolutionFlag,
|
|
13710
13705
|
isAspectAgnosticResolutionAlias
|
|
13711
13706
|
} from "@hyperframes/core";
|
|
13707
|
+
import { parseEncoderOptions } from "@hyperframes/studio-server/encoder-options";
|
|
13712
13708
|
|
|
13713
13709
|
// src/renderRequest.ts
|
|
13714
13710
|
import {
|
|
@@ -14018,13 +14014,16 @@ function parseRenderOptions(body) {
|
|
|
14018
14014
|
const entryFile = nonEmptyString(body.entryFile);
|
|
14019
14015
|
const format = parseServerFormat(body.format);
|
|
14020
14016
|
const outputDynamicRange = parseServerOutputDynamicRange(body.outputDynamicRange) ?? fromRenderHdrMode(parseLegacyServerHdrMode(body.hdrMode));
|
|
14021
|
-
const
|
|
14017
|
+
const encoder = parseEncoderOptions(body, format ?? "mp4");
|
|
14018
|
+
const { crf, videoBitrate, videoFrameFormat } = encoder.ok ? encoder.options : {};
|
|
14022
14019
|
const { variables, outputResolution, outputResolutionAspectAgnostic } = parseRenderOverrides(body);
|
|
14023
14020
|
return {
|
|
14024
14021
|
outputPath,
|
|
14025
14022
|
fps,
|
|
14026
14023
|
quality,
|
|
14027
14024
|
workers,
|
|
14025
|
+
crf,
|
|
14026
|
+
videoBitrate,
|
|
14028
14027
|
useGpu,
|
|
14029
14028
|
debug,
|
|
14030
14029
|
strictness,
|
|
@@ -14056,6 +14055,8 @@ function buildRenderJobConfig(input, outputPath, log) {
|
|
|
14056
14055
|
quality: input.quality,
|
|
14057
14056
|
format: input.format ?? "mp4",
|
|
14058
14057
|
workers: input.workers,
|
|
14058
|
+
crf: input.crf,
|
|
14059
|
+
videoBitrate: input.videoBitrate,
|
|
14059
14060
|
useGpu: input.useGpu,
|
|
14060
14061
|
debug: input.debug,
|
|
14061
14062
|
strictness: input.strictness,
|
|
@@ -14077,6 +14078,8 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
|
|
|
14077
14078
|
return { input, cleanupProjectDir, absoluteOutputPath };
|
|
14078
14079
|
}
|
|
14079
14080
|
function validateRenderOverrides(body) {
|
|
14081
|
+
const encoder = parseEncoderOptions(body, parseServerFormat(body.format) ?? "mp4");
|
|
14082
|
+
if (!encoder.ok) return encoder.error;
|
|
14080
14083
|
if (body.variables !== void 0 && !isPlainObject2(body.variables)) {
|
|
14081
14084
|
return 'variables must be a JSON object keyed by variable id (e.g. {"title":"Hello"})';
|
|
14082
14085
|
}
|
package/dist/server.d.ts
CHANGED
|
@@ -43,6 +43,8 @@ interface RenderInput {
|
|
|
43
43
|
videoFrameFormat?: RenderConfig["videoFrameFormat"];
|
|
44
44
|
outputDynamicRange?: "auto" | "hdr" | "sdr";
|
|
45
45
|
workers?: number;
|
|
46
|
+
crf?: number;
|
|
47
|
+
videoBitrate?: string;
|
|
46
48
|
useGpu: boolean;
|
|
47
49
|
debug: boolean;
|
|
48
50
|
strictness: RenderConfig["strictness"];
|
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
* for moving `outputPath` to its orchestration-level storage.
|
|
24
24
|
*/
|
|
25
25
|
import { type ProducerLogger } from "../../logger.js";
|
|
26
|
+
import type { LockedRenderConfig } from "../render/stages/freezePlan.js";
|
|
26
27
|
/**
|
|
27
28
|
* Result of {@link assemble}. `fileSize` reflects the final file on disk
|
|
28
29
|
* (mp4/mov) or the cumulative byte total of the frame directory
|
|
@@ -34,6 +35,8 @@ export interface AssembleResult {
|
|
|
34
35
|
framesEncoded: number;
|
|
35
36
|
fileSize: number;
|
|
36
37
|
}
|
|
38
|
+
type CfrRateControlSource = Partial<Pick<LockedRenderConfig, "quality" | "crf" | "bitrate">>;
|
|
39
|
+
export declare function cfrRateControlArgs(locked: CfrRateControlSource): string[];
|
|
37
40
|
/**
|
|
38
41
|
* Assemble the chunk outputs into a single deliverable.
|
|
39
42
|
*
|
|
@@ -60,10 +63,11 @@ export declare function assemble(planDir: string, chunkPaths: readonly string[],
|
|
|
60
63
|
* duration lands on the requested `frameCount / fps` to ms
|
|
61
64
|
* precision, with no PTS-derived drift). Trade-off: ~2-5x the
|
|
62
65
|
* stitch time for a 60s 1080p clip plus second-generation H.264
|
|
63
|
-
* quality loss (
|
|
66
|
+
* quality loss (at the chunks' own CRF or bitrate, non-zero). Default
|
|
64
67
|
* `false` preserves the existing `-c copy` behavior. mp4 only
|
|
65
68
|
* (libx264); webm / mov pass through unchanged because their
|
|
66
69
|
* stream-copy paths don't exhibit the same avg-frame-rate drift.
|
|
67
70
|
*/
|
|
68
71
|
cfr?: boolean;
|
|
69
72
|
}): Promise<AssembleResult>;
|
|
73
|
+
export {};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.155",
|
|
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/
|
|
38
|
+
"@hyperframes/core": "0.8.155",
|
|
39
|
+
"@hyperframes/engine": "0.8.155",
|
|
40
|
+
"@hyperframes/lint": "0.8.155",
|
|
41
|
+
"@hyperframes/parsers": "0.8.155",
|
|
42
|
+
"@hyperframes/studio-server": "0.8.155"
|
|
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.155"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|