使用 PHP-FFMpeg 操作视频/音频文件

做音频合成的时候找到的一个php操作ffmpeg 的类库。GitHub地址:https://github.com/PHP-FFMpeg/PHP-FFMpeg/。本文的例子大部分都是上面的

在使用之前请安装好 FFMpeg 。如何安装?请看 FFmpeg 安装教程。

使用composer快速安装 > composer require php-ffmpeg/php-ffmpeg。

注意:请在 php.ini 中开启这两个函数proc_open,proc_get_status。找到 disable_functions 将里面的这两个函数去掉就行了

目录说明

/usr/loca/bin ffmpeg 的执行目录

/mnt/hgfs/www/test 本文章的测试目录

这里主要用 1080.mp4 这个视频做测试,下面就是这个 18 秒的视频(chrome 谷歌浏览器不显示播放器是因为https 的站不能使用未加密的http资源,唉)

https://www.bilibili.com/video/av17244788/

使用时请配置 ffmpeg,ffprobe 的执行文件绝对路径。我定义了一些测试用的视频音频文件

$path = [
    'ffmpeg.binaries'  => '/usr/local/bin/avconv',
    'ffmpeg.binaries' => '/usr/local/bin/ffmpeg',
    'ffprobe.binaries' => '/usr/local/bin/avprobe',
    'ffprobe.binaries' => '/usr/local/bin/ffprobe',
];
$ffmpeg = FFMpeg\FFMpeg::create($path);
$a1 = '/mnt/hgfs/www/test/a1.mp3';
$v1 = '/mnt/hgfs/www/test/v1.mp4';
$v2 = '/mnt/hgfs/www/test/v2.mp4';
$v3 = '/mnt/hgfs/www/test/v3.mp4';
$v1080 = '/mnt/hgfs/www/test/1080.mp4';

1、拼接视频/音频

$newFile = '/mnt/hgfs/www/test/video.mp4';
$video = $ffmpeg->open($v1);
$video->concat(array($v1,$v2,$v3))->saveFromSameCodecs($newFile, TRUE);

若是已存在合成的新文件 ($newFile 已存在),将会报错,请确保同一目录下不存在相同的文件

2、提取图像

提取一张

$video = $ffmpeg->open($v1080);
$frame = $video->frame(FFMpeg\Coordinate\TimeCode::fromSeconds(2));//提取第几秒的图像
$frame->save('image.jpg');

抽取多张

$video = $ffmpeg->open($v1080);
$video->filters()
    ->extractMultipleFrames(FFMpeg\Filters\Video\ExtractMultipleFramesFilter::FRAMERATE_EVERY_SEC, '/mnt/hgfs/www/test/image/')
    ->synchronize();
 
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/v2new.mp4');

注意:此方法会抽取对应的图片帧,而且每次都提取 400 张,不知道是不是我参数设置的问题(试了 FRAMERATE_EVERY_SEC,FRAMERATE_EVERY_2SEC,FRAMERATE_EVERY_10SEC)

3、生成音频波形

$audio = $ffmpeg->open($a1);
$waveform = $audio->waveform(640, 120, array('#00FF00'));
$waveform->save('waveform.png');//必须保存为 png 格式

若要提取视频的音频波形,须先转换为音频

// Open your video file
$video = $ffmpeg->open( 'video.mp4' );
 
// Set an audio format
$audio_format = new FFMpeg\Format\Audio\Mp3();
 
// Extract the audio into a new file as mp3
$video->save($audio_format, 'audio.mp3');
// Set the audio file
$audio = $ffmpeg->open( 'audio.mp3' );
 
// Create the waveform
$waveform = $audio->waveform();
$waveform->save( 'waveform.png' );

【免费分享】音视频学习资料包、大厂面试题、技术视频和学习路线图,资料包括(C/C++,Linux,FFmpeg webRTC rtmp hls rtsp ffplay srs 等等)有需要的可以点击788280672加群免费领取~

4、调整视频大小

$video = $ffmpeg->open($v1080);
$video->filters()->resize(new FFMpeg\Coordinate\Dimension(200,400), FFMpeg\Filters\Video\ResizeFilter::RESIZEMODE_FIT, true);
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/v1080_new.mp4');

