VideoReceiveStream::Start方法分析

发布于:2024-05-21 ⋅ 阅读:(117) ⋅ 点赞:(0)

源码:

void VideoReceiveStream::Start() {
  RTC_DCHECK_RUN_ON(&worker_sequence_checker_);

  if (decoder_running_) {
    return;
  }

  const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
                                rtp_video_stream_receiver_.IsUlpfecEnabled();

  if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
      protected_by_fec) {
    frame_buffer_->SetProtectionMode(kProtectionNackFEC);
  }

  transport_adapter_.Enable();
  rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
  if (config_.enable_prerenderer_smoothing) {
    incoming_video_stream_.reset(new IncomingVideoStream(
        task_queue_factory_, config_.render_delay_ms, this));
    renderer = incoming_video_stream_.get();
  } else {
    renderer = this;
  }

  for (const Decoder& decoder : config_.decoders) {
    std::unique_ptr<VideoDecoder> video_decoder =
        config_.decoder_factory->LegacyCreateVideoDecoder(decoder.video_format,
                                                          config_.stream_id);
    // If we still have no valid decoder, we have to create a "Null" decoder
    // that ignores all calls. The reason we can get into this state is that the
    // old decoder factory interface doesn't have a way to query supported
    // codecs.
    if (!video_decoder) {
      video_decoder = std::make_unique<NullVideoDecoder>();
    }

    std::string decoded_output_file =
        field_trial::FindFullName("WebRTC-DecoderDataDumpDirectory");
    // Because '/' can't be used inside a field trial parameter, we use ';'
    // instead.
    // This is only relevant to WebRTC-DecoderDataDumpDirectory
    // field trial. ';' is chosen arbitrary. Even though it's a legal character
    // in some file systems, we can sacrifice ability to use it in the path to
    // dumped video, since it's developers-only feature for debugging.
    absl::c_replace(decoded_output_file, ';', '/');
    if (!decoded_output_file.empty()) {
      char filename_buffer[256];
      rtc::SimpleStringBuilder ssb(filename_buffer);
      ssb << decoded_output_file << "/webrtc_receive_stream_"
          << this->config_.rtp.remote_ssrc << "-" << rtc::TimeMicros()
          << ".ivf";
      video_decoder = CreateFrameDumpingDecoderWrapper(
          std::move(video_decoder), FileWrapper::OpenWriteOnly(ssb.str()));
    }

    video_decoders_.push_back(std::move(video_decoder));

    video_receiver_.RegisterExternalDecoder(video_decoders_.back().get(),
                                            decoder.payload_type);
    VideoCodec codec = CreateDecoderVideoCodec(decoder);

    const bool raw_payload =
        config_.rtp.raw_payload_types.count(decoder.payload_type) > 0;
    rtp_video_stream_receiver_.AddReceiveCodec(decoder.payload_type, codec,
                                               decoder.video_format.parameters,
                                               raw_payload);
    RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
                             decoder.payload_type, &codec, num_cpu_cores_));
  }

  RTC_DCHECK(renderer != nullptr);
  video_stream_decoder_.reset(
      new VideoStreamDecoder(&video_receiver_, &stats_proxy_, renderer));

  // Make sure we register as a stats observer *after* we've prepared the
  // |video_stream_decoder_|.
  call_stats_->RegisterStatsObserver(this);

  // Start decoding on task queue.
  video_receiver_.DecoderThreadStarting();
  stats_proxy_.DecoderThreadStarting();
  decode_queue_.PostTask([this] {
    RTC_DCHECK_RUN_ON(&decode_queue_);
    decoder_stopped_ = false;
    StartNextDecode();
  });
  decoder_running_ = true;
  rtp_video_stream_receiver_.StartReceive();
}

解释:

1运行环境检查

RTC_DCHECK_RUN_ON(&worker_sequence_checker_);
2检查解码器是否已运行:如果解码器已经在运行,则直接返回,避免重复启动

if (decoder_running_) {
  return;
}

3设置保护模式:

