You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PHP调用FFmpeg后台运行后如何获取执行结果及方案选型

咱们一步步来解决你的问题,结合Windows和Linux跨平台的需求,给你实用的方案:


1. proc_open是不是解决初始阻塞问题的最佳方案?

proc_open确实是PHP中处理子进程的优质选择,但不是唯一方案——它的优势在于能精细控制子进程的输入/输出流、环境变量,适合需要对进程做深度管控的场景;如果只是单纯想解除阻塞,Linux下用exec($cmd . ' &')、Windows下用exec('start /B ' . $cmd)也能实现。

但结合你后续需要获取执行状态的需求,proc_open的可控性更强,能更好地封装跨平台的启动逻辑,所以用它来实现后台执行是很合适的。


2. 如何在不阻塞脚本的前提下获取FFmpeg执行结果?

核心思路是异步监控:主脚本启动FFmpeg后立即返回,通过记录进程ID(PID)和退出码到临时文件,后续通过轮询或定时任务检查状态。以下是跨平台的实现代码:

// 定义跨平台配置
$ffmpegPath = PHP_OS_FAMILY === 'Windows' ? 'D:\FFMPEG\bin\ffmpeg.exe' : '/usr/bin/ffmpeg';
$statusFile = __DIR__ . "/ffmpeg_status_{uniqid()}.txt";
$logFile = __DIR__ . "/ffmpeg_log_{uniqid()}.txt";

/**
 * 启动后台FFmpeg任务,返回状态文件路径
 */
function startFFmpegBackground($videoCode, $outputFile, $statusFile, $logFile) {
    global $ffmpegPath;
    $m3u8Url = "https://linkplaylist/{$videoCode}.m3u8";
    $cmd = [];

    if (PHP_OS_FAMILY === 'Windows') {
        // Windows:用start /B后台执行,记录PID和退出码到状态文件
        $cmd = sprintf(
            'cmd.exe /c start /B "" %s -y -i %s -map 0:1 -map 0:2 -acodec copy -bsf:a aac_adtstoasc -vcodec copy %s 1>>%s 2>&1 & echo %%ERRORLEVEL%% > %s & echo %%PID%% >> %s',
            escapeshellarg($ffmpegPath),
            escapeshellarg($m3u8Url),
            escapeshellarg($outputFile),
            escapeshellarg($logFile),
            escapeshellarg($statusFile),
            escapeshellarg($statusFile)
        );
    } else {
        // Linux:用nohup后台执行,记录PID和退出码到状态文件
        $cmd = sprintf(
            'bash -c "nohup %s -y -i %s -map 0:1 -map 0:2 -acodec copy -bsf:a aac_adtstoasc -vcodec copy %s 1>>%s 2>&1 & echo $! > %s && wait $! && echo $? >> %s"',
            escapeshellarg($ffmpegPath),
            escapeshellarg($m3u8Url),
            escapeshellarg($outputFile),
            escapeshellarg($logFile),
            escapeshellarg($statusFile),
            escapeshellarg($statusFile)
        );
    }

    // 启动进程并立即关闭管道,不阻塞脚本
    $proc = proc_open($cmd, [], $pipes);
    if ($proc) {
        proc_close($proc);
        return $statusFile;
    }
    return false;
}

/**
 * 检查FFmpeg任务状态
 */
function checkFFmpegStatus($statusFile) {
    if (!file_exists($statusFile)) {
        return ['status' => 'unknown', 'error' => '状态文件丢失'];
    }

    $content = trim(file_get_contents($statusFile));
    $lines = explode("\n", $content);

    if (PHP_OS_FAMILY === 'Windows') {
        $exitCode = isset($lines[0]) ? intval($lines[0]) : null;
        $pid = isset($lines[1]) ? intval($lines[1]) : null;

        // 检查进程是否存活
        $isRunning = false;
        if ($pid) {
            exec("tasklist /FI \"PID eq $pid\"", $output);
            $isRunning = count($output) > 1;
        }

        if (!$isRunning && $exitCode !== null) {
            return [
                'status' => 'completed',
                'exit_code' => $exitCode,
                'success' => $exitCode === 0
            ];
        } else {
            return ['status' => 'running', 'pid' => $pid];
        }
    } else {
        $pid = isset($lines[0]) ? intval($lines[0]) : null;
        $exitCode = isset($lines[1]) ? intval($lines[1]) : null;

        // 检查进程是否存活
        $isRunning = false;
        if ($pid) {
            exec("ps -p $pid", $output);
            $isRunning = count($output) > 1;
        }

        if (!$isRunning && $exitCode !== null) {
            return [
                'status' => 'completed',
                'exit_code' => $exitCode,
                'success' => $exitCode === 0
            ];
        } else {
            return ['status' => 'running', 'pid' => $pid];
        }
    }
}

// ------------------------------
// 使用示例
// ------------------------------
// 1. 启动后台下载任务
$statusFile = startFFmpegBackground('football', 'football.mp4', $statusFile, $logFile);

// 2. 前端可通过AJAX轮询以下接口获取状态
// $status = checkFFmpegStatus($statusFile);
// echo json_encode($status);

关键说明:

  • 启动任务时,将FFmpeg的PID和执行完成后的退出码写入临时状态文件;
  • 主脚本启动进程后立即返回,不会阻塞页面;
  • 通过checkFFmpegStatus函数,可随时查询任务是否在运行、执行是否成功;
  • 记得定期清理临时状态文件和日志文件,避免磁盘占用;
  • 所有路径和参数都用escapeshellarg转义,避免命令注入风险。

内容的提问来源于stack exchange,提问作者Bruno Andrade

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.28 07:16:05