音視頻入門必備項目-最新FFmpeg7.1播放器開發(fā)
1. 整體架構
1.1 架構框圖
這個FFmpeg播放器采用多線程架構,將媒體處理流程分為解復用、解碼和渲染三個主要階段,通過隊列機制實現(xiàn)各階段的解耦和異步處理。
配套視頻講解:**********************************************(播放器源碼領取方式見視頻講解)
1.2 主要組件
1. Main函數(shù)(主控制)
- 負責初始化和協(xié)調各個模塊
- 創(chuàng)建和管理其他組件的生命周期
- 處理整體程序流程控制
2. DemuxThread(解復用線程)
- 繼承自Thread基類
- 負責打開媒體文件,分離音視頻流
- 將分離的音視頻數(shù)據(jù)包放入相應的AVPacketQueue
3. DecodeThread(解碼線程)
- 繼承自Thread基類
- 從AVPacketQueue獲取壓縮數(shù)據(jù)包
- 將壓縮數(shù)據(jù)解碼為原始音視頻幀
- 將解碼后的幀放入AVFrameQueue
4. AudioOutput(聲音輸出)
- 使用SDL音頻庫播放音頻
- 從AVFrameQueue獲取音頻幀
- 進行必要的音頻重采樣
- 維護主時鐘,提供音視頻同步基準
5. VideoOutput(畫面輸出)
- 使用SDL視頻庫顯示視頻
- 從AVFrameQueue獲取視頻幀
- 處理用戶界面事件
- 根據(jù)AVSync提供的時鐘控制視頻幀的顯示時機
6. AVSync(音視頻同步)
- 維護音頻時鐘
- 提供同步機制,確保音視頻同步播放
7. AVPacketQueue(數(shù)據(jù)包隊列)
- 存儲解復用后的壓縮音視頻數(shù)據(jù)包
- 連接DemuxThread和DecodeThread
- 提供線程安全的隊列操作
8. AVFrameQueue(幀隊列)
- 存儲解碼后的原始音視頻幀
- 連接DecodeThread和輸出模塊
- 提供線程安全的隊列操作
1.3 基礎架構
1. Thread(線程基類)
- 提供基本的線程管理功能
- 實現(xiàn)啟動、停止等通用線程控制方法
- 為派生線程類提供統(tǒng)一的接口
1.4 外部庫依賴
1. FFmpeg庫
- 提供媒體文件解析、解碼等功能
- 包括libavformat、libavcodec等組件
2. SDL庫
- 提供跨平臺的音視頻輸出能力
- 處理用戶界面和事件
這個架構采用了生產(chǎn)者-消費者模式,通過隊列解耦各個模塊,使得解復用、解碼和渲染可以在不同的線程中并行執(zhí)行,提高播放性能和流暢度。同時,通過明確的音視頻同步機制,確保了播放的準確性。
2. 詳細流程
播放器的運行流程從初始化開始,到資源釋放結束,中間經(jīng)過多個處理階段。
2.1 main函數(shù)流程圖
main.cpp main()函數(shù)
2.2 流程說明
1. 初始化:創(chuàng)建并初始化必要的隊列、線程和組件
2. 媒體處理:
解復用線程從文件讀取數(shù)據(jù)包
解碼線程將數(shù)據(jù)包解碼為幀
音視頻輸出模塊將幀渲染輸出
3. 用戶交互:處理用戶事件,如暫停、退出等
4. 資源釋放:程序結束時按正確順序釋放資源,避免內存泄漏
3. 隊列設計
隊列是連接各處理階段的關鍵組件,負責數(shù)據(jù)緩沖和線程間通信。
3.1 隊列框圖
3.2 隊列設計原理
1. 模板設計:使用C++模板實現(xiàn)通用隊列結構,提高代碼復用率
2. 線程安全:使用互斥鎖和條件變量保證多線程環(huán)境下的數(shù)據(jù)一致性
3. 特化實現(xiàn):為AVPacket和AVFrame提供特化隊列,處理FFmpeg資源的引用計數(shù)
4. 終止機制:通過abort標志控制隊列終止,實現(xiàn)優(yōu)雅退出
5. 資源管理:
- AVPacketQueue負責管理AVPacket資源,使用av_packet_free釋放
- AVFrameQueue負責管理AVFrame資源,使用av_frame_free釋放
4. 線程設計
播放器采用多線程架構,通過基類Thread實現(xiàn)通用線程控制,派生類實現(xiàn)具體功能。
4.1 線程框圖
4.2 線程設計原理
1. 基類封裝:Thread基類封裝線程創(chuàng)建、啟動和停止的通用邏輯
2. 虛函數(shù)機制:通過純虛函數(shù)Run()要求派生類實現(xiàn)具體業(yè)務邏輯
3. 狀態(tài)控制:使用abort_標志控制線程循環(huán)狀態(tài),實現(xiàn)優(yōu)雅退出
4. 資源管理:
- DemuxThread管理文件讀取和格式解析資源(AVFormatContext)
- DecodeThread管理解碼器資源(AVCodecContext)
5. 線程協(xié)作:通過隊列實現(xiàn)線程間數(shù)據(jù)傳遞,解耦生產(chǎn)者和消費者
5.音頻輸出設計
聲音輸出模塊負責從幀隊列獲取音頻幀,進行必要的重采樣,并通過SDL輸出音頻。
5.1音頻輸出框圖
5.2音頻輸出原理
1. 初始化流程:
- 初始化SDL音頻子系統(tǒng)
- 設置音頻參數(shù)(采樣率、通道數(shù)、格式)
- 設置音頻回調函數(shù)
- 創(chuàng)建重采樣上下文(如需要)
2. 回調機制:
- SDL音頻系統(tǒng)在需要數(shù)據(jù)時調用設置的回調函數(shù)
- 回調函數(shù)從幀隊列獲取音頻幀
- 根據(jù)需要進行重采樣(使用SwrContext)
- 將處理后的音頻數(shù)據(jù)填充到SDL提供的緩沖區(qū)
3. 音頻時鐘:
- 以音頻PTS作為主時鐘
- 在每次回調中更新音頻時鐘
- 作為視頻同步的基準
4. 資源管理:
- 管理重采樣上下文(SwrContext)
- 管理音頻緩沖區(qū)
- 在DeInit和析構函數(shù)中釋放資源
6.視頻輸出設計
畫面輸出模塊負責從幀隊列獲取視頻幀,與音頻同步,并通過SDL渲染到屏幕。
6.1視頻輸出框圖
6.2視頻輸出原理
1. 初始化流程:
- 初始化SDL視頻子系統(tǒng)
- 創(chuàng)建窗口和渲染器
- 創(chuàng)建紋理用于視頻渲染
2. 主循環(huán)機制:
- 處理SDL事件(如退出、按鍵等)
- 刷新視頻幀
- 控制幀率以實現(xiàn)音視頻同步
3. 同步策略:
- 比較視頻幀PTS與音頻時鐘
- 如果視頻超前,等待適當時間再顯示
- 如果視頻滯后,立即顯示并可能丟幀
4. 渲染過程:
- 將YUV數(shù)據(jù)更新到SDL紋理
- 將紋理渲染到窗口
- 釋放已顯示的幀
5. 資源管理:
- 管理SDL資源(窗口、渲染器、紋理)
- 在DeInit和析構函數(shù)中釋放資源
7. 音視頻同步
音視頻同步是播放器的核心功能,確保音頻和視頻以正確的時間關系播放。
7.1 同步框圖
7.2 同步原理
1. 主時鐘選擇:
- 使用音頻PTS作為主時鐘基準
- 音頻在回調函數(shù)中更新時鐘值
2. 視頻同步策略:
- 計算視頻幀PTS與當前音頻時鐘的差值
- 差值為正(視頻超前):延遲顯示
- 差值為負(視頻滯后):立即顯示
- 差值過大:考慮跳幀或重復幀
3. 時鐘管理:
- AVSync類提供時鐘讀寫接口
- 音頻線程設置時鐘
- 視頻線程讀取時鐘
8. 數(shù)據(jù)流向
播放器中的數(shù)據(jù)從媒體文件讀取,經(jīng)過多個處理階段,最終輸出到顯示設備。
8.1 數(shù)據(jù)流圖
8.2 數(shù)據(jù)流說明
1. 解復用階段:
- DemuxThread讀取媒體文件
- 分離音視頻數(shù)據(jù)包
- 將音視頻包放入對應的AVPacketQueue
2. 解碼階段:
- DecodeThread從AVPacketQueue獲取數(shù)據(jù)包
- 使用FFmpeg解碼器解碼數(shù)據(jù)包
- 生成音視頻幀并放入AVFrameQueue
3. 渲染階段:
- AudioOutput/VideoOutput從AVFrameQueue獲取幀
- 處理幀數(shù)據(jù)(重采樣、格式轉換等)
- 通過SDL渲染到輸出設備
9. 內存管理與資源釋放
良好的內存管理和資源釋放策略是保證播放器穩(wěn)定性的關鍵。
9.1 內存管理策略
1. FFmpeg資源管理:
- 使用適當?shù)腇Fmpeg API釋放資源(av_frame_free, av_packet_free等)
- 在隊列的release()方法中處理隊列中殘留的資源
2. SDL資源管理:
- 在析構函數(shù)或DeInit方法中釋放SDL資源
- 按正確順序釋放(texture → renderer → window)
3. 線程資源管理:
- 使用Thread::Stop()方法安全停止線程
- 在Stop()中等待線程結束(join)后釋放線程資源
9.2 資源釋放順序
為避免資源依賴問題,釋放順序非常重要:
1. 首先停止所有線程(先解碼線程,再解復用線程)
2. 釋放音視頻輸出資源
3. 清空并終止所有隊列
4. 刪除線程對象
5. 其它資源清理
#校招過來人的經(jīng)驗分享##校招##項目##C++##簡歷中的項目經(jīng)歷要怎么寫#