用 FFmpeg 写播放器就四步:用 avformat 解封装拿到【包】,用 avcodec 解码拿到【帧】,再转格式、输出——记住包与帧这两个名字,整条链路就通了。
5.4.1 讲了播放器的四个环节,这一节看用 FFmpeg 库具体怎么落地。
一、两个关键数据结构
AVPacket(包):压缩后的一段数据——解封装之后、解码之前。 AVFrame(帧):解码后的原始数据——解码之后、送屏之前。 整条播放链路,本质就是在【包】与【帧】之间来回转换。 记住这两个名字,看任何播放器代码都不会迷路。
二、四步走
① 打开与解封装(libavformat):读文件、找出各路流、读出包。 ② 解码(libavcodec):把包送进解码器,取得帧。 ③ 格式转换:视频用 libswscale 转像素格式,音频用 libswresample 转采样格式。 ④ 输出与呈现:交给显示与音频设备。
三、第三步为什么不能省
因为解码器输出的格式,往往不是显示设备想要的格式。 比如解码出来是 YUV 4:2:0,而渲染层要 RGB——中间必须转一次。 音频同理:解码出来可能是 48 kHz 单声道,设备要 44.1 kHz 立体声。 所以格式转换是播放链路里固定的一环,不是可选的优化。
四、和 3.5.1 的分工对上
第 3.5.1 节讲过 FFmpeg 的六个核心库,这里正好用到了四个。 avformat 管进出、avcodec 管压解、swscale 管视频换算、swresample 管音频换算。 剩下两个(avutil 管公共工具、avfilter 管滤镜)在播放链路里是辅助角色。 这也印证了那句话:这些库本来就是一条流水线拆开的结果。
五、动手 Demo:FFmpeg 播放架构,四步走
用 FFmpeg 库写播放器,核心就是这四步。
rows = [("打开与解封装", "libavformat", "AVPacket 压缩包"),
("解码", "libavcodec", "AVFrame 原始帧"),
("格式转换", "libswscale/libswresample", "统一的像素或采样格式"),
("输出与呈现", "(交给设备)", "画面、声音")]
for a, b, c in rows:
print("%-10s %-24s %s" % (a, b, c))
实跑输出:
--------------------------------------------------------------------
FFmpeg 播放架构,四步走
--------------------------------------------------------------------
用 FFmpeg 库写播放器,核心就是这四步。
步骤 用哪个库 产出
-------------------------------------------------------------------
打开与解封装 libavformat AVPacket 压缩包
解码 libavcodec AVFrame 原始帧
格式转换 libswscale/libswresample 统一的像素或采样格式
输出与呈现 (交给设备) 画面、声音
记住两个名字:**包(Packet)是压缩后的数据,帧(Frame)是解码后的数据。**
整条链路就是在两者之间来回转换。
记住两个名字:包(Packet)是压缩后的数据,帧(Frame)是解码后的数据。 整条链路就是在两者之间来回转换。
30 秒实验
- 翻一遍 FFmpeg 官方示例里的最小播放程序,找出这四步分别对应哪几行。
- 你会发现代码结构和这张表一一对应。
常见误区
- 跳过格式转换直接送屏。解码器输出格式与设备要求常常不一致。
- 把包与帧混用。包是压缩的,帧是解压的,两者不能互换。
自测三问(点开对答案)
1. AVPacket 与 AVFrame 分别是什么? —— AVPacket 是压缩后的一段数据,AVFrame 是解码后的原始数据。 2. FFmpeg 播放架构的四步是什么? —— 解封装、解码、格式转换、输出呈现。 3. 为什么格式转换不能省? —— 解码器输出的像素或采样格式常常与显示/播放设备要求不一致。- ☐ 下一节(5.4.3 VLC播放原理)
相关笔记
- 视频播放器简介 — 这四步在整体里的位置
- FFmpeg — 六个库的整体分工
- 现代播放器架构 — 工业级播放器怎么分层
- 🎬 FFmpeg入门详解 · 索引