本文作者:申嫱嫱
🚩是什么?(Fast forward moving picture expert groups)
A complete, cross-platform solution to record, convert and stream audio and video.
FFmpeg 提供了多种媒体格式的封装和解封装,比如多种音视频编码,多种协议的流媒体,
多种色彩格式转换,多种采样率转换,多种码率切换,可以在多种操作系统安装使用。
🔫 ffplay的使用
作为FFmpeg的基础组件之一,它具有强大的音视频解码播放能力,也可以作为音视频数据的图形化分析工具,是Linux和macOS系统中最常用的多媒体播放器之一,目前它广泛被各种流行播放器(QQ影音、暴风影音等)集成应用;可随时快速地调用ffplay对音视频文件播放和测试;
// ffplay按某个日志输出级别进行播放
ffplay -loglevel [debug|quiet|panic|fatal|error|warning...] -i demo.mp4
// 全屏播放 可选择禁用音视频字幕流
ffplay [-an|-vn|-sn] -i demo.mkv -fs
// 指定播放起始时间 时长
ffplay -ss 300 -t 20 -i input.avi -autoexit
// 查看音频波形/频谱
ffplay -showmode [1|2] test.mp3
.....
🔫 ffprobe的使用
是FFmpeg提供的媒体信息检测工具,使用ffprobe不仅可以检测音视频文件的整体封装格式,还可以分析其中每一路音频流或视频流信息,甚至可以进一步分析音视频流的每一个码流包或图像帧的信息
ffprobe -i demo.mp4
- 默认情况下会检测输入音视频文件的封装格式、metadata信息,以及媒体文件的总时长、起始时间及码率、每一路媒体流的信息:
-
- 对视频流,输出编码格式、图像颜色格式、图像的宽与高、纵横比和视频码率;
- 对音频流,输出编码格式、采样率、音频类型、音频码率
//显示详细的封装格式信息
ffprobe -show_format -i demo.mp4
//显示每一路媒体流信息(一个音视频文件通常包括两路及以上媒体流)
ffprobe -show_streams -i demo.mp4
//音频采样和视频的图像帧都被压缩为多个码流包,再保存在容器文件中
//显示每一个码流包信息
ffprobe -show_packets -i demo.mp4
//显示每一帧图像的信息(对视频流的每一帧图像进行解码)
ffprobe -show_frames -i demo.mp4
🔫 ffmpeg的命令
通常一路音频信号或一路视频信号编码后会生成各自的编码数据流,媒体信息在播放时会同时播放这样的多路媒体流,为了解决多路音视频流的同步问题,基本数据流在经过处理后需复用到一个文件中,这就是文件容器格式/封装格式,包含了音视频码流信息、音视频同步信息、以及可能有的字幕流数据和元数据(发行商、语言、演员信息等)。
视频播放器播放一个视频文件,会经历下面的过程,随后根据解封装时获取到的参数信息,同步解码出来的视频和音频数据,将其送至系统的显卡和声卡播放出来
💁🏻 封装格式转变
ffmpeg -i demo.mp4 output.avi
可以看出,输出文件的视频流和音频流的编码格式都发生了改变,说明在转封装同时发生了转码操作,它会将音视频流转码为目标封装格式的默认编码格式。
🚰 转码输出的过程
将一个音视频文件作为输入源,设置编码参数和封装格式,指定输出文件后转码
ffmpeg -i input.flv -c:v libx264 -b:v 3000k -r 25 new_output.mp4
因为编解码耗cpu资源,所以如果直接把输入文件中的音视频包封装入输出文件,速度会快很多
🚰 流复制
只执行demuxing和muxing。它对于更改容器格式或修改容器级元数据非常有用。
应用过滤器显然也是不可能的,因为过滤器处理未压缩的数据。
ffmpeg -i demo.mp4 -c copy output.avi
ffmpeg -i demo.mp4 -codec copy output.avi
🚰 数据流选择
- 每个输入或输出原则上可以包含任意数量的不同类型的流(视频/音频/字幕/附件/数据)。允许的流的数量和/或类型可能受到容器格式的限制。选择哪个流进入哪个流输出,要么自动完成,要么使用-map选项来指定媒体流。
-
-
ffmpeg -i input1.mp4 -i input2.mp4 -map 0:a -map 1:v output.mp4
-
文件中的流通过其索引来引用
ffmpeg不验证指定的编码器是否可以转换所选流,或者转换后的流在输出格式中是否可接受。所以这将导致:当用户手动设置编码器时,流选择过程不能检查编码的流是否可以混合到输出文件中。如果不能,ffmpeg将中止,所有输出文件将无法处理。
💁🏻 滤镜使用
avfilter组件用于多媒体的处理和编辑
🌰:
- 为视频加水印:
-
- 文字水印:
-
ffmpeg -i demo.mp4 -vf "drawtext=fontsize=60:fontfile=lazy.ttf:text='hello sqq %{localtime:%Y-%m-%d}':x=100:y=100:fontcolor=green:box=1:boxcolor=yellow:enable=lt(mod(t,3),1)" out.mp4 - 暂时无法在飞书文档外展示此内容
- 图片水印
- 使用movie滤镜
-
ffmpeg -i demo.mp4 -vf "movie=icon.jpeg[wm];[in][wm]overlay=30:10[out]" output.mp4
画中画:
ffmpeg -y -re -i demo.mp4 -t 10 -vf "movie=333.mp4,scale=480x320[test];[in][test] overlay =x='if(gte(t,2),-w+(t-2)*200,NAN)':y=0 [out]" -vcodec libx264 output_danmu.flv
多宫格
ffmpeg -re -i demo.mp4 -re -i ./video/1.avi -re -i ./video/2.wmv -re -i ./video/8.flv -t 5 -filter_complex "nullsrc=size=640x480 [base]; [0:v] setpts=PTS-STARTPTS,scale=320x240 [upperleft]; [1:v] setpts=PTS-STARTPTS, scale=320x240 [upperright];[2:v] setpts=PTS-STARTPTS, scale=320x240 [lowerleft]; [3:v] setpts=PTS-STARTPTS, scale=320x240 [lowerright]; [base][upperleft] overlay=shortest=1[tmp1]; [tmp1][upperright] overlay=shortest=1:x=320 [tmp2]; [tmp2][lowerleft]overlay=shortest=1:y=240 [tmp3]; [tmp3][lowerright] overlay=shortest=1:x=320:y=240" -c:v libx264 output_4.mp4
字幕滤镜:
- 将字幕编码进入视频流,和视频增加水印相似
- 在封装容器中加入字幕流(需要容器支持加入字幕流)
ffmpeg -i ./video/2.wmv -vf ass=test.ass -f mp4 -t 10 output_ass.mp4
ffmpeg -i output_4.mp4 -i test.ass -acodec copy -vcodec copy -scodec copy -t 10 output.mkv
-
- 音频流滤镜 包含了重采样、混音器 、调整音频时间戳、淡入淡出、静音检测等几十种滤镜
- 视频滤镜 包含图像剪切、水印处理、色彩空间变换、3d视频处理、定时视频截图、音视频倍速等许多渲染效果...
🔫 FFmpeg在浏览器中的使用
FFmpeg底层用c语言实现,基于WebAssembly,使得我们在浏览器上也可以调用ffmpeg,ffmpeg.wasm是FFmpeg的纯Webassembly端口。它可以让我们在浏览器内部进行视频和音频录制,转码和传输。通过npm 安装 npm install @ffmpeg/ffmpeg @ffmpeg/core
//加载可供使用的 WebAssembly 文件,创建 FFmpeg 实例
const { createFFmpeg } = FFmpeg;
this.ffmpeg = createFFmpeg({log: true });
...
async clipFile(){
...
ffmpeg.FS('writeFile', name, await fetchFile(file));
await ffmpeg.run('-y','-i', name,'-ss', startTime,'-to', endTime,'-c:a', 'copy', 'outputs.mp4');
const data = ffmpeg.FS('readFile', 'outputs.mp4');
const tempURL = URL.createObjectURL(new Blob([data.buffer], { type: 'video/mp4' }));
...
}
也可以根据自己的业务需求,来调整包大小,或者如果想用新版本的 FFmpeg 来打包,可以编译自己的wasm包.(可以参考编译ffmpeg.wasm)