github:https://github.com/bigonelby/webrtcUml/tree/master/latest
这张图介绍了数据从编码器中输出,最终流入pacing的过程
首先看看CorePipeline,编码后的帧通过EncodedImageCallback返回,那么数据从VideoStreamEncoder出发,将会如何流到下游呢?VideoStreamEncoderInterface提供了一个关键的方法:SetSink,给出了下一步数据流的重要指示。持有这个接口的是VideoSendStreamImpl,其在RegisterProcessThread的时候,会调用该接口的SetSink方法,为编码器设置下游。这个sink,即为EncoderSink,这个EncoderSink本身也是继承自EncodedImageCallback,因此他也具有接收EncodedImage的能力。而实现EncoderSink接口的,是VideoSendStreamImpl。因此编码器在产生编码数据后,通过EncoderSink这个设置的sink,就将EncodedImage成功的送到了VideoSendStreamImpl中
后面的重点操作,当然就是将EncodedImage打包成rtp,然后发送出去。处理这个工作的,可不是VideoSendStreamImpl。因此VideoSendStreamImpl会将数据继续送给负责的模块。谁来负责这个事情呢?就是RtpVideoSenderInterface这个接口,这个接口本身也是继承了EncodedImageCallback这个接口,因此显然,他也具备处理EncodedImage的能力!这个接口的实现类为RtpVideoSender,这个类是由RtpTransportControllerSendInterface这个接口的CreateRtpVideoSender方法创建的。这个过程前面的图里有过介绍
由此数据到达了RtpVideoSender这个重要的模块,RtpVideoSender的处理单元为Stream,因为对于video而言,也许含有多个stream,simulcast等。那么负责每个模块的发送的,即为RtpVideoSender的助手,RtpStreamSender。从名字就可以看出来,这个类是负责stream的发送的。RtpStreamSender是一个组长,其有两个组员,ModuleRtpRtcpImpl2,RtpSenderVideo。ModuleRtpRtcpImpl2本身掌握很多关于rtprtcp发送的重要信息,他的创建依赖于Configuration;而RtpSenderVideo是真正的发送视频数据的类
RtpSenderVideo主要做了三件事,通过RtpSender的AllocatePacket方法,创建了RtpPacketToSend对象;通过RtpPacketizer进行打包,最终填充RtpPacketToSend对象;然后通过RtpSender的EnqueuePackets方法,将打包好的RtpPacketToSend对象送给RtpPacketSender
接着,我们看看RtpPacket对象。首先先看看RTPVideoHeader。这个对象是由RtpPayloadParams的GetRtpVideoHeader方法创建的。其主要内容是从EncodedImage中来。再来看看RtpPacketToSend,其本身就是RtpPacket,对于Rtp包而言,除了基本头信息,重要的就是扩展头了,即extension,因此这是Rtp包的一个重点。这些Extension由ExtensionManager管理,每个Extension必须提供kId,kUri,kValueSizeBytes,以及Write,ValueSize,Parse方法。这些Extension本身并没有共同的基类,但是由于都遵守这样的规则,可以通过模板函数的方法操作。每个Extension的关键信息由ExtensionInfo这个类来记录,包括了id,length和offset。其中offset是相对于packet的buffer_的偏移量。可以通过RtpPacket的ReserverExtension,HasExtension,AllocateExtension,等方法操作Extension。如果需要自定义的Extension,也需要按照Extension的固定格式开发
我们继续看看Packetizer,这个模块由RtpSenderVideo模块在发送每个EncodedImage时创建,通过RtpPacketizer的Create静态方法创建,对于h264而言,其实现类为RtpPacketizerH264。打包的过程是这样的,通过工具方法FindNaluIndices找到EncodedImage中的所有Nalu单元,即结构体NaluIndex,这个结构体里记录了每个Nalu单元中的起始偏移,payload偏移,以及payload大小。根据这些找到的NaluIndex就可以构建相对应的ArrayView了,每个ArrayView包含了一个NaluIndex所对应的buffer。RtpPacketizerH264,通过GeneratePackets方法,将这些ArrayView进一步封装为PacketUnit,根据实际情况,通过PacketizeSingeNalu或PacketizeFuA或PacketizeStapA进行打包。这个结构体里记录了first_fragment,last_fragment,aggregated,header,以及source_fragment。每次调用Packetizer的NextPacket方法时,就会通过PacketUnit生成对应的RtpPacketToSend对象
准备好了一切,有了RtpPacketToSend这个发送对象,最后RtpSenderVideo将准备好的RtpPacketToSend,通过RtpSender的EnqueuePackets入队列,准备发送。RtpSender进一步调用了RtpPacketSender的EnqeuuePackets方法,这个RtpPacketSender是一个接口类,其实现类为PacedSender,最终PacedSender将这个RtpPacket交由PacingController发送,PacingController将其放入了自己的队列packet_queue_中
至于PacingController后续如何将RtpPacket发送出去,下次再继续