注意:x264 类默认使用 libfaac 为编码器,但我安装的是 libfdk_aac,所以这里要指定为 libfdk_aac,不然会报错

参数说明:

resize(Dimension $dimension, $mode = ResizeFilter::RESIZEMODE_FIT, $forceStandards = true)

$dimension 调整后的视频宽高

$mode 四种缩放模式

RESIZEMODE_FIT 按给定值调整

RESIZEMODE_INSET 在给定的尺寸内调整大小,可能是按宽为基准(高等比缩放),也可能是按高为基准(宽等比缩放)

RESIZEMODE_SCALE_WIDTH 高为给定值,宽按比例缩放

RESIZEMODE_SCALE_HEIGHT 宽为给定值,高按比例缩放

$forceStandards ture / false,是否强制使用最近的纵横比标准


5、视频添加水印

$video = $ffmpeg->open($v1080);
$watermarkPath = '/mnt/hgfs/www/test/water.png';
$absolute = ['x' => 50,'y' => 100];
$relative = [
    'position' => 'relative',
    'bottom' => 50,
    'right' => 50
 ];
$video->filters()->watermark($watermarkPath, $absolute);
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/1080_new.mp4');

watermark($imagePath, array $coordinates = array())

$imagePath 水印图片路径

$coordinates 水印坐标

position 可选项 relative(相对定位) / absolute(绝对,默认)

若为 relative,有四个参数可选,top 、bottom、left、right ,分别对应四个方位

在上面的例子中就是在视频的右下角,距离右边50,距离下边50 的位置处添加水印(这个位置坐标是水印图片的左下角位置),如图

若为 absolute,直接填写 x 和 y 坐标即可 ,如图

6、调整视频的帧率

关于 帧率 和 GOP 介绍 http://blog.csdn.net/xiangjai/article/details/44238005

这玩意儿我也不懂,设置了几个值进行转换,但都time out 了,1g的虚拟机玩不起

$video = $ffmpeg->open($v1080);
$video->filters()->framerate(new \FFMpeg\Coordinate\FrameRate(3000), 120);
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/1080_new.mp4');

7、截取视频/音频

$video = $ffmpeg->open($v1080);
$video->filters()->clip(FFMpeg\Coordinate\TimeCode::fromSeconds(10));
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/1080_new.mp4');

clip($start, $duration = null)

从第 $start 秒开始,取 $duration 秒,若 $duration 不填,则截取至最后

8、裁剪视频

$video = $ffmpeg->open($v1080);
$video->filters()->crop(new FFMpeg\Coordinate\Point("t*100", 0, true), new FFMpeg\Coordinate\Dimension(960, 540));
$video->save(new FFMpeg\Format\Video\X264('libfdk_aac'), '/mnt/hgfs/www/test/1080_new.mp4');

crop(Point $point, Dimension $dimension)

$dimension 为裁剪后的尺寸

Point($x, $y, $dynamic = false)

$x 和 $y 为裁剪的起始坐标,$dynamic 为是否动态裁剪

动态裁剪是什么意思呢,比如:

Point("t*100", 0, true) 裁剪出来的视频就是画面从左边动态的移动到右边,然后就固定在左边

100 为速度,值越大,移动速度越快。话说这个动态裁剪没啥用的感觉

下面的视频为上面代码裁剪的,对比一下有什么不同

https://www.bilibili.com/video/av17244824/

9、音频转换

$audio = $ffmpeg->open($a1);
$format = new FFMpeg\Format\Audio\Flac();
$format->on('progress', function ($audio, $format, $percentage) {
    echo "$percentage % 进度";
});
$format->setAudioChannels(2)->setAudioKiloBitrate(256);
$audio->save($format, 'a1.flac');

Flac 为无损压缩格式

setAudioChannels 声道设置,1单声道,2双声道,3立体声

setAudioKiloBitrate 比特率

11、音频添加元数据

$audio = $ffmpeg->open($a1);
$audio->filters()->addMetadata([
    "title" => "Test Title",
    "artist" => "Jam00 artist",
    "album" => "Test album",
    "composer" => "Jam00",
    "track" => 1,
    "year" => 2017,
    "description" => "jam00 test description",
]);
$audio->save(new \FFMpeg\Format\Audio\Mp3, 'a1_new.mp3');

