大家好,今天小编来为大家解答以下的问题,关于WebRTC视频通信流程解析,这个很多人还不知道,现在让我们一起来看看吧!
构造一个VideoEngineImpl对象,该对象继承ViEBaseImpl、ViECodecImpl、ViECaptureImpl,
ViEFileImpl、ViEImageProcessImpl、ViENetworkImpl、ViERenderImpl、
ViERTP_RTCPImpl、ViEExternalCodecImpl、VideoEngine 类、
同时,ViEBaseImpl实例化视频共享数据单元ViEShareData,并将共享数据对象分发到各个Impl类中。图解TD
A[VideoEngine:Create] --|vie_impl.cc|B(新VideoEngineImpl:new Config, true)
B --B1(ViENetworkImpl)
B --B2(ViECodecImpl)
B --B3(ViECaptureImpl)
B --B4(ViEFileImpl)
B --B5(ViEImageProcessImpl)
B --B6(ViEBaseImpl)
B --B7(ViERenderImpl)
B --B8(ViERTP_RTCPImpl)
B --B9(ViEExternalCodecImpl)
B --B10(视频引擎)
B6--|vie_shared_data.cc| B6A(ViESharedData:ViESharedData)
B6A --|创建日志跟踪对象|B6A1(Trace:CreateTrace)
B6A --|获取CPU核心数number_cores_|B6A2(CpuInfo:DetectNumberOfCores)
B6A --|创建频道管理对象channel_manager_|B6A3(new ViEChannelManager)
B6A --|创建视频输入设备管理对象input_manager_|B6A4(new ViEInputManager)
B6A --|创建视频渲染管理对象render_manager_| B6A5(新的ViERRenderManager)
B6A --|创建并启动模块运行线程module_process_thread_: ProcessThread| B6A6(ProcessThread:Create)其中Impl类是引擎API接口类,
用户通过各个API类的GetInterface()获取到的实际上是引擎对象到API父类的转换,如:
ViEBase* ViEBase:GetInterface(VideoEngine* video_engine) {
如果(!video_engine){
返回空值;
}
VideoEngineImpl* vie_impl=static_cast(video_engine);
ViEBaseImpl* vie_base_impl=vie_impl;
(*vie_base_impl)++; //增加引用计数。
返回vie_base_impl;
}
2. 创建视频通道
函数:int ViEBaseImpl:CreateChannel(int video_channel)
视频频道创建涉及各种视频相关模块的创建和观察者注册。图解TD
A[ViEBaseImpl:CreateChannel] --|vie_channel_manager.cc| B(ViEChannelManager:创建频道)
B --|vie_channel_group.cc 创建通道组对象,管理remb、bitrateControler 等| C(新频道组)
C --D(ChannelGroup:CreateSendChannel)
D --|创建视频编码管理对象| E(新ViEEncoder)
E --|初始化ViEEncoder| F(vie_encoder-初始化)
F --|创建视频频道| G(新ViEChannel)
G --|初始化视频通道| H(channel-Init)
2.1 通道组ChannelGroup
ChannelGroup 包含以下模块的创建:
1. VieRemb
Remb发包模块:负责将RemoteBitrateEstimator模块的码率预测值通过RTCP模块反馈给远程发送方,调整远程发送码率
2. BitrateAllocator
码率变化分配模块:作为BitrateController和ViEEncoder之间的桥梁,当BitrateController模块的码率发生变化时,通过ViEEncoder在模块中注册的观察者对象会告诉ViEEncoder变化后的码率值。具体函数是OnNetworkChanged()
ChannelGroup:ChannelGroup(ProcessThread* process_thread, const Config* config)
--bitrate_allocator_(new BitrateAllocator()) 调用过程
图解TD
A[BitrateControllerImpl:MaybeTriggerOnNetworkChanged] --|observer_对象是ChannelGroup| B(观察者_-OnNetworkChanged)
B --|vie_channel_group.cc| C(ChannelGroup:OnNetworkChanged)
C --D(bitrate_allocator_-OnNetworkChanged)
D --|bitrate_allocator.cc| E(BitrateAllocator:OnNetworkChanged)
E --|vie_encoder.cc| F(BitrateObserver:OnNetworkChanged)
F --G(ViEEncoder:OnNetworkChanged) BitrateAllocator 中的BitrateObserver 在执行ViEEncoder:SetEncoder() 时调用bitrate_allocator_-AddBitrateObserver(bitrate_observer_.get(),) 时添加。
3. BitrateController
发送端码率控制模块:负责发送端码率控制,综合远端Remb反馈的接收码率和发送端根据评估的丢包率等码率调整最终发送码率。
该模块继承Module类,将被注册在ProcessThread线程中运行。默认轮询时间为25 毫秒。
ChannelGroup:ChannelGroup(ProcessThread* process_thread, const Config* config)
//这是ChannelGroup,它继承了BitrateObserver类。
--比特率控制器_(
BitrateController:CreateBitrateController(GetRealTimeClock(), this))
//观察者就是传入的this
--new BitrateControllerImpl(时钟, 观察者)
--observer_(观察者)
//将模块注册到ProcessThread线程
--process_thread-RegisterModule(bitrate_controller_.get())
因此,BitrateController中的observer_对象就是ChannelGroup继承的BitrateObserver。
它在预测码率变化时使用。
4. EncoderStateFeedback
编码器状态反馈模块:将关键帧请求反馈给ViEEncoder
//建造
ChannelGroup:ChannelGroup(ProcessThread* process_thread, const Config* config)
--encoder_state_feedback_(new EncoderStateFeedback())
//添加视频编码器
ChannelGroup:CreateSendChannel()
--encoder_state_feedback_-AddEncoder(ssrc, 编码器)
//赋予EncoderStateFeedback 内部RtcpIntraFrameObserver 观察对象
//转到ViEChannel,依次传给RtpRtcp模块。
ChannelGroup:CreateChannel()
--new ViEChannel(.encoder_state_feedback_-GetRtcpIntraFrameObserver(),)
--intra_frame_observer_(intra_frame_observer)
--ViEChannel:CreateRtpRtcpConfiguration()
--configuration.intra_frame_callback=intra_frame_observer_;
//将RtcpIntraFrameObserver传递给RtpRtcp模块
--rtp_rtcp_.reset(RtpRtcp:CreateRtpRtcp(配置));
--ModuleRtpRtcpImpl:ModuleRtpRtcpImpl(const 配置配置)
//将RtcpIntraFrameObserver 传递给RtcpReceiver 模块
--rtcp_receiver_(configuration.intra_frame_callback)
--RTCPReceiver:RTCPReceiver
--_cbRtcpIntraFrameObserver(rtcp_intra_frame_observer)
因此,ViEChannel和RTCPReceiver模块
ViEChannel 内由解码线程DecodingThread调用,更新解码速度。目前该功能没实现
图TD中会有RtcpIntraFrameObserver对象
A[ViEChannel:ChannelDecodeProcess] --|vie_channel.cc| B(intra_frame_observer_-设置视频解码速度)
B --|encoder_state_feedback.cc| C(EncoderStateFeedbackObserver:SetVideoDecodingSpeed)
本地SSRC变化
图TD
A[RTCPReceiver:SetSsrcs] --|rtcp_receiver.cc| B(_cbRtcpIntraFrameObserver-OnLocalSsrcChanged)
B --|encoder_state_feedback.cc| C(EncoderStateFeedbackObserver:OnLocalSsrcChanged)
C --D(EncoderStateFeedback:OnLocalSsrcChanged)
D --E(编码器-OnLocalSsrcChanged)
E --|vie_encoder.cc| F(ViEEncoder:OnLocalSsrcChanged)
视频中的RTCP包
类别1:关键帧请求
主要包括SLI/PLI/FIR,其作用是当关键帧丢失且无法解码时,请求发送方重新生成并发送关键帧。
这本质上是一次重传,但与传输层重传不同的是,它重传的是最新生成的帧。
PLI是图片丢失指示,SLI是切片丢失指示。
当发送方收到接收方反馈的PLI或SLI时,需要要求编码器重新生成关键帧并发送给接收方。
FIR是Full Intra Request,很多人可能不知道Intra的含义。
Intra表示图像内编码,不需要其他图像信息就可以解码; Inter表示图像间编码,解码需要参考帧。
因此,Intra Frame实际上指的是I帧,Inter Frame指的是P帧或B帧。
那么为什么除了PLI 和SLI 之外还需要FIR 呢?
原因是使用场景不同。 FIR更多的是集中式视频会议。当新的参与者加入时,他需要发送一个FIR,其他参与者向他发送一个关键帧,以便他可以解码。
PLI和SLI的含义更多的是在丢包或者解码错误的情况下使用。
类别2:重传请求
主要包括RTX/NACK/RPSI
此重传与关键帧请求之间的区别在于,它可以要求重传任何帧。
第三类:码率控制
主要包括REMB/TMMBR/TMMBN
TMMBR是Temporal Max Media Bitrate Request,表示临时最大比特率请求。表示接收端当前带宽受限,告知发送端控制码率。
REMB是ReceiverEstimated Max Bitrate,接收端估计的最大比特率。
TMMBN 是临时最大媒体比特率通知
图解TD
A[RTCPReceiver:TriggerCallbacksFromRTCPPacket] --|收到关键帧请求| A1(_cbRtcpIntraFrameObserver-OnReceivedIntraFrameRequest)
A1 --|encoder_state_feedback.cc| A1A(EncoderStateFeedbackObserver:OnReceivedIntraFrameRequest)
A1A --A1B(EncoderStateFeedback:OnReceivedIntraFrameRequest)
A1B --|vie_encoder.cc| A1C(ViEEncoder:OnReceivedIntraFrameRequest)
A1C --|video_coding_impl.cc| A1D(VideoCodingModuleImpl:IntraFrameRequest)
A1D --|video_sender.cc| A1E(VideoSender:IntraFrameRequest)
A1E --|generic_encoder.cc| A1F(VCMGericEncoder:RequestFrame)
A1F --A1G(H264EncoderImpl:Encode)
A --|收到SLI 帧请求| A2(_cbRtcpIntraFrameObserver-OnReceivedSLI)
A2 --|encoder_state_feedback.cc| A2A(EncoderStateFeedbackObserver:OnReceivedSLI)
A2A --A2B(编码器状态反馈:OnReceivedSLI)
A2B --|vie_encoder.cc| A2C(ViEEncoder:OnReceivedSLI)
A --|收到RPSI 帧请求| A3(_cbRtcpIntraFrameObserver-OnReceivedRPSI)
A3 --A3A(EncoderStateFeedbackObserver:OnReceivedRPSI)
A3A --A3B(编码器状态反馈:OnReceivedRPSI)
A3B --|vie_encoder.cc| A3C(ViEEncoder:OnReceivedRPSI)
5. RemoteBitrateEstimator
接收端码率预测模块:使用卡尔曼算法等进行码率预测。
该模块继承Module类,将被注册在ProcessThread线程中运行。默认轮询时间为2000 毫秒。
6. CallStats
RTT值反馈模块:将RTT值反馈给视频JitterBuffer和RemoteBitrateEstimator模块进行相关调整。
该模块继承Module类,将被注册在ProcessThread线程中运行。默认轮询时间为1000 毫秒。
即每1000ms就会将RTT值反馈给JitterBuffer和RemoteBitrateEstimator模块。
ChannelGroup:ChannelGroup(ProcessThread* process_thread, const Config* config)
--call_stats_(新CallStats())
//添加RemoteBitrateEstimator作为观察者
--call_stats_-RegisterStatsObserver(remote_bitrate_estimator_.get());
//注册运行在ProcessThread线程中
--process_thread-RegisterModule(call_stats_.get());
传递给RtpRtcp模块
ChannelGroup:CreateChannel()
--new ViEChannel(. call_stats_-rtcp_rtt_stats(),)
--rtt_stats_(rtt_stats) //将channel中rtt_stats的值赋值给CallStats中的RtcpRttStats对象
--ViEChannel:CreateRtpRtcpConfiguration()
--configuration.rtt_stats=rtt_stats_
--rtp_rtcp_.reset(RtpRtcp:CreateRtpRtcp(configuration)) //将rtt_stats_传递给RtpRtcp模块
--ModuleRtpRtcpImpl:ModuleRtpRtcpImpl(const 配置配置)
--rtt_stats_(configuration.rtt_stats) //RtpRtcp模块将拥有CallStats模块的RtcpRttStats对象
--call_stats_-RegisterStatsObserver(channel-GetStatsObserver()) //将通道中的CallStatsObserver 注册为观察者
最后,CallStats 模块将有两个观察者,即ViEChannel 中的RemoteBitrateEstimator 和CallStatsObserver。在调用过程中,首先RtpRtcp模块Process()轮询并执行向CallStats报告RTT更新,然后CallStats模块在Process()轮询期间将更新的RTT分发给两个观察者。
图解TD
A[ModuleRtpRtcpImpl:Process] --|rtp_rtcp_impl.cc| B(rtt_stats_-OnRttUpdate)
B --|call_stats.cc| C(RtcpObserver:OnRttUpdate)
C --D(CallStats:OnRttUpdate)
D --E(CallStats:进程)
E --|vie_channel.cc| E1(ChannelStatsObserver:OnRttUpdate)
E1 --E1A(ViEChannel:OnRttUpdate)
E1A --|video_coding_impl.cc| E1B(VideoCodingModuleImpl:SetReceiveChannelParameters)
E1B --|video_receiver.cc| E1C(VideoReceiver:SetReceiveChannelParameters)
E1C--|接收器.cc| E1D(VCMReceiver:UpdateRtt)
E1D --|jitter_buffer.cc| E1E(VCMJitterBuffer:UpdateRtt)
E --|vie_channel_group.cc| E2(WrappingBitrateEstimator:OnRttUpdate)
E2 --|remote_bitrate_estimator_single_stream.cc| E2A(RemoteBitrateEstimatorImpl:OnRttUpdate)
E2A --|aimd_rate_control.cc| E2B(AimdRateControl:SetRtt)
2.2 ViEEncoder视频编码模块创建
ViEEncoder 负责创建和维护VCM、VPM 和PacedSender 模块。
VCM(VideoCodingModule),视频编码器相关管理模块。
VPM(VideoProcessingModule),视频预处理模块。
PacedSender,负责定时发送视频数据包,以免因视频帧过大、分割数据包过多而造成网络拥塞。
==注意:PacedSender 作为模块,未注册为由ViEShareData 启动
ModuleProcessThread 处理队列,但在ViEEncoder 中单独创建它
PacedProcesssThread线程处理==
ChannelGroup:CreateSendChannel()
//创建ViEEncoder对象
--new ViEEncoder(. process_thread_, bitrate_allocator_, bitrate_controller_,)
--ViEEncoder:ViEEncoder
//VCM模块
--VideoCodingModule:Create(此)
//VPM模块
--VideoProcessingModule:Create()
//PacedProcesssThread处理线程,专用于处理视频有序发送模块
--pacer_thread_(ProcessThread:Create())
--bitrate_observer_.reset(new ViEBitrateObserver(this))
//将BitrateController对象保存到ViEEncoder中,主要用于更新
//BitrateController的最大、最小和起始码率
--bitrate_controller_(bitrate_controller)
//这是ViEEncoder 对象
--pacing_callback_.reset(new ViEPacedSenderCallback(this))
--paced_sender_.reset(new PacedSender(. pacing_callback_,))
1 VCM(VideoCodingModule)
2 VPM(VideoProcessingModule)
3 PacedSender
PacedSender 模块将由线程PacedProcessThread 定期执行。当需要发送视频数据包时,数据包发送过程会通过pacing_callback_回调到ViEEncoder中执行。
ViEEncoder:ViEEncoder()
--pacer_thread_(ProcessThread:Create("PacerProcessThread"))
--pacing_callback_.reset(new ViEPacedSenderCallback(this));
--paced_sender_.reset(新的PacedSender(
Clock:GetRealTimeClock(),
pacing_callback_.get(),
kDefaultStartBitrateKbps,
PacedSender:kDefaultPaceMultiplier * kDefaultStartBitrateKbps,
0));
--PacedSender:PacedSender(. 回调,)
--callback_(回调)图TD
A[PacedSender:Process] --|paced_sender.cc| A1(PacedSender:发送数据包)
A1 --A1A(回调_-发送数据包时间)
A1A --|vie_encoder.cc| A1B(ViEPacedSenderCallback:发送数据包时间)
A1B --A1C(ViEEncoder:发送数据包时间)
A1C --A1D(send_payload_router_-TimeToSendPacket)
A1D --|payload_router.cc| A1E(PayloadRouter:发送数据包时间)
A1E --A1F(rtp_module-发送数据包时间)
A1F --|rtp_rtcp_impl.cc| A1G(ModuleRtpRtcpImpl:TimeToSendPacket)
A1G --A1H(rtp_sender_.TimeToSendPacket)
A1H --|rtp_sender.cc| A1I(RTPSender:发送数据包时间)
A1I --A1J(packet_history_.GetPacketAndSetSendTime)
A1J --A1K(RTPSender:准备并发送数据包)
A1K --A1L(RTPSender:SendPacketToNetwork)
A1L --A1M(传输_-发送数据包)
A1M --|vie_sender.cc| B(ViESender:发送数据包)
A[PacedSender:Process] --|paced_sender.cc| A2(PacedSender:SendPadding)
A2 --A2A(回调_-TimeToSendPadding)
A2A --|vie_encoder.cc| A2B(ViEPacedSenderCallback:TimeToSendPadding)
A2B --A2C(ViEEncoder:TimeToSendPadding)
A2C --A2D(send_payload_router_-TimeToSendPadding)
A2D --|payload_router.cc| A2E(PayloadRouter:TimeToSendPadding)
A2E --A2F(rtp_module-TimeToSendPadding)
A2F --|rtp_rtcp_impl.cc| A2G(ModuleRtpRtcpImpl:TimeToSendPadding)
A2G --A2H(rtp_sender_.TimeToSendPadding)
A2H --|rtp_sender.cc| A2I(RTPSender:TimeToSendPadding)
A2I --A2J(RTPSender:TrySendPadData)
A2J --A2K(RTPSender:SendPadData)
A2K --A2L(RTPSender:SendPacketToNetwork)
A2L --A2M(传输_-发送数据包)
A2M --|vie_sender.cc|乙
好了,关于WebRTC视频通信流程解析和的问题到这里结束啦,希望可以解决您的问题哈!
【WebRTC视频通信流程解析】相关文章:
2.米颠拜石
3.王羲之临池学书
8.郑板桥轶事十则
用户评论
这篇文章会不会讲解webrtc通用的视频录制流程啊?
有16位网友表示赞同!
想了解下webrtc视频传输过程中有哪些关键技术点!
有10位网友表示赞同!
最近在学习webrtc,希望这篇博客能帮我更全面地理解视频流程。
有11位网友表示赞同!
以前只知道webrtc可以做视频通话,但具体流程还是比较模糊的,希望能在这篇文章中有所提升。
有8位网友表示赞同!
想了解一下webrtc视频编码和解码的过程,这篇文章合适吗?
有20位网友表示赞同!
我还在纠结选择哪种编解码器更适合我们项目,这篇文章里有解吗?
有11位网友表示赞同!
期待这篇文章能够从底层原理到高级应用都讲全面一些!
有15位网友表示赞同!
希望可以看到一些具体的webrtc视频应用案例,能更好地理解它的实际应用场景。
有5位网友表示赞同!
看了很多关于webrtc的资料,但这篇博客看起来视角比较独特,值得一读。
有18位网友表示赞同!
我平时都在用zoom这样的平台进行视频通话,不知道他们是否使用了webrtc呢?
有10位网友表示赞同!
这篇文章能详细解释一些webrtc相关协议吗?比如SDP、RTCP什么的。
有11位网友表示赞同!
我想开发一个基于webrtc的实时视频监控系统,这篇文章能提供一些启发吗?
有14位网友表示赞同!
我比较好奇webrtc在未来发展会走向哪里,这篇文章会不会有所分析?
有14位网友表示赞同!
希望文章能够讲清楚webrtc视频流程中的网络传输环节,以及如何解决丢包问题。
有20位网友表示赞同!
最近开始接触webrtc,感觉它的架构确实很有创新之处,期待深入了解其工作原理。
有15位网友表示赞同!
这篇文章对新手用户友好吗?我看标题好像比较专业啊。
有19位网友表示赞同!
希望能看到针对不同应用场景,webrtc视频流程的差异性分析!
有18位网友表示赞同!
我想要探索如何将webrtc技术应用于我的项目中,这篇文章能提供一些参考吗?
有20位网友表示赞同!