github:https://github.com/bigonelby/webrtcUml/tree/master/latest
這張圖介紹了數(shù)據(jù)從編碼器中輸出挖炬,最終流入pacing的過程
首先看看CorePipeline褪秀,編碼后的幀通過EncodedImageCallback返回启上,那么數(shù)據(jù)從VideoStreamEncoder出發(fā)矿微,將會(huì)如何流到下游呢?VideoStreamEncoderInterface提供了一個(gè)關(guān)鍵的方法:SetSink念搬,給出了下一步數(shù)據(jù)流的重要指示抑堡。持有這個(gè)接口的是VideoSendStreamImpl,其在RegisterProcessThread的時(shí)候朗徊,會(huì)調(diào)用該接口的SetSink方法首妖,為編碼器設(shè)置下游。這個(gè)sink爷恳,即為EncoderSink有缆,這個(gè)EncoderSink本身也是繼承自EncodedImageCallback,因此他也具有接收EncodedImage的能力温亲。而實(shí)現(xiàn)EncoderSink接口的棚壁,是VideoSendStreamImpl。因此編碼器在產(chǎn)生編碼數(shù)據(jù)后铸豁,通過EncoderSink這個(gè)設(shè)置的sink灌曙,就將EncodedImage成功的送到了VideoSendStreamImpl中
后面的重點(diǎn)操作菊碟,當(dāng)然就是將EncodedImage打包成rtp节芥,然后發(fā)送出去。處理這個(gè)工作的,可不是VideoSendStreamImpl头镊。因此VideoSendStreamImpl會(huì)將數(shù)據(jù)繼續(xù)送給負(fù)責(zé)的模塊蚣驼。誰(shuí)來負(fù)責(zé)這個(gè)事情呢?就是RtpVideoSenderInterface這個(gè)接口相艇,這個(gè)接口本身也是繼承了EncodedImageCallback這個(gè)接口颖杏,因此顯然,他也具備處理EncodedImage的能力坛芽!這個(gè)接口的實(shí)現(xiàn)類為RtpVideoSender留储,這個(gè)類是由RtpTransportControllerSendInterface這個(gè)接口的CreateRtpVideoSender方法創(chuàng)建的。這個(gè)過程前面的圖里有過介紹
由此數(shù)據(jù)到達(dá)了RtpVideoSender這個(gè)重要的模塊咙轩,RtpVideoSender的處理單元為Stream获讳,因?yàn)閷?duì)于video而言,也許含有多個(gè)stream活喊,simulcast等丐膝。那么負(fù)責(zé)每個(gè)模塊的發(fā)送的,即為RtpVideoSender的助手钾菊,RtpStreamSender帅矗。從名字就可以看出來,這個(gè)類是負(fù)責(zé)stream的發(fā)送的煞烫。RtpStreamSender是一個(gè)組長(zhǎng)浑此,其有兩個(gè)組員,ModuleRtpRtcpImpl2红竭,RtpSenderVideo尤勋。ModuleRtpRtcpImpl2本身掌握很多關(guān)于rtprtcp發(fā)送的重要信息,他的創(chuàng)建依賴于Configuration茵宪;而RtpSenderVideo是真正的發(fā)送視頻數(shù)據(jù)的類
RtpSenderVideo主要做了三件事最冰,通過RtpSender的AllocatePacket方法,創(chuàng)建了RtpPacketToSend對(duì)象稀火;通過RtpPacketizer進(jìn)行打包暖哨,最終填充RtpPacketToSend對(duì)象;然后通過RtpSender的EnqueuePackets方法凰狞,將打包好的RtpPacketToSend對(duì)象送給RtpPacketSender
接著篇裁,我們看看RtpPacket對(duì)象。首先先看看RTPVideoHeader赡若。這個(gè)對(duì)象是由RtpPayloadParams的GetRtpVideoHeader方法創(chuàng)建的达布。其主要內(nèi)容是從EncodedImage中來。再來看看RtpPacketToSend逾冬,其本身就是RtpPacket黍聂,對(duì)于Rtp包而言躺苦,除了基本頭信息,重要的就是擴(kuò)展頭了产还,即extension匹厘,因此這是Rtp包的一個(gè)重點(diǎn)。這些Extension由ExtensionManager管理脐区,每個(gè)Extension必須提供kId愈诚,kUri,kValueSizeBytes牛隅,以及Write炕柔,ValueSize,Parse方法媒佣。這些Extension本身并沒有共同的基類汗唱,但是由于都遵守這樣的規(guī)則,可以通過模板函數(shù)的方法操作丈攒。每個(gè)Extension的關(guān)鍵信息由ExtensionInfo這個(gè)類來記錄哩罪,包括了id,length和offset巡验。其中offset是相對(duì)于packet的buffer_的偏移量际插。可以通過RtpPacket的ReserverExtension显设,HasExtension框弛,AllocateExtension,等方法操作Extension捕捂。如果需要自定義的Extension瑟枫,也需要按照Extension的固定格式開發(fā)
我們繼續(xù)看看Packetizer,這個(gè)模塊由RtpSenderVideo模塊在發(fā)送每個(gè)EncodedImage時(shí)創(chuàng)建指攒,通過RtpPacketizer的Create靜態(tài)方法創(chuàng)建慷妙,對(duì)于h264而言,其實(shí)現(xiàn)類為RtpPacketizerH264允悦。打包的過程是這樣的膝擂,通過工具方法FindNaluIndices找到EncodedImage中的所有Nalu單元,即結(jié)構(gòu)體NaluIndex隙弛,這個(gè)結(jié)構(gòu)體里記錄了每個(gè)Nalu單元中的起始偏移架馋,payload偏移,以及payload大小全闷。根據(jù)這些找到的NaluIndex就可以構(gòu)建相對(duì)應(yīng)的ArrayView了叉寂,每個(gè)ArrayView包含了一個(gè)NaluIndex所對(duì)應(yīng)的buffer。RtpPacketizerH264总珠,通過GeneratePackets方法屏鳍,將這些ArrayView進(jìn)一步封裝為PacketUnit伊约,根據(jù)實(shí)際情況,通過PacketizeSingeNalu或PacketizeFuA或PacketizeStapA進(jìn)行打包孕蝉。這個(gè)結(jié)構(gòu)體里記錄了first_fragment,last_fragment腌逢,aggregated降淮,header,以及source_fragment搏讶。每次調(diào)用Packetizer的NextPacket方法時(shí)佳鳖,就會(huì)通過PacketUnit生成對(duì)應(yīng)的RtpPacketToSend對(duì)象
準(zhǔn)備好了一切,有了RtpPacketToSend這個(gè)發(fā)送對(duì)象媒惕,最后RtpSenderVideo將準(zhǔn)備好的RtpPacketToSend系吩,通過RtpSender的EnqueuePackets入隊(duì)列,準(zhǔn)備發(fā)送妒蔚。RtpSender進(jìn)一步調(diào)用了RtpPacketSender的EnqeuuePackets方法穿挨,這個(gè)RtpPacketSender是一個(gè)接口類,其實(shí)現(xiàn)類為PacedSender肴盏,最終PacedSender將這個(gè)RtpPacket交由PacingController發(fā)送科盛,PacingController將其放入了自己的隊(duì)列packet_queue_中
至于PacingController后續(xù)如何將RtpPacket發(fā)送出去,下次再繼續(xù)