8-18-19 源码分析-连接Filter(调用SetCameraOutput函数) - 图1
h:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\modules\video_capture\windows\video_capture_ds.cc

VideoCaptureDS::Init

  1. int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
  2. ***
  3. // Temporary connect here.
  4. // This is done so that no one else can use the capture device.
  5. if (SetCameraOutput(_requestedCapability) != 0) {
  6. return -1;
  7. }
  8. ****
  9. return 0;
  10. }

—》

VideoCaptureDS::SetCameraOutput

  1. int32_t VideoCaptureDS::SetCameraOutput(
  2. const VideoCaptureCapability& requestedCapability) {
  3. // Get the best matching capability
  4. VideoCaptureCapability capability;
  5. int32_t capabilityIndex;
  6. // Store the new requested size
  7. _requestedCapability = requestedCapability;
  8. //1、 Match the requested capability with the supported.
  9. // 先调用CreateCapabilityMap获取系统支持的所有capability,然后寻找最佳的capability的索引
  10. if ((capabilityIndex = _dsInfo.GetBestMatchedCapability(
  11. _deviceUniqueId, _requestedCapability, capability)) < 0) {
  12. return -1;
  13. }
  14. //2、 Reduce the frame rate if possible.
  15. if (capability.maxFPS > requestedCapability.maxFPS) {
  16. capability.maxFPS = requestedCapability.maxFPS;
  17. } else if (capability.maxFPS <= 0) {
  18. capability.maxFPS = 30;
  19. }
  20. //2、 Convert it to the windows capability index since they are not nexessary
  21. // the same
  22. // 根据索引,获取最佳capability
  23. VideoCaptureCapabilityWindows windowsCapability;
  24. if (_dsInfo.GetWindowsCapability(capabilityIndex, windowsCapability) != 0) {
  25. return -1;
  26. }
  27. IAMStreamConfig* streamConfig = NULL;
  28. AM_MEDIA_TYPE* pmt = NULL;
  29. VIDEO_STREAM_CONFIG_CAPS caps;
  30. HRESULT hr = _outputCapturePin->QueryInterface(IID_IAMStreamConfig,
  31. (void**)&streamConfig);
  32. if (hr) {
  33. RTC_LOG(LS_INFO) << "Can't get the Capture format settings.";
  34. return -1;
  35. }
  36. // Get the windows capability from the capture device
  37. // 从采集设备获取系统 capability,用于修改
  38. bool isDVCamera = false;
  39. hr = streamConfig->GetStreamCaps(windowsCapability.directShowCapabilityIndex,
  40. &pmt, reinterpret_cast<BYTE*>(&caps));
  41. if (hr == S_OK) {
  42. if (pmt->formattype == FORMAT_VideoInfo2) {
  43. VIDEOINFOHEADER2* h = reinterpret_cast<VIDEOINFOHEADER2*>(pmt->pbFormat);
  44. if (capability.maxFPS > 0 && windowsCapability.supportFrameRateControl) {
  45. h->AvgTimePerFrame = REFERENCE_TIME(10000000.0 / capability.maxFPS);
  46. }
  47. } else { // 本机是这个类型
  48. VIDEOINFOHEADER* h = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
  49. if (capability.maxFPS > 0 && windowsCapability.supportFrameRateControl) {
  50. h->AvgTimePerFrame = REFERENCE_TIME(10000000.0 / capability.maxFPS);
  51. }
  52. }
  53. // Set the sink filter to request this capability
  54. // 设置capability到filter
  55. sink_filter_->SetRequestedCapability(capability);
  56. // Order the capture device to use this capability
  57. // 设置最终的格式
  58. hr += streamConfig->SetFormat(pmt);
  59. // Check if this is a DV camera and we need to add MS DV Filter
  60. if (pmt->subtype == MEDIASUBTYPE_dvsl ||
  61. pmt->subtype == MEDIASUBTYPE_dvsd || pmt->subtype == MEDIASUBTYPE_dvhd)
  62. isDVCamera = true; // This is a DV camera. Use MS DV filter
  63. }
  64. RELEASE_AND_CLEAR(streamConfig);
  65. if (FAILED(hr)) {
  66. RTC_LOG(LS_INFO) << "Failed to set capture device output format";
  67. return -1;
  68. }
  69. if (isDVCamera) {
  70. hr = ConnectDVCamera();
  71. } else {
  72. // 调用后,后面会进去CaptureInputPin::ReceiveConnection
  73. hr = _graphBuilder->ConnectDirect(_outputCapturePin, _inputSendPin, NULL);
  74. }
  75. if (hr != S_OK) {
  76. RTC_LOG(LS_INFO) << "Failed to connect the Capture graph " << hr;
  77. return -1;
  78. }
  79. return 0;
  80. }

