首先,我花了一周的时间在Google上搜索和尝试各种针对Unix的答案,但这已经完全失败了,我需要针对 Windows 的答案,所以这是不是 Unix等效项的重复问题。
我们正在尝试创建一个计划任务,该任务将处理PHP中的任务队列,并一次维护最多10个ffmpeg实例的数组。我尝试了exec
,shell_exec
和proc_open
,加上/没有start /B
,但没有“完全”的运气。
我也很确定,这与设置描述符规范和管道(我完全不熟悉)有关,这就是原因:
每https://trac.ffmpeg.org/wiki/PHP,
“> / dev / null”部分将重定向标准输出 ffmpeg实例的(stdout)到/ dev / null(有效地忽略了 输出)和“ 2> / dev / null”会将标准错误(stderr)重定向到 / dev / null(有效地忽略任何错误日志消息)。这两个可以 组合成一个较短的表示形式:“> / dev / null 2>&1”。如果你 例如,您可以?了解有关I / O重定向的更多信息。
此处应提及一个重要说明。 ffmpeg命令行 该工具使用stderr来输出错误日志消息,而stdout是 保留供管道使用(重定向输出媒体) 从ffmpeg生成的流到其他命令行工具)。那 有人说,如果您在后台运行ffmpeg,您将 可能希望将stderr重定向到日志文件,以便能够 以后再检查。
要注意的另一件事是标准INPUT(stdin)。 命令行ffmpeg工具被设计为一种交互式实用程序, 接受用户的输入(通常是通过键盘输入)并报告错误日志 在用户当前的屏幕/终端上。当我们在 背景,我们要告诉ffmpeg不应接受任何输入 (也没有等待)从标准输入。我们可以使用I / O告诉ffmpeg 再次重定向”
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -y -i input.avi output.avi </dev/null >/dev/null 2>/var/log/ffmpeg.log &");
echo "Done.\n";
尽管我们想使用proc_open,所以此示例实际上使用shell_exec
,以便我们可以使用循环来检查该过程是否已完成。
这是我尝试过的基本示例循环。执行此操作的问题是实际的ffmpeg处理已完成,但是进程挂起了“正在等待某事”。当我使用调试并退出循环并在几分钟后终止该过程时,将写入ffmpeg输出,脚本将继续执行。 (从命令行中,ffmpeg只需不到一分钟即可完成)
$descriptorspec = array(
array('pipe', 'r'),
array('pipe', 'w'),
array('pipe', 'w'),
);
$pipes = null;
$cwd = null;
$env = null;
$process = proc_open('start /B ffmpeg.exe -i input.mov output.mp4 -nostdin', $descriptorspec, $pipes, $cwd, $env);
$status = proc_get_status($process);
while($status['running']) {
sleep (60);
$status = proc_get_status($process);
}
proc_terminate($process);
此外,如ffmpeg Main-options所述:
在标准输入上启用交互。除非标准,否则默认为开 输入用作输入。要明确禁用交互,您需要 指定
-nostdin
。
-nostdin
选项似乎表明它解决了我的问题,但是没有明显的影响。在我发现的所有Unix解决方案中,似乎仍需要此unix添加的某种形式:</dev/null
或2>&1
。
因此,以那篇详尽的序言,有人可以解释如何正确配置proc_open
函数以满足ffmpeg.exe
与I / O的交互方式吗?如果有更好或更合适的方法,我很乐意这样做,但重要的是能够通过一系列过程循环检查它们是否完成,以便其他更快的过程可以在同时。
更新
经过详尽的R&D之后,似乎I / O并不是实现这一点的问题(-nostdin
选项似乎如广告所示那样工作)。我设计的前提是使用proc_get_status()
确定ffmpeg
的完成时间。这种方法的缺陷在于,显然它不返回ffmpeg进程的实际PID,而是返回 parent PID。因此,当proc_get_status()
返回视频转换已完成时,它实际上仍在运行,没有挂起。通过在较大的视频文件上进行测试,这变得更加复杂。视频越大,实际完成“剩余”时间所花费的时间就越长-I / O并不是问题-观看父PID而不是子PID是问题。因此,如果不进入Windows的底层系统内部,则直接使用PHP似乎无法实现。我决定放弃这种方法,但希望这一发现将为其他人节省一些时间和麻烦。