mirror of
https://github.com/qTox/qTox.git
synced 2024-03-22 14:00:36 +08:00
f0f069114c
We can now get the list of video devices with the dshow ffmpeg device (so, on Windows). Most of this patch is adapted from libavdevice's dshow private internal interface, which retrieves useful info but is only designed to log it to stdout. We reimplement that to get an actual list of devices names/descriptions, that we can then open with ffmpeg the refular way.
86 lines
2.4 KiB
C++
86 lines
2.4 KiB
C++
#include "directshow.h"
|
|
|
|
#include <cstdint>
|
|
#include <Objbase.h>
|
|
#include <Strmif.h>
|
|
#include <uuids.h>
|
|
|
|
/**
|
|
* Most of this file is adapted from libavdevice's dshow.c,
|
|
* which retrieves useful information but only exposes it to
|
|
* stdout and is not part of the public API for some reason.
|
|
*/
|
|
|
|
static char *wcharToUtf8(wchar_t *w)
|
|
{
|
|
int l = WideCharToMultiByte(CP_UTF8, 0, w, -1, 0, 0, 0, 0);
|
|
char *s = new char[l];
|
|
if (s)
|
|
WideCharToMultiByte(CP_UTF8, 0, w, -1, s, l, 0, 0);
|
|
return s;
|
|
}
|
|
|
|
QVector<QPair<QString,QString>> DirectShow::getDeviceList()
|
|
{
|
|
IMoniker* m = nullptr;
|
|
QVector<QPair<QString,QString>> devices;
|
|
|
|
ICreateDevEnum* devenum = nullptr;
|
|
if (CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER,
|
|
IID_ICreateDevEnum, (void**) &devenum) != S_OK)
|
|
return devices;
|
|
|
|
IEnumMoniker* classenum = nullptr;
|
|
if (devenum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory,
|
|
(IEnumMoniker**)&classenum, 0) != S_OK)
|
|
return devices;
|
|
|
|
while (classenum->Next(1, &m, nullptr) == S_OK)
|
|
{
|
|
VARIANT var;
|
|
IPropertyBag* bag = nullptr;
|
|
LPMALLOC coMalloc = nullptr;
|
|
IBindCtx* bindCtx = nullptr;
|
|
LPOLESTR olestr = nullptr;
|
|
char *devIdString=nullptr, *devHumanName=nullptr;
|
|
|
|
if (CoGetMalloc(1, &coMalloc) != S_OK)
|
|
goto fail;
|
|
if (CreateBindCtx(0, &bindCtx) != S_OK)
|
|
goto fail;
|
|
if (m->GetDisplayName(bindCtx, nullptr, &olestr) != S_OK)
|
|
goto fail;
|
|
|
|
devIdString = wcharToUtf8(olestr);
|
|
|
|
// replace ':' with '_' since FFmpeg uses : to delimitate sources
|
|
for (unsigned i = 0; i < strlen(devIdString); i++)
|
|
if (devIdString[i] == ':')
|
|
devIdString[i] = '_';
|
|
|
|
if (m->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void**)&bag) != S_OK)
|
|
goto fail;
|
|
|
|
var.vt = VT_BSTR;
|
|
if (bag->Read(L"FriendlyName", &var, nullptr) != S_OK)
|
|
goto fail;
|
|
devHumanName = wcharToUtf8(var.bstrVal);
|
|
|
|
devices += {QString("video=")+devIdString, devHumanName};
|
|
|
|
fail:
|
|
if (olestr && coMalloc)
|
|
coMalloc->Free(olestr);
|
|
if (bindCtx)
|
|
bindCtx->Release();
|
|
delete[] devIdString;
|
|
delete[] devHumanName;
|
|
if (bag)
|
|
bag->Release();
|
|
m->Release();
|
|
}
|
|
classenum->Release();
|
|
|
|
return devices;
|
|
}
|