在之前的文章入门视频看这一篇足够 中我们提到了 FFmpeg,也使用了 FFmpeg 最基本的命令:ffmpeg -i somemoive.mp4
。今天我们就通过源码的方式来剖析 FFmpeg 的运行机制。
概览
ffmpeg总共有 7 大库,分别是
- avdevice
- avcodec
- avformat
- swresample
- swscale
- postproc
- avfilter
加上他们的共同依赖avutil,就算是八大库吧。
这几大库按需配置,为了减少体积,建议将不用的关闭掉,关闭的时候还要根据他们之间的依赖关系,这个依赖关系可以在源代码ffbuild/config.mak
中看出。
下载/编译/运行(VSCode)
git clone
git clone https://git.ffmpeg.org/ffmpeg.git ffmpeg
配置
./configure --enable-debug=3 --disable-optimizations
比如我只想编译 h264 的解码器和支持硬解,那么只需要如下即可,没有配置的都会关闭,只打开你所配置的。
./configure --disable-everything --enable-decoder=h264 --enable-hwaccel=h264_dxva2
其他参数
–enable-shared
默认情况下编译的库是静态的,如果我们想编译动态的,那么就可以加上这个选项。
make
make -j2
执行这一步后会发现多了很多文件。其中,以 _g 结尾的就是可以调试的程序
- ffmpeg_g
- ffplay_g
- ffprobe_g
编辑 launch.json 文件
{
"version": "0.2.0",
"configurations": [
{
"type": "lldb",
"request": "launch",
"name": "Debug",
"program": "${workspaceFolder}/ffmpeg_g",
"args": [
"-i",
"/Users/kyson.cn/Downloads/kyson.cn.mp4"
],
"cwd": "${workspaceFolder}"
}
]
}
运行
运行后打印出了如下信息:
ffmpeg version N-115575-g4e120fbbbd Copyright (c) 2000-2024 the FFmpeg developers
built with Apple clang version 15.0.0 (clang-1500.3.9.4)
configuration: --enable-debug=3 --disable-optimizations
libavutil 59. 21.100 / 59. 21.100
libavcodec 61. 6.100 / 61. 6.100
libavformat 61. 3.104 / 61. 3.104
libavdevice 61. 2.100 / 61. 2.100
libavfilter 10. 2.102 / 10. 2.102
libswscale 8. 2.100 / 8. 2.100
libswresample 5. 2.100 / 5. 2.100
Input #0, mov,mp4,m4a,3gp,3g2,mj2, from '/Users/kyson/Downloads/7365320336742599978.mp4':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
comment : vid:v12044gd0000cordva7og65qe9e89sqg
aigc_info : {"aigc_label_type": 0}
encoder : Lavf58.76.100
Duration: 00:01:12.91, start: 0.000000, bitrate: 948 kb/s
Stream #0:0[0x1](und): Video: h264 (High) (avc1 / 0x31637661), yuv420p(tv, bt709, progressive), 576x768 [SAR 1:1 DAR 3:4], 909 kb/s, 30 fps, 30 tbr, 15360 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
Stream #0:1[0x2](und): Audio: aac (HE-AACv2) (mp4a / 0x6134706D), 44100 Hz, stereo, fltp, 32 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
At least one output file must be specified
这是因为我们在 launch.json
中指定的参数是 -i
,也就相当于执行我们之前提到的 ffmpeg -i yourmovie.mp4
命令。
下载/编译/运行(Xcode)
相信大部分人在 Mac 开发使用的还是 Xcode,因此我这边顺带把 Xcode 的配置也说了,懒得操作的,可以到 GitHub 里找一个别人现成编译好的,比如这个:FFmpeg-in-Xcode。
大概思路就是:
- 新建一个 Mac 下的命令行工程,暂且命名为 ffmpegDemo;
- 拿到 make 产物,然后拖到 Xcode 项目中,等待其 index 完成(过程漫长)
- 新建一个 target,暂且命名为 ffmpeg_cmd ,设置其 directory 以及 scheme
- 搞定
最终版本给大家截个图:
小试身手
在 ffmpeg.c 中打个断点,可以看到成功了。
调用栈:
我们看一下堆栈,分别在如下文件中:
ffmpeg_opt.c
:负责解析命令行输入的参数
更进一步
格式转换
ffmpeg 的另外一个功能是转换文件类型,比如将 mp4 文件转换为 avi,对应的命令为: ffmpeg -i yourvideo.mp4 target.avi
如果要逐步调试,查看调用堆栈的话,我们只需要在 launch.json 中稍加改动即可。
"args": [
"-i",
"/Users/kyson.cn/Downloads/kyson.cn.mp4"
"/Users/kyson.cn/Downloads/target.avi"
],
改完后,点击编译运行,就能在 /Users/kyson.cn/Downloads 文件夹下找到 target.avi 文件;另一方面,在 vscode 中也会打印出相应的数据,来展示 avi 文件的信息:
Output #0, avi, to '/Users/kyson.cn/Downloads/target.avi':
Metadata:
major_brand : isom
minor_version : 512
compatible_brands: isomiso2avc1mp41
ICMT : vid:v12044gd0000cordva7og65qe9e89sqg
aigc_info : {"aigc_label_type": 0}
ISFT : Lavf61.3.104
Stream #0:0(und): Video: mpeg4 (FMP4 / 0x34504D46), yuv420p(tv, bt709, progressive), 576x768 [SAR 1:1 DAR 3:4], q=2-31, 200 kb/s, 30 fps, 30 tbn (default)
Metadata:
handler_name : VideoHandler
vendor_id : [0][0][0][0]
encoder : Lavc61.6.100 mpeg4
Side data:
cpb: bitrate max/min/avg: 0/0/200000 buffer size: 0 vbv_delay: N/A
Stream #0:1(und): Audio: ac3 ([0] [0][0] / 0x2000), 44100 Hz, stereo, fltp, 192 kb/s (default)
Metadata:
handler_name : SoundHandler
vendor_id : [0][0][0][0]
encoder : Lavc61.6.100 ac3
[out#0/avi @ 0x7f9288707140] video:6605KiB audio:1710KiB subtitle:0KiB other streams:0KiB global headers:0KiB muxing overhead: 1.337688%
frame= 2187 fps=1126 q=31.0 Lsize= 8427KiB time=00:01:12.90 bitrate= 946.9kbits/s speed=37.5x
视频截取
命令为: ffmpeg -ss 00:00:00 -t 00:00:30 -i yourvideo.mp4 -vcodec copy -acodec copy target.mp4
,含义是截取视频 00:00:00 到 00:00:30 的视频,不改变音视频编码方式,目标视频文件名为 target.mp4
提取音频
对应的命令为:ffmpeg -i yourvideo.mp4 -vn getAudio.mp3
。
提取图片
每隔 5s 提取视频中的一张图片:ffmpeg -i yourvideo.mp4 -r 5 -f image2 image_%2d.png
。
转 m3u8 文件
将视频转成 m3u8 格式,方便网络传输:
ffmpeg -i yourvideo.mp4 -vcodec copy -acodec copy -hls_list_size 0 -f hls/index.m3u8
需要注意的是,要提前建一个 hls 文件夹。
设置 IDR 帧间隔
可以通过 -g(GOP size)参数控制 IDR 帧的间隔。GOP 是指 "Group of Pictures",设置 GOP size 也意味着设置了插入 IDR 帧的频率。
ffmpeg -i input.mp4 -g 60 output.mp4
这意味着每隔 60 帧插入一个 IDR 帧(在 30fps 的视频中相当于每隔 2 秒插入一个 IDR 帧)。
其他
其他还有转码之类。