mirror of
https://github.com/C4illin/ConvertX.git
synced 2026-11-06 05:24:20 +01:00
fix(ffmpeg): raise execFile maxBuffer so long conversions don't overflow stderr (#629)
This commit is contained in:
@@ -1,5 +1,22 @@
|
||||
import { execFile as execFileOriginal } from "node:child_process";
|
||||
import { ExecFileFn } from "./types";
|
||||
import {
|
||||
execFile as execFileOriginal,
|
||||
type ChildProcess,
|
||||
type ExecFileOptions,
|
||||
} from "node:child_process";
|
||||
|
||||
// ffmpeg streams continuous progress to stderr, so a long conversion overflows
|
||||
// execFile's 1 MB default maxBuffer and fails with "stderr maxBuffer length
|
||||
// exceeded" (issue #565). Raise it well above that. The options object must be
|
||||
// passed before the callback: execFile ignores an options argument placed after
|
||||
// the callback, which is why the shared ExecFileFn type cannot carry it.
|
||||
const FFMPEG_MAX_BUFFER = 1024 * 1024 * 64; // 64 MB
|
||||
|
||||
type FfmpegExecFile = (
|
||||
cmd: string,
|
||||
args: string[],
|
||||
options: ExecFileOptions,
|
||||
callback: (err: Error | null, stdout: string, stderr: string) => void,
|
||||
) => ChildProcess | void;
|
||||
|
||||
// This could be done dynamically by running `ffmpeg -formats` and parsing the output
|
||||
export const properties = {
|
||||
@@ -694,7 +711,7 @@ export async function convert(
|
||||
convertTo: string,
|
||||
targetPath: string,
|
||||
options?: unknown,
|
||||
execFile: ExecFileFn = execFileOriginal, // to make it mockable
|
||||
execFile: FfmpegExecFile = execFileOriginal as FfmpegExecFile, // to make it mockable
|
||||
): Promise<string> {
|
||||
let extraArgs: string[] = [];
|
||||
let message = "Done";
|
||||
@@ -739,6 +756,7 @@ export async function convert(
|
||||
execFile(
|
||||
"ffmpeg",
|
||||
[...ffmpegArgs, "-i", filePath, ...ffmpegOutputArgs, ...extraArgs, targetPath],
|
||||
{ maxBuffer: FFMPEG_MAX_BUFFER },
|
||||
(error, stdout, stderr) => {
|
||||
if (error) {
|
||||
reject(`error: ${error}`);
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
import { beforeEach, expect, test } from "bun:test";
|
||||
import { convert } from "../../src/converters/ffmpeg";
|
||||
import type { ExecFileOptions } from "node:child_process";
|
||||
|
||||
let calls: string[][] = [];
|
||||
let lastOptions: ExecFileOptions | undefined;
|
||||
|
||||
function mockExecFile(
|
||||
_cmd: string,
|
||||
args: string[],
|
||||
options: ExecFileOptions,
|
||||
callback: (err: Error | null, stdout: string, stderr: string) => void,
|
||||
) {
|
||||
calls.push(args);
|
||||
lastOptions = options;
|
||||
if (args.includes("fail.mov")) {
|
||||
callback(new Error("mock failure"), "", "Fake stderr: fail");
|
||||
} else {
|
||||
@@ -18,6 +22,7 @@ function mockExecFile(
|
||||
|
||||
beforeEach(() => {
|
||||
calls = [];
|
||||
lastOptions = undefined;
|
||||
delete process.env.FFMPEG_ARGS;
|
||||
});
|
||||
|
||||
@@ -168,6 +173,7 @@ test("logs stderr when execFile returns only stderr and no error", async () => {
|
||||
const mockExecFileStderrOnly = (
|
||||
_cmd: string,
|
||||
_args: string[],
|
||||
_options: ExecFileOptions,
|
||||
callback: (err: Error | null, stdout: string, stderr: string) => void,
|
||||
) => {
|
||||
callback(null, "", "Only stderr output");
|
||||
@@ -179,3 +185,13 @@ test("logs stderr when execFile returns only stderr and no error", async () => {
|
||||
|
||||
expect(loggedMessage).toBe("stderr: Only stderr output");
|
||||
});
|
||||
|
||||
test("passes a maxBuffer above the 1 MB default so long conversions don't overflow stderr (#565)", async () => {
|
||||
await convert("in.mkv", "mkv", "h264.mp4", "out.mp4", undefined, mockExecFile);
|
||||
|
||||
// execFile's default maxBuffer is 1 MB; ffmpeg's progress output on a long
|
||||
// encode exceeds it and the conversion fails with "stderr maxBuffer length
|
||||
// exceeded". Lock in the raised buffer (must match FFMPEG_MAX_BUFFER in
|
||||
// ffmpeg.ts) so a regression to a smaller-but-still-over-1-MB value is caught.
|
||||
expect(lastOptions?.maxBuffer).toBe(1024 * 1024 * 64);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user