-》1、_dsInfo.GetBestMatchedCapability

DeviceInfoImpl::GetBestMatchedCapability

  1. int32_t DeviceInfoImpl::GetBestMatchedCapability(
  2. const char* deviceUniqueIdUTF8,
  3. const VideoCaptureCapability& requested, // 可修改
  4. VideoCaptureCapability& resulting) { //可以修改
  5. if (!deviceUniqueIdUTF8)
  6. return -1;
  7. MutexLock lock(&_apiLock);
  8. if (!absl::EqualsIgnoreCase(
  9. deviceUniqueIdUTF8,
  10. absl::string_view(_lastUsedDeviceName, _lastUsedDeviceNameLength))) {
  11. if (-1 == CreateCapabilityMap(deviceUniqueIdUTF8)) {
  12. return -1;
  13. }
  14. }
  15. // 下面的是获取跟想要设备的Capability最接近的Capability
  16. int32_t bestformatIndex = -1;
  17. int32_t bestWidth = 0;
  18. int32_t bestHeight = 0;
  19. int32_t bestFrameRate = 0;
  20. VideoType bestVideoType = VideoType::kUnknown;
  21. const int32_t numberOfCapabilies =
  22. static_cast<int32_t>(_captureCapabilities.size());
  23. for (int32_t tmp = 0; tmp < numberOfCapabilies;
  24. ++tmp) // Loop through all capabilities
  25. {
  26. VideoCaptureCapability& capability = _captureCapabilities[tmp];
  27. const int32_t diffWidth = capability.width - requested.width;
  28. const int32_t diffHeight = capability.height - requested.height;
  29. const int32_t diffFrameRate = capability.maxFPS - requested.maxFPS;
  30. const int32_t currentbestDiffWith = bestWidth - requested.width;
  31. const int32_t currentbestDiffHeight = bestHeight - requested.height;
  32. const int32_t currentbestDiffFrameRate = bestFrameRate - requested.maxFPS;
  33. if ((diffHeight >= 0 &&
  34. diffHeight <= abs(currentbestDiffHeight)) // Height better or equalt
  35. // that previouse.
  36. || (currentbestDiffHeight < 0 && diffHeight >= currentbestDiffHeight)) {
  37. if (diffHeight ==
  38. currentbestDiffHeight) // Found best height. Care about the width)
  39. {
  40. if ((diffWidth >= 0 &&
  41. diffWidth <= abs(currentbestDiffWith)) // Width better or equal
  42. || (currentbestDiffWith < 0 && diffWidth >= currentbestDiffWith)) {
  43. if (diffWidth == currentbestDiffWith &&
  44. diffHeight == currentbestDiffHeight) // Same size as previously
  45. {
  46. // Also check the best frame rate if the diff is the same as
  47. // previouse
  48. if (((diffFrameRate >= 0 &&
  49. diffFrameRate <=
  50. currentbestDiffFrameRate) // Frame rate to high but
  51. // better match than previouse
  52. // and we have not selected IUV
  53. || (currentbestDiffFrameRate < 0 &&
  54. diffFrameRate >=
  55. currentbestDiffFrameRate)) // Current frame rate is
  56. // lower than requested.
  57. // This is better.
  58. ) {
  59. if ((currentbestDiffFrameRate ==
  60. diffFrameRate) // Same frame rate as previous or frame rate
  61. // allready good enough
  62. || (currentbestDiffFrameRate >= 0)) {
  63. if (bestVideoType != requested.videoType &&
  64. requested.videoType != VideoType::kUnknown &&
  65. (capability.videoType == requested.videoType ||
  66. capability.videoType == VideoType::kI420 ||
  67. capability.videoType == VideoType::kYUY2 ||
  68. capability.videoType == VideoType::kYV12)) {
  69. bestVideoType = capability.videoType;
  70. bestformatIndex = tmp;
  71. }
  72. // If width height and frame rate is full filled we can use the
  73. // camera for encoding if it is supported.
  74. if (capability.height == requested.height &&
  75. capability.width == requested.width &&
  76. capability.maxFPS >= requested.maxFPS) {
  77. bestformatIndex = tmp;
  78. }
  79. } else // Better frame rate
  80. {
  81. bestWidth = capability.width;
  82. bestHeight = capability.height;
  83. bestFrameRate = capability.maxFPS;
  84. bestVideoType = capability.videoType;
  85. bestformatIndex = tmp;
  86. }
  87. }
  88. } else // Better width than previously
  89. {
  90. bestWidth = capability.width;
  91. bestHeight = capability.height;
  92. bestFrameRate = capability.maxFPS;
  93. bestVideoType = capability.videoType;
  94. bestformatIndex = tmp;
  95. }
  96. } // else width no good
  97. } else // Better height
  98. {
  99. bestWidth = capability.width;
  100. bestHeight = capability.height;
  101. bestFrameRate = capability.maxFPS;
  102. bestVideoType = capability.videoType;
  103. bestformatIndex = tmp;
  104. }
  105. } // else height not good
  106. } // end for
  107. RTC_LOG(LS_VERBOSE) << "Best camera format: " << bestWidth << "x"
  108. << bestHeight << "@" << bestFrameRate
  109. << "fps, color format: "
  110. << static_cast<int>(bestVideoType);
  111. // Copy the capability
  112. if (bestformatIndex < 0)
  113. return -1;
  114. resulting = _captureCapabilities[bestformatIndex];
  115. return bestformatIndex;
  116. }
  117. // Default implementation. This should be overridden by Mobile implementations.
  118. int32_t DeviceInfoImpl::GetOrientation(const char* deviceUniqueIdUTF8,
  119. VideoRotation& orientation) {
  120. orientation = kVideoRotation_0;
  121. return -1;
  122. }

