Laravel 下使用 FFmpeg 处理多媒体文件

说明#

最近在项目里使用 FFmpeg 做音频格式转换,这里做个笔记.

什么是 FFmpeg?#

  • FFmpeg 是一个自由软件,可以运行音频和视频多种格式的录影、转换、流功能,包含了 libavcodec ─这是一个用于多个项目中音频和视频的解码器库,以及 libavformat—— 一个音频与视频格式转换库。
  • 这个项目最初是由 Fabrice Bellard 发起的,而现在是由 Michael Niedermayer 在进行维护。许多 FFmpeg 的开发者同时也是 MPlayer 项目的成员,FFmpeg 在 MPlayer 项目中是被设计为服务器版本进行开发。
  • -- 上面的解释引自 Wiki

应用领域#

  • FFmpeg 被许多开源项目采用,比如 ffmpeg2theora, VLC, MPlayer, HandBrake, Blender, Google Chrome 等。
  • 还有 DirectShow/VFW 的 ffdshow (external project) 和 QuickTime 的 Perian (external project) 也采用了 FFmpeg。
  • KMPlayer、格式工厂、暴风影音、QQ 影音、KMP、GOM Player、PotPlayer(2010)都在其列。

安装 FFmpeg 命令#

下面是 Ubuntu 14 LTS 的安装方法:

sudo apt-add-repository ppa:mc3man/trusty-media
sudo apt-get update
sudo apt-get install -y ffmpeg gstreamer0.10-ffmpeg

安装成功后测试:

$ ffmpeg -version

file

PHP-FFMpeg#

PHP-FFMpeg 是 FFMpeg 和 FFProbe 命令的 PHP 面对对象 Wrapper.

安装#

项目根目录下:

$ composer require "php-ffmpeg/php-ffmpeg:~0.5"

使用#

创建 FFMpeg\FFMpeg 对象:

$ffmpeg = FFMpeg\FFMpeg::create(array(
    'ffmpeg.binaries'  => '/opt/local/ffmpeg/bin/ffmpeg',
    'ffprobe.binaries' => '/opt/local/ffmpeg/bin/ffprobe',
    'timeout'          => 3600, // The timeout for the underlying process
    'ffmpeg.threads'   => 12,   // The number of threads that FFMpeg should use
), $logger);

视频处理#

视频转码#

$video = $ffmpeg->open('video.mpeg');

$format = new Format\Video\X264();
$format->on('progress', function ($video, $format, $percentage) {
    echo "$percentage % transcoded";
});

$format
    -> setKiloBitrate(1000)          // 视频码率
    -> setAudioChannels(2)        // 音频声道
    -> setAudioKiloBitrate(256); // 音频码率

// 保存为
$video->save($format, public_path().'/uploads/video/video.avi');

视频截图#

// 在视频 42 秒的地方截图
$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(42));
$frame->save('image.jpg');

视频旋转#

$video->filters()->rotate($angle)->synchronize();

$angle 参数的选项从下面选取:

  • FFMpeg\Filters\Video\RotateFilter::ROTATE_90 : 90° 顺时针方向
  • FFMpeg\Filters\Video\RotateFilter::ROTATE_180 : 180°
  • FFMpeg\Filters\Video\RotateFilter::ROTATE_270 : 90° 逆时针方向

synchronize 方法是触发保存的动作,因为 filters 可以多个链接起来,如下:

$video
    ->filters()
    ->resize($dimension, $mode, $useStandards)
    ->framerate($framerate, $gop)
    ->synchronize();

调整视频尺寸#

$video->filters()->resize($dimension, $mode, $useStandards);

传参见: 文档

视频帧速率#

$video->filters()->framerate($framerate, $gop);

传参见: 文档

视频裁剪#

$video->filters()->clip(FFMpeg\Coordinate\TimeCode::fromSeconds(30), FFMpeg\Coordinate\TimeCode::fromSeconds(15));

传参见: 文档

音频处理#

音频格式转换#

$audio = $ffmpeg->open('track.mp3');

$format = new FFMpeg\Format\Audio\Flac();
$format->on('progress', function ($audio, $format, $percentage) {
    echo "$percentage % transcoded";
});

$format
    -> setAudioChannels(2)
    -> setAudioKiloBitrate(256);

$audio->save($format, public_path().'/uploads/video/track.flac');

音频采样率#

$audio->filters()->resample(16000);

音频转换示例#

在我的项目中,需要把 8khz 采样率, 单声道的 amr 文件 转换为 16khz 采样率, 单声道的 wav 文件 , 下面是实例代码:

