WebRtc的推流过成

WebRTC我编译的97版本的webrtc_android,这里我就以Android视角从视频采集,渲染,编码,发送四个流程来答题说一下WebRtc的视频推流过程,

采集

Android摄像头采集可以调用WebRtc提供的VideoCapturer,他封装了Camera和Camera2的两套api在里面。
VideoCapturer

public interface VideoCapturer {
  void initialize(
      SurfaceTextureHelper surfaceTextureHelper,
      Context applicationContext,
      CapturerObserver capturerObserver);
}

SurfaceTextureHelper封装了SurfaceTexture,使用Camera2 api 可以直接调用CameraDevice.createCaptureSession()打开摄像头,把Surface传进去。

private class CameraStateCallback extends CameraDevice.StateCallback {
  // other definitions...
  @Override
  public void onOpened(CameraDevice camera) {
    // method body...
    surfaceTextureHelper.setTextureSize(captureFormat.width, captureFormat.height);
    surface = new Surface(surfaceTextureHelper.getSurfaceTexture());
    try {
      camera.createCaptureSession(
          Arrays.asList(surface), new CaptureSessionCallback(), cameraThreadHandler);
    } catch (CameraAccessException e) {
      // method body...
    }
  }
  // other definitions...
}

摄像头就会将输出直接输出到绑定的Surface中去。
当SurfaceTexture缓冲区BufferQueue中存在帧数据的时候,会回调CapturerObserver.onFrameCaptured(frame)把帧数据通过NativeAndroidVideoTrackSource传到WebRTC的native层。

public class VideoSource extends MediaSource {
  // other definitions...
  private final CapturerObserver capturerObserver = new CapturerObserver() {
    // other definitions..
    @Override
    public void onFrameCaptured(VideoFrame frame) {
      // body method...

      VideoFrame adaptedFrame = VideoProcessor.applyFrameAdaptationParameters(frame, parameters);
      if (adaptedFrame != null) {
        nativeAndroidVideoTrackSource.onFrameCaptured(adaptedFrame);
        adaptedFrame.release();
      }
    }
  };
}

在打印NavtiveAndroidVideoTrackSource的调用站

webrtc::jni::AndroidVideoTrackSource::onFrameCaptured
  → rtc::AdaptedVideoTrackSource::OnFrame
  → rtc::VideoBroadcaster::OnFrame

采集过程大致是这样子。

渲染过程

Android上的渲染主要是显示的预览画面内容。我们直接调用VideoTrack.addsink(sink)添加预览画面进去,这时候就相当于是订阅了VideoBroadCaster,当有数据进来的时候,VideoBroadCaster会回调VideoSink.onFrame(frame),然后回渲染到EGL中去了。

编码和发送

因为编码和发送大部分都是在native层实现的,这里我直接弄出他们的调用栈来。

webrtc::VideoStreamEncoder::OnFrame
  → webrtc::VideoStreamEncoder::MaybeEncodeVideoFrame
  → webrtc::VideoStreamEncoder::EncodeVideoFrame
  → webrtc::LibvpxVp8Encoder::Encode #1
  → webrtc::LibvpxVp8Encoder::GetEncodedPartitions
  → webrtc::VideoStreamEncoder::OnEncodedImage
  → webrtc::internal::VideoSendStreamImpl::OnEncodedImage
  → webrtc::RtpVideoSender::OnEncodedImage
  → webrtc::RTPSenderVideo::SendEncodedImage
  → webrtc::RTPSenderVideo::SendVideo
  → webrtc::RTPSenderVideo::LogAndSendToNetwork
  → webrtc::RTPSender::EnqueuePackets
  → webrtc::PacedSender::EnqueuePackets
  → webrtc::PacingController::EnqueuePacket
  → webrtc::PacingController::EnqueuePacketInternal
  → webrtc::PacedSender::Process #2
  → webrtc::PacingController::ProcessPackets
  → webrtc::PacedSender::SendRtpPacket
  → webrtc::ModuleRtpRtcpImpl2::TrySendPacket
  → webrtc::RtpSenderEgress::SendPacket
  → webrtc::RtpSenderEgress::SendPacketToNetwork
  → cricket::WebRtcVideoChannel::SendRtp
  → cricket::MediaChannel::SendPacket
  → cricket::MediaChannel::DoSendPacket
  → cricket::VideoChannel::SendPacket
  → webrtc::DtlsSrtpTransport::SendRtpPacket #3

从调用栈可以看到编码器是LibvpxVp8Encoder,当然可以自己换成H264Encoder.
然后就进入了PeerConnection的发送数据包流程了。
体外话:
1.其实这里我们可以做的事情很多,比如保存录制回放可以可以不用Camera2的信息,直接读取我们本地的信息进去。或者给摄像头添加滤镜什么的。还有一些事添加人脸识别进去的,拿到流检测书人脸,拿到人脸信息直接添加到流上去。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容