如何从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
相关产品推荐
相关产品推荐

