【问题标题】:FFMpeg working in command line but not in PHP scriptFFMpeg 在命令行中工作,但不在 PHP 脚本中
【发布时间】:2014-11-07 04:52:58
【问题描述】:

我正在使用 FFMpeg 转换视频,它在命令行中运行良好。我正在使用以下命令:

ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv

但是,当我使用 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 安装路径:

[root@localhost ~]# which ffmpeg

/root/bin/ffmpeg

我的脚本路径:

www.domainname.com/core/foldername/ffmpeg.php

请尽快为我提供同样的解决方案。

谢谢。

【问题讨论】:

    标签: php video ffmpeg flv server


    【解决方案1】:

    我在另一个帖子中介绍了可以帮助与我交谈过的大多数人的解决方案。

    https://*.com/a/38626752/2074077

    本质上,您的用户需要访问公共目录。

    <?php 
       exec('whoami'); // Gives you the running user; often it's www-data
    ?>
    

    然后将您的公共所有权更改为whoami 用户。

    sudo chown -R www-data:root /var/www
    

    【讨论】:

    • 这是正确答案!感谢分享!
    【解决方案2】:

    从 PHP 脚本运行 ffmpeg 的自然方式类似于:

    <?php
        echo "Starting ffmpeg...\n\n";
        echo shell_exec("ffmpeg -i input.avi output.avi &");
        echo "Done.\n";
    ?>
    

    这里有几个问题需要指出。第一个是,虽然我们指定我们希望 ffmpeg 在后台执行(使用与号运算符“&”),但 PHP 脚本将不会继续它会在 ffmpeg 完成之前执行它的执行。这是因为,在 PHP 的 exec() 函数的注释之一中提到:

    如果一个程序是用这个函数启动的,为了让它 继续在后台运行,程序的输出必须是 重定向到文件或另一个输出流。不这样做会 导致 PHP 挂起,直到程序执行结束。

    不要对显示shell_exec() 调用而不是​exec() 的示例感到困惑。 PHP 的所有程序执行函数共享相似的代码库和限制。

    所以,要解决这个问题,我们需要这样做:

    <?php
        echo "Starting ffmpeg...\n\n";
        echo shell_exec("ffmpeg -i input.avi output.avi >/dev/null 2>/dev/null &");
        echo "Done.\n";
    ?>
    

    ">/dev/null" 部分会将ffmpeg 实例的标准输出(stdout)重定向到/dev/null(有效地忽略输出)和" 2>/dev/null" 将标准错误(stderr)重定向到/dev/null(有效地忽略任何错误日志消息)。这两个可以组合成一个更短的表示:">/dev/null 2>&1"。如果你喜欢,你可以阅读更多关于 I/O 重定向的内容。

    这里应该提到一个重要的注意事项。 ffmpeg 命令行工具使用stderr 输出错误日志消息,stdout 保留用于可能使用管道(将ffmpeg 生成的输出媒体流重定向到其他命令行工具)。话虽如此,如果您在后台运行ffmpeg,您很可能希望将stderr 重定向到日志文件,以便稍后检查。

    还有一点需要注意的是标准输入(stdin)。命令行ffmpeg 工具被设计为一个交互式实用程序,它接受用户的输入(通常来自键盘)并在用户的当前屏幕/终端上报告错误日志。当我们在后台运行ffmpeg 时,我们想告诉ffmpeg 不应接受(也不等待)来自stdin 的输入。我们可以告诉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";
    ?>
    

    “-y” 选项用于自动覆盖输出文件(output.avi)而不要求yes/no 确认。如果您需要相反的情况,如果输出文件已经存在,则自动取消整个过程,然后使用 "-n" 选项。

    包装库

    一些 PHP 库允许将 ffmpeg 调用包装到 PHP 对象中,如果您不喜欢使用命令行,则可以使用很好的语法。其中之一是积极维护的PHP-FFMpeg。除了安装 PHP 组件外,它只需要您下载最近的 ffmpegffprobe 构建。然后你可以像这样运行 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')
    

    当然,您需要注意在后台运行这样的任务。像GearmanClient 这样的库促进了这一点。

    注意:ffmpeg-php 是自 2007 年以来未开发的扩展(并且需要 “ffmpeg-0.4.9_pre1 或更高版本”),这意味着您仅限使用非常旧版本的 ffmpeg,无法将其更新到最新版本。由于正在进行大量更改/改进,在ffmpeg's 代码中,每天都会使ffmpeg-php 与最新的ffmpeg 不兼容。

    阅读official documentation了解更多信息。

    【讨论】:

      【解决方案3】:

      这发生在我身上,我在另一个论坛上找到了这个; PHP 内部的技巧是提供 FFMPEG 的绝对路径。尝试像这样运行它..

      exec("/root/bin/ffmpeg -i input.avi -ab 56 -ar 44100 -b 200 -r 15 -s 320x240 -f flv output.flv",$output, $returnvalue);
      

      关于 php 与您直接输入命令行时的用户不同这一事实。我猜它没有相同的快捷方式列表或其他任何东西。

      不知道为什么,但它对我有用!

      祝你好运。

      【讨论】:

        最近更新 更多