轉載請注明出處:http://www.cnblogs.com/fangkm/p/3797278.html
承接上一篇文章。媒體播放,需要指定一個源文件,html5用URL格式來指定視頻源文件地址,可以是http鏈接,也可以使本地源文件(不能直接指定,需要借助blob二進制類型)。播放網絡文件比播放本地文件多了個下載流程, 所以下面直接分析網絡文件的播放流程,本地文件的播放流程也就清楚了。首先分析下網絡視頻資源的加載流程,相關結構圖如下:
WebMediaPlayerImpl類有一成員BufferedDataSource來負責管理URL網絡資源的加載邏輯。
BufferedDataSource資源加載邏輯主要由BufferedResourceLoader完成,
BufferedResourceLoader類維護一個WebURLLoader接口的派生類AssociatedURLLoader對象, AssociatedURLLoader類也並沒有真正的和webkit_glue層的WebURLLoaderImpl一樣實現WebURLLoader的接口,而是通過DocumentThreadableLoader類最終依賴WebURLLoaderImpl的實現給主進程發送URL請求WebURLLoaderImpl(WebURLLoaderImpl的流程請參見:http://www.cnblogs.com/fangkm/p/3784660.html)。
AssociatedURLLoader對象與frame對象關聯,當調用WebFrame的stopLoading方法時,該請求也會取消。
BufferedResourceLoader內部維護一個可增長的內存緩沖區來保存請求到的視頻數據。
分析到這里我始終沒發現暫停緩沖機制,也沒有找到緩沖到磁盤文件的地方,如果視頻文件過大的話,全部積放在內存,資源消耗過大肯定造成極不好的程序體驗。當然我這里的Chromium代碼也有點老了,可能新版的已經改進了。
視頻數據已經准備完畢,接下來的工作就是解析音視頻數據了。在分析這部分之前首先簡單普及下音視頻的相關概念。一般的視頻文件都有視頻流和音頻流兩部分組成,不同的視頻格式音視頻的封裝格式肯定不一樣。將音頻流和視頻流合成文件的過程稱為muxer,反之從媒體文件中分離音頻流和視頻流的過程稱為demuxer. 播放視頻文件就需要從文件流中分離出音頻流和視頻流,分別對其進行解碼,解碼后的視頻幀可以直接渲染,音頻幀可以送到音頻輸出設備的緩沖區進行播放,當然,視頻渲染和音頻播放的時間戳一定要控制同步。
WebMediaPlayerImpl中有關demuxer的邏輯結構如下:
WebMediaPlayerImpl根據資源的不同創建不同的demuxer對象。
如果視頻源是通過JavaScript傳送過來的二進制數據,則創建ChunkDemuxer對象來分離音頻流和視頻流;
如果視頻源是通過URL指定的網絡源,則創建FFmpegDemuxer對象,依賴BufferedDataSource對象來訪問通過網絡加載的媒體流數據。
ChunkDemuxer和FFmpegDemuxer的具體實現暫且不表,先只需要了解他們的作用是將媒體流分離出視頻流和音頻流。先分析整個播放流程。
WebMediaPlayerImpl類有一個Pipeline對象來負責視頻的播放流程, Pipeline本身就是流水線的意思,正適合視頻播放的一系列流程。Pipeline內部利用狀態機維護播放中的各種階段的邏輯。Pipeline調用AudioRendererImpl初始化時,會調用Demuxer的GetStream方法,指定獲取音頻流數據傳入AudioRendererImpl對象;同理調用VideoRendererBase初始化時,會取到視頻流數據來傳入。音視頻流的讀取操作由DemuxerStream接口來抽象。
下面分析一下VideoRendererBase的流程, VideoRendererBase這名字起的有點奇怪,帶個Render單詞,確做的是視頻流的解碼邏輯,真正的繪制操作還是拋到WebMediaPlayerImpl類,具體請參見WebMediaPlayerImpl的paint方法。先看結構:
VideoRendererBase維護了一個VideoDecoder列表,內部主要邏輯都交給VideoFrameStream處理, VideoFrameStream的主要功能包括解碼器的選取、從DemuxerStream讀取視頻流進行解碼,解碼后的結果為一視頻幀結構VideoFrame,這個結構封裝的是YUV數據,可以直接或轉換成RGB進行渲染操作。
簡單介紹下這里的視頻解碼器創建和選取邏輯:
在WebMediaPlayerImpl類中就已經創建好視頻解碼器列表,按順序依次為:
1. 如果gpu支持視頻解碼,則創建GpuVideoDecoder對象
2. 創建VpxVideoDecoder對象
3. 創建FFmpegVideoDecoder對象
創建好解碼器列表后傳入VideoRendererBase對象,最終由VideoFrameStream來管理選取邏輯:
1. 如果視頻配置信息里有加密選項,則創建DecryptingVideoDecoder做為解碼器
2. 如果無加密選項,則從傳入的解碼器列表中選擇第一個做為解碼器。
3. 如果調用選擇的解碼器的Initialize無效(解碼器不支持該格式的解碼),則按順序選擇列表中的下一個解碼器。
AudioRendererImpl的結構與VideoRendererBase類似,在音頻渲染方面比視頻渲染稍微復雜一點,需要將音頻數據輸出到聲卡設備進行播放。相關結構圖:
到此為止,網頁播放器整個流程差不多已經清晰了,當然還有很多細節沒扒,比如說Media Source流對應的分離器ChunkDemuxer的實現、FFmpegDemuxer內部怎么對ffmpeg的使用、各種解碼器的實現等,沒有開發經驗,要研究透這些細節真的很耗時,有興趣的童鞋可以自己研究。