前言image.png

peerconnection_client中也实现了视频渲染,是通过GDI的方式实现的,因此其性能相较于使用D3D来说要差很多。

源码分析

MainWnd::VideoRenderer::OnFrame

image.png

  1. void MainWnd::VideoRenderer::OnFrame(const webrtc::VideoFrame& video_frame) {
  2. {
  3. AutoLock<VideoRenderer> lock(this);
  4. // 视频帧转为i420格式,然后保存到buffer
  5. rtc::scoped_refptr<webrtc::I420BufferInterface> buffer(
  6. video_frame.video_frame_buffer()->ToI420());
  7. // 如果视频有旋转,则偏转回去并保存到buffer
  8. if (video_frame.rotation() != webrtc::kVideoRotation_0) {
  9. buffer = webrtc::I420Buffer::Rotate(*buffer, video_frame.rotation());
  10. }
  11. SetSize(buffer->width(), buffer->height());
  12. // 将yuv数据转换为RGB,转换好的数据保存到image_
  13. RTC_DCHECK(image_.get() != NULL);
  14. libyuv::I420ToARGB(buffer->DataY(), buffer->StrideY(), buffer->DataU(),
  15. buffer->StrideU(), buffer->DataV(), buffer->StrideV(),
  16. image_.get(),
  17. bmi_.bmiHeader.biWidth * bmi_.bmiHeader.biBitCount / 8,
  18. buffer->width(), buffer->height());
  19. }
  20. // 主动触发WM_PAINT消息
  21. InvalidateRect(wnd_, NULL, TRUE);
  22. }

当需要重绘窗口时,只要调一下InvalidateRect()函数,就会发送一个WM_PAINT消息。

rtc::VideoBroadcaster::OnFrame(const webrtc::VideoFrame & frame)
VideoBroadcaster获取的数据,分发到各个模块进行处理。

MainWnd::OnPaint

image.png
渲染显示本端和远端的数据。

总结

每次peerconnection_client从WebRTC库收到一帧视频数据时,就会调用一次InvalidateRect()函数,触发WM_PAINT消息的发送;该消息被WndProc()方法接收,调用OnPaint()方法对视频窗口进行重绘,从而实现视频的连续渲染与播放的。