目前支持的数据是 title(标题),artist(艺术家),album(专辑),artist(艺术家),composer(作曲家),track(轨道),year(年),description(描述),artwork(艺术作品)

注:FFmpeg(3.2.2版本)只支持MP3文件添加 artwork 元数据

使用格式工厂查看a1_new.mp3的元数据

...
Format                                   : MPEG Audio
File size                                : 1.43 MiB
Duration                                 : 1 min 33 s
Overall bit rate mode                    : Constant
Overall bit rate                         : 128 kb/s
Album                                    : Test album
Track name                               : Test Title
Track name/Position                      : 1
Performer                                : Jam00 artist
Composer                                 : Jam00
Writing library                          : LAME3.99.5
year                                     : 2017
description                              : jam00 test description
...

12、Frame 提取图像

$video = $ffmpeg->open($v1080);
$frame = new FFMpeg\Media\Frame($video, FFMpeg\Driver\FFMpegDriver::load($path), FFMpeg\FFProbe::create($path), FFMpeg\Coordinate\TimeCode::fromSeconds(10));
$frame->save('frame.jpg');

其实 例子2 提取视频图像的方法 frame 调用的就是 Frame 类

13、从视频中提取动图

$video = $ffmpeg->open($v1080);
$video->gif(FFMpeg\Coordinate\TimeCode::fromSeconds(10), new FFMpeg\Coordinate\Dimension(400, 200), 3)->save('1080.gif');

gif(TimeCode $at, Dimension $dimension, $duration = null)

从第 $at 秒开始提取,持续 $duration 秒,保存为 $dimension指定大小(下面的例子为400x200) 的gif图

若不设置 $duration ,将会得到一个静止的gif图

动图太大,我就不上传了

14、视频格式转换

$video = $ffmpeg->open($v1080);
$format = new FFMpeg\Format\Video\X264('libfdk_aac');
$format->setKiloBitrate(1000)->setAudioChannels(2)->setAudioKiloBitrate(256);
$format->on('progress', function ($video, $format, $percentage) {
    echo "$percentage % 进度";
});
$video->save($format, '/mnt/hgfs/www/test/video.avi');

setKiloBitrate 设置视频比特率

setAudioChannels 声道设置,1单声道,2双声道,3立体声

setAudioKiloBitrate 设置音频比特率

15、添加额外参数(若你精通 ffmpeg 命令行参数)

$video = $ffmpeg->open($v1080);
$format = new FFMpeg\Format\Video\X264('libfdk_aac');
$format->setAdditionalParameters(array('foo', 'bar'));
$video->save($format, 'video.avi');

foo / bar 为 ffmpeg 支持的参数,这个就不测了

16、使用 FFProbe 提取元数据

$ffprobe = FFMpeg\FFProbe::create($path);
//视频
$videoInfo = $ffprobe->format($v1080);
//音频
$audioInfo = $ffprobe->format($a1);
//也可以使用 get 获取特定值,第二个参数为默认值(若该参数不存在将返回此默认值)
$duration = $ffprobe->format($v1080)->get('duration',100);
echo "<pre>";
print_r($videoInfo);
print_r($audioInfo);
echo "</pre>";
echo '视频时长:'.$duration;

FFMpeg\FFProbe\DataMapping\Format Object
(
    [properties:FFMpeg\FFProbe\DataMapping\AbstractData:private] => Array
        (
            [filename] => /mnt/hgfs/www/test/1080.mp4
            [nb_streams] => 2
            [nb_programs] => 0
            [format_name] => mov,mp4,m4a,3gp,3g2,mj2
            [format_long_name] => QuickTime / MOV
            [start_time] => 0.000000
            [duration] => 18.882000
            [size] => 9062983
            [bit_rate] => 3839840
            [probe_score] => 100
            [tags] => Array
                (
                    [major_brand] => isom
                    [minor_version] => 512
                    [compatible_brands] => isomiso2mp41
                    [encoder] => Lavf57.41.100
                )
 
        )
 
)
FFMpeg\FFProbe\DataMapping\Format Object
(
    [properties:FFMpeg\FFProbe\DataMapping\AbstractData:private] => Array
        (
            [filename] => /mnt/hgfs/www/test/a1.mp3
            [nb_streams] => 1
            [nb_programs] => 0
            [format_name] => mp3
            [format_long_name] => MP2/3 (MPEG audio layer 2/3)
            [start_time] => 0.000000
            [duration] => 93.348000
            [size] => 186696
            [bit_rate] => 16000
            [probe_score] => 51
        )
 
)
视频时长:18.882000

