(六)WebRTC手記之WebRtcVideoEngine2模塊

轉自:http://www.cnblogs.com/fangkm/p/4401143.htmlhtml

 

終於講到視頻數據的編碼發送模塊了,不容易。整體來講也看了很多時間WebRTC的源碼了,最大的感觸就是各個模塊在開發的時候很是獨立,每一個模塊都定義了本身的一套接口,最後串起來的時候添加各類適配對象來轉接。這給咱們這些剛開始源碼閱讀的人帶來很是大的苦惱,不過WebRTC的模塊內的結構設計仍是很不錯的,否則我也沒有看下去的動力。網絡

注意命名,WebRtcVideoEngine2帶了個2字,不用想,這確定是個升級版本的VideoEngine,還有個WebRtcVideoEngine類。從目前個人理解來看,WebRtcVideoEngine2比WebRtcVideoEngine改進之處在於將視頻流一分爲二:發送流(WebRtcVideoSendStream)和接收流(WebRtcVideoReceiveStream),從而結構上更合理,源碼更清晰。這個部分等下會細說。在介紹WebRtcVideoEngine2以前,先簡單地分析一下WebRTC的Media Engine結構,說實話,我真不會表達Engine是個怎樣的概念,但既然這樣命名,核心模塊確定是錯不了的。結構很簡單:tcp

 

  • MediaEngineInterface:抽象Media Engine的邏輯接口,負責建立用於視頻傳輸的VideoMediaChannel、用於音頻傳輸的VoiceMediaChannel、註冊音頻數據處理接口等。
  • CompositeMediaEngine:實現MediaEngineInterface接口,自己也是個模板類,兩個模板參數分別是視頻Engine和音頻Engine。其派生類WebRtcMediaEngine依賴的模板參數是WebRtcVoiceEngine和WebRtcVideoEngine,而用於Chromium的WebRtcMediaEngine2則依賴WebRtcVoiceEngine和WebRtcVideoEngine2。

WebRtcVideoEngine2主要做用在於建立視頻channel對象WebRtcVideoChannel2。結構以下:ide

當調用WebRtcVideoChannel2的AddSendStream方法時,會建立一個WebRtcVideoSendStream對象,一樣,調用AddRecvStream成員方法,會建立一個WebRtcVideoReceiveStream對象。函數

當外部調用WebRtcVideoChannel2的SetCapturer方法時,會轉給WebRtcVideoSendStream來響應,WebRtcVideoSendStream內部將InputFrame成員方法掛接VideoCapturer的SignalVideoFrame信號來接收視頻採集器傳輸過來的視頻幀數據。編碼

WebRtcVideoChannel2的AddSendStream和SetCapturer的調用時機這裏暫時不考慮,這些涉及到網絡鏈接,等每一個節點的內容分析完後,再探討整個流程。線程

如圖所示,WebRtcVideoSendStream和WebRtcVideoReceiveStream也只是個包裝類,內部依賴Call接口建立對應的VideoSendStream接口實現類和VideoReceiveStream接口實現類。在internal命名空間內,分別有一個Call類、VideoSendStream類、VideoReceiveStream類來實現這三個接口,Call類建立關鍵的VideoEngine對象來管理視頻數據發送過程當中的一系列處理邏輯。從代碼結構上看,VideoEngine是一個相對獨立的模塊,它封裝視頻數據採集後的處理、編碼等邏輯,下面仔細分析一下VideoEngine的結構:設計

 

VideoEngine模塊裏有ViEBase、ViECodec、ViECapture、ViEImageProcess、ViENetwork、ViERender、ViERTP_RTCP、ViEExternalCodec接口,注意,這些都是功能性的接口,它們相應的實現分別對應於上圖中的XXXImpl類,VideoEngineImpl類從全部的XXXImpl接口派生,所以外部有了VideoEngine接口,均可以經過強轉的方式獲取ViEBase、ViECapture等之類的接口(根據VideoEngine強轉成相應的接口的邏輯封裝在目標接口的GetInterface靜態方法中),外界能夠經過這些接口來完成視頻數據作相應的設置,而這些設置最終都反映到一個名叫ViESharedData的類對象裏。該對象由ViEBaseImpl建立並在各接口的實現之間共享,XXXImpl能夠經過ViEBaseImpl的shared_data方法來訪問,用於共享的數據有三類:ViEInputManager、ViEChannelManager和ViERenderManager。下面分別介紹一下這關鍵的三個對象。3d

  • ViEInputManager:封裝了視頻採集/輸入邏輯(哈哈,又是一套視頻輸入邏輯),結構:

