零、前言

        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 生态路径:须从应用层俯冲——先用工具搭系统,再借问题溯内核

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