里面调用 DeviceInfoDS::CreateCapabilityMap

  1. int32_t DeviceInfoDS::CreateCapabilityMap(const char* deviceUniqueIdUTF8)
  2. {
  3. // Reset old capability list
  4. _captureCapabilities.clear();
  5. const int32_t deviceUniqueIdUTF8Length =
  6. (int32_t)strlen((char*)deviceUniqueIdUTF8);
  7. if (deviceUniqueIdUTF8Length > kVideoCaptureUniqueNameLength) {
  8. RTC_LOG(LS_INFO) << "Device name too long";
  9. return -1;
  10. }
  11. RTC_LOG(LS_INFO) << "CreateCapabilityMap called for device "
  12. << deviceUniqueIdUTF8;
  13. char productId[kVideoCaptureProductIdLength];
  14. IBaseFilter* captureDevice = DeviceInfoDS::GetDeviceFilter(
  15. deviceUniqueIdUTF8, productId, kVideoCaptureProductIdLength);
  16. if (!captureDevice)
  17. return -1;
  18. IPin* outputCapturePin = GetOutputPin(captureDevice, GUID_NULL);
  19. if (!outputCapturePin) {
  20. RTC_LOG(LS_INFO) << "Failed to get capture device output pin";
  21. RELEASE_AND_CLEAR(captureDevice);
  22. return -1;
  23. }
  24. IAMExtDevice* extDevice = NULL;
  25. HRESULT hr =
  26. captureDevice->QueryInterface(IID_IAMExtDevice, (void**)&extDevice);
  27. if (SUCCEEDED(hr) && extDevice) {
  28. RTC_LOG(LS_INFO) << "This is an external device";
  29. extDevice->Release();
  30. }
  31. IAMStreamConfig* streamConfig = NULL;
  32. hr = outputCapturePin->QueryInterface(IID_IAMStreamConfig,
  33. (void**)&streamConfig);
  34. if (FAILED(hr)) {
  35. RTC_LOG(LS_INFO) << "Failed to get IID_IAMStreamConfig interface "
  36. "from capture device";
  37. return -1;
  38. }
  39. // this gets the FPS
  40. IAMVideoControl* videoControlConfig = NULL;
  41. HRESULT hrVC = captureDevice->QueryInterface(IID_IAMVideoControl,
  42. (void**)&videoControlConfig);
  43. if (FAILED(hrVC)) {
  44. RTC_LOG(LS_INFO) << "IID_IAMVideoControl Interface NOT SUPPORTED";
  45. }
  46. AM_MEDIA_TYPE* pmt = NULL;
  47. VIDEO_STREAM_CONFIG_CAPS caps;
  48. int count, size;
  49. // 这里本机调试的count=5, size=128
  50. // 一共有5个Capabilities,每个fCapabilities占用空间128字节
  51. hr = streamConfig->GetNumberOfCapabilities(&count, &size);
  52. if (FAILED(hr)) {
  53. RTC_LOG(LS_INFO) << "Failed to GetNumberOfCapabilities";
  54. RELEASE_AND_CLEAR(videoControlConfig);
  55. RELEASE_AND_CLEAR(streamConfig);
  56. RELEASE_AND_CLEAR(outputCapturePin);
  57. RELEASE_AND_CLEAR(captureDevice);
  58. return -1;
  59. }
  60. // Check if the device support formattype == FORMAT_VideoInfo2 and
  61. // FORMAT_VideoInfo. Prefer FORMAT_VideoInfo since some cameras (ZureCam) has
  62. // been seen having problem with MJPEG and FORMAT_VideoInfo2 Interlace flag is
  63. // only supported in FORMAT_VideoInfo2
  64. bool supportFORMAT_VideoInfo2 = false;
  65. bool supportFORMAT_VideoInfo = false;
  66. bool foundInterlacedFormat = false;
  67. GUID preferedVideoFormat = FORMAT_VideoInfo;
  68. for (int32_t tmp = 0; tmp < count; ++tmp) {
  69. hr = streamConfig->GetStreamCaps(tmp, &pmt, reinterpret_cast<BYTE*>(&caps));
  70. if (hr == S_OK) {
  71. if (pmt->majortype == MEDIATYPE_Video &&
  72. pmt->formattype == FORMAT_VideoInfo2) {
  73. ****
  74. }
  75. if (pmt->majortype == MEDIATYPE_Video &&
  76. pmt->formattype == FORMAT_VideoInfo) {
  77. RTC_LOG(LS_INFO) << "Device support FORMAT_VideoInfo2";
  78. supportFORMAT_VideoInfo = true; // 本机只支持这个
  79. }
  80. }
  81. }
  82. if (supportFORMAT_VideoInfo2) {
  83. if (supportFORMAT_VideoInfo && !foundInterlacedFormat) {
  84. preferedVideoFormat = FORMAT_VideoInfo;
  85. } else {
  86. preferedVideoFormat = FORMAT_VideoInfo2;
  87. }
  88. }
  89. for (int32_t tmp = 0; tmp < count; ++tmp) {
  90. hr = streamConfig->GetStreamCaps(tmp, &pmt, reinterpret_cast<BYTE*>(&caps));
  91. if (hr != S_OK) {
  92. RTC_LOG(LS_INFO) << "Failed to GetStreamCaps";
  93. RELEASE_AND_CLEAR(videoControlConfig);
  94. RELEASE_AND_CLEAR(streamConfig);
  95. RELEASE_AND_CLEAR(outputCapturePin);
  96. RELEASE_AND_CLEAR(captureDevice);
  97. return -1;
  98. }
  99. if (pmt->majortype == MEDIATYPE_Video &&
  100. pmt->formattype == preferedVideoFormat) {
  101. VideoCaptureCapabilityWindows capability;
  102. int64_t avgTimePerFrame = 0;
  103. if (pmt->formattype == FORMAT_VideoInfo) {
  104. VIDEOINFOHEADER* h = reinterpret_cast<VIDEOINFOHEADER*>(pmt->pbFormat);
  105. assert(h);
  106. capability.directShowCapabilityIndex = tmp;
  107. capability.width = h->bmiHeader.biWidth;
  108. capability.height = h->bmiHeader.biHeight;
  109. avgTimePerFrame = h->AvgTimePerFrame;
  110. }
  111. ***
  112. if (hrVC == S_OK) {
  113. LONGLONG* frameDurationList;
  114. LONGLONG maxFPS;
  115. long listSize;
  116. SIZE size;
  117. size.cx = capability.width;
  118. size.cy = capability.height;
  119. // GetMaxAvailableFrameRate doesn't return max frame rate always
  120. // eg: Logitech Notebook. This may be due to a bug in that API
  121. // because GetFrameRateList array is reversed in the above camera. So
  122. // a util method written. Can't assume the first value will return
  123. // the max fps.
  124. hrVC = videoControlConfig->GetFrameRateList(
  125. outputCapturePin, tmp, size, &listSize, &frameDurationList);
  126. // On some odd cameras, you may get a 0 for duration.
  127. // GetMaxOfFrameArray returns the lowest duration (highest FPS)
  128. if (hrVC == S_OK && listSize > 0 &&
  129. 0 != (maxFPS = GetMaxOfFrameArray(frameDurationList, listSize))) {
  130. capability.maxFPS = static_cast<int>(10000000 / maxFPS); // 本机是30fps
  131. capability.supportFrameRateControl = true;
  132. }
  133. ****
  134. // can't switch MEDIATYPE :~(
  135. if (pmt->subtype == MEDIASUBTYPE_I420) {
  136. capability.videoType = VideoType::kI420;
  137. } else if (pmt->subtype == MEDIASUBTYPE_IYUV) {
  138. capability.videoType = VideoType::kIYUV;
  139. } else if (pmt->subtype == MEDIASUBTYPE_RGB24) {
  140. capability.videoType = VideoType::kRGB24;
  141. } else if (pmt->subtype == MEDIASUBTYPE_YUY2) {
  142. capability.videoType = VideoType::kYUY2; // 本机支持这个适配类型
  143. } else if (pmt->subtype == MEDIASUBTYPE_RGB565) {
  144. capability.videoType = VideoType::kRGB565;
  145. } else if (pmt->subtype == MEDIASUBTYPE_MJPG) {
  146. capability.videoType = VideoType::kMJPEG;
  147. }
  148. ****
  149. _captureCapabilities.push_back(capability);
  150. _captureCapabilitiesWindows.push_back(capability);
  151. RTC_LOG(LS_INFO) << "Camera capability, width:" << capability.width
  152. << " height:" << capability.height
  153. << " type:" << static_cast<int>(capability.videoType)
  154. << " fps:" << capability.maxFPS;
  155. }
  156. FreeMediaType(pmt);
  157. pmt = NULL;
  158. }
  159. ****
  160. return static_cast<int32_t>(_captureCapabilities.size());
  161. }

—》2、_dsInfo.GetWindowsCapability(capabilityIndex, windowsCapability)

DeviceInfoDS::GetWindowsCapability

  1. int32_t DeviceInfoDS::GetWindowsCapability(
  2. const int32_t capabilityIndex,
  3. VideoCaptureCapabilityWindows& windowsCapability) {
  4. MutexLock lock(&_apiLock);
  5. if (capabilityIndex < 0 || static_cast<size_t>(capabilityIndex) >=
  6. _captureCapabilitiesWindows.size()) {
  7. return -1;
  8. }
  9. windowsCapability = _captureCapabilitiesWindows[capabilityIndex];
  10. return 0;
  11. }

—》3、 hr = _graphBuilder->ConnectDirect(_outputCapturePin, _inputSendPin, NULL);
调用后,会进入CaptureInputPin::ReceiveConnection

CaptureInputPin::ReceiveConnection

里面会判断是否会支持这个连接

  1. STDMETHODIMP CaptureInputPin::ReceiveConnection(
  2. IPin* connector,
  3. const AM_MEDIA_TYPE* media_type) {
  4. RTC_DCHECK_RUN_ON(&main_checker_);
  5. RTC_DCHECK(Filter()->IsStopped());
  6. if (receive_pin_) {
  7. RTC_DCHECK(false);
  8. return VFW_E_ALREADY_CONNECTED;
  9. }
  10. HRESULT hr = CheckDirection(connector);
  11. if (FAILED(hr))
  12. return hr;
  13. // 将media_type,转为resulting_capability_
  14. if (!TranslateMediaTypeToVideoCaptureCapability(media_type,
  15. &resulting_capability_))
  16. return VFW_E_TYPE_NOT_ACCEPTED;
  17. // Complete the connection
  18. receive_pin_ = connector;
  19. ResetMediaType(&media_type_);
  20. CopyMediaType(&media_type_, media_type);
  21. return S_OK;
  22. }

image.png
该函数返回后,就好开始创建内存分配器了CaptureInputPin::GetAllocator