Webrtc源码开发笔记1 —Webrtc视频编码打包流程模块图解

一、Channel相关模块
Channel主要维护编解码,RTP/RTCP相关逻辑模块以及维护Transport模块发送等,其中编解码与RTP/RTCP相关处理逻辑主要在Call模块下创建的各种Stream中封装。目前Webrtc中有多种Channel,下面简单梳理一下Channel间关系,然后针对视频发送流程整理一下每层Channel中对应的主要功能。
在这里插入图片描述

2.1 VideoChannel
VideoChannel是channel中的最外层,对应音频为VoiceChannel,RtpTransceiver模块中的BaseChannel可以设置为VideoChannel或者VoiceChannel。这里对外主要提供SetLocalContent_w和SetRemoteContent_w方法,也就是只要得到SDP解析后的封装cricket::VideoContentDescription的对象,就可以初始化VideoChannel。另外一个重要方法就是SetRtpTransport,这里可以设置当前选中真正数据发送的Transport模块。

2.2BaseChannel
BaseChannel是VideoChannel的父类,这里关联了两个重要模块。RtpTransportInternal指向实际负责数据收发功能的模块,最终打包好的RTP/RTCP信息会调用这里的发送功能发出。MediaChannel指针最终指向的实现是WebRtcVideoChannel,这里封装了编码和rtp打包rtcp处理的相关操作。

2.3 WebRtcVideoChannel
WebRtcVideoChannel是各种channel中最下层的一类,其中维护了WebRtcVideoSendStream和WebRtcVideoReceiveStream,这些模块中封装了上层传入的视频source和encoder,其内部VideoSendStream最终封装了编码器模块和RTP/RTCP模块。

3.Call模块与Stream
这里介绍Call实例中包含多个发送和接收流,同时这里规定这些流都是与同一个远端通信,共享一个带宽估计。

Call相关模块主要在源码目录中call文件夹下,其中在初始化Webrtc时需要初始化一个Call对象,主要提供VideoSendStream,VideoReceiveStream等模块。创建Call时可以使用webrtc::Call::Config作为参数,配置带宽相关,同时还可以配置fec,neteq,network_state_predictor的相关factory,可见数据包收发控制相关内容都与Call相关模块有关。下面是一个初始化Call模块的简单例子。

webrtc::Call::Config call_config(event_log);
 
  
FieldTrialParameter<DataRate> min_bandwidth("min", DataRate::kbps(30));
FieldTrialParameter<DataRate> start_bandwidth("start", DataRate::kbps(300));
FieldTrialParameter<DataRate> max_bandwidth("max", DataRate::kbps(2000));
 
ParseFieldTrial({ &min_bandwidth, &start_bandwidth, &max_bandwidth },
trials_->Lookup("WebRTC-PcFactoryDefaultBitrates"));
 
    
call_config.bitrate_config.min_bitrate_bps = rtc::saturated_cast<int>(min_bandwidth->bps());
 
call_config.bitrate_config.start_bitrate_bps =rtc::saturated_cast<int>(start_bandwidth->bps());
 
call_config.bitrate_config.max_bitrate_bps = rtc::saturated_cast<int>(max_bandwidth->bps());
 
    
call_config.fec_controller_factory = nullptr;
call_config.task_queue_factory = task_queue_factory_.get();
call_config.network_state_predictor_factory = nullptr;
call_config.neteq_factory = nullptr;
call_config.trials = trials_.get();
 
    
std::unique_ptr<Call>(call_factory_->CreateCall(call_config));

VideoSendStream由Call对象创建,真正实现是实现internal::VideoSendStream。
在这里插入图片描述
VideoSendStreamImpl创建销毁为了保证顺序,需要在worker_queue中进行。DeliverRtcp会在网络线程被调用。编码器可能通过任意线程通过EncodedImageCallback接口抛出编码后的数据。这里数据会转到RtpVideoSenderInterface的实现类中进行RTP打包和相关处理。

VideoStreamEncoder中封装了编码相关操作,Source传入原始数据,Sink吐出编码后的数据,同时有码率设置,关键帧请求等接口。