$audio_path = public_path().'/uploads/audio/';
$random_string = str_random(10);
$amr_filename = $random_string.'.amr';
$wav_filename = $random_string.'.wav';

Input::file('audio_file')->move($audio_path, $amr_filename);

$audio = $ffmpeg->open($audio_path.$amr_filename);
$format = new FFMpeg\Format\Audio\Wav();
$format->setAudioChannels(1);
$audio->filters()->resample('16000');

$audio->save($format, $audio_path.$wav_filename);

总结#

利用此工具,可以对多媒体文件进行自由修改,在很多应用场景下都能应用上,把 TA 放到你的工具箱里面吧 :sparkles: .

另外,还有一个很棒的项目 sonus, 专门为 Laravel 框架而写的,唯一遗憾的是未能支持 filters.

摈弃世俗浮躁,追求技术精湛
本帖已被设为精华帖!
Summer
《L03 构架 API 服务器》
你将学到如 RESTFul 设计风格、PostMan 的使用、OAuth 流程,JWT 概念及使用 和 API 开发相关的进阶知识。
《L02 从零构建论坛系统》
以构建论坛项目 LaraBBS 为线索,展开对 Laravel 框架的全面学习。应用程序架构思路贴近 Laravel 框架的设计哲学。
讨论数量: 22
Summer

@fasthold 你遇到问题了?能分享下细节不.

10年前 评论
李小明 4年前
Summer

@fasthold 多谢你的分享,很宝贵的经验,aac 还是挺常见的格式,我在项目里面只用到 amrwav 之间的互转.

10年前 评论

报错 Unable to load FFProbe

file
改怎么解决?

7年前 评论
AdamLu 5年前
virtual

laravel 5.6 安装 php-ffmpeg
$sudo composer require "php-ffmpeg/php-ffmpeg"
[sudo] password for mrchen:
Do not run Composer as root/super user! See https://getcomposer.org/root for details
Using version ^0.12.0 for php-ffmpeg/php-ffmpeg
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

