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 你遇到问题了? 能分享下细节不.

9年前 评论
李小明 3年前
Summer

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

9年前 评论

报错Unable to load FFProbe

file
改怎么解决?

6年前 评论
AdamLu 4年前
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,
    安装不上,这是不兼容还是,人有碰到过吗,应该怎样解决呢???
5年前 评论
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

5年前 评论

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

5年前 评论

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

5年前 评论

@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');

}

}

5年前 评论

@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

5年前 评论

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

5年前 评论

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

5年前 评论

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

4年前 评论

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

4年前 评论

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:

4年前 评论

$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');

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

4年前 评论

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

4年前 评论
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');
4年前 评论

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

4年前 评论
李小明 3年前
$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打开失败

4年前 评论
phpervip 3年前

由于环境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
    在命令行,转码几个文件试试,就好了。
3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!