4.RTP/RTCP
视频编码完成数据到达RtpVideoSenderInterface接口后,下一步就进入RTP/RTCP相关操作的模块中。
在这里插入图片描述
4.1 RtpStreamSender
这里RtpVideoSender的作用是根据RTP头将RTP包送到对应的模块。RtpVideoSender中持有一个RtpStreamSender数组,这里就是创建每个具体的rtp流发送模块,这里会根据当前rtp设置中ssrc的数量创建多个RtpStreamSender。RtpStreamSender中的很多模块将在RtpVideoSender中初始化。其中RtpRtcp和RTPSenderVideo是其主要组成部分。下面这个函数非常重要,可以具体看到RtpStreamSender中的元素是如何初始化的。

std::vector<RtpStreamSender> CreateRtpStreamSenders(
    Clock* clock,
    const RtpConfig& rtp_config,
    const RtpSenderObservers& observers,
    int rtcp_report_interval_ms,
    Transport* send_transport,
    RtcpBandwidthObserver* bandwidth_callback,
    RtpTransportControllerSendInterface* transport,
    FlexfecSender* flexfec_sender,
    RtcEventLog* event_log,
    RateLimiter* retransmission_rate_limiter,
    OverheadObserver* overhead_observer,
    FrameEncryptorInterface* frame_encryptor,
    const CryptoOptions& crypto_options) {
 
  RTC_DCHECK_GT(rtp_config.ssrcs.size(), 0);
 
 
 
  RtpRtcp::Configuration configuration;
 
  configuration.clock = clock;
 
  configuration.audio = false;
 
  configuration.receiver_only = false;
 
  configuration.outgoing_transport = send_transport;
 
  configuration.intra_frame_callback = observers.intra_frame_callback;
 
  configuration.rtcp_loss_notification_observer =
 
      observers.rtcp_loss_notification_observer;
 
  configuration.bandwidth_callback = bandwidth_callback;
 
  configuration.network_state_estimate_observer =
 
      transport->network_state_estimate_observer();
 
  configuration.transport_feedback_callback =
 
      transport->transport_feedback_observer();
 
  configuration.rtt_stats = observers.rtcp_rtt_stats;
 
  configuration.rtcp_packet_type_counter_observer =
 
      observers.rtcp_type_observer;
 
  configuration.paced_sender = transport->packet_sender();
 
  configuration.send_bitrate_observer = observers.bitrate_observer;
 
  configuration.send_side_delay_observer = observers.send_delay_observer;
 
  configuration.send_packet_observer = observers.send_packet_observer;
 
  configuration.event_log = event_log;
 
  configuration.retransmission_rate_limiter = retransmission_rate_limiter;
 
  configuration.overhead_observer = overhead_observer;
 
  configuration.rtp_stats_callback = observers.rtp_stats;
 
  configuration.frame_encryptor = frame_encryptor;
 
  configuration.require_frame_encryption =
 
      crypto_options.sframe.require_frame_encryption;
 
  configuration.extmap_allow_mixed = rtp_config.extmap_allow_mixed;
 
  configuration.rtcp_report_interval_ms = rtcp_report_interval_ms;
 
 
 
  std::vector<RtpStreamSender> rtp_streams;
 
  const std::vector<uint32_t>& flexfec_protected_ssrcs =
 
      rtp_config.flexfec.protected_media_ssrcs;
 
  RTC_DCHECK(rtp_config.rtx.ssrcs.empty() ||
 
             rtp_config.rtx.ssrcs.size() == rtp_config.rtx.ssrcs.size());
 
  for (size_t i = 0; i < rtp_config.ssrcs.size(); ++i) {
 
    configuration.local_media_ssrc = rtp_config.ssrcs[i];
 
    bool enable_flexfec = flexfec_sender != nullptr &&
 
                          std::find(flexfec_protected_ssrcs.begin(),
 
                                    flexfec_protected_ssrcs.end(),
 
                                    configuration.local_media_ssrc) !=
 
                              flexfec_protected_ssrcs.end();
 
    configuration.flexfec_sender = enable_flexfec ? flexfec_sender : nullptr;
 
    auto playout_delay_oracle = std::make_unique<PlayoutDelayOracle>();
 
 
 
    configuration.ack_observer = playout_delay_oracle.get();
 
    if (rtp_config.rtx.ssrcs.size() > i) {
 
      configuration.rtx_send_ssrc = rtp_config.rtx.ssrcs[i];
 
    }
 
 
 
    auto rtp_rtcp = RtpRtcp::Create(configuration);
 
    rtp_rtcp->SetSendingStatus(false);
 
    rtp_rtcp->SetSendingMediaStatus(false);
 
    rtp_rtcp->SetRTCPStatus(RtcpMode::kCompound);
 
    // Set NACK.
 
    rtp_rtcp->SetStorePacketsStatus(true, kMinSendSidePacketHistorySize);
 
 
 
    FieldTrialBasedConfig field_trial_config;
 
    RTPSenderVideo::Config video_config;
 
    video_config.clock = configuration.clock;
 
    video_config.rtp_sender = rtp_rtcp->RtpSender();
 
    video_config.flexfec_sender = configuration.flexfec_sender;
 
    video_config.playout_delay_oracle = playout_delay_oracle.get();
 
    video_config.frame_encryptor = frame_encryptor;
 
    video_config.require_frame_encryption =
 
        crypto_options.sframe.require_frame_encryption;
 
    video_config.need_rtp_packet_infos = rtp_config.lntf.enabled;
 
    video_config.enable_retransmit_all_layers = false;
 
    video_config.field_trials = &field_trial_config;
 
    const bool should_disable_red_and_ulpfec =
 
        ShouldDisableRedAndUlpfec(enable_flexfec, rtp_config);
 
    if (rtp_config.ulpfec.red_payload_type != -1 &&
 
        !should_disable_red_and_ulpfec) {
 
      video_config.red_payload_type = rtp_config.ulpfec.red_payload_type;
 
    }
 
    if (rtp_config.ulpfec.ulpfec_payload_type != -1 &&
 
        !should_disable_red_and_ulpfec) {
 
      video_config.ulpfec_payload_type = rtp_config.ulpfec.ulpfec_payload_type;
 
    }
 
    auto sender_video = std::make_unique<RTPSenderVideo>(video_config);
 
    rtp_streams.emplace_back(std::move(playout_delay_oracle),
 
                             std::move(rtp_rtcp), std::move(sender_video));
 
  }
 
  return rtp_streams;
 
}

