【问题标题】:How to parse ffmpeg info in PHP?如何在 PHP 中解析 ffmpeg 信息?
【发布时间】:2012-08-02 01:29:24
【问题描述】:

如何从ffmpeg -i /var/thismovie.avi 的输出中获取特定信息,例如“持续时间”?

我需要帧高、帧宽、影片时长和帧频。所有这些都在上述命令的输出中,但是我如何单独获取我需要的位并将它们放入 PHP 中的变量中?

我已经放弃尝试安装ffmpeg-php,这是我在此之前用来完成相同工作的工具。

谢谢

ffmpeg -i /var/thismovie.avi 产生这样的输出

ffmpeg version N-43171-ga763caf Copyright (c) 2000-2012 the FFmpeg developers built on Aug 3 2012 07:56:19 with gcc 4.1.2 (GCC) 20080704 (Red Hat 4.1.2-52) configuration: --enable-version3 --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libvpx --enable-libfaac --enable-libmp3lame --enable-libtheora --enable-libvorbis --enable-pic --enable-libx264 --enable-libxvid --disable-ffplay --enable-shared --enable-gpl --enable-postproc --enable-nonfree --enable-avfilter --enable-pthreads --extra-cflags=-fPIC libavutil 51. 66.100 / 51. 66.100 libavcodec 54. 48.100 / 54. 48.100 libavformat 54. 22.100 / 54. 22.100 libavdevice 54. 2.100 / 54. 2.100 libavfilter 3. 5.102 / 3. 5.102 libswscale 2. 1.100 / 2. 1.100 libswresample 0. 15.100 / 0. 15.100 libpostproc 52. 0.100 / 52. 0.100 [avi @ 0x18e8e240] non-interleaved AVI [avi @ 0x18e8e240] max_analyze_duration 5000000 reached at 5000000 Input #0, avi, from '/var/www/vhosts/mysite.com/httpdocs/movie.avi': Duration: 00:00:10.76, start: 0.000000, bitrate: 5180 kb/s Stream #0:0: Video: h264 (High) (H264 / 0x34363248), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 25 fps, 25 tbr, 25 tbn, 50 tbc Stream #0:1: Audio: ac3 ([0] [0][0] / 0x2000), 48000 Hz, stereo, s16, 128 kb/s At least one output file must be specified` 

【问题讨论】:

  • ffmpeg-php 听起来完全是适合这项工作的工具。您尝试执行的操作听起来像是无法安装扩展程序的糟糕解决方法。
  • 如果你能够使用exec从php执行命令,你可以将命令的输出捕获为php变量,然后按照你喜欢的方式解析它
  • @Matt Ball 相反,它让我不必安装 ffmpeg-php 只是为了从电影中获取 4 个值。另一个原因是 ffmpeg-php 从我收集到的信息自 2007 年以来就没有开发过。我已经(并且需要)安装了 ffmpeg,那么为什么不直接利用它来获取我想要的信息呢?
  • @Hawili 是的,这就是我要去的地方,但是如何准确地解析信息?
  • 添加一个示例输出,我会尝试告诉你如何

标签: php ffmpeg


【解决方案1】:

你可以使用 ffprobe,它有一个输出 JSON 格式的选项。

看看这个例子:

ffprobe -v quiet -print_format json -show_format Ramp\ -\ Apathy.mp3

产生以下输出:

{
    "format": {
        "filename": "Ramp - Apathy.mp3",
        "nb_streams": 2,
        "format_name": "mp3",
        "format_long_name": "MP2/3 (MPEG audio layer 2/3)",
        "start_time": "0.000000",
        "duration": "203.638856",
        "size": "4072777",
        "bit_rate": "159999",
        "tags": {
            "title": "Apathy",
            "artist": "Ramp",
            "album": "Evolution Devolution Revolution",
            "date": "1999",
            "genre": "Metal"
        }
    }
}

我使用的是 ffprobe 1.0.7 版。

【讨论】:

  • 感谢 Paulo 提供的信息,但这与上面也使用 ffprobe 的已接受答案没有太大区别,您的方法只是看起来更干净一些。
【解决方案2】:

基于@blahdiblah 建议并受another question 启发的ffprobe 解决方案,答案:https://github.com/paulofreitas/php-ffprobe

注意:需要 ffmpeg 0.9+,支持所有 ffmpeg 支持的文件类型

使用类

// Example 1
$info = new ffprobe($filename);
var_dump($info->format->format_long_name); // e.g. string(10) "AVI format"
var_dump($info->streams[0]->duration);     // e.g. string(11) "5674.674675"

// Example 2 (prettified)
$info = new ffprobe($filename, true);
var_dump($info->format->format_long_name); // e.g. string(10) "AVI format"
var_dump($info->streams[0]->duration);     // e.g. string(14) "1:34:34.674675"

扩展类

class ffprobe_ext extends ffprobe
{
    public function __construct($filename)
    {
        parent::__construct($filename);
    }

    public function getVideoStream()
    {
        foreach ($this->streams as $stream) {
            if ($stream->codec_type == 'video') {
                return $stream;
            }
        }
    }

