作者: 葉餘 來源: 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使用基礎另外,本文最後的參考資料對了解源碼幫助很大,在此向各位分享者表示感謝。參考資料内容更精彩,建議閱讀。
本筆記隻放在一篇文檔裡的話篇幅過長,遂拆分成下面一系列文章:
ffplay源碼分析1-概述 ffplay源碼分析2-資料結構 ffplay源碼分析3-代碼架構 ffplay源碼分析4-音視訊同步 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(CD光牒驅動器):CD光牒媒體控制
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 整理章節排序
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。