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);