Problem 1

  • Installation request for php-ffmpeg/php-ffmpeg ^0.12.0 -> satisfiable by php-ffmpeg/php-ffmpeg[v0.12].
  • Conclusion: remove symfony/console v4.1.3

  • php-ffmpeg/php-ffmpeg v0.12 requires alchemy/binary-driver ^1.5 -> satisfiable by alchemy/binary-driver[1.5.0, 1.6.0].
  • alchemy/binary-driver 1.5.0 requires symfony/process ~2.0 -> satisfiable by symfony/process[2.0.4, 2.0.5, 2.0.6, 2.0.7,
    安装不上,这是不兼容还是,人有碰到过吗,应该怎样解决呢???
6年前 评论
virtual

转码 3.2GB 的 mp4 文件,快完的时候报这个错误,请问有人碰以过吗??
message Encoding failed
exception FFMpeg\Exception\RuntimeException
file /data/VirtualData/web/company/Star-Video-Control/vendor/php-ffmpeg/php-ffmpeg/src/FFMpeg/Media/AbstractVideo.php
line 106

6年前 评论

@yxiawen 解决了么?我今天也遇到了

6年前 评论

在 windows 上使用是不是需要给 php 安装.dll 文件的扩展?我在官网下载下来的是.exe。github 上的说的是:For Windows users: Please find the binaries at http://ffmpeg.zeranoe.com/builds/. 这个 binaries 是什么??怎么用???在此先谢过各位!

6年前 评论

@qingyi https://www.cnblogs.com/love-snow/articles...

config/element.php:

<?php
return [
'ffmpegpath' =>'E:/ 谷歌浏览器下载 /ffmpeg-20181105-beaa350-win64-static/bin/ffmpeg.exe -i "% s" 2>&1',
'ffmpeg' =>'E:/ 谷歌浏览器下载 /ffmpeg-20181105-beaa350-win64-static/bin/ffmpeg.exe',
'ffprobe' =>'E:/ 谷歌浏览器下载 /ffmpeg-20181105-beaa350-win64-static/bin/ffprobe.exe',
];

使用:

<?php

namespace App\Http\Controllers;

use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Validator;
use FFMpeg;
use Config;

class IndexController extends Controller
{
public function index(Request $request)
{
$ffmpeg_path = Config::get ("element.ffmpeg");//ffmpeg 运行的路径
$ffprobe_path = Config::get ("element.ffprobe");//ffprobe 运行路径
$ffmpeg = FFMpeg\FFMpeg::create(array(
'ffmpeg.binaries' => $ffmpeg_path,
'ffprobe.binaries' => $ffprobe_path,
'timeout' => 30000, // The timeout for the underlying process
'ffmpeg.threads' => 12, // The number of threads that FFMpeg should use
));

    $video = $ffmpeg->open('../video.mp4');

    $format = new FFMpeg\Format\Video\X264('libmp3lame', 'libx264');
    $format->on('progress', function ($video, $format, $percentage) {
        echo "$percentage % transcoded";
    });

    $format
        -> setKiloBitrate(1000)          // 视频码率
        -> setAudioChannels(2)        // 音频声道
        -> setAudioKiloBitrate(256); // 音频码率

    // 保存为
    $video->save($format, 'test.mp4');

}

}

6年前 评论

@xkcaaa 我用 laravel5.7 window 平台 phpstudy php7.2+apache , 按照你说的配置 ,可以获取到 $ffmepg 对象,但是在对文件进行转码时就包 服务器 500 错误了,我查看 error.log 显示
[core:error] [pid 5268:tid 2132] [client 127.0.0.1:57428] End of script output before headers: index.php

6年前 评论

@景哥哥
你的视频文件是多大的?换个小点的视频文件试一下?会不会是因为转码时间过长?之前我只是图快随意写在控制器里了,这种场景还是使用 laravel 新建一个命令来运行比较合适。

6年前 评论

sudo apt-get install -y ffmpeg 后面版本是不该去了啊

6年前 评论

如果只是两个音视频的简单合并,有什么好的方法推荐?

6年前 评论

我的视频切割后有声音,无画面,要怎么解决呢,求大佬回复啊

6年前 评论

FFMpeg \ Exception \ RuntimeException
Unable to save frame
Previous exceptions
ffmpeg failed to execute command '/usr/local/Cellar/ffmpeg/4.1.3_1/bin/ffmpeg' '-y' '-ss' '00:00:05.00' '-i' 'http://vfx.mtime.cn/Video/2019/02/04/mp4/1...' '-vframes' '1' '-f' 'image2' 'image1.mjpeg': Error Output: ffmpeg version 4.1.3 Copyright (c) 2000-2019 the FFmpeg developers built with Apple LLVM version 10.0.1 (clang-1001.0.46.4) configuration: --prefix=/usr/local/Cellar/ffmpeg/4.1.3_1 --enable-shared --enable-pthreads --enable-version3 --enable-hardcoded-tables --enable-avresample --cc=clang --host-cflags='-I/Library/Java/JavaVirtualMachines/adoptopenjdk-11.0.2.jdk/Contents/Home/include -I/Library/Java/JavaVirtualMachines/adoptopenjdk-11.0.2.jdk/Contents/Home/include/darwin' --host-ldflags= --enable-ffplay --enable-gnutls --enable-gpl --enable-libaom --enable-libbluray --enable-libmp3lame --enable-libopus --enable-librubberband --enable-libsnappy --enable-libtesseract --enable-libtheora --enable-libvorbis --enable-libvpx --enable-libx264 --enable-libx265 --enable-libxvid --enable-lzma --enable-libfontconfig --enable-libfreetype --enable-frei0r --enable-libass --enable-libopencore-amrnb --enable-libopencore-amrwb --enable-libopenjpeg --enable-librtmp --enable-libspeex --enable-videotoolbox --disable-libjack --disable-indev=jack --enable-libaom --enable-libsoxr libavutil 56. 22.100 / 56. 22.100 libavcodec 58. 35.100 / 58. 35.100 libavformat 58. 20.100 / 58. 20.100 libavdevice 58. 5.100 / 58. 5.100 libavfilter 7. 40.101 / 7. 40.101 libavresample 4. 0. 0 / 4. 0. 0 libswscale 5. 3.100 / 5. 3.100 libswresample 3. 3.100 / 3. 3.100 libpostproc 55. 3.100 / 55. 3.100 Input #0, mov,mp4,m4a,3gp,3g2,mj2, from 'http://vfx.mtime.cn/Video/2019/02/04/mp4/1...': Metadata: major_brand : isom minor_version : 512 compatible_brands: isomiso2avc1mp41 encoder : www.aliyun.com - Media Transcoding Duration:

6年前 评论

$ffmpeg = FFMpeg::create(array(
'ffmpeg.binaries' => '/usr/local/Cellar/ffmpeg/4.1.3_1/bin/ffmpeg',
'ffprobe.binaries' => '/usr/local/Cellar/ffmpeg/4.1.3_1/bin/ffprobe',
'timeout' => 3600, // The timeout for the underlying process
'ffmpeg.threads' => 12, // The number of threads that FFMpeg should use
));

    $file = "http://vfx.mtime.cn/Video/2019/02/04/mp4/190204084208765161.mp4";
    $video = $ffmpeg->open($file);

    $time = TimeCode::fromSeconds(5);
    $frame = $video->frame($time);
    $frame->save('image1.jpg');

不知道什么原因报楼上的错误

6年前 评论

一个视频有多条音频,怎么提取特定的一条音频?

5年前 评论
wanghan

@Summer 根据该拓展包的 issues,新版本的 ffmpeg 如果用格式转换需要这样用

$video = $ffmpeg->open('video.mpeg');

$format = new Format\Video\X264('libmp3lame');  //我改了这里!!这里!!看这里~~
$format->on('progress', function ($video, $format, $percentage) {
    echo "$percentage % transcoded";
});

$format
    -> setKiloBitrate(1000)          // 视频码率
    -> setAudioChannels(2)        // 音频声道
    -> setAudioKiloBitrate(256); // 音频码率

// 保存为
$video->save($format, public_path().'/uploads/video/video.avi');
5年前 评论

ffmpeg 太占资源了。看到进程了出现 ffmpeg 就哆嗦,CPU 直接满格

5年前 评论
李小明 4年前

大佬 pcm 怎么转 wav

5年前 评论
$ffmpeg = \FFMpeg\FFMpeg::create(array(
    'ffmpeg.binaries'  => 'D:/ffmpeg/bin/ffmpeg.exe',
    'ffprobe.binaries' => 'D:/ffmpeg/bin/ffprobe.exe',
    'timeout'          => 3600, // The timeout for the underlying process
    'ffmpeg.threads'   => 12,   // The number of threads that FFMpeg should use
));                             
$audio = $ffmpeg->open($audio_path.$file_name);

open 打开失败

5年前 评论
phpervip 5年前

由于环境 ubuntu 版本不一样,用楼主的方法安装不了了,
环境是课程里的:
vagrant@homestead:~/code/myblog$ uname -a
Linux homestead 4.15.0-38-generic #41-Ubuntu SMP Wed Oct 10 10:59:38 UTC 2018 x86_64 x86_64 x86_64 GNU/Linu

后来参考这一篇:www.jianshu.com/p/d461a27edf0d


下载源码包,再解压。再按教程一步步。
code.videolan.org/videolan/x264#
安装 x264
最后安装成功:

可以处理 http://…./video.mp4 网络的视频,

 //1.获取ffmpeg实例
$ffmpeg = FFMpeg::create(array(
    'ffmpeg.binaries' => '/usr/local/ffmpeg/bin/ffmpeg',//安装的ffmpeg服务绝对地址
    'ffprobe.binaries' => '/usr/local/ffmpeg/bin/ffprobe',//安装的ffprobe服务绝对地址
    'timeout' => 3600, // The timeout for the underlying process
    'ffmpeg.threads' => 12,   // The number of threads that FFMpeg should use
));
//打开视频文件
 // 绝对路径 或 网络url
$video = $ffmpeg->open('/home/vagrant/code/laravel6_edu/storage/app/public/upload/file/202006/7f0ea1077c04b5f09c5626f23f51e2c4.mp4');
//视频的视频信息
$video_info = $video->getStreams()->videos()->first()->all();
//单独获取某一个
$profile = $video->getStreams()->videos()->first()->get('profile');
//获取视频尺寸有单独的方法  $dimensions=$video->getStreams()->videos()->first()->getDimensions();
//视频的音频信息
$audio_info_rate = $video->getStreams()->audios()->first()->all();
//单独获取某一个
$sample_rate = $video->getStreams()->audios()->first()->get('sample_rate');

有同学一起学习讨论么。
补充:在转码时,报了错,后来发现是没有安装 libx264, libmp3lame,

  1. unknown encoder ‘libx264’
    要安装 libx264, 上面有网址
  2. ERROR: libmp3lame >= 3.98.3 not found
    sudo apt-get install yasm libmp3lame-dev
    安装之后,再进入 ffmpeg 源码目录编译:
    ./configure –prefix=/usr/local/ffmpeg –enable-shared –disable-static –disable-doc –enable-ffplay –enable-libmp3lame –enable-libx264 –enable-gpl –disable-asm
    make (这个时间较长,10 分钟)
    sudo make install
    在命令行,转码几个文件试试,就好了。
5年前 评论