mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 14:50:02 +00:00
fix: bound HDR and video extraction resources (#2955)
* fix: bound HDR and video extraction resources * fix: trim negative video extraction preroll * fix: skip invisible video extraction windows * fix: preserve negative-start loop and held tails * fix: cap finite video slots to source duration * fix: bound held-tail frame extraction * fix: plan from playable video duration * fix: preserve open-ended held video tails * fix: resolve held tails from decoded frames * fix: normalize final-frame probe timestamps * fix: handle unseekable final-frame sources * fix: dedupe final-frame probes per render * refactor: clarify output dynamic range contract
This commit is contained in:
@@ -84,6 +84,7 @@ interface RenderInput {
|
||||
quality: "draft" | "standard" | "high";
|
||||
format?: "mp4" | "webm" | "mov";
|
||||
videoFrameFormat?: RenderConfig["videoFrameFormat"];
|
||||
outputDynamicRange?: "auto" | "hdr" | "sdr";
|
||||
workers?: number;
|
||||
useGpu: boolean;
|
||||
debug: boolean;
|
||||
@@ -158,6 +159,28 @@ function parseServerFormat(value: unknown): RenderInput["format"] {
|
||||
return value === "mp4" || value === "webm" || value === "mov" ? value : undefined;
|
||||
}
|
||||
|
||||
function parseServerOutputDynamicRange(value: unknown): RenderInput["outputDynamicRange"] {
|
||||
return value === "auto" || value === "hdr" || value === "sdr" ? value : undefined;
|
||||
}
|
||||
|
||||
function parseLegacyServerHdrMode(value: unknown): RenderConfig["hdrMode"] {
|
||||
return value === "auto" || value === "force-hdr" || value === "force-sdr" ? value : undefined;
|
||||
}
|
||||
|
||||
function fromRenderHdrMode(hdrMode: RenderConfig["hdrMode"]): RenderInput["outputDynamicRange"] {
|
||||
if (hdrMode === "force-hdr") return "hdr";
|
||||
if (hdrMode === "force-sdr") return "sdr";
|
||||
return hdrMode;
|
||||
}
|
||||
|
||||
function toRenderHdrMode(
|
||||
outputDynamicRange: RenderInput["outputDynamicRange"],
|
||||
): RenderConfig["hdrMode"] {
|
||||
if (outputDynamicRange === "hdr") return "force-hdr";
|
||||
if (outputDynamicRange === "sdr") return "force-sdr";
|
||||
return outputDynamicRange;
|
||||
}
|
||||
|
||||
export function parseRenderOptions(body: Record<string, unknown>): Omit<RenderInput, "projectDir"> {
|
||||
// Accept either a JSON `number` (integer fps) or a JSON `string` (rational
|
||||
// like "30000/1001"). Falls back to 30 fps on parse failure to preserve the
|
||||
@@ -176,6 +199,9 @@ export function parseRenderOptions(body: Record<string, unknown>): Omit<RenderIn
|
||||
const outputPath = parseOutputCandidate(body);
|
||||
const entryFile = nonEmptyString(body.entryFile);
|
||||
const format = parseServerFormat(body.format);
|
||||
const outputDynamicRange =
|
||||
parseServerOutputDynamicRange(body.outputDynamicRange) ??
|
||||
fromRenderHdrMode(parseLegacyServerHdrMode(body.hdrMode));
|
||||
const videoFrameFormat = isVideoFrameFormat(body.videoFrameFormat)
|
||||
? body.videoFrameFormat
|
||||
: undefined;
|
||||
@@ -193,6 +219,7 @@ export function parseRenderOptions(body: Record<string, unknown>): Omit<RenderIn
|
||||
strictness,
|
||||
entryFile,
|
||||
format,
|
||||
outputDynamicRange,
|
||||
variables,
|
||||
outputResolution,
|
||||
outputResolutionAspectAgnostic,
|
||||
@@ -254,6 +281,7 @@ function buildRenderJobConfig(input: RenderInput, outputPath: string, log: Produ
|
||||
outputResolution: input.outputResolution,
|
||||
outputResolutionAspectAgnostic: input.outputResolutionAspectAgnostic,
|
||||
videoFrameFormat: input.videoFrameFormat,
|
||||
hdrMode: toRenderHdrMode(input.outputDynamicRange),
|
||||
},
|
||||
});
|
||||
return renderConfigFromRequest(request, { logger: log });
|
||||
@@ -286,6 +314,24 @@ function validateRenderOverrides(body: Record<string, unknown>): string | undefi
|
||||
if (body.variables !== undefined && !isPlainObject(body.variables)) {
|
||||
return 'variables must be a JSON object keyed by variable id (e.g. {"title":"Hello"})';
|
||||
}
|
||||
if (
|
||||
body.outputDynamicRange !== undefined &&
|
||||
parseServerOutputDynamicRange(body.outputDynamicRange) === undefined
|
||||
) {
|
||||
return 'outputDynamicRange must be one of: "auto", "hdr", "sdr"';
|
||||
}
|
||||
const legacyHdrMode = parseLegacyServerHdrMode(body.hdrMode);
|
||||
if (body.hdrMode !== undefined && legacyHdrMode === undefined) {
|
||||
return 'legacy hdrMode must be one of: "auto", "force-hdr", "force-sdr"';
|
||||
}
|
||||
const outputDynamicRange = parseServerOutputDynamicRange(body.outputDynamicRange);
|
||||
if (
|
||||
outputDynamicRange !== undefined &&
|
||||
legacyHdrMode !== undefined &&
|
||||
outputDynamicRange !== fromRenderHdrMode(legacyHdrMode)
|
||||
) {
|
||||
return "outputDynamicRange and legacy hdrMode must describe the same output policy";
|
||||
}
|
||||
return validateOutputResolutionOverride(body);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user