@hyperframes/producer 0.8.154 → 0.8.156
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/hyperframe.manifest.json +1 -1
- package/dist/hyperframe.runtime.iife.js +35 -35
- package/dist/index.js +36 -18
- package/dist/public-server.js +22 -11
- package/dist/server.d.ts +2 -0
- package/dist/services/distributed/assemble.d.ts +5 -1
- package/dist/services/render/videoFrameCoverage.d.ts +3 -3
- package/package.json +7 -7
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,
|
|
@@ -4128,6 +4124,14 @@ async function createSegmentWorker(run, id) {
|
|
|
4128
4124
|
}
|
|
4129
4125
|
};
|
|
4130
4126
|
}
|
|
4127
|
+
async function openSegmentWorkersTogether(run, workersToCloseLater) {
|
|
4128
|
+
const opened = await Promise.allSettled(
|
|
4129
|
+
Array.from({ length: run.workerCount }, (_, id) => createSegmentWorker(run, id))
|
|
4130
|
+
);
|
|
4131
|
+
for (const o of opened) if (o.status === "fulfilled") workersToCloseLater.push(o.value);
|
|
4132
|
+
const failure = opened.find((o) => o.status === "rejected");
|
|
4133
|
+
if (failure && failure.status === "rejected") throw failure.reason;
|
|
4134
|
+
}
|
|
4131
4135
|
async function recycleWorkerSession(run, worker, why) {
|
|
4132
4136
|
run.input.dedupPerfs.push(getCapturePerfSummary2(worker.ctx.session));
|
|
4133
4137
|
const memory = worker.ctx.session.chromeMemory?.stats();
|
|
@@ -4250,7 +4254,7 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4250
4254
|
};
|
|
4251
4255
|
try {
|
|
4252
4256
|
assertNotAborted();
|
|
4253
|
-
|
|
4257
|
+
await openSegmentWorkersTogether(run, workers);
|
|
4254
4258
|
const outcomes = await Promise.allSettled(workers.map((w) => runWorkerLoop(w)));
|
|
4255
4259
|
for (const worker of workers) dedupPerfs.push(getCapturePerfSummary2(worker.ctx.session));
|
|
4256
4260
|
const failure = outcomes.find((o) => o.status === "rejected");
|
|
@@ -12209,7 +12213,7 @@ async function executeRenderPipeline(input) {
|
|
|
12209
12213
|
code: "start_browsers"
|
|
12210
12214
|
});
|
|
12211
12215
|
const resolvedBrowserGpuMode = await resolveBrowserGpuMode(cfg.browserGpuMode, {
|
|
12212
|
-
chromePath:
|
|
12216
|
+
chromePath: resolveHeadlessShellPath(cfg),
|
|
12213
12217
|
browserTimeout: cfg.browserTimeout
|
|
12214
12218
|
});
|
|
12215
12219
|
captureForceScreenshot = applyConcreteGpuScreenshotClamp(
|
|
@@ -12554,7 +12558,7 @@ async function executeRenderPipeline(input) {
|
|
|
12554
12558
|
}
|
|
12555
12559
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12556
12560
|
platform: process.platform,
|
|
12557
|
-
headlessShell:
|
|
12561
|
+
headlessShell: resolveHeadlessShellPath(cfg) !== null,
|
|
12558
12562
|
forceScreenshot: captureForceScreenshot,
|
|
12559
12563
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12560
12564
|
});
|
|
@@ -14241,12 +14245,12 @@ function resolveWorkerEntry2() {
|
|
|
14241
14245
|
}
|
|
14242
14246
|
|
|
14243
14247
|
// src/server.ts
|
|
14244
|
-
import { isVideoFrameFormat as isVideoFrameFormat3 } from "@hyperframes/engine";
|
|
14245
14248
|
import {
|
|
14246
14249
|
parseFps,
|
|
14247
14250
|
normalizeResolutionFlag,
|
|
14248
14251
|
isAspectAgnosticResolutionAlias
|
|
14249
14252
|
} from "@hyperframes/core";
|
|
14253
|
+
import { parseEncoderOptions } from "@hyperframes/studio-server/encoder-options";
|
|
14250
14254
|
var DEFAULT_SERVER_FPS = { num: 30, den: 1 };
|
|
14251
14255
|
var SAFE_RENDER_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
14252
14256
|
"ASSET_MEDIA_TYPE_MISMATCH",
|
|
@@ -14320,13 +14324,16 @@ function parseRenderOptions(body) {
|
|
|
14320
14324
|
const entryFile = nonEmptyString(body.entryFile);
|
|
14321
14325
|
const format = parseServerFormat(body.format);
|
|
14322
14326
|
const outputDynamicRange = parseServerOutputDynamicRange(body.outputDynamicRange) ?? fromRenderHdrMode(parseLegacyServerHdrMode(body.hdrMode));
|
|
14323
|
-
const
|
|
14327
|
+
const encoder = parseEncoderOptions(body, format ?? "mp4");
|
|
14328
|
+
const { crf, videoBitrate, videoFrameFormat } = encoder.ok ? encoder.options : {};
|
|
14324
14329
|
const { variables, outputResolution, outputResolutionAspectAgnostic } = parseRenderOverrides(body);
|
|
14325
14330
|
return {
|
|
14326
14331
|
outputPath,
|
|
14327
14332
|
fps,
|
|
14328
14333
|
quality,
|
|
14329
14334
|
workers,
|
|
14335
|
+
crf,
|
|
14336
|
+
videoBitrate,
|
|
14330
14337
|
useGpu,
|
|
14331
14338
|
debug,
|
|
14332
14339
|
strictness,
|
|
@@ -14358,6 +14365,8 @@ function buildRenderJobConfig(input, outputPath, log) {
|
|
|
14358
14365
|
quality: input.quality,
|
|
14359
14366
|
format: input.format ?? "mp4",
|
|
14360
14367
|
workers: input.workers,
|
|
14368
|
+
crf: input.crf,
|
|
14369
|
+
videoBitrate: input.videoBitrate,
|
|
14361
14370
|
useGpu: input.useGpu,
|
|
14362
14371
|
debug: input.debug,
|
|
14363
14372
|
strictness: input.strictness,
|
|
@@ -14379,6 +14388,8 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
|
|
|
14379
14388
|
return { input, cleanupProjectDir, absoluteOutputPath };
|
|
14380
14389
|
}
|
|
14381
14390
|
function validateRenderOverrides(body) {
|
|
14391
|
+
const encoder = parseEncoderOptions(body, parseServerFormat(body.format) ?? "mp4");
|
|
14392
|
+
if (!encoder.ok) return encoder.error;
|
|
14382
14393
|
if (body.variables !== void 0 && !isPlainObject2(body.variables)) {
|
|
14383
14394
|
return 'variables must be a JSON object keyed by variable id (e.g. {"title":"Hello"})';
|
|
14384
14395
|
}
|
|
@@ -17083,12 +17094,20 @@ import {
|
|
|
17083
17094
|
appendRenderProvenanceArgs,
|
|
17084
17095
|
applyFaststart as applyFaststart2,
|
|
17085
17096
|
describeFfmpegFailure as describeFfmpegFailure2,
|
|
17097
|
+
getEncoderPreset as getEncoderPreset5,
|
|
17086
17098
|
MIXED_AUDIO_FILENAME as MIXED_AUDIO_FILENAME4,
|
|
17087
17099
|
muxVideoWithAudio as muxVideoWithAudio2,
|
|
17088
17100
|
resolveConfig as resolveConfig6,
|
|
17089
17101
|
runFfmpeg as runFfmpeg5
|
|
17090
17102
|
} from "@hyperframes/engine";
|
|
17091
17103
|
import { fpsToFfmpegArg as fpsToFfmpegArg3 } from "@hyperframes/core";
|
|
17104
|
+
function cfrRateControlArgs(locked) {
|
|
17105
|
+
const preset = getEncoderPreset5(locked.quality ?? "standard", "mp4");
|
|
17106
|
+
if (locked.crf == null && locked.bitrate) {
|
|
17107
|
+
return ["-preset", preset.preset, "-b:v", locked.bitrate];
|
|
17108
|
+
}
|
|
17109
|
+
return ["-preset", preset.preset, "-crf", String(locked.crf ?? preset.quality)];
|
|
17110
|
+
}
|
|
17092
17111
|
async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
17093
17112
|
const start = Date.now();
|
|
17094
17113
|
const log = options?.logger ?? defaultLogger;
|
|
@@ -17185,7 +17204,9 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
17185
17204
|
if (!existsSync25(encoderJsonPath)) {
|
|
17186
17205
|
throw new Error(`[assemble] planDir missing meta/encoder.json: ${encoderJsonPath}`);
|
|
17187
17206
|
}
|
|
17188
|
-
const encoderJson = JSON.parse(
|
|
17207
|
+
const encoderJson = JSON.parse(
|
|
17208
|
+
readFileSync13(encoderJsonPath, "utf-8")
|
|
17209
|
+
);
|
|
17189
17210
|
if (encoderJson.encoder === "libx265-software") {
|
|
17190
17211
|
throw new Error(
|
|
17191
17212
|
`[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 +17218,7 @@ async function assemble(planDir, chunkPaths, audioPath, outputPath, options) {
|
|
|
17197
17218
|
concatOutputPath,
|
|
17198
17219
|
"-c:v",
|
|
17199
17220
|
"libx264",
|
|
17200
|
-
|
|
17201
|
-
"medium",
|
|
17202
|
-
"-crf",
|
|
17203
|
-
"18",
|
|
17221
|
+
...cfrRateControlArgs(encoderJson),
|
|
17204
17222
|
"-pix_fmt",
|
|
17205
17223
|
"yuv420p",
|
|
17206
17224
|
"-fps_mode",
|
|
@@ -17352,7 +17370,7 @@ import {
|
|
|
17352
17370
|
createVideoFrameInjector as createVideoFrameInjector2,
|
|
17353
17371
|
deriveBeginFrameProbeTimeTicks as deriveBeginFrameProbeTimeTicks2,
|
|
17354
17372
|
extractVideoFramesRange,
|
|
17355
|
-
getEncoderPreset as
|
|
17373
|
+
getEncoderPreset as getEncoderPreset6,
|
|
17356
17374
|
initializeSession as initializeSession9,
|
|
17357
17375
|
probeBeginFrameLiveness as probeBeginFrameLiveness2,
|
|
17358
17376
|
readWebGlVendorInfoFromCanvas,
|
|
@@ -17903,7 +17921,7 @@ async function renderChunk(planDir, chunkIndex, outputChunkPath) {
|
|
|
17903
17921
|
const isPngSequence = plan2.dimensions.format === "png-sequence";
|
|
17904
17922
|
outputKind = isPngSequence ? "frame-dir" : "file";
|
|
17905
17923
|
const presetFormat = isPngSequence ? "mp4" : plan2.dimensions.format;
|
|
17906
|
-
const basePreset =
|
|
17924
|
+
const basePreset = getEncoderPreset6(job.config.quality, presetFormat, void 0);
|
|
17907
17925
|
const preset = resolvePresetForLockedEncoder(basePreset, encoder.encoder);
|
|
17908
17926
|
const effectiveQuality = encoder.crf ?? preset.quality;
|
|
17909
17927
|
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,
|
|
@@ -4147,6 +4143,14 @@ async function createSegmentWorker(run, id) {
|
|
|
4147
4143
|
}
|
|
4148
4144
|
};
|
|
4149
4145
|
}
|
|
4146
|
+
async function openSegmentWorkersTogether(run, workersToCloseLater) {
|
|
4147
|
+
const opened = await Promise.allSettled(
|
|
4148
|
+
Array.from({ length: run.workerCount }, (_, id) => createSegmentWorker(run, id))
|
|
4149
|
+
);
|
|
4150
|
+
for (const o of opened) if (o.status === "fulfilled") workersToCloseLater.push(o.value);
|
|
4151
|
+
const failure = opened.find((o) => o.status === "rejected");
|
|
4152
|
+
if (failure && failure.status === "rejected") throw failure.reason;
|
|
4153
|
+
}
|
|
4150
4154
|
async function recycleWorkerSession(run, worker, why) {
|
|
4151
4155
|
run.input.dedupPerfs.push(getCapturePerfSummary2(worker.ctx.session));
|
|
4152
4156
|
const memory = worker.ctx.session.chromeMemory?.stats();
|
|
@@ -4269,7 +4273,7 @@ async function runCaptureSegmentedStage(input) {
|
|
|
4269
4273
|
};
|
|
4270
4274
|
try {
|
|
4271
4275
|
assertNotAborted();
|
|
4272
|
-
|
|
4276
|
+
await openSegmentWorkersTogether(run, workers);
|
|
4273
4277
|
const outcomes = await Promise.allSettled(workers.map((w) => runWorkerLoop(w)));
|
|
4274
4278
|
for (const worker of workers) dedupPerfs.push(getCapturePerfSummary2(worker.ctx.session));
|
|
4275
4279
|
const failure = outcomes.find((o) => o.status === "rejected");
|
|
@@ -12192,7 +12196,7 @@ async function executeRenderPipeline(input) {
|
|
|
12192
12196
|
code: "start_browsers"
|
|
12193
12197
|
});
|
|
12194
12198
|
const resolvedBrowserGpuMode = await resolveBrowserGpuMode(cfg.browserGpuMode, {
|
|
12195
|
-
chromePath:
|
|
12199
|
+
chromePath: resolveHeadlessShellPath(cfg),
|
|
12196
12200
|
browserTimeout: cfg.browserTimeout
|
|
12197
12201
|
});
|
|
12198
12202
|
captureForceScreenshot = applyConcreteGpuScreenshotClamp(
|
|
@@ -12537,7 +12541,7 @@ async function executeRenderPipeline(input) {
|
|
|
12537
12541
|
}
|
|
12538
12542
|
const parallelCaptureMode = resolveParallelCaptureMode({
|
|
12539
12543
|
platform: process.platform,
|
|
12540
|
-
headlessShell:
|
|
12544
|
+
headlessShell: resolveHeadlessShellPath(cfg) !== null,
|
|
12541
12545
|
forceScreenshot: captureForceScreenshot,
|
|
12542
12546
|
deviceScaleFactor: captureOptions.deviceScaleFactor
|
|
12543
12547
|
});
|
|
@@ -13703,12 +13707,12 @@ function resolveWorkerEntry2() {
|
|
|
13703
13707
|
}
|
|
13704
13708
|
|
|
13705
13709
|
// src/server.ts
|
|
13706
|
-
import { isVideoFrameFormat as isVideoFrameFormat3 } from "@hyperframes/engine";
|
|
13707
13710
|
import {
|
|
13708
13711
|
parseFps,
|
|
13709
13712
|
normalizeResolutionFlag,
|
|
13710
13713
|
isAspectAgnosticResolutionAlias
|
|
13711
13714
|
} from "@hyperframes/core";
|
|
13715
|
+
import { parseEncoderOptions } from "@hyperframes/studio-server/encoder-options";
|
|
13712
13716
|
|
|
13713
13717
|
// src/renderRequest.ts
|
|
13714
13718
|
import {
|
|
@@ -14018,13 +14022,16 @@ function parseRenderOptions(body) {
|
|
|
14018
14022
|
const entryFile = nonEmptyString(body.entryFile);
|
|
14019
14023
|
const format = parseServerFormat(body.format);
|
|
14020
14024
|
const outputDynamicRange = parseServerOutputDynamicRange(body.outputDynamicRange) ?? fromRenderHdrMode(parseLegacyServerHdrMode(body.hdrMode));
|
|
14021
|
-
const
|
|
14025
|
+
const encoder = parseEncoderOptions(body, format ?? "mp4");
|
|
14026
|
+
const { crf, videoBitrate, videoFrameFormat } = encoder.ok ? encoder.options : {};
|
|
14022
14027
|
const { variables, outputResolution, outputResolutionAspectAgnostic } = parseRenderOverrides(body);
|
|
14023
14028
|
return {
|
|
14024
14029
|
outputPath,
|
|
14025
14030
|
fps,
|
|
14026
14031
|
quality,
|
|
14027
14032
|
workers,
|
|
14033
|
+
crf,
|
|
14034
|
+
videoBitrate,
|
|
14028
14035
|
useGpu,
|
|
14029
14036
|
debug,
|
|
14030
14037
|
strictness,
|
|
@@ -14056,6 +14063,8 @@ function buildRenderJobConfig(input, outputPath, log) {
|
|
|
14056
14063
|
quality: input.quality,
|
|
14057
14064
|
format: input.format ?? "mp4",
|
|
14058
14065
|
workers: input.workers,
|
|
14066
|
+
crf: input.crf,
|
|
14067
|
+
videoBitrate: input.videoBitrate,
|
|
14059
14068
|
useGpu: input.useGpu,
|
|
14060
14069
|
debug: input.debug,
|
|
14061
14070
|
strictness: input.strictness,
|
|
@@ -14077,6 +14086,8 @@ function resolvePreparedRenderOutput(prepared, rendersDir, log) {
|
|
|
14077
14086
|
return { input, cleanupProjectDir, absoluteOutputPath };
|
|
14078
14087
|
}
|
|
14079
14088
|
function validateRenderOverrides(body) {
|
|
14089
|
+
const encoder = parseEncoderOptions(body, parseServerFormat(body.format) ?? "mp4");
|
|
14090
|
+
if (!encoder.ok) return encoder.error;
|
|
14080
14091
|
if (body.variables !== void 0 && !isPlainObject2(body.variables)) {
|
|
14081
14092
|
return 'variables must be a JSON object keyed by variable id (e.g. {"title":"Hello"})';
|
|
14082
14093
|
}
|
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 {};
|
|
@@ -84,9 +84,9 @@ export declare function isVideoFrameCoverageError(err: unknown): err is VideoFra
|
|
|
84
84
|
*/
|
|
85
85
|
export declare function resolveVideoCoverageThreshold(envValue?: string | undefined): number | null;
|
|
86
86
|
/**
|
|
87
|
-
* Count frames in a clip's authored `[start,end)` window. CFR extraction
|
|
88
|
-
*
|
|
89
|
-
*
|
|
87
|
+
* Count frames in a clip's authored `[start,end)` window. CFR extraction
|
|
88
|
+
* rounds to the nearest output-frame boundary and VFR extraction rounds up,
|
|
89
|
+
* as `extractionFrameCountForDuration` does. Missing entries
|
|
90
90
|
* retain the fail-closed `ceil` default. Positive sub-frame clips emit one.
|
|
91
91
|
*/
|
|
92
92
|
export declare function expectedFramesForClip(start: number, end: number, fps: FpsInput, rounding?: "ceil" | "nearest"): number;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hyperframes/producer",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.156",
|
|
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/engine": "0.8.
|
|
39
|
-
"@hyperframes/
|
|
40
|
-
"@hyperframes/
|
|
41
|
-
"@hyperframes/
|
|
42
|
-
"@hyperframes/
|
|
38
|
+
"@hyperframes/engine": "0.8.156",
|
|
39
|
+
"@hyperframes/parsers": "0.8.156",
|
|
40
|
+
"@hyperframes/core": "0.8.156",
|
|
41
|
+
"@hyperframes/lint": "0.8.156",
|
|
42
|
+
"@hyperframes/studio-server": "0.8.156"
|
|
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.156"
|
|
52
52
|
},
|
|
53
53
|
"engines": {
|
|
54
54
|
"node": ">=22"
|