ViEInputManager爲每一個通道分配一個ViECapturer對象來作爲視頻源,ViECapturer能夠傳入也能夠本身建立一個VideoCaptureModule視頻採集模塊,並經過VideoCaptureDataCallback接口從其接收數據,也能夠直接經過ViEExternalCapture接口接收從外部直接傳入的視頻幀數據(調用ViEExternalCapture接口的IncomingFrame方法)。VideoSendStream就是經過ViEInputManager建立一個ViEExternalCapture對象來傳入外界傳來的視頻幀數據(經過WebRtcVideoSendStream的InputFrame傳來)。這裏要注意,ViEInputManager爲建立的ViECapturer對象分配一個capture_id,外界能夠經過這個capture_id來操做其對應的ViECapturer。視頻源傳入邏輯已經明瞭,接下來分析一下視頻是怎麼傳出去的。不管經過哪一種視頻數據接收方法,ViECapturer都不會當即將數據傳遞出去,由於它內部須要對這些視頻數據作相關的處理。數據處理必然耗時,若是採用同步的方式,必將阻塞視頻傳入的流程。所以,在建立ViECapturer的時候,會啓動一採集線程,該線程調用ViECaptureProcess處理函數,在該處理函數裏,先調用VideoProcessingModule對視頻數據進行處理(燈光加亮、去閃爍),若是在ViEImageProcessImpl裏註冊了ViEEffectFilter處理對象,這裏也會調用該對象來處理視頻幀數據,最後經過DeliverFrame方法分發到註冊進來的全部ViEFrameCallback接口。code

  • ViEChannelManager:封裝了視頻編碼和傳輸邏輯,這塊結構比較複雜,整體以下:

ViEChannelManager維護了ViEEncoder和ViEChannel對象,ViEEncoder實現了ViEFrameCallback接口從ViECapturer對象中接收視頻幀數據,ViEEncoder對接收到的視頻幀數據進行編碼,而後將編碼後的數據傳給ViEChannel(經過二者之間共享的PayloadRouter對象),ViEChannel將編碼後的視頻數據經過RTP/RTCP協議發送出去。下面分別分析一下ViEEncoder和ViEChannel。

    1) ViEEncoder類:封裝了視頻編碼流程。

視頻編碼由VideoCodingModule模塊統一管理,視頻幀傳入接口是經過VideoCodingModule的的AddVideoFrame方法,編碼後的視頻傳出接口是藉助VCMPacketizationCallback接口來回調。具體選取哪一種視頻編碼的邏輯位於VCMCodecDataBase類,當前支持VP8編碼、VP9編碼和視頻格式到I420格式的轉換。

2)ViEChannel類:封裝了編碼後的視頻數據發送邏輯和視頻數據接收解碼邏輯。

視頻數據發送邏輯是經過PayloadRouter對象委託給RtpRtcp模塊作RTP協議的封裝,具體的網絡發送操做仍是回託給ViESender作數據的網絡發送操做。ViESender的邏輯相對簡單,限於篇幅,圖中沒法作詳細的標註。ViESender的發送操做依賴外部設置給它的Transport接口(經過VideoEngine模塊的ViENetwork接口來完成設置)。

當WebRtcVideoChannel2接收到網路數據包後(經過OnPacketReceived或OnRtcpReceived方法響應),會在VideoReceiveStream對象中經過VideoEngine模塊暴露出去的ViENetwork接口來響應數據包處理,最終觸發到ViEChannel的ReceivedRTPPacket或ReceivedRTCPPacket方法。ViEChannel中將接收並解碼網絡視頻數據的任務分配給ViEReceiver對象。ViEReceiver先調用RTP/RTCP模塊作協議的解析(圖中限於篇幅未標註出來),解析完成後調用VideoCodingModule模塊進行數據的解碼操做(參見ViEReceiver的OnReceivedPayloadData方法),VideoCodingModule模塊內部維護了一個與VideoSender對應的VideoReceiver來完成解碼邏輯,這塊與VideoSender的編碼邏輯徹底對稱,這裏再也不表述。

  • ViERenderManager:這個類封裝了視頻渲染邏輯,結構以下:

當ViEChannel接收到網絡數據解包並解碼後,就會開啓觸發渲染流程(參見FrameToRender方法),ViEChannel會調用向其註冊的ViEFrameCallback接口來派發視頻幀數據。ViERenderManager維護了一個ViERenderer對象來實現ViEFrameCallback接口,它將數據進一步派發,最終經過ExternalRenderer接口派發給WebRtcVideoChannel2的VideoReceiveStream對象。VideoReceiveStream經過VideoSource設置進來的VideoRenderer接口將數據派發給VideoTrack,用戶能夠掛接VideoRendererInterface接口來接收視頻幀數據。真夠繞的,並且那麼多命名的類似性(好比VideoRender/VideoRenderer),感受各模塊開發期間,都實現了本身的一套接口規範,最後強行串在一塊兒了。

相關文章
相關標籤/搜索