检查是否启用了 FEC(前向纠错)保护,并根据需要设置帧缓冲区的保护模式。kProtectionNackFEC

const bool protected_by_fec = config_.rtp.protected_by_flexfec ||
                              rtp_video_stream_receiver_.IsUlpfecEnabled();

if (rtp_video_stream_receiver_.IsRetransmissionsEnabled() &&
    protected_by_fec) {
  frame_buffer_->SetProtectionMode(kProtectionNackFEC);
}
4启用传输适配器

transport_adapter_.Enable();

5设置视频渲染器

rtc::VideoSinkInterface<VideoFrame>* renderer = nullptr;
if (config_.enable_prerenderer_smoothing) {
  incoming_video_stream_.reset(new IncomingVideoStream(
      task_queue_factory_, config_.render_delay_ms, this));
  renderer = incoming_video_stream_.get();
} else {
  renderer = this;
}
6.初始化解码器

遍历配置中的所有解码器,尝试使用解码器工厂创建解码器对象。如果创建失败,使用一个空解码器(NullVideoDecoder)。

for (const Decoder& decoder : config_.decoders) {
  std::unique_ptr<VideoDecoder> video_decoder =
      config_.decoder_factory->LegacyCreateVideoDecoder(decoder.video_format,
                                                        config_.stream_id);
  if (!video_decoder) {
    video_decoder = std::make_unique<NullVideoDecoder>();
  }
 

7.处理解码数据转储

如果启用了解码数据转储功能,则设置解码数据转储路径,并用 CreateFrameDumpingDecoderWrapper 包装解码器,以便将解码帧保存到文件中

std::string decoded_output_file =
    field_trial::FindFullName("WebRTC-DecoderDataDumpDirectory");
absl::c_replace(decoded_output_file, ';', '/');
if (!decoded_output_file.empty()) {
  char filename_buffer[256];
  rtc::SimpleStringBuilder ssb(filename_buffer);
  ssb << decoded_output_file << "/webrtc_receive_stream_"
      << this->config_.rtp.remote_ssrc << "-" << rtc::TimeMicros()
      << ".ivf";
  video_decoder = CreateFrameDumpingDecoderWrapper(
      std::move(video_decoder), FileWrapper::OpenWriteOnly(ssb.str()));
}
8.注册解码器

将创建的解码器添加到 video_decoders_ 列表中,并注册到 video_receiver_ 中。然后,根据解码器的配置,向 rtp_video_stream_receiver_ 注册接收编解码器,并向 video_receiver_ 注册接收编解码器

video_decoders_.push_back(std::move(video_decoder));

video_receiver_.RegisterExternalDecoder(video_decoders_.back().get(),
                                        decoder.payload_type);
VideoCodec codec = CreateDecoderVideoCodec(decoder);

const bool raw_payload =
    config_.rtp.raw_payload_types.count(decoder.payload_type) > 0;
rtp_video_stream_receiver_.AddReceiveCodec(decoder.payload_type, codec,
                                           decoder.video_format.parameters,
                                           raw_payload);
RTC_CHECK_EQ(VCM_OK, video_receiver_.RegisterReceiveCodec(
                         decoder.payload_type, &codec, num_cpu_cores_));
9设置视频流解码器

RTC_DCHECK(renderer != nullptr);
video_stream_decoder_.reset(
    new VideoStreamDecoder(&video_receiver_, &stats_proxy_, renderer));
10注册统计观察者

call_stats_->RegisterStatsObserver(this);
11启动解码线程

启动解码线程,调用 DecoderThreadStarting 方法,并在任务队列上发布任务以启动下一个解码操作。将 decoder_running_ 设置为 true,并启动 RTP 视频流接收

video_receiver_.DecoderThreadStarting();
stats_proxy_.DecoderThreadStarting();
decode_queue_.PostTask([this] {
  RTC_DCHECK_RUN_ON(&decode_queue_);
  decoder_stopped_ = false;
  StartNextDecode();
});
decoder_running_ = true;
rtp_video_stream_receiver_.StartReceive();
 


网站公告

今日签到

点亮在社区的每一天
去签到