RtpRtcp这里负责RTCP数据的处理和收发,对应的实现是ModuleRtpRtcpImpl,ModuleRtpRtcpImpl实现了RtpRtcp和MoudleRtpRtcp两个接口,实现了rtcp处理相关功能。同时内部还持有实体std::unique_ptr rtp_sender_,RTCPSender rtcp_sender,RTCPReceiver rtcp_receiver_用于rtp/rtcp的收发。

RTPSenderVideo封装了具体发送的逻辑,内部发送模块实际指向RtpRtcp中的实体。这里还有fec相关功能开关的控制逻辑。

RTPSender实例在RtpRtcp中,RTPSenderVideo中持有这个实例的指针,其中封装了Pacer和PacketHistory模块,用于控制发送频率和重传。最终在PacedSender中交给PacketRouter,最终交给RtpSenderEgress的Transport指针指向对象。这个对象就是最开始的WebRtcVideoChannel,WebRtcVideoChannel调用其中的RTPTransport将rtp包发送到网络。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
WebRTC是一个实时通信的开源项目,其源码开发涵盖了视频编码打包以及流程模块等。在这个开发笔记中,我将对WebRTC视频编码打包流程模块进行图解说明。 WebRTC视频编码打包流程主要涉及到以下几个模块:视频源模块视频编码模块打包模块和传输模块。 首先是视频源模块,它负责从摄像头或者文件中获取视频数据。该模块通过调用底层API来获取视频帧,并将其传递给下一个模块。 接下来是视频编码模块,它负责将获取到的视频帧进行压缩编码。具体来说,该模块会对视频帧进行压缩算法处理,将其转换为可传输的数据格式。WebRTC支持多种视频编码算法,如VP8、H.264等。 然后是打包模块,它负责将编码后的视频数据打包成数据包。该模块会对视频数据进行分片,并为每个片设置头部信息,以便接收端能够正确解析和处理。 最后是传输模块,它负责将打包好的视频数据通过网络传输到接收端。该模块依赖于网络协议,如UDP或TCP等进行数据传输。在传输过程中,还会涉及到网络拥塞控制和丢包重传等机制,以保证传输的稳定性和可靠性。 以上就是WebRTC视频编码打包流程模块图解说明。通过这些模块的协作,WebRTC能够实现实时的视频传输和通信功能。开发者可以根据需要对各个模块进行定制和扩展,以满足不同的应用场景需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值