本内容为博主原创,转载请注明出处。

本文链接使用 PHP-FFMpeg 操作视频/音频文件

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/304569.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arcgis像元统计数据

目录 单幅影像统计多幅影像统计 单幅影像统计 现有一幅NDVI影像&#xff0c;如何知道影像中NDVI的分布情况呢&#xff1f; 先栅格转点&#xff0c;然后在属性表中查看汇总情况 还有一种方法就是在ENVI中打开&#xff0c; -0.3-0.338占据了99% 多幅影像统计 现有多幅NDVI影…

设置flex布局的元素,其子元素宽度和超过其本身时,其宽度值未被撑起问题

如图父元素main-content设置了display:flex. 里面包含了不确定个数的子元素&#xff0c;子元素样式为&#xff1a; flex: 1; min-width: 240px;现在想获取父元素的宽度&#xff0c;发现无论子元素的个数为多少&#xff0c;父元素的宽度都是一样的大小&#xff0c;并没有被子元…

使用 CompletableFuture 分批处理任务

一、无返回值任务函数 // 数据分批 List<List<StatisticsDTO>> batches Lists.partition(statisticsList, BATCH_SIZE); List<CompletableFuture<Void>> futures new ArrayList<>(batches.size());// 数据处理 for (int i 0; i < batches…

初学者的基本 Python 面试问题和答案

文章目录 专栏导读1、什么是Python&#xff1f;列出 Python 在技术领域的一些流行应用。2、在目前场景下使用Python语言作为工具有什么好处&#xff1f;3、Python是编译型语言还是解释型语言&#xff1f;4、Python 中的“#”符号有什么作用&#xff1f;5、可变数据类型和不可变…

imgaug库指南(12):从入门到精通的【图像增强】之旅

引言 在深度学习和计算机视觉的世界里&#xff0c;数据是模型训练的基石&#xff0c;其质量与数量直接影响着模型的性能。然而&#xff0c;获取大量高质量的标注数据往往需要耗费大量的时间和资源。正因如此&#xff0c;数据增强技术应运而生&#xff0c;成为了解决这一问题的…

【PB续命06】JDBC连接Oracle数据库

JDBC(Java DataBase Connectivity) 称为Java数据库连接&#xff0c;它是一种用于数据库访问的应用程序API&#xff0c;由一组用Java语言编写的类和接口组成&#xff0c;有了JDBC就可以用同一的语法对多种关系数据库进行访问&#xff0c;而不用担心其数据库操作语言的差异。 有了…

Git分支学习

Commit 每次 Commit &#xff0c;都会多一个节点&#xff0c;C1是C2的父节点&#xff0c;在C1的基础上产生。 使用 git commit 提交代码分支。 Branch 根据逻辑分解工作到不同的分支&#xff0c;在将分支和提交记录结合起来后&#xff0c;我们会看到两者如何协作。 在 mai…

KazooClient出现【句柄无效】错误

报错信息&#xff1b; Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection dropped: socket connection error: 句柄无效。 Connection …

一夜爆火,3天60亿,这泼天的富贵也轮到我们尔滨了

近日&#xff0c;哈尔滨这座北国之城突然成为全国瞩目的焦点&#xff0c;一夜之间&#xff0c;冰雪大世界、索菲亚大教堂、中央大街等老牌旅游景点在网络短视频和游客们的热切关注下&#xff0c;成为了这个冬季的新“顶流”。当地市民姚先生和胡先生异口同声表示&#xff1a;“…

