43 static char* wcharToUtf8(
wchar_t* w)
45 int l = WideCharToMultiByte(CP_UTF8, 0, w, -1,
nullptr, 0,
nullptr,
nullptr);
46 char* s =
new char[l];
48 WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l,
nullptr,
nullptr);
54 IMoniker* m =
nullptr;
55 QVector<QPair<QString, QString>> devices;
57 ICreateDevEnum* devenum =
nullptr;
58 if (CoCreateInstance(CLSID_SystemDeviceEnum,
nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
59 reinterpret_cast<void**
>(&devenum))
63 IEnumMoniker* classenum =
nullptr;
64 if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
reinterpret_cast<IEnumMoniker**
>(&classenum), 0)
68 while (classenum->Next(1, &m,
nullptr) == S_OK) {
70 IPropertyBag* bag =
nullptr;
71 LPMALLOC coMalloc =
nullptr;
72 IBindCtx* bindCtx =
nullptr;
73 LPOLESTR olestr =
nullptr;
74 char *devIdString =
nullptr, *devHumanName =
nullptr;
76 if (CoGetMalloc(1, &coMalloc) != S_OK)
78 if (CreateBindCtx(0, &bindCtx) != S_OK)
82 if (m->GetDisplayName(bindCtx,
nullptr, &olestr) != S_OK)
84 devIdString = wcharToUtf8(olestr);
87 for (
size_t i = 0; i < strlen(devIdString); ++i)
88 if (devIdString[i] ==
':')
92 if (m->BindToStorage(
nullptr,
nullptr, IID_IPropertyBag,
reinterpret_cast<void**
>(&bag)) != S_OK)
96 if (bag->Read(L
"FriendlyName", &var,
nullptr) != S_OK)
98 devHumanName = wcharToUtf8(var.bstrVal);
100 devices += {QString(
"video=") + devIdString, devHumanName};
103 if (olestr && coMalloc)
104 coMalloc->Free(olestr);
107 delete[] devIdString;
108 delete[] devHumanName;
113 classenum->Release();
120 static IBaseFilter* getDevFilter(QString devName)
122 IBaseFilter* devFilter =
nullptr;
123 devName = devName.mid(6);
124 IMoniker* m =
nullptr;
126 ICreateDevEnum* devenum =
nullptr;
127 if (CoCreateInstance(CLSID_SystemDeviceEnum,
nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum,
128 reinterpret_cast<void**
>(&devenum))
132 IEnumMoniker* classenum =
nullptr;
133 if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
reinterpret_cast<IEnumMoniker**
>(&classenum), 0)
137 while (classenum->Next(1, &m,
nullptr) == S_OK) {
138 LPMALLOC coMalloc =
nullptr;
139 IBindCtx* bindCtx =
nullptr;
140 LPOLESTR olestr =
nullptr;
143 if (CoGetMalloc(1, &coMalloc) != S_OK)
145 if (CreateBindCtx(0, &bindCtx) != S_OK)
148 if (m->GetDisplayName(bindCtx,
nullptr, &olestr) != S_OK)
150 devIdString = wcharToUtf8(olestr);
153 for (
size_t i = 0; i < strlen(devIdString); ++i)
154 if (devIdString[i] ==
':')
155 devIdString[i] =
'_';
157 if (devName != devIdString)
160 if (m->BindToObject(
nullptr,
nullptr, IID_IBaseFilter,
reinterpret_cast<void**
>(&devFilter)) != S_OK)
164 if (olestr && coMalloc)
165 coMalloc->Free(olestr);
168 delete[] devIdString;
171 classenum->Release();
174 qWarning() <<
"Couldn't find the device " << devName;
181 QVector<VideoMode> modes;
183 IBaseFilter* devFilter = getDevFilter(devName);
190 IEnumPins* pins =
nullptr;
192 if (devFilter->EnumPins(&pins) != S_OK)
195 while (pins->Next(1, &pin,
nullptr) == S_OK) {
196 IKsPropertySet* p =
nullptr;
199 pin->QueryPinInfo(&info);
200 info.pFilter->Release();
201 if (info.dir != PINDIR_OUTPUT)
203 if (pin->QueryInterface(IID_IKsPropertySet,
reinterpret_cast<void**
>(&p)) != S_OK)
205 if (p->Get(AMPROPSETID_Pin, AMPROPERTY_PIN_CATEGORY,
nullptr, 0, &category,
sizeof(GUID), &r2)
208 if (!IsEqualGUID(category, PIN_CATEGORY_CAPTURE))
214 IAMStreamConfig* config =
nullptr;
215 VIDEO_STREAM_CONFIG_CAPS* vcaps =
nullptr;
217 if (pin->QueryInterface(IID_IAMStreamConfig,
reinterpret_cast<void**
>(&config)) != S_OK)
219 if (config->GetNumberOfCapabilities(&n, &size) != S_OK)
222 assert(size ==
sizeof(VIDEO_STREAM_CONFIG_CAPS));
223 vcaps =
new VIDEO_STREAM_CONFIG_CAPS;
225 for (
int i = 0; i < n; ++i) {
226 AM_MEDIA_TYPE* type =
nullptr;
228 if (config->GetStreamCaps(i, &type,
reinterpret_cast<BYTE*
>(vcaps)) != S_OK)
231 if (!IsEqualGUID(type->formattype, FORMAT_VideoInfo)
232 && !IsEqualGUID(type->formattype, FORMAT_VideoInfo2))
235 mode.
width = vcaps->MaxOutputSize.cx;
236 mode.
height = vcaps->MaxOutputSize.cy;
237 mode.
FPS = 1e7 / vcaps->MinFrameInterval;
238 if (!modes.contains(mode))
239 modes.append(std::move(mode));
243 CoTaskMemFree(type->pbFormat);