WebRTC 音视频同步

WebRTC 音视频同步

直播场景的音视频同步很多情况基本都是以音频为基准,视频去同步音频,从而达到音视频同步的目的,本文从 RTP 和 RTCP 协议出发讲解 WebRTC 接收端音视频同步流程

视频 Rtp 包时间戳

视频数据包在发送时都会打上 rtp 时间戳,详见 video_stream_encoder.cc set_timestamp


// 获取视频采集 ntp 时间戳
  int64_t capture_ntp_time_ms;
  if (video_frame.ntp_time_ms() > 0) {
    capture_ntp_time_ms = video_frame.ntp_time_ms();
  } else if (video_frame.render_time_ms() != 0) {
    capture_ntp_time_ms = video_frame.render_time_ms() + delta_ntp_internal_ms_;
  } else {
    capture_ntp_time_ms = current_time_ms + delta_ntp_internal_ms_;
  }
  incoming_frame.set_ntp_time_ms(capture_ntp_time_ms);

  // 将 ntp 时戳转换为 Rtp Timestamp
  const int kMsToRtpTimestamp = 90;
  incoming_frame.set_timestamp(
      kMsToRtpTimestamp * static_cast<uint32_t>(incoming_frame.ntp_time_ms()));

音频 Rtp 包时间戳

音频时间戳以采样点总数递增,和系统时间戳无关,该时间戳和 RTCP 和Sender Report 会有一个对应关系


 // 编码 10 ms 数据

        // 音频编码模块内部会自动重传样
        audio_frame->timestamp_ = _timeStamp;
        // 编码,编码完成后自动触发打包和发送方法
        if (audio_coding_->Add10MsData(*audio_frame) < 0) {
          RTC_DLOG(LS_ERROR) << "ACM::Add10MsData() failed.";
          return;
        }
        // 时间戳生成规则,以采样点总数递增,注意此处和系统时间是没有关系的
        _timeStamp += static_cast<uint32_t>(audio_frame->samples_per_channel_);

RTCP 生成包规则

音频和视频 RTP 包发送时仅仅发送自身打包时的相对时间戳,需要通过 SR(Sender Report)携带时间基准来进行音视频同步,也就是 SR 会定时发送视频 RTP 时戳对应的 NTP 时间戳以及音频 RTP 时间戳对应的 NTP 时间戳,二者的 NTP 时间戳都是系统时间,基准是相同的

接收端处理原则

接收端先利用 SR 包将音视频 RTP 的时间戳统一到当前系统时间戳(计算逻辑其实很简单,由于二者是线性关系,使用最小二乘法算出斜率即可)
rtp_streams_synchronizer2.cc UpdateDelay
stream_synchronization.cc ComputeRelativeDelay


// 音频时间同步到当前系统时间更新
  absl::optional<Syncable::Info> audio_info = syncable_audio_->GetInfo();
  if (!audio_info || !UpdateMeasurements(&audio_measurement_, *audio_info)) {
    return;
  }

// 视频时间同步到当前系统时间更新
  int64_t last_video_receive_ms = video_measurement_.latest_receive_time_ms;
  absl::optional<Syncable::Info> video_info = syncable_video_->GetInfo();
  if (!video_info || !UpdateMeasurements(&video_measurement_, *video_info)) {
    return;
  }


// 计算出以当前系统时间为基准的音频采集时间
  int64_t audio_last_capture_time_ms;
  if (!audio_measurement.rtp_to_ntp.Estimate(audio_measurement.latest_timestamp,
                                             &audio_last_capture_time_ms)) {
    return false;
  }
// 计算出以当前系统时间为基准的视频采集时间
  int64_t video_last_capture_time_ms;
  if (!video_measurement.rtp_to_ntp.Estimate(video_measurement.latest_timestamp,
                                             &video_last_capture_time_ms)) {
    return false;
  }

音视频各自正常播放

  1. 进行音视频同步前需要先确保音视频各自能单独正常流畅播放,需要二者先流畅播放后才考虑同步。由于音频和视频有自己各自的网络延迟,也就是音视频各自流畅播放的延迟是不相同的,在该延迟的基础上二者能正常播放;(WebRTC 内部叫 target_delay 目标延迟,计算方法后续文章给出)

  2. 在音视频能正常流畅播放的前提下,计算二者的延迟大小,有以下几种场景


  • 视频延迟小、音频延迟大;此时需要增加视频延迟以保持二则同步
  • 音频延迟小、视频延迟大;此时需要增加音频延迟以保持二则同步
  • 此处增加的延迟在 WebRTC 叫 extra_delay

stream_synchronization.cc ComputeDelays


// 首先计算出最后一对音视频包的相对延迟,最后一对音视频包往往能表现后续音视频同步的附加延迟趋势,正数表示视频慢于音频

  // Positive diff means that video_measurement is behind audio_measurement.
  *relative_delay_ms =
      video_measurement.latest_receive_time_ms -
      audio_measurement.latest_receive_time_ms -
      (video_last_capture_time_ms - audio_last_capture_time_ms);

  if (*relative_delay_ms > kMaxDeltaDelayMs ||
      *relative_delay_ms < -kMaxDeltaDelayMs) {
    return false;
  }

通过当前视频延迟和当前音频延迟之差,加上最后一对音视频包的相对延迟能够确定当前音视频的总体延迟,该延迟最终会以其他延迟附加到音频或者视频延迟之中,(注:WebRTC 并不是一次性把所有延迟附加到音视频延迟中,每次都会限定一个阈值 80ms、也就是音视频每次进行音视频同步时附加的延迟不超过 80 ms


  // Calculate the difference between the lowest possible video delay and the
  // current audio delay.
  int current_diff_ms =
      current_video_delay_ms - current_audio_delay_ms + relative_delay_ms;

  avg_diff_ms_ =
      ((kFilterLength - 1) * avg_diff_ms_ + current_diff_ms) / kFilterLength;
  if (abs(avg_diff_ms_) < kMinDeltaMs) {
    // Don't adjust if the diff is within our margin.
    return false;
  }

延迟同步到音频和视频模块

上诉计算的音频延迟和视频延迟通过下面接口传值到音频和视频对应的模块,视频延迟最终控制 timing.h 类、音频延迟最终控制 DelayManager 类

syncable_audio_->SetMinimumPlayoutDelay(target_audio_delay_ms);
syncable_video_->SetMinimumPlayoutDelay(target_video_delay_ms);

至此音视频同步的大致流程结束,WebRTC 音视频演示 Demo 可以体验一下,有问题随时交流

Badwin

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值