[英]FFMpeg working in command line but not in PHP script
I am using FFMpeg to convert videos and it is working fine from the command line. 我正在使用FFMpeg转换视频,它在命令行中工作正常。 I am using the following command: 我使用以下命令:
ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv
However, when I run the command using PHP script, the output video is not encoded. 但是,当我使用PHP脚本运行命令时,输出视频不会被编码。
exec("ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv",$output, $returnvalue);
$returnvalue = 127;
FFMPEG installed path : FFMPEG安装路径:
[root@localhost ~]# which ffmpeg
/root/bin/ffmpeg
My Script Path : 我的脚本路径:
www.domainname.com/core/foldername/ffmpeg.php www.domainname.com/core/foldername/ffmpeg.php
Please provide me solution for the same ASAP. 请尽快为我提供解决方案。
Thank you. 谢谢。
The natural way to run ffmpeg
from PHP scripts is something like: 从PHP脚本运行ffmpeg
的自然方式如下:
<?php
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -i input.avi output.avi &");
echo "Done.\n";
?>
There are several issues that need to be pointed out here. 这里有几个问题需要指出。 The first one is that, although we specified we want ffmpeg
to be executed in the background (using the ampersand operator "&"), PHP script will not continue it's execution until ffmpeg
has finished its execution. 第一个是,虽然我们指定我们希望ffmpeg
在后台执行(使用&符号运算符“&”),PHP脚本将不会继续执行,直到ffmpeg
完成执行。 This is due to the fact, mentioned in one of the notes for the PHP's exec()
function that says: 这是因为在PHP的exec()
函数的一个注释中提到的事实是:
If a program is started with this function, in order for it to continue running in the background, the output of the program must be redirected to a file or another output stream. 如果使用此函数启动程序,为了使其在后台继续运行,必须将程序的输出重定向到文件或其他输出流。 Failing to do so will cause PHP to hang until the execution of the program ends. 如果不这样做将导致PHP挂起,直到程序执行结束。
Don't be confused about the example showing shell_exec()
call instead of exec()
. 不要混淆的例子显示shell_exec()
调用,而不是exec()
All of the PHP's Program execution functions share the similar code base and limitations. 所有PHP的程序执行函数都共享相似的代码库和限制。
So, to work around this issue, we need to do something like this: 因此,要解决此问题,我们需要执行以下操作:
<?php
echo "Starting ffmpeg...\n\n";
echo shell_exec("ffmpeg -i input.avi output.avi >/dev/null 2>/dev/null &");
echo "Done.\n";
?>
The part that says ">/dev/null" will redirect the standard OUTPUT (stdout) of the ffmpeg
instance to /dev/null
(effectively ignoring the output) and "2>/dev/null" will redirect the standard ERROR (stderr) to /dev/null
(effectively ignoring any error log messages). “> / dev / null”部分将ffmpeg
实例的标准OUTPUT(stdout)重定向到/dev/null
(实际上忽略输出), “2> / dev / null”将重定向标准ERROR(stderr) )到/dev/null
(有效地忽略任何错误日志消息)。 These two can be combined into a shorter representation: ">/dev/null 2>&1" . 这两个可以组合成一个较短的表示: “> / dev / null 2>&1” 。 If you like, you can read more about I/O Redirection. 如果您愿意,可以阅读有关I / O重定向的更多信息。
An important note should be mentioned here. 这里应该提到一个重要的注意事项。 The ffmpeg
command-line tool uses stderr
for output of error log messages and stdout
is reserved for possible use of pipes (to redirect the output media stream generated from ffmpeg
to some other command line tool). ffmpeg
命令行工具使用stderr
输出错误日志消息,并保留stdout
以便可能使用管道(将ffmpeg
生成的输出媒体流重定向到其他命令行工具)。 That being said, if you run your ffmpeg
in the background, you'll most probably want to redirect the stderr
to a log file, to be able to check it later. 话虽这么说,如果你在后台运行你的ffmpeg
,你很可能想要将stderr
重定向到一个日志文件,以便以后检查它。
One more thing to take care about is the standard INPUT (stdin). 另外需要注意的是标准的INPUT(标准输入)。 Command-line ffmpeg
tool is designed as an interactive utility that accepts user's input (usually from keyboard) and reports the error log on the user's current screen/terminal. 命令行ffmpeg
工具被设计为一个交互式实用程序,它接受用户的输入(通常来自键盘)并在用户的当前屏幕/终端上报告错误日志。 When we run ffmpeg
in the background, we want to tell ffmpeg
that no input should be accepted (nor waited for) from the stdin
. 当我们在后台运行ffmpeg
时,我们想告诉ffmpeg
不应该从stdin
接受(也不等待)任何stdin
。 We can tell this to ffmpeg
, using I/O redirection again ** "ffmpeg command-line tool in the background would be similar to this: 我们可以告诉ffmpeg
,再次使用I / O重定向**“后台的ffmpeg命令行工具将类似于:
<?php
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";
?>
The "-y" option is used to auto-overwrite the output file (output.avi) without asking for yes/no
confirmation. 该“-y”选项用于自动覆盖输出文件(output.avi)不要求yes/no
确认。 If you need the opposite scenario, to auto-cancel the entire process if the output file already exists, then use "-n" option instead. 如果您需要相反的方案,如果输出文件已存在,则自动取消整个过程,然后使用“-n”选项。
Wrapper Libraries 包装库
Some PHP libraries allow wrapping ffmpeg
calls into PHP objects, and give you a nice syntax to work with if you don't like to use the command line. 一些PHP库允许将ffmpeg
调用包装到PHP对象中,如果您不喜欢使用命令行,可以使用一个很好的语法。 One of these is the actively maintained PHP-FFMpeg . 其中一个是积极维护PHP-FFmpeg的 。 It only requires you to download a recent ffmpeg
and ffprobe
build apart from installing the PHP components. 除了安装PHP组件之外,它只需要您下载最近的ffmpeg
和ffprobe
构建。 Then you can run PHP code like this: 然后你可以像这样运行PHP代码:
$ffmpeg = FFMpeg\FFMpeg::create();
$video = $ffmpeg->open('video.mpg');
$video
->filters()
->resize(new FFMpeg\Coordinate\Dimension(320, 240))
->synchronize();
$video
->save(new FFMpeg\Format\Video\X264(), 'export-x264.mp4')
Of course you need to take care of running such a task in the background. 当然,你需要在后台运行这样的任务。 Libraries such as GearmanClient facilitate this. 库如GearmanClient促进这一点。
Note: ffmpeg-php is an extension that is not developed since 2007 (and requires "ffmpeg-0.4.9_pre1 or higher" ), which means that you are restricted to use a very old version of ffmpeg, without possibility to update it to the latest version. 注: ffmpeg的- PHP的是,2007年以来没有开发出扩大(并要求“的ffmpeg-0.4.9_pre1或更高”),这意味着你被限制使用,一个很老版本的ffmpeg的,没有可能将其更新为最新版本。 Since a lot of changes/improvements are being made, inside ffmpeg's
code, every day, it makes ffmpeg-php
incompatible with the latest ffmpeg
. 由于在ffmpeg's
代码中进行了大量的更改/改进,每天都会使ffmpeg-php
与最新的ffmpeg
不兼容。
Read the official documentation for more info. 阅读官方文档了解更多信息。
This happened to me, I found this on another forum; 这发生在我身上,我在另一个论坛上找到了这个; the trick inside of PHP is to give the absolute path to FFMPEG. PHP内部的技巧是给出FFMPEG的绝对路径。 Try running it like this.. 尝试像这样运行它..
exec("/root/bin/ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv",$output, $returnvalue);
Something about the fact that php is a different user than you are when typing straight into the command line. 关于php与用户直接输入命令行时的用户不同的事实。 I guess it doesn't have the same shortcut list or whatever it is. 我猜它没有相同的快捷列表或者它是什么。
Not sure exactly why but it worked for me! 不确定为什么,但它对我有用!
Good luck. 祝好运。
I covered the solution that helps most people that I spoke to about this in another thread. 我介绍了解决方案,帮助大多数人在另一个线程中谈到这一点。
https://stackoverflow.com/a/38626752/2074077 https://stackoverflow.com/a/38626752/2074077
Essentially, your user needs access to the public directories. 实质上,您的用户需要访问公共目录。
<?php
exec('whoami'); // Gives you the running user; often it's www-data
?>
Then change your public ownership to the whoami
user. 然后将您的公共所有权更改为whoami
用户。
sudo chown -R www-data:root /var/www
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.