前言

CaptureFilter就是用dshow采集视频数据,然后添加到filter graph中,获取数据后调用filter来处理。
image.png

代码分析

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. _captureFilter = _dsInfo.GetDeviceFilter(deviceUniqueIdUTF8);
  4. if (!_captureFilter) {
  5. RTC_LOG(LS_INFO) << "Failed to create capture filter.";
  6. return -1;
  7. }
  8. // Get the interface for DirectShow's GraphBuilder
  9. HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
  10. IID_IGraphBuilder, (void**)&_graphBuilder);
  11. if (FAILED(hr)) {
  12. RTC_LOG(LS_INFO) << "Failed to create graph builder.";
  13. return -1;
  14. }
  15. hr = _graphBuilder->QueryInterface(IID_IMediaControl, (void**)&_mediaControl);
  16. if (FAILED(hr)) {
  17. RTC_LOG(LS_INFO) << "Failed to create media control builder.";
  18. return -1;
  19. }
  20. hr = _graphBuilder->AddFilter(_captureFilter, CAPTURE_FILTER_NAME);
  21. if (FAILED(hr)) {
  22. RTC_LOG(LS_INFO) << "Failed to add the capture device to the graph.";
  23. return -1;
  24. }
  25. _outputCapturePin = GetOutputPin(_captureFilter, PIN_CATEGORY_CAPTURE);
  26. if (!_outputCapturePin) {
  27. RTC_LOG(LS_INFO) << "Failed to get output capture pin";
  28. return -1;
  29. }
  30. ***
  31. }

—》 _captureFilter = _dsInfo.GetDeviceFilter(deviceUniqueIdUTF8);

DeviceInfoDS::GetDeviceFilter

  1. IBaseFilter* DeviceInfoDS::GetDeviceFilter(const char* deviceUniqueIdUTF8,
  2. char* productUniqueIdUTF8,
  3. uint32_t productUniqueIdUTF8Length) {
  4. ***
  5. // enumerate all video capture devices
  6. RELEASE_AND_CLEAR(_dsMonikerDevEnum);
  7. // 遍历获取视频输入设备
  8. HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
  9. &_dsMonikerDevEnum, 0);
  10. if (hr != NOERROR) {
  11. RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"
  12. << rtc::ToHex(hr) << ". No webcam exist?";
  13. return 0;
  14. }
  15. _dsMonikerDevEnum->Reset();
  16. ULONG cFetched;
  17. IMoniker* pM;
  18. IBaseFilter* captureFilter = NULL;
  19. bool deviceFound = false;
  20. // 遍历每个设备,这里只找到一个可用的设备就退出循环了
  21. while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound) {
  22. IPropertyBag* pBag;
  23. // 获取IID_IPropertyBag接口属性
  24. hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
  25. if (S_OK == hr) {
  26. // Find the description or friendly name.
  27. VARIANT varName;
  28. VariantInit(&varName);
  29. if (deviceUniqueIdUTF8Length > 0) {
  30. hr = pBag->Read(L"DevicePath", &varName, 0);
  31. if (FAILED(hr)) {
  32. hr = pBag->Read(L"Description", &varName, 0);
  33. if (FAILED(hr)) {
  34. hr = pBag->Read(L"FriendlyName", &varName, 0);
  35. }
  36. }
  37. if (SUCCEEDED(hr)) {
  38. char tempDevicePathUTF8[256];
  39. tempDevicePathUTF8[0] = 0;
  40. WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,
  41. tempDevicePathUTF8, sizeof(tempDevicePathUTF8),
  42. NULL, NULL);
  43. if (strncmp(tempDevicePathUTF8, (const char*)deviceUniqueIdUTF8,
  44. deviceUniqueIdUTF8Length) == 0) {
  45. // We have found the requested device
  46. deviceFound = true; //找到了可用设备
  47. // 找到获取数据的filter
  48. hr =
  49. pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&captureFilter);
  50. if
  51. FAILED(hr) {
  52. RTC_LOG(LS_ERROR) << "Failed to bind to the selected "
  53. "capture device "
  54. << hr;
  55. }
  56. if (productUniqueIdUTF8 &&
  57. productUniqueIdUTF8Length > 0) // Get the device name
  58. {
  59. GetProductId(deviceUniqueIdUTF8, productUniqueIdUTF8,
  60. productUniqueIdUTF8Length);
  61. }
  62. }
  63. }
  64. }
  65. VariantClear(&varName);
  66. pBag->Release();
  67. }
  68. pM->Release();
  69. }
  70. return captureFilter;
  71. }