我proc_open
在 Windows 上遇到了问题,尝试使用 转换 wmv 文件(到 flv)时ffmpeg
,但是我怀疑每当发生某些情况时我都会遇到相同的情况。
基本上我的代码如下:
$descriptorspec = array
(
array("pipe", "r"),
array("pipe", "w"),
array("pipe", "w")
);
$pipes = array();
$procedure = proc_open('cd "C:/Program Files/ffmpeg/bin" && "ffmpeg.exe" -i "C:/wamp/www/project/Wildlife.wmv" -deinterlace -qdiff 2 -ar 22050 "C:/wamp/www/project/Wildlife.flv"', $descriptorspec, $pipes);
var_dump(stream_get_contents($pipes[1]));
stream_get_contents
现在,这段代码将导致 PHP 无限期挂起(我是否使用fgets
or来代替并不重要stream_select
,行为是一致的)。
其原因(我怀疑)是,虽然 STDOUT 流成功打开,但该进程不会向其写入任何内容(即使在 cmd 中运行相同的命令会显示输出),因此,尝试从此类流中读取,会导致与此处描述的相同的问题,因此 - PHP 等待流中包含任何内容,进程不会向其中写入任何内容。
但是(额外的乐趣),设置stream_set_timeout
或stream_set_blocking
没有任何效果。
因此 - 有人可以确认/否认正在发生的事情,如果可能的话,展示我如何应对这种情况?我查看了 PHP 错误,所有错误proc_open hangs
似乎都已修复。
暂时我已经实施了这样的解决方案:
$timeout = 60;
while (true) {
sleep(1);
$status = proc_get_status($procedure);
if (!$status['running'] || $timeout == 0) break;
$timeout--;
}
但是,我真的不想依赖这样的东西:
- 我将有运行超过一分钟的进程 - 这些进程将被错误地报告为上述类型
- 我想知道 ffmpeg 何时完成视频转换 - 目前我只会在一分钟后知道该进程仍在运行,我无法真正做任何事情来检查是否有任何输出(因为它会挂起 PHP)。
此外,我真的不想等待一整分钟来检查该过程(例如 - 从命令行转换给定的视频需要 <10 秒),而且我会有需要更多时间来转换的视频。
根据@Sjon 的评论,这是stream_select
我正在使用的,由于相同的问题而阻塞 - STDOUT 未写入:
$descriptorspec = array
(
array("pipe", "r"),
array("pipe", "w"),
array("pipe", "w")
);
$pipes = array();
$procedure = proc_open('cd "C:/Program Files/ffmpeg/bin" && "ffmpeg.exe" -i "C:/wamp/www/sandbox/Wildlife.wmv" -deinterlace -qdiff 2 -ar 22050 "C:/wamp/www/sandbox/Wildlife.flv"', $descriptorspec, $pipes);
$read = array($pipes[0]);
$write = array($pipes[1], $pipes[2]);
$except = array();
while(true)
if(($num_changed_streams = stream_select($read, $write, $except, 10)) !== false)
{
foreach($write as $stream)
var_dump(stream_get_contents($stream));
exit;
}
else
break;
每次与@Sjon 的对话 - 从 Windows 上的缓冲流中读取数据被破坏。最终的解决方案是通过shell使用流重定向,然后读取创建的文件 - 这样
$descriptorspec = array
(
array("pipe", "r"),
array("pipe", "w"),
array("pipe", "w")
);
$pipes = array();
$procedure = proc_open('cd "C:/Program Files/ffmpeg/bin" && "ffmpeg.exe" -i "C:/wamp/www/sandbox/Wildlife.mp4" -deinterlace -qdiff 2 -ar 22050 "C:/wamp/www/sandbox/Wildlife.flv" > C:/stdout.log 2> C:/stderr.log', $descriptorspec, $pipes);
proc_close($procedure);
$output = file_get_contents("C:/stdout.log");
$error = file_get_contents("C:/stderr.log");
unlink("C:/stdout.log");
unlink("C:/stderr.log");
由于流是缓冲的,在文件中我们将得到无缓冲的输出(我也在追求)。而且我们不需要检查文件是否更改,因为来自 shell 的结果是无缓冲且同步的。