new mars3d.graphic.CloudPrimitive({实现移动的积云云图效果

问题说明&#xff1a; 1.在Mars3d的示例中找到了【积云】的效果&#xff0c;查看【积云】的api的时候&#xff0c;发现了支持属性机制的property属性。 相关api链接&#xff1a; CloudPrimitive - V3.7.0 - Mars3D API文档 2.但是不知道该属性机制如何使用&#xff0c;于是翻…

最全最详细ChatGPT预设词Prompt教程

使用指南 1、可直复制使用 2、可以前往已经添加好Prompt预设的AI系统测试使用&#xff08;可自定义添加使用&#xff09; https://ai.sparkaigf.com 雅思写作考官 我希望你假定自己是雅思写作考官&#xff0c;根据雅思评判标准&#xff0c;按我给你的雅思考题和对应答案给我…

揭秘!更适合“SaaS体质”的用户反馈收集方式

用户反馈是收集用户需求最直观也是最有效的方法之一。特别是SaaS企业&#xff0c;经常需要收集用户反馈&#xff0c;再从中提取出真实需求进行产品或服务的迭代和升级。然而&#xff0c;在服务了多家SaaS企业之后&#xff0c;我们发现&#xff0c;无法在短时间内收集到足够多的…

CRM系统是否适合企业,有哪些判断标准?

现如今&#xff0c;以客户为中心不再是一句空话&#xff0c;哪个企业能与客户建立长久的关系&#xff0c;那它就能获得业绩的增长。CRM管理系统的初衷就是维护客户关系&#xff0c;通过深入了解客户&#xff0c;提高转化率&#xff0c;并推动业绩增长。企业在选型时&#xff0c…

Win提示“d3dx9_27.dll文件缺失,程序无法启动运行”,修复大全

d3dx9_27.dll是一个被多个软件和游戏共享的动态链接库文件&#xff0c;主要用于Microsoft DirectX软件的功能。它是DirectX 9的一部分&#xff0c;DirectX是一种使得Windows成为理想平台进行高性能多媒体和游戏的API。 d3dx9_27.dll主要与计算机图形和视频渲染有关&#xff0c…

SG-8018CA 系列 (晶体振荡器 可编程 可用+105°C )

SG-8018系列是可编程晶体振荡器系列与CMOS输出。虽然该系列提供了与早期SG-8002/SG-8003系列相同的易于编程的频率和其他参数的相似性&#xff0c;但它们也有一个更广泛的工作温度范围&#xff0c;最高限制为105C。除了2.52.0 mm封装&#xff0c;将使电子产品制造商节省板空间&…

为什么大型服务器要用 Linux 系统?

为什么大型服务器要用 Linux 系统&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「Linux的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff…

【Databand】日期时间函数

文章目录 获取当前日期和时间日期格式化函数日期加减运算日期时间和时间戳转化日期时间各部分拆分日期时间加减运算实际应用扩展总结 获取当前日期和时间 Databend 使用 UTC 作为默认时区&#xff0c;并允许您将时区更改为当前地理位置。 -- 查看时区 select timezone(); ---…

Qt 使用WINDOWS API读取SMBIOS信息,并通过CMD命令打印相关信息,参考DumpSMBIOS项目

在获取PE系统中的CPU、主板、内存信息时&#xff0c;发现使用WMI部分信息无法获取&#xff0c;通过gitGub上的DumpSMBIOS完全解决了这个问题&#xff0c;并单独做成了个案例&#xff0c;以下示例和代码都是参考DumpSMBIOS项目 SMBIOS这个数据还是用到的比较少。但是DumpSMBIOS项…

系列十四、理解MySQL varchar(50)

一、理解MySQL varchar(50) 1.1、概述 日常开发中&#xff0c;数据库建表是必不可少的一个环节&#xff0c;建表的时候通常会看到设定某个字段的长度为varchar(50)&#xff0c;例如如下建表语句&#xff1a; 那么怎么理解varchar(50)&#xff1f;这个分情况的&#xff0c;MySQ…

基于SpringBoot的教学管理系统

文章目录 项目介绍主要功能截图&#xff1a;部分代码展示设计总结项目获取方式 &#x1f345; 作者主页&#xff1a;超级无敌暴龙战士塔塔开 &#x1f345; 简介&#xff1a;Java领域优质创作者&#x1f3c6;、 简历模板、学习资料、面试题库【关注我&#xff0c;都给你】 &…