使用exec()执行FFmpeg命令生成双PID进程是否正常?
问题:exec()执行FFmpeg命令时生成两个PID进程是否正常?
我在PHP中使用exec()执行以下FFmpeg命令时,发现系统里会同时出现两个不同PID的进程,但直接在终端shell中执行相同命令却只会有一个进程。想请教这个行为是否正常?
代码示例
$ffmpeg = "/home/user/bin/ffmpeg -hide_banner -loglevel verbose -n -i https://sitelink/list.m3u8 -map 0:4 -map 0:5 -acodec copy -bsf:a aac_adtstoasc -vcodec copy video.mp4 1> log.txt 2>&1"; exec($ffmpeg, $output, $var);
生成的进程示例
user+ 24414 24413 0 13:42 pts/2 00:00:00 sh -c /home/user/bin/ffmpeg -hide_banner -loglevel verbose -n -i https://sitelink/list.m3u8 -map 0:4 -map 0:5 -acodec copy -bsf:a aac_adtstoasc -vcodec copy video.mp4 1> log.txt 2>&1 user+ 24415 24414 1 13:42 pts/2 00:00:00 /home/user/bin/ffmpeg -hide_banner -loglevel verbose -n -i https://sitelink/list.m3u8 -map 0:4 -map 0:5 -acodec copy -bsf:a aac_adtstoasc -vcodec copy video.mp4
解答
这是完全正常的行为,核心原因在于PHP exec()函数的工作机制,以及你命令里包含的shell语法:
- 当你在
exec()中传入一个包含重定向(比如1> log.txt 2>&1)的完整命令字符串时,PHP无法直接解析这些shell特有的语法,所以它会先启动一个sh子进程,让这个shell进程来处理命令解析、重定向逻辑,然后再由这个shell进程去启动真正的FFmpeg进程。这就是你看到两个进程的原因:第一个是负责中转的shell进程,第二个才是实际执行转码的FFmpeg进程。 - 而当你直接在终端执行命令时,命令是由当前终端的shell进程直接解析执行的,不需要额外启动新的shell子进程,所以只会看到FFmpeg这一个进程。
如何避免额外的shell进程?
如果你想去掉这个中转的shell进程,可以改用proc_open()函数,它支持直接传递命令参数数组,并且可以手动处理标准输出/错误的重定向,不需要依赖shell:
$ffmpegPath = '/home/user/bin/ffmpeg'; $commandArgs = [ '-hide_banner', '-loglevel', 'verbose', '-n', '-i', 'https://sitelink/list.m3u8', '-map', '0:4', '-map', '0:5', '-acodec', 'copy', '-bsf:a', 'aac_adtstoasc', '-vcodec', 'copy', 'video.mp4' ]; // 定义文件描述符:将标准输出和错误都写入log.txt $descriptors = [ 0 => ['pipe', 'r'], // 标准输入(这里用不到,后续关闭即可) 1 => ['file', 'log.txt', 'w'], 2 => ['file', 'log.txt', 'w'] ]; // 启动FFmpeg进程 $process = proc_open($ffmpegPath, $descriptors, $pipes); if (is_resource($process)) { fclose($pipes[0]); // 关闭未使用的输入管道 $exitStatus = proc_close($process); // 等待进程结束并获取退出码 // 可以根据$exitStatus判断命令是否执行成功 }
这种方式会直接启动FFmpeg进程,不会生成额外的shell进程,同时也能实现日志写入文件的需求。
内容的提问来源于stack exchange,提问作者Bruno Andrade
相关产品推荐
相关产品推荐

