前言

image.png

代码分析

H:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\modules\video_capture\windows\sink_filter_ds.cc

CaptureInputPin::Receive

采集的数据首先经过这里。

  1. STDMETHODIMP CaptureInputPin::Receive(IMediaSample* media_sample) {
  2. //RTC_DCHECK_RUN_ON(&capture_checker_);
  3. CaptureSinkFilter* const filter = static_cast<CaptureSinkFilter*>(Filter());
  4. if (flushing_.load(std::memory_order_relaxed))
  5. return S_FALSE;
  6. if (runtime_error_.load(std::memory_order_relaxed))
  7. return VFW_E_RUNTIME_ERROR;
  8. if (!capture_thread_id_) {
  9. // Make sure we set the thread name only once.
  10. capture_thread_id_ = GetCurrentThreadId();
  11. rtc::SetCurrentThreadName("webrtc_video_capture");
  12. }
  13. AM_SAMPLE2_PROPERTIES sample_props = {};
  14. GetSampleProperties(media_sample, &sample_props);
  15. // Has the format changed in this sample?
  16. if (sample_props.dwSampleFlags & AM_SAMPLE_TYPECHANGED) {
  17. // Check the derived class accepts the new format.
  18. // This shouldn't fail as the source must call QueryAccept first.
  19. // Note: This will modify resulting_capability_.
  20. // That should be OK as long as resulting_capability_ is only modified
  21. // on this thread while it is running (filter is not stopped), and only
  22. // modified on the main thread when the filter is stopped (i.e. this thread
  23. // is not running).
  24. if (!TranslateMediaTypeToVideoCaptureCapability(sample_props.pMediaType,
  25. &resulting_capability_)) {
  26. // Raise a runtime error if we fail the media type
  27. runtime_error_ = true;
  28. EndOfStream();
  29. Filter()->NotifyEvent(EC_ERRORABORT, VFW_E_TYPE_NOT_ACCEPTED, 0);
  30. return VFW_E_INVALIDMEDIATYPE;
  31. }
  32. }
  33. filter->ProcessCapturedFrame(sample_props.pbBuffer, sample_props.lActual,
  34. resulting_capability_);
  35. return S_OK;
  36. }

—》 filter->ProcessCapturedFrame(sampleprops.pbBuffer, sample_props.lActual,
resulting_capability
);

CaptureSinkFilter::ProcessCapturedFrame

  1. void CaptureSinkFilter::ProcessCapturedFrame(
  2. unsigned char* buffer,
  3. size_t length,
  4. const VideoCaptureCapability& frame_info) {
  5. // Called on the capture thread.
  6. capture_observer_->IncomingFrame(buffer, length, frame_info);
  7. }

—》

  1. int32_t VideoCaptureImpl::IncomingFrame(uint8_t* videoFrame,
  2. size_t videoFrameLength,
  3. const VideoCaptureCapability& frameInfo,
  4. int64_t captureTime /*=0*/) {
  5. MutexLock lock(&api_lock_);
  6. const int32_t width = frameInfo.width;
  7. const int32_t height = frameInfo.height;
  8. TRACE_EVENT1("webrtc", "VC::IncomingFrame", "capture_time", captureTime);
  9. // Not encoded, convert to I420.
  10. if (frameInfo.videoType != VideoType::kMJPEG &&
  11. CalcBufferSize(frameInfo.videoType, width, abs(height)) !=
  12. videoFrameLength) {
  13. RTC_LOG(LS_ERROR) << "Wrong incoming frame length.";
  14. return -1;
  15. }
  16. int stride_y = width;
  17. int stride_uv = (width + 1) / 2;
  18. int target_width = width;
  19. int target_height = abs(height);
  20. // SetApplyRotation doesn't take any lock. Make a local copy here.
  21. bool apply_rotation = apply_rotation_;
  22. if (apply_rotation) {
  23. // Rotating resolution when for 90/270 degree rotations.
  24. if (_rotateFrame == kVideoRotation_90 ||
  25. _rotateFrame == kVideoRotation_270) {
  26. target_width = abs(height);
  27. target_height = width;
  28. }
  29. }
  30. // Setting absolute height (in case it was negative).
  31. // In Windows, the image starts bottom left, instead of top left.
  32. // Setting a negative source height, inverts the image (within LibYuv).
  33. // TODO(nisse): Use a pool?
  34. rtc::scoped_refptr<I420Buffer> buffer = I420Buffer::Create(
  35. target_width, target_height, stride_y, stride_uv, stride_uv);
  36. libyuv::RotationMode rotation_mode = libyuv::kRotate0;
  37. if (apply_rotation) {
  38. switch (_rotateFrame) {
  39. case kVideoRotation_0:
  40. rotation_mode = libyuv::kRotate0;
  41. break;
  42. case kVideoRotation_90:
  43. rotation_mode = libyuv::kRotate90;
  44. break;
  45. case kVideoRotation_180:
  46. rotation_mode = libyuv::kRotate180;
  47. break;
  48. case kVideoRotation_270:
  49. rotation_mode = libyuv::kRotate270;
  50. break;
  51. }
  52. }
  53. // 将输入数据转为I420
  54. const int conversionResult = libyuv::ConvertToI420(
  55. videoFrame, videoFrameLength, buffer.get()->MutableDataY(),
  56. buffer.get()->StrideY(), buffer.get()->MutableDataU(),
  57. buffer.get()->StrideU(), buffer.get()->MutableDataV(),
  58. buffer.get()->StrideV(), 0, 0, // No Cropping
  59. width, height, target_width, target_height, rotation_mode,
  60. ConvertVideoType(frameInfo.videoType));
  61. if (conversionResult < 0) {
  62. RTC_LOG(LS_ERROR) << "Failed to convert capture frame from type "
  63. << static_cast<int>(frameInfo.videoType) << "to I420.";
  64. return -1;
  65. }
  66. VideoFrame captureFrame =
  67. VideoFrame::Builder()
  68. .set_video_frame_buffer(buffer)
  69. .set_timestamp_rtp(0)
  70. .set_timestamp_ms(rtc::TimeMillis())
  71. .set_rotation(!apply_rotation ? _rotateFrame : kVideoRotation_0)
  72. .build();
  73. captureFrame.set_ntp_time_ms(captureTime);
  74. DeliverCapturedFrame(captureFrame);
  75. return 0;
  76. }

—> DeliverCapturedFrame(captureFrame);

VideoCaptureImpl::DeliverCapturedFrame

  1. int32_t VideoCaptureImpl::DeliverCapturedFrame(VideoFrame& captureFrame) {
  2. UpdateFrameCount(); // frame count used for local frame rate callback.
  3. if (_dataCallBack) {
  4. _dataCallBack->OnFrame(captureFrame);
  5. }
  6. return 0;
  7. }

—> _dataCallBack->OnFrame(captureFrame);
h:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\test\vcm_capturer.cc

VcmCapturer::OnFrame

  1. void VcmCapturer::OnFrame(const VideoFrame& frame) {
  2. TestVideoCapturer::OnFrame(frame); // 里面调用broadcaster_.OnFrame分发数据
  3. }