mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 17:27:09 +00:00
fix(producer): forward GPU preference to HDR streaming encoder (#5030)
This commit is contained in:
@@ -267,6 +267,7 @@ export async function runCaptureHdrStage(
|
||||
width,
|
||||
height,
|
||||
codec: preset.codec,
|
||||
useGpu: job.config.useGpu,
|
||||
preset: preset.preset,
|
||||
quality: effectiveQuality,
|
||||
bitrate: effectiveBitrate,
|
||||
|
||||
@@ -9,6 +9,7 @@ const framesDir = join(fixtureRoot, "frames");
|
||||
afterAll(() => rmSync(fixtureRoot, { recursive: true, force: true }));
|
||||
import { getCaptureStageBrowserConsole } from "../captureStageError.js";
|
||||
import { createCapturePlan } from "../capturePlan.js";
|
||||
import type { CaptureHdrStageInput } from "./captureHdrStage.js";
|
||||
|
||||
type MinimalEngineConfig = {
|
||||
forceScreenshot: boolean;
|
||||
@@ -72,6 +73,7 @@ mock.module("@hyperframes/engine", () => ({
|
||||
return { buffer: Buffer.from("frame"), captureTimeMs: 1 };
|
||||
},
|
||||
closeCaptureSession,
|
||||
cloneCaptureWarnings: () => [],
|
||||
completeDeferredDrawElementInit: async () => {},
|
||||
createCaptureSession: async () => ({
|
||||
isInitialized: false,
|
||||
@@ -79,6 +81,12 @@ mock.module("@hyperframes/engine", () => ({
|
||||
options: { captureBeyondViewport: false },
|
||||
workerEncodeEnabled: sessionWorkerEncodeEnabled,
|
||||
captureMode: captureSessionMode,
|
||||
page: {
|
||||
evaluate: mock(async (): Promise<unknown> => [])
|
||||
.mockResolvedValueOnce([])
|
||||
.mockResolvedValueOnce({}),
|
||||
},
|
||||
warnings: [],
|
||||
}),
|
||||
createFrameReorderBuffer: () => ({
|
||||
waitForFrame: async () => {},
|
||||
@@ -753,6 +761,94 @@ describe("runCaptureStage", () => {
|
||||
});
|
||||
|
||||
describe("runCaptureHdrStage", () => {
|
||||
function createHdrInput(useGpu: boolean | undefined): CaptureHdrStageInput {
|
||||
const plan = createCapturePlan({
|
||||
workerCount: 1,
|
||||
forceScreenshot: true,
|
||||
useStreamingEncode: false,
|
||||
useLayeredComposite: true,
|
||||
usePageSideCompositing: false,
|
||||
hasHdrContent: true,
|
||||
needsAlpha: false,
|
||||
});
|
||||
if (plan.kind !== "hdr_layered") throw new Error("Expected an HDR layered capture plan");
|
||||
return {
|
||||
job: {
|
||||
id: "capture-hdr-stage-test",
|
||||
config: { fps: { num: 30, den: 1 }, quality: "draft", useGpu },
|
||||
status: "queued",
|
||||
progress: 0,
|
||||
currentStage: "HDR Capture",
|
||||
createdAt: new Date(0),
|
||||
duration: 1,
|
||||
},
|
||||
cfg: { forceScreenshot: true },
|
||||
plan,
|
||||
log: { error: () => {}, warn: () => {}, info: () => {}, debug: () => {} },
|
||||
projectDir: fixtureRoot,
|
||||
compiledDir: fixtureRoot,
|
||||
framesDir,
|
||||
videoOnlyPath: join(fixtureRoot, "video-only.mp4"),
|
||||
width: 64,
|
||||
height: 64,
|
||||
totalFrames: 1,
|
||||
composition: { duration: 1, videos: [], audios: [], images: [], width: 64, height: 64 },
|
||||
hasHdrContent: true,
|
||||
effectiveHdr: { transfer: "pq" },
|
||||
nativeHdrVideoIds: new Set<string>(),
|
||||
nativeHdrImageIds: new Set<string>(),
|
||||
videoTransfers: new Map(),
|
||||
imageTransfers: new Map(),
|
||||
hdrImageSrcPaths: new Map(),
|
||||
preset: {
|
||||
preset: "ultrafast",
|
||||
quality: 28,
|
||||
codec: "h265",
|
||||
pixelFormat: "yuv420p10le",
|
||||
hdr: { transfer: "pq" },
|
||||
},
|
||||
effectiveQuality: 28,
|
||||
effectiveBitrate: undefined,
|
||||
fileServer: {
|
||||
url: "http://127.0.0.1:4173",
|
||||
port: 4173,
|
||||
close: () => {},
|
||||
addPreHeadScript: () => {},
|
||||
},
|
||||
buildCaptureOptions: () => ({}),
|
||||
createRenderVideoFrameInjector: () => null,
|
||||
hdrDiagnostics: { videoExtractionFailures: 0, imageDecodeFailures: 0 },
|
||||
abortSignal: undefined,
|
||||
assertNotAborted: () => {},
|
||||
};
|
||||
}
|
||||
|
||||
it.each([true, false, undefined])("forwards useGpu=%s to the HDR encoder", async (useGpu) => {
|
||||
failCaptureFrameToBuffer = false;
|
||||
failInitializeSession = false;
|
||||
spawnStreamingEncoder.mockClear();
|
||||
closeEncoder.mockClear();
|
||||
const { runCaptureHdrStage } = await import("./captureHdrStage.js");
|
||||
const input = createHdrInput(useGpu);
|
||||
|
||||
const result = await runCaptureHdrStage(input);
|
||||
|
||||
expect(spawnStreamingEncoder).toHaveBeenCalledTimes(1);
|
||||
expect(spawnStreamingEncoder).toHaveBeenCalledWith(
|
||||
input.videoOnlyPath,
|
||||
expect.objectContaining({
|
||||
useGpu,
|
||||
codec: "h265",
|
||||
hdr: { transfer: "pq" },
|
||||
rawInputFormat: "rgb48le",
|
||||
}),
|
||||
undefined,
|
||||
{ ffmpegStreamingTimeout: 3_600_000 },
|
||||
);
|
||||
expect(closeEncoder).toHaveBeenCalledTimes(1);
|
||||
expect(result.encodeMs).toBe(123);
|
||||
});
|
||||
|
||||
it("wraps HDR capture failures with the browser console buffer", async () => {
|
||||
failCaptureFrameToBuffer = false;
|
||||
failInitializeSession = true;
|
||||
|
||||
Reference in New Issue
Block a user