前言
CaptureFilter就是用dshow采集视频数据,然后添加到filter graph中,获取数据后调用filter来处理。
代码分析
h:\webrtc-20210315\webrtc-20210315\webrtc\webrtc-checkout\src\modules\video_capture\windows\video_capture_ds.cc
VideoCaptureDS::Init
int32_t VideoCaptureDS::Init(const char* deviceUniqueIdUTF8) {
***
_captureFilter = _dsInfo.GetDeviceFilter(deviceUniqueIdUTF8);
if (!_captureFilter) {
RTC_LOG(LS_INFO) << "Failed to create capture filter.";
return -1;
}
// Get the interface for DirectShow's GraphBuilder
HRESULT hr = CoCreateInstance(CLSID_FilterGraph, NULL, CLSCTX_INPROC_SERVER,
IID_IGraphBuilder, (void**)&_graphBuilder);
if (FAILED(hr)) {
RTC_LOG(LS_INFO) << "Failed to create graph builder.";
return -1;
}
hr = _graphBuilder->QueryInterface(IID_IMediaControl, (void**)&_mediaControl);
if (FAILED(hr)) {
RTC_LOG(LS_INFO) << "Failed to create media control builder.";
return -1;
}
hr = _graphBuilder->AddFilter(_captureFilter, CAPTURE_FILTER_NAME);
if (FAILED(hr)) {
RTC_LOG(LS_INFO) << "Failed to add the capture device to the graph.";
return -1;
}
_outputCapturePin = GetOutputPin(_captureFilter, PIN_CATEGORY_CAPTURE);
if (!_outputCapturePin) {
RTC_LOG(LS_INFO) << "Failed to get output capture pin";
return -1;
}
***
}
—》 _captureFilter = _dsInfo.GetDeviceFilter(deviceUniqueIdUTF8);
DeviceInfoDS::GetDeviceFilter
IBaseFilter* DeviceInfoDS::GetDeviceFilter(const char* deviceUniqueIdUTF8,
char* productUniqueIdUTF8,
uint32_t productUniqueIdUTF8Length) {
***
// enumerate all video capture devices
RELEASE_AND_CLEAR(_dsMonikerDevEnum);
// 遍历获取视频输入设备
HRESULT hr = _dsDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
&_dsMonikerDevEnum, 0);
if (hr != NOERROR) {
RTC_LOG(LS_INFO) << "Failed to enumerate CLSID_SystemDeviceEnum, error 0x"
<< rtc::ToHex(hr) << ". No webcam exist?";
return 0;
}
_dsMonikerDevEnum->Reset();
ULONG cFetched;
IMoniker* pM;
IBaseFilter* captureFilter = NULL;
bool deviceFound = false;
// 遍历每个设备,这里只找到一个可用的设备就退出循环了
while (S_OK == _dsMonikerDevEnum->Next(1, &pM, &cFetched) && !deviceFound) {
IPropertyBag* pBag;
// 获取IID_IPropertyBag接口属性
hr = pM->BindToStorage(0, 0, IID_IPropertyBag, (void**)&pBag);
if (S_OK == hr) {
// Find the description or friendly name.
VARIANT varName;
VariantInit(&varName);
if (deviceUniqueIdUTF8Length > 0) {
hr = pBag->Read(L"DevicePath", &varName, 0);
if (FAILED(hr)) {
hr = pBag->Read(L"Description", &varName, 0);
if (FAILED(hr)) {
hr = pBag->Read(L"FriendlyName", &varName, 0);
}
}
if (SUCCEEDED(hr)) {
char tempDevicePathUTF8[256];
tempDevicePathUTF8[0] = 0;
WideCharToMultiByte(CP_UTF8, 0, varName.bstrVal, -1,
tempDevicePathUTF8, sizeof(tempDevicePathUTF8),
NULL, NULL);
if (strncmp(tempDevicePathUTF8, (const char*)deviceUniqueIdUTF8,
deviceUniqueIdUTF8Length) == 0) {
// We have found the requested device
deviceFound = true; //找到了可用设备
// 找到获取数据的filter
hr =
pM->BindToObject(0, 0, IID_IBaseFilter, (void**)&captureFilter);
if
FAILED(hr) {
RTC_LOG(LS_ERROR) << "Failed to bind to the selected "
"capture device "
<< hr;
}
if (productUniqueIdUTF8 &&
productUniqueIdUTF8Length > 0) // Get the device name
{
GetProductId(deviceUniqueIdUTF8, productUniqueIdUTF8,
productUniqueIdUTF8Length);
}
}
}
}
VariantClear(&varName);
pBag->Release();
}
pM->Release();
}
return captureFilter;
}