如何在Windows上为ffmpeg stdin / stderr配置proc_open“管道”?

时间:2018-09-07 13:50:04

标签: php ffmpeg window proc-open

首先,我花了一周的时间在Google上搜索和尝试各种针对Unix的答案,但这已经完全失败了,我需要针对 Windows 的答案,所以这是不是 Unix等效项的重复问题。

我们正在尝试创建一个计划任务,该任务将处理PHP中的任务队列,并一次维护最多10个ffmpeg实例的数组。我尝试了execshell_execproc_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/null2>&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似乎无法实现。我决定放弃这种方法,但希望这一发现将为其他人节省一些时间和麻烦。

0 个答案:

没有答案