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

如何从PHP调用的bash命令中获取ffmpeg PID并精准终止进程

精准终止PHP启动的FFmpeg进程方案

我来帮你解决这个问题——要精准终止对应bash命令里的ffmpeg进程,而不是一刀切杀掉所有ffmpeg,这里有两个可靠的实现思路,你可以根据自己的场景选择:

方案一:启动时让FFmpeg写入PID文件(最稳定可靠)

这个方法直接让ffmpeg在启动时把自身PID写入一个唯一的文件,因为你已经用了随机目录$randomFolder,正好可以把PID文件放在这个目录下,和视频文件关联起来,后续终止时直接读取即可。

修改你的playCam方法里的exec命令部分:

public function playCam($ip) {
    $dataPlay = array();
    $randomFolder = rand(5, 15);
    $vidDir = '/var/www/cctv/public/video/'.$randomFolder.'/';
    // 先确保目录存在,如果exec里的mkdir没做的话
    if (!is_dir($vidDir)) {
        mkdir($vidDir, 0755, true);
    }
    $ffmpegPidFile = $vidDir . 'ffmpeg.pid';
    $bashPidFile = $vidDir . 'bash.pid';
    
    // 替换成你实际的ffmpeg命令,末尾加 & 后台运行,同时写入PID到文件
    $ffmpegCmd = "ffmpeg -i rtsp://{$ip}/your-stream-path -c:v copy -c:a copy {$vidDir}/output.mp4 & echo \$! > {$ffmpegPidFile}";
    // 把bash进程的PID也写入文件,方便后续清理
    $fullCmd = "({$ffmpegCmd}) & echo \$! > {$bashPidFile}";
    
    exec($fullCmd, $output, $returnVar);
    
    // 可以把$randomFolder或者PID文件路径返回/存储,方便后续终止调用
    $dataPlay['folder'] = $randomFolder;
    return $dataPlay;
}

终止进程的方法

当需要停止对应摄像头的流时,根据存储的$randomFolder读取PID文件,精准杀死进程:

public function stopCam($folder) {
    $vidDir = '/var/www/cctv/public/video/'.$folder.'/';
    $ffmpegPidFile = $vidDir . 'ffmpeg.pid';
    $bashPidFile = $vidDir . 'bash.pid';
    
    // 先杀死ffmpeg进程
    if (file_exists($ffmpegPidFile)) {
        $ffmpegPid = trim(file_get_contents($ffmpegPidFile));
        // 检查进程是否还存在,再执行kill
        exec("ps -p {$ffmpegPid} > /dev/null", $output, $ret);
        if ($ret === 0) {
            exec("kill {$ffmpegPid}");
        }
        unlink($ffmpegPidFile);
    }
    
    // 再清理bash进程
    if (file_exists($bashPidFile)) {
        $bashPid = trim(file_get_contents($bashPidFile));
        exec("ps -p {$bashPid} > /dev/null", $output, $ret);
        if ($ret === 0) {
            exec("kill {$bashPid}");
        }
        unlink($bashPidFile);
    }
    
    // 可选:清理视频目录
    // rm -rf $vidDir
}

方案二:通过Bash进程PID查找子进程(无需额外文件)

如果你不想维护PID文件,可以利用Linux的进程父子关系,通过你已经获取的bash进程PID,查找它的子进程(也就是ffmpeg)。

获取FFmpeg PID的代码

假设你已经把bash的PID存在了$bashPid变量中:

// 查询父进程为$bashPid的所有子进程PID,只输出PID列
exec("ps -o pid= --ppid {$bashPid}", $childPids);
// 过滤掉空行,ffmpeg一般只有一个子进程
$ffmpegPid = !empty($childPids) ? trim($childPids[0]) : null;

if ($ffmpegPid) {
    // 杀死ffmpeg进程
    exec("kill {$ffmpegPid}");
    // 再杀死bash进程
    exec("kill {$bashPid}");
}

注意事项

  • 如果你的ffmpeg命令用了nohup或者setsid,会导致ffmpeg脱离bash的父进程关系,这时方案一的PID文件方法会更可靠。
  • 确保PHP进程拥有足够的权限执行kill命令,以及读写目录/文件(如果用方案一)。
  • 每次启动生成的$randomFolder要妥善存储(比如存在数据库或缓存),这样终止时才能找到对应的PID文件或关联的bash PID。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.21 08:14:48