    public function getVideoInfo()
    {
        $stream = $this->getVideoStream();
        $info   = new ArrayObject(array(), ArrayObject::ARRAY_AS_PROPS);
        $info->duration     = (float) $stream->duration;
        $info->frame_height = (int) $stream->height;
        $info->frame_width  = (int) $stream->width;
        eval("\$frame_rate = {$stream->r_frame_rate};");
        $info->frame_rate   = (float) $frame_rate;

        return $info;
    }
}

$ffprobe = new ffprobe_ext($filename);
$info = $ffprobe->getVideoInfo();
var_dump($info->duration); // e.g. float(5674.674675)

欢迎进一步改进! :-)

【讨论】:

  • 感谢保罗的详细回答。这看起来正是我所需要的,但由于某种原因,该课程在这条线上失败了。我已经尝试过 .avi 和 .mpeg ,它们肯定是标准文件类型。我也在通过 git 使用最新版本的 ffmpeg: if (!isset($json->format)){throw new Exception('Unsupported file type');}
  • 这出乎意料...尝试在 if (...) 声明之前的 var_dump($json);,看看你从 shell_exec() 得到了什么。如果您的$json 转储{},则可能是某些事情没有按预期工作。在这种情况下,请告诉我您的终端为ffprobe -loglevel quiet -show_format -show_streams -print_format json video_file.avi 命令转储了什么(使用此更新编辑您的问题,cmets 有一些限制)。谢谢! :)
  • 我忘记在 json_decode 命令中添加 ffprobe 的路径。它现在有效,而且非常棒。非常感谢。最后一个问题,我怎样才能得到say var_dump($info->duration); 的值例如,对于 4.4 秒的视频,只返回 4.4 而不是返回 float(4.4)
  • 只需在您的代码上使用$info->duration(没有var_dump() 调用,我在示例中使用它来进行演示),例如如果您想显示该值,只需使用print $info->duration;printf('%0.2f', $info->duration); 打印它,如果您需要格式化它。 :)
  • 是的,我刚刚解决了,正要删除最后一条评论。再次感谢,非常感谢。
【解决方案3】:
$output = `ffmpeg -i /var/thismovie.avi`; //note that back quote is like exec
preg_match('/Duration: (.*?),.*?Video:.*?0x.*?([0-9]+)x([[0-9]+).*?([0-9]+) fps/i'
    ,$output , $result);

$result 数组的输出应该是这样的:

Array
(
    [0] => Duration: 00:00:10.76, start: 0.000000, bitrate: 5180 kb/s Stream #0:0: Video: h264 (High) (H264 / 0x34363248), yuv420p, 1280x720 [SAR 1:1 DAR 16:9], 25 fps
    [1] => 00:00:10.76
    [2] => 1280
    [3] => 720
    [4] => 25
)

更新

实际输出是多行,所以请将pattern更新成

/Duration: (.*?),.*?([0-9]+)x([0-9]+) \[.*?([0-9]+) fps/is

【讨论】:

  • 非常感谢。这里有一个完全的菜鸟问题,但我如何只获得其中一个值?我尝试了以下但只是得到一个错误,我看不出有什么问题 - $output = shell_exec($ffmpegPath . ' -i ' . $srcFile . ' 2>&1'); //注意反引号就像 exec preg_match('/Duration: (.*?),.*?Video:.*?0x.*?([0-9]+)x([[0-9]+ ).*?([0-9]+) fps/i',$output , $result); print_r($result[0]);
  • $output的内容是什么?只需执行echo $output 即可验证上述命令是否给出了结果
  • 如果你确定有输出,就做var_dump($result),如果数组和我发布的一样,你可以使用$result[1]访问变量持续时间,$result[2]访问宽度等等
  • 是的,它没有发生,var_dump($result) 给出一个空数组,var_dump($output) 给我整个 ffmpeg 输出,这是太多信息 - $output = shell_exec($ffmpegPath .' -我 /var/www/vhosts/somesite.com/httpdocs/movie.avi 2>&1');所以 $output 得到了一些东西,但 $result 什么也没得到。 '//note that back quote is like exec'是什么意思...什么是反引号?
  • 首先,编辑主要问题,将$output值粘贴到那里作为代码,似乎正则表达式中需要更改一些内容。现在关于反引号`你可以使用它而不是shell_exec,只需检查我的原始代码,看看我没有使用任何函数!
【解决方案4】:

请改用ffprobe

ffprobe 是与 FFmpeg 一起打包的工具,完全符合您所追求的目的:提取视频信息。输出各种容易解析的格式,比解析FFmpeg输出的附带信息要容易得多。

例如:

$ ffprobe -show_format -loglevel quiet mptestsrc.mp4 
[FORMAT]
filename=mptestsrc.mp4
nb_streams=1
format_name=mov,mp4,m4a,3gp,3g2,mj2
format_long_name=QuickTime/MPEG-4/Motion JPEG 2000 format
start_time=0.000000
duration=12.040000
size=237687
bit_rate=157931
TAG:major_brand=isom
TAG:minor_version=512
TAG:compatible_brands=isomiso2avc1mp41
TAG:encoder=Lavf54.20.100
[/FORMAT]

【讨论】:

  • 好的,这太棒了......但是,我如何获得我需要的具体信息。如何在 php 中仅提取持续时间、帧高度、帧宽度、帧速率?现在它与 ffmpeg -i 给出的输出几乎相同,只是它位于不同的行上。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-05
相关资源
最近更新 更多