fix(studio-server): the render route passes a MOV ProRes profile to the render (#6644)

* fix(studio-server): the render route passes a MOV ProRes profile to the render

* fix(studio-server): drop the added comment line so the comment share does not rise
This commit is contained in:
Miguel Ángel
2026-10-28 09:44:32 +00:00
committed by GitHub
parent 7758d9b8fd
commit 5a0179b88e
4 changed files with 31 additions and 1 deletions
@@ -41,6 +41,15 @@ describe("parseEncoderOptions", () => {
expect(parseEncoderOptions({ hdrMode: "on" }, "mp4").ok).toBe(false);
});
it("takes a ProRes profile for mov only, and rejects an unknown one", () => {
expect(parseEncoderOptions({ proresProfile: "hq" }, "mov")).toEqual({
ok: true,
options: { proresProfile: "hq" },
});
expect(parseEncoderOptions({ proresProfile: "hq" }, "mp4")).toEqual({ ok: true, options: {} });
expect(parseEncoderOptions({ proresProfile: "422hq" }, "mov").ok).toBe(false);
});
it("accepts a keyframe interval and a rate cap for mp4", () => {
expect(
parseEncoderOptions(
@@ -2,6 +2,7 @@ const CRF_MAX_BY_FORMAT: Record<string, number> = { mp4: 51, webm: 63 };
const VIDEO_BITRATE = /^\d+(\.\d+)?[kKmMgG]?$/;
const VIDEO_FRAME_FORMATS = ["auto", "jpg", "png"] as const;
const HDR_MODES = ["auto", "force-hdr", "force-sdr"] as const;
const PRORES_PROFILES = ["4444", "hq", "422", "lt", "proxy"] as const;
interface EncoderOptions {
gifLoop?: number;
@@ -9,6 +10,7 @@ interface EncoderOptions {
videoBitrate?: string;
videoFrameFormat?: (typeof VIDEO_FRAME_FORMATS)[number];
hdrMode?: (typeof HDR_MODES)[number];
proresProfile?: (typeof PRORES_PROFILES)[number];
keyframeIntervalSeconds?: number;
maxBitrate?: string;
bufferSize?: string;
@@ -20,6 +22,7 @@ export interface EncoderOptionsBody {
videoBitrate?: unknown;
videoFrameFormat?: unknown;
hdrMode?: unknown;
proresProfile?: unknown;
keyframeIntervalSeconds?: unknown;
maxBitrate?: unknown;
bufferSize?: unknown;
@@ -96,13 +99,23 @@ function parseDelivery(body: EncoderOptionsBody, format: string): Parsed {
return { ok: true, options };
}
function parseProres(value: unknown, format: string): Parsed {
if (!isSet(value)) return { ok: true, options: {} };
if (!oneOf(value, PRORES_PROFILES)) {
return { ok: false, error: `proresProfile must be one of ${PRORES_PROFILES.join(", ")}` };
}
return { ok: true, options: format === "mov" ? { proresProfile: value } : {} };
}
/** Explicit encoder overrides from a render request. MOV (ProRes) takes no rate control. */
export function parseEncoderOptions(body: EncoderOptionsBody, format: string): Parsed {
const rate = parseRateControl(body, format);
if (!rate.ok) return rate;
const delivery = parseDelivery(body, format);
if (!delivery.ok) return delivery;
const options: EncoderOptions = { ...rate.options, ...delivery.options };
const prores = parseProres(body.proresProfile, format);
if (!prores.ok) return prores;
const options: EncoderOptions = { ...rate.options, ...delivery.options, ...prores.options };
if (isSet(body.gifLoop)) {
if (
typeof body.gifLoop !== "number" ||
@@ -374,6 +374,13 @@ describe("POST /projects/:id/render — crf", () => {
expect(both.opts).toBeUndefined();
});
it("forwards a ProRes profile for mov to the render adapter and refuses an unknown one", async () => {
expect((await post({ format: "mov", proresProfile: "hq" })).opts.proresProfile).toBe("hq");
const unknown = await post({ format: "mov", proresProfile: "422hq" });
expect(unknown.res.status).toBe(400);
expect(unknown.opts).toBeUndefined();
});
it("forwards the keyframe interval and the rate cap to the render adapter", async () => {
const { res, opts } = await post({
format: "mp4",
+1
View File
@@ -183,6 +183,7 @@ export interface StudioApiAdapter {
bufferSize?: string;
videoFrameFormat?: "auto" | "jpg" | "png";
hdrMode?: "auto" | "force-hdr" | "force-sdr";
proresProfile?: "4444" | "hq" | "422" | "lt" | "proxy";
jobId: string;
/**
* The triggering browser profile has telemetry disabled (localStorage