← Files Cecil-IA Labs FFmpegARCHIVED FILE

dist/core/ffmpeg-runner.js

4.39 KB · Sep 30, 2026 · 23:17 UTC

↓ Download file

import { resolveBinary } from "./binary-resolver.js";
import { renderCommandForDisplay, runCommand } from "./command-result.js";
import { ToolkitRuntimeError } from "./errors.js";
import { currentProgressObserver, nextProgressRunId, progressMediaDuration, } from "./progress-context.js";
import { deriveProgressEvent, estimateProgressDuration, FFmpegProgressParser, inputSources, } from "./progress.js";
function executionDetails(execution) {
    return {
        binary: execution.binary,
        args: execution.args,
        exitCode: execution.exitCode,
        ...(execution.signal !== undefined ? { signal: execution.signal } : {}),
        ...(execution.stderr ? { stderrTail: execution.stderr } : {}),
        ...(execution.stdout ? { stdoutTail: execution.stdout } : {}),
        stderrTruncated: execution.stderrTruncated,
        stdoutTruncated: execution.stdoutTruncated,
    };
}
function canInstrumentProgress(args, dryRun) {
    if (dryRun)
        return false;
    if (args.includes("-progress"))
        return false;
    // Avoid claiming stdout when the media payload itself is explicitly written there.
    return args.at(-1) !== "-" && !args.includes("pipe:1");
}
export async function runFFmpeg(args, options = {}) {
    const env = { ...process.env, ...(options.env ?? {}) };
    const binary = await resolveBinary({
        kind: "ffmpeg",
        ...(options.ffmpegPath !== undefined ? { explicitPath: options.ffmpegPath } : {}),
        ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
        env,
    });
    const observer = currentProgressObserver();
    const instrumentProgress = observer !== undefined && canInstrumentProgress(args, options.dryRun);
    const effectiveArgs = instrumentProgress
        ? ["-progress", "pipe:1", "-nostats", ...args]
        : [...args];
    const runId = instrumentProgress ? nextProgressRunId() : undefined;
    const source = instrumentProgress ? inputSources(args)[0] : undefined;
    const duration = instrumentProgress
        ? estimateProgressDuration(args, progressMediaDuration)
        : undefined;
    const parser = instrumentProgress ? new FFmpegProgressParser() : undefined;
    const emit = (chunk) => {
        if (!observer || !parser || !runId)
            return;
        for (const snapshot of parser.push(chunk)) {
            try {
                observer(deriveProgressEvent(runId, snapshot, {
                    ...(source !== undefined ? { source } : {}),
                    ...(duration !== undefined ? { duration } : {}),
                }));
            }
            catch {
                // Progress display/collection must never make a media operation fail.
            }
        }
    };
    const invocation = {
        binary,
        args: effectiveArgs,
        ...(options.cwd !== undefined ? { cwd: options.cwd } : {}),
        env,
    };
    let execution;
    try {
        execution = await runCommand(invocation, {
            ...options,
            ...(instrumentProgress
                ? {
                    onStdout: (chunk) => {
                        options.onStdout?.(chunk);
                        emit(chunk);
                    },
                }
                : {}),
        });
        if (observer && parser && runId) {
            for (const snapshot of parser.flush()) {
                try {
                    observer(deriveProgressEvent(runId, snapshot, {
                        ...(source !== undefined ? { source } : {}),
                        ...(duration !== undefined ? { duration } : {}),
                    }));
                }
                catch {
                    // Progress display/collection must never make a media operation fail.
                }
            }
        }
    }
    catch (error) {
        if (error instanceof ToolkitRuntimeError &&
            error.code === "E_INTERNAL_INVARIANT" &&
            error.details?.["systemCode"] === "ENOENT") {
            throw new ToolkitRuntimeError("E_ENV_FFMPEG_NOT_FOUND", "FFmpeg disappeared before execution.", {
                details: { command: renderCommandForDisplay(invocation) },
                cause: error,
            });
        }
        throw error;
    }
    if (execution.exitCode !== 0) {
        throw new ToolkitRuntimeError("E_FFMPEG_EXECUTION_FAILED", `FFmpeg exited with code ${execution.exitCode ?? "unknown"}.`, { details: executionDetails(execution) });
    }
    return execution;
}
//# sourceMappingURL=ffmpeg-runner.js.map

SHA-256: 55558f4edc4972debc55159ddbd322446ad0c3c661d27e477669e7e8ad08faab