mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-10-30 09:16:55 +00:00
fix(engine): h265 renders no longer fail on hosts with more than 16 cores (#6193)
* fix(engine): h265 renders no longer fail on hosts with more than 16 cores libx265 rejects more than 16 frame threads, so the thread count taken from the CPU quota is now capped at 16 for x265. x264 is unchanged. * fix(engine): pass the encoder to the thread cap in the CFR re-encode
This commit is contained in:
@@ -327,7 +327,7 @@ export function buildEncoderArgs(
|
||||
} else {
|
||||
const encoderName = codec === "h264" ? "libx264" : "libx265";
|
||||
args.push("-c:v", encoderName, "-preset", preset);
|
||||
appendSoftwareEncoderThreadsArg(args);
|
||||
appendSoftwareEncoderThreadsArg(args, encoderName);
|
||||
if (bitrate) args.push("-b:v", bitrate);
|
||||
else args.push("-crf", String(quality));
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ vi.mock("node:os", async (importOriginal) => ({
|
||||
|
||||
import { buildEncoderArgs } from "./chunkEncoder.js";
|
||||
import type { EncoderOptions } from "./chunkEncoder.types.js";
|
||||
import { appendSoftwareEncoderThreadsArg } from "./softwareEncoderThreads.js";
|
||||
import { appendSoftwareEncoderThreadsArg, X265_MAX_THREADS } from "./softwareEncoderThreads.js";
|
||||
import { buildStreamingArgs } from "./streamingEncoder.js";
|
||||
|
||||
const FFMPEG = getFfmpegBinary();
|
||||
@@ -42,11 +42,22 @@ const threadsOf = (args: string[]) => args[args.indexOf("-threads") + 1];
|
||||
describe("software encoder thread count", () => {
|
||||
it("takes the CPU quota and floors at one", () => {
|
||||
const args: string[] = [];
|
||||
appendSoftwareEncoderThreadsArg(args, 6.9);
|
||||
appendSoftwareEncoderThreadsArg(args, 0);
|
||||
appendSoftwareEncoderThreadsArg(args, "libx264", 6.9);
|
||||
appendSoftwareEncoderThreadsArg(args, "libx264", 0);
|
||||
expect(args).toEqual(["-threads", "6", "-threads", "1"]);
|
||||
});
|
||||
|
||||
it("caps libx265 at 16 threads and leaves libx264 uncapped", () => {
|
||||
const x265: string[] = [];
|
||||
const x264: string[] = [];
|
||||
appendSoftwareEncoderThreadsArg(x265, "libx265", 64);
|
||||
appendSoftwareEncoderThreadsArg(x264, "libx264", 64);
|
||||
expect([x265, x264]).toEqual([
|
||||
["-threads", "16"],
|
||||
["-threads", "64"],
|
||||
]);
|
||||
});
|
||||
|
||||
it.each(["h264", "h265"] as const)(
|
||||
"pins %s threads in both encoders to the quota, not the host",
|
||||
(codec) => {
|
||||
@@ -65,6 +76,28 @@ describe("software encoder thread count", () => {
|
||||
);
|
||||
});
|
||||
|
||||
describe.skipIf(!HAS_FFMPEG)("libx265 thread limit", () => {
|
||||
const encode = (threads: number) =>
|
||||
spawnSync(FFMPEG, [
|
||||
...QUIET,
|
||||
...SOURCE,
|
||||
"-frames:v",
|
||||
"4",
|
||||
"-c:v",
|
||||
"libx265",
|
||||
"-threads",
|
||||
String(threads),
|
||||
"-f",
|
||||
"null",
|
||||
"-",
|
||||
]).status;
|
||||
|
||||
it("rejects 17 threads and accepts the cap", () => {
|
||||
expect(encode(X265_MAX_THREADS + 1)).not.toBe(0);
|
||||
expect(encode(X265_MAX_THREADS)).toBe(0);
|
||||
}, 60_000);
|
||||
});
|
||||
|
||||
describe.skipIf(!HAS_TASKSET || !HAS_FFMPEG)("encoded bytes across host sizes", () => {
|
||||
const dirs: string[] = [];
|
||||
afterEach(() => {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import { availableParallelism } from "node:os";
|
||||
|
||||
export const X265_MAX_THREADS = 16;
|
||||
|
||||
/** x264/x265 bitstreams depend on the thread count, so it comes from the CPU quota, never ffmpeg's host-core guess. */
|
||||
export function appendSoftwareEncoderThreadsArg(
|
||||
args: string[],
|
||||
encoder: "libx264" | "libx265",
|
||||
parallelism: number = availableParallelism(),
|
||||
): void {
|
||||
args.push("-threads", String(Math.max(1, Math.floor(parallelism))));
|
||||
const cap = encoder === "libx265" ? X265_MAX_THREADS : Infinity;
|
||||
args.push("-threads", String(Math.min(cap, Math.max(1, Math.floor(parallelism)))));
|
||||
}
|
||||
|
||||
@@ -339,7 +339,7 @@ export function buildStreamingArgs(
|
||||
} else {
|
||||
const encoderName = codec === "h264" ? "libx264" : "libx265";
|
||||
args.push("-c:v", encoderName, "-preset", preset);
|
||||
appendSoftwareEncoderThreadsArg(args);
|
||||
appendSoftwareEncoderThreadsArg(args, encoderName);
|
||||
if (bitrate) args.push("-b:v", bitrate);
|
||||
else args.push("-crf", String(quality));
|
||||
|
||||
|
||||
@@ -285,7 +285,7 @@ export function cfrEncodeArgs(
|
||||
"-r",
|
||||
fpsArg,
|
||||
];
|
||||
appendSoftwareEncoderThreadsArg(args);
|
||||
appendSoftwareEncoderThreadsArg(args, "libx264");
|
||||
return args;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user