6:FFmpeg--音视频领域绕不开的工具(上)
零、前言
FFmpeg的这篇文章,我迟迟没有动笔,怕自己写不好,查了很多资料,又看了好多关于FFmpeg的书籍。因为它实在是太庞大了,功能又极其丰富。
动笔的这一刻我想明白了,一切还是要以我们的最终项目--“运动相机”为目的,用到什么就些什么,用不到的就不写。毕竟我们这个系列并不是专门研究FFmpeg的。本篇我们需要使用到的功能,包括转码、封装等最核心的功能,是我们将这个项目进行下去的必要步骤。
如果你对它感兴趣,可以选择阅读相关的书籍、博客等,也可以使用AI辅助开发。但重申我们的原则,不能陷入进去,用到什么加什么、遇到什么问题找相应的解决方案,效率才是最高的。
PS:笔者第一次接触到FFmpeg是在CSDN上雷霄华的系列文章,该系列文章由浅入深的介绍了FFmpeg,对我来说是一个启蒙。遗憾的是,雷霄华博士已英年早逝,深感惋惜!
一、FFmpeg介绍
1、它有哪些功能?
FFmpeg读作 "ef ef em peg"(国际通用读法)。书写的话正规应该是前两个FF为大写,后面的为小写。
这个工具究竟有多强大呢?让我们看看它都可以做什么:
| 功能大类 | 功能子类 | 支持格式示例 |
|---|---|---|
| 媒体处理核心 | 视频编解码 | H.264, H.265, VP9, AV1, MPEG-4 |
| 音频编解码 | AAC, MP3, FLAC | |
| 容器格式 | MP4, MKV, AVI, MOV, FLV, TS | |
| 视频处理 | 画面变换 | 缩放、裁剪、旋转、镜像 |
| 画面增强 | 降噪、色彩校正、锐化、电子稳像 | |
| 特殊效果 | 水印、画中画、绿幕抠像 | |
| 关键帧操作 | 截取、抽帧、帧类型分析 | |
| 音频处理 | 音效处理 | 音量调整、静音检测、回声消除、混响、变速变调 |
| 音轨操作 | 声道分离/合并、音轨抽取 | |
| 流媒体处理 | 直播推流 | RTMP, SRT, RTP, HLS |
| 直播拉流 | RTSP, HLS, DASH, WebRTC | |
| 媒体操作 | 时间截取、内容拼接 | |
| 设备支持 | 视频输入 | 摄像头、屏幕捕捉 |
| 音频输入 | 麦克风、系统音频 | |
| 输出设备 | 显示器、音响系统 | |
| 字幕 | 字幕 | 硬字幕、软字幕、字幕提取 |
| 网络协议 | 流媒体协议 | HLS, DASH, RTSP, WebRTC |
通过上面这个表格,我们可以知道FFmpeg真的是功能齐全,并且据笔者所了解,抖音、bilibili、迅雷、海康威视等等与音视频相关的企业,都少不了ffmpeg的身影。如果读者感兴趣,可以在电脑上搜索一下“ffmpeg”,能够看到非常多的软件使用了ffmpeg的库。我们尊称FFmpeg为音视频界的扛把子,将其比作音视频领域的‘瑞士军刀’恰如其分。
在音视频行业除了FFmpeg之外,还有GStreamer。它们的功能类似。这里就不再展开,有兴趣的朋友可以查阅一下相关资料。
2、 我们这个系列文章会用到哪些功能?
回答这个问题前,需要先回答另外一个问题:如果开发运动相机,会用到哪个芯片方案?
因为芯片方案不同,使用到FFmpeg的功能略有不同。例如笔者有计划尝试使用IMX6ULL作为主控IC,但是因为没有硬件编码器,经过计算,有可能经过1080P的软编码之后帧率大概不会超过10帧,基本上就是卡成PPT。所以笔者后续计划使用RV1126芯片进行运动相机开发,虽然RV1126并非现在主流的运动相机芯片,但考虑到其SDK易用性、开发难度和资料丰富度,是一个折中的理想选择。该芯片具有YUV采集、硬件编码器的功能,所以FFmpeg需要用到封装MP4、直播推流等几个功能。
然而,对于我们使用的USB摄像头,通过V4L2采集到的是原始YUV数据(如NV12)。若想将其封装为MP4或用于推流,必须先使用FFmpeg进行纯软件的H.264编码。
稍作总结:
1)在USB阶段,我们会使用到FFmpeg的编码、封装、直播推流等。 2)在RV1126嵌入式平台,我们会使用到FFmpeg的封装、直播推流等。
二、还是先打个招呼
我们知道v4l2是Linux中起到了屏蔽厂商细节、能够按照统一接口进行获取图像的一套机制,它也是一个庞然大物,甚至可以专门为其写一本书。但是我们前面在写Demo的时候,好像并没有感觉很难。其实难点不在于“如何使用”,而是在于“如何运行”。毕竟这些开发出来都是给人使用的,未来我们可能需要对其(V4L2/FFmpeg)进行定制或调优,但那也是我们学会“如何使用”之后的事情了。
同理,本篇文章对于FFmpeg也只讲“如何使用”(学会如何使用已经很了不起了!),“如何运行”不在我们此系列之中讨论。
1、安装FFmpeg
通过以下命令安装:
# 更新软件包列表
sudo apt update
# 安装FFmpeg
sudo apt install ffmpeg
# 验证安装
ffmpeg -version
在Ubuntu20.04TLS版本上,安装的版本应该是4.2.x。
2、小试牛刀
FFmpeg命令行遵循以下格式:
ffmpeg [全局选项] -i [输入源] [处理选项] [输出文件]
2.1 生成一个视频文件
执行下面的命令,就可以生成一段10秒的mp4文件,使用VLC播放器或者ffplay进行播放。这样就不用经常去找素材了,直接生成。
-f lavfi指定使用Libavfilter的虚拟输入设备
-i testsrc表示测试视频源,色条+渐变彩带。更多视频源见表1
size=800x600:rate=25表示视频的尺寸和帧率,如果有多个参数则使用冒号分割
-t 10表示视频的时长,这里是10秒
output.mp4表示生成的视频文件
ffmpeg -f lavfi -i testsrc=size=800x600:rate=25 -t 10 output.mp4
| 视频源 | 推荐场景 | 示例命令 | 特点说明 |
|---|---|---|---|
testsrc |
通用测试 (默认) | -i testsrc |
彩条+滚动色带 |
color |
纯色背景需求 | -i color=color=red |
单一纯色 |
smptebars |
色彩/亮度测试 | -i smptebars |
电视台标准测试图 |
mandelbrot |
科技/数学演示 | -i mandelbrot |
分形几何图案 |
cellauto |
动态效果展示 | -i cellauto=rule=110 |
自动生长的细胞动画 |
表1
执行完毕后可以通过VLC查看我们生成的视频,并在工具-->编解码信息可以查看当前视频相关信息:

