简体   繁体   English

FFMpeg在命令行中工作,但在PHP脚本中没有

[英]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组件之外,它只需要您下载最近的ffmpegffprobe构建。 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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM