本文为作者原创,转载请注明出处:https://www.cnblogs.com/leisure_chn/p/10301215.html
ffplay是一个很简单的播放器,但是初次接触仍会感到概念和细节相当繁多,分析并不容易。深入理解一项技术需要足够的时间和大量的实践,由浅入深逐步迭代,没有时间就成了最大难题。本次分析过程断断续续持续了挺久,先是边读代码边加注释,后面才整理了笔记,再加上理解浅薄很难精简语言,因此行文比较啰嗦。笔记记录仓促,错误难免,欢迎指正交流。后续若有时间继续研究,将持续修正错误完善文档。
ffplay是FFmpeg工程自带的简单播放器,使用FFmpeg提供的解码器和SDL库进行视频播放。本文基于FFmpeg工程4.1版本进行分析,其中ffplay源码清单如下:
https://github.com/FFmpeg/FFmpeg/blob/n4.1/fftools/ffplay.c
在尝试分析源码前,可先阅读如下参考文章作为铺垫:
[1]. 雷霄骅,视音频编解码技术零基础学习方法
[2]. 视频编解码基础概念
[3]. 色彩空间与像素格式
[4]. 音频参数解析
[5]. FFmpeg使用基础
另外,本文最后的参考资料对理解源码帮助很大,在此向各位分享者表示感谢。参考资料内容更精彩,建议阅读。
本笔记只放在一篇文档里的话篇幅过长,遂拆分成下面一系列文章:
[1]. ffplay源码分析1-概述
[2]. ffplay源码分析2-数据结构
[3]. ffplay源码分析3-代码框架
[4]. ffplay源码分析4-音视频同步
[5]. ffplay源码分析5-图像格式转换
[6]. ffplay源码分析6-音频重采样
[7]. ffplay源码分析7-播放控制
1. 基本原理
1.1 播放器基本原理
下图引用自“雷霄骅,视音频编解码技术零基础学习方法”,因原图太小,看不太清楚,故重新制作了一张图片。
如下内容引用自“雷霄骅,视音频编解码技术零基础学习方法”:
解协议
将流媒体协议的数据,解析为标准的相应的封装格式数据。视音频在网络上传播的时候,常常采用各种流媒体协议,例如HTTP,RTMP,或是MMS等等。这些协议在传输视音频数据的同时,也会传输一些信令数据。这些信令数据包括对播放的控制(播放,暂停,停止),或者对网络状态的描述等。解协议的过程中会去除掉信令数据而只保留视音频数据。例如,采用RTMP协议传输的数据,经过解协议操作后,输出FLV格式的数据。解封装
将输入的封装格式的数据,分离成为音频流压缩编码数据和视频流压缩编码数据。封装格式种类很多,例如MP4,MKV,RMVB,TS,FLV,AVI等等,它的作用就是将已经压缩编码的视频数据和音频数据按照一定的格式放到一起。例如,FLV格式的数据,经过解封装操作后,输出H.264编码的视频码流和AAC编码的音频码流。解码
将视频/音频压缩编码数据,解码成为非压缩的视频/音频原始数据。音频的压缩编码标准包含AAC,MP3,AC-3等等,视频的压缩编码标准则包含H.264,MPEG2,VC-1等等。解码是整个系统中最重要也是最复杂的一个环节。通过解码,压缩编码的视频数据输出成为非压缩的颜色数据,例如YUV420P,RGB等等;压缩编码的音频数据输出成为非压缩的音频抽样数据,例如PCM数据。音视频同步
根据解封装模块处理过程中获取到的参数信息,同步解码出来的视频和音频数据,并将视频音频数据送至系统的显卡和声卡播放出来。
1.2 FFmpeg转码流程
_______ ______________
| | | |
| input | demuxer | encoded data | decoder
| file | ---------> | packets | -----+
|_______| |______________| |
v
_________
| |
| decoded |
| frames |
|_________|
________ ______________ |
| | | | |
| output | <-------- | encoded data | <----+
| file | muxer | packets | encoder
|________| |______________|
ffmpeg
调用libavformat库(包含解复用器demuxer),从输入文件中读取到包含编码数据的包(packet)。如果有多个输入文件,ffmpeg
尝试追踪多个有效输入流的最小时间戳(timestamp),用这种方式实现多个输入文件的同步。
然后编码包被传递到解码器(decoder),解码器解码后生成原始帧(frame),原始帧可以被滤镜(filter)处理(图中未画滤镜),经滤镜处理后的帧送给编码器,编码器将之编码后输出编码包。最终,由复用器(muxex)将编码码写入特定封装格式的输出文件。
ffplay不需要编码过程,是将上图中的解码后帧送往屏幕显示。
1.3 SDL播放过程简介
本节内容引用自“雷霄骅,最简单的视音频播放示例7:SDL2播放RGB/YUV”
SDL(Simple DirectMedia Layer)是一套开放源代码的跨平台多媒体开发库,使用C语言写成。SDL提供了数种控制图像、声音、输出入的函数,让开发者只要用相同或是相似的代码就可以开发出跨多个平台(Linux、Windows、Mac OS X等)的应用软件。目前SDL多用于开发游戏、模拟器、媒体播放器等多媒体应用领域。用下面这张图可以很明确地说明SDL的位置。
SDL实际上并不限于视音频的播放,它将功能分成下列数个子系统(subsystem):
Video(图像):图像控制以及线程(thread)和事件管理(event)
Audio(声音):声音控制
Joystick(摇杆):游戏摇杆控制
CD-ROM(光盘驱动器):光盘媒体控制
Window Management(视窗管理):与视窗程序设计集成
Event(事件驱动):处理事件驱动
SDL播放视频流程如下:
- 初始化
- 初始化SDL
- 创建窗口(Window)
- 基于窗口创建渲染器(Render)
- 创建纹理(Texture)
- 循环显示画面
- 设置纹理的数据
- 纹理复制给渲染目标
- 显示
可参考示例程序:“FFmpeg简易播放器的实现-最简版”
8. 参考资料
[1] 雷霄骅,视音频编解码技术零基础学习方法
[2] 视频编解码基础概念, https://www.cnblogs.com/leisure_chn/p/10285829.html
[3] 色彩空间与像素格式, https://www.cnblogs.com/leisure_chn/p/10290575.html
[4] 音频参数解析, https://blog.csdn.net/caoshangpa/article/details/51218597
[5] FFmpeg基础概念, https://www.cnblogs.com/leisure_chn/p/10297002.html
[6] 零基础读懂视频播放器控制原理:ffplay播放器源代码分析, https://cloud.tencent.com/developer/article/1004559
[7] An ffmpeg and SDL Tutorial, Tutorial 05: Synching Video
[8] 视频同步音频, https://zhuanlan.zhihu.com/p/44615401
[9] 即时通讯音视频开发(一):视频编解码之理论概述, http://www.52im.net/thread-228-1-1.html
[10] 音频同步视频, https://zhuanlan.zhihu.com/p/44680734
[11] 音视频同步(播放)原理, https://blog.csdn.net/zhuweigangzwg/article/details/25815851
[12] 对ffmpeg的时间戳的理解笔记, https://blog.csdn.net/topsluo/article/details/76239136
[13] ffmpeg音视频同步—视频同步到音频时钟, https://my.oschina.net/u/735973/blog/806117
[14] FFmpeg音视频同步原理与实现, https://www.jianshu.com/p/3578e794f6b5
[15] FFmpeg学习4:音频格式转换, https://www.cnblogs.com/wangguchangqing/p/5851490.html
[16] ffmpeg关于音频的总结(一), https://blog.csdn.net/zhuweigangzwg/article/details/51499123
[17] FFmpeg关于nb_smples,frame_size以及profile的解释, https://blog.csdn.net/zhuweigangzwg/article/details/53335941
[18] ffplay frame queue分析, https://zhuanlan.zhihu.com/p/43564980
[19] 难点seek操作, https://github.com/rockcarry/ffplayer/wiki/难点-seek-操作
9. 修改记录
2018-12-28 V1.0 初稿
2019-01-15 V1.0 增加FrameQueue数据结构说明
2019-01-15 V1.0 增加图像格式转换说明,新增音频重采样章节
2019-01-18 V1.0 增加SEEK操作说明章节
2019-01-19 V1.0 整理章节排序