2.2 格式转换
FFmpeg 的核心能力正是实现任意格式视频的输入和输出转换,这是它被称为“多媒体瑞士军刀”的根本原因。目前笔者所接触到的常见格式,FFmpeg都可以实现转换。还记得之前有一些格式转换工具,要么做的不好用,要么还要收费。掌握了FFmpeg,便足以替代市面上许多功能单一的格式转换工具。
下面我们将使用FFmpeg实现格式转换:
1)使用FFmpeg生成一个NV12的视频流,如果对NV12还有点陌生,请参考上一章关于NV12格式的讲解:
ffmpeg -f lavfi -i testsrc=size=1280x720:rate=30:duration=5 -pix_fmt nv12 -f rawvideo testsrc_1280x720_nv12.yuv
2)使用YUVPlayer打开视频,确认是否正确:

3)使用FFmpeg将生成的NV12裸数据编码成H264:
ffmpeg -f rawvideo \
-pix_fmt nv12 \
-video_size 1280x720 \
-framerate 30 \
-i testsrc_1280x720_nv12.yuv \
-c:v libx264 \
-profile:v high \
-preset slow \
-crf 23 \
-f h264 \
output.h264
实现转换后,裸数据已经被编码成了output.h264文件,使用VLC打开,确认转换是否正确:

PS:这个时候,大家可以做一下对比,看一下5秒钟、720p、30fps的视频。yuv裸数据和H264的大小对比,一个198MB,另一个只有69KB,压缩比达 198MB/69KB ≈ 2900:1!这就是编码的魅力。后续我们用到h264的时候,专门开个章节,好好讲一下到底是为什么。
axk@axk-virtual-machine:/home/chapter6$ ll output.h264 testsrc_1280x720_nv12.yuv -lh
-rw-rw-r-- 1 axk axk 69K 7月 8 18:11 output.h264
-rw-rw-r-- 1 axk axk 198M 7月 8 18:02 testsrc_1280x720_nv12.yuv
4)然后使用FFmpeg将H264数据封装成MP4格式。
ffmpeg -f h264 -i output.h264 -c:v copy output.mp4
使用VLC打开,确认封装是否正确:

注意:这里我们使用的操作是‘封装’(Muxing),而非‘格式转换’(Transcoding)。
因为该操作仅涉及将已编码的H.264基本流(Elementary Stream) ‘打包’(或称为‘复用’)到MP4容器格式中,无需对视频内容进行重新编码(Re-encoding)。这类似于将成品放入标准化的盒子中保存。通过查看媒体信息(如上图所示)可以验证,生成的MP4文件内部封装的视频流依然是H.264编码格式。
因此,‘格式转换’通常指改变视频/音频的编码方式或像素格式(如YUV转RGB, H.264转H.265),本质是数据内容的再处理;而‘封装’仅改变数据的组织结构和元信息,将其放入容器(如MP4, MKV),原始编码数据本身未被改变——如同换了个盒子装东西。
MP4等容器格式能够封装视频流、音频流、字幕轨道等多种媒体成分,从而组合成我们日常接触到的多媒体文件。
三、总结
首先看下面这张图。
在第二节,我们采样FFmpeg生成了NV12的裸数据,并进行了H264编码,最后进行了MP4封装。
下一章,我们将会实现中间的部分,也就是USB摄像头部分。可以看到除了获取NV12不同之外,其他的都一样。
最终我们需要实现的是基于RV1126的SOC方案,这里面的获取编码都是硬件自带的,FFmpeg只需要实现音视频的封装。

其次,我们这一章使用的是命令行操作,主要是熟悉一下FFmpeg以及基本操作。下一章开始采用API方式进行编程。
最后,大家可以通过命令行的方式多尝试FFmpeg的功能,拓宽自己对这个工具的认识。但是先不必研究源码,等我们需要调优或者定制的时候再去做。
因为我们这一路见到的每一样技术,几乎都够我们陷进去很长一段时间。所以,这里与第0章做一下呼应:
单片机式路径:从外设寄存器逐点攻破,因知识体量小、依赖少,可线性推进;
Linux 生态路径:须从应用层俯冲——先用工具搭系统,再借问题溯内核
更多推荐

所有评论(0)