diff options
Diffstat (limited to 'compat/camera-names.cpp')
| -rw-r--r-- | compat/camera-names.cpp | 117 |
1 files changed, 79 insertions, 38 deletions
diff --git a/compat/camera-names.cpp b/compat/camera-names.cpp index 22dcdd8f..b9511037 100644 --- a/compat/camera-names.cpp +++ b/compat/camera-names.cpp @@ -1,95 +1,130 @@ #include "camera-names.hpp" +#include <algorithm> +#include <iterator> + #ifdef _WIN32 +# include <cwchar> # define NO_DSHOW_STRSAFE # include <dshow.h> -# include <cwchar> -#elif defined(__unix) || defined(__linux) || defined(__APPLE__) +#elif defined(__unix) || defined(__linux__) || defined(__APPLE__) # include <unistd.h> #endif -#ifdef __linux +#ifdef __APPLE__ +# include <QCameraInfo> +#endif + +#ifdef __linux__ # include <fcntl.h> # include <sys/ioctl.h> # include <linux/videodev2.h> # include <cerrno> +# include <cstring> #endif #include <QDebug> -OTR_COMPAT_EXPORT int camera_name_to_index(const QString &name) +int camera_name_to_index(const QString &name) { auto list = get_camera_names(); - int ret = list.indexOf(name); - if (ret < 0) - ret = 0; + auto it = std::find_if(list.cbegin(), list.cend(), [&name](const auto& tuple) { + const auto& [str, idx] = tuple; + return str == name; + }); + if (it != list.cend()) + { + const auto& [ str, idx ] = *it; + return idx; + } + + return -1; +} + +#ifdef _WIN32 +# include <QRegularExpression> + +static QString prop_to_qstring(IPropertyBag* pPropBag, const wchar_t* name) +{ + QString ret{}; + VARIANT var; + VariantInit(&var); + HRESULT hr = pPropBag->Read(name, &var, nullptr); + if (SUCCEEDED(hr)) + ret = QString{(const QChar*)var.bstrVal, int(std::wcslen(var.bstrVal))}; + VariantClear(&var); return ret; } -OTR_COMPAT_EXPORT QList<QString> get_camera_names() +static QString device_path_from_qstring(const QString& str) +{ + // language=RegExp prefix=R"/( suffix=)/" + static const QRegularExpression regexp{R"/(#vid_([0-9a-f]{4})&pid_([0-9a-f]{4})&mi_([0-9a-f]{2})#([^#]+))/", + QRegularExpression::CaseInsensitiveOption}; + auto match = regexp.match(str); + if (!match.hasMatch()) + return {}; + QString id = match.captured(4); + id.replace('&', '_'); + return id; +} + +#endif + +std::vector<std::tuple<QString, int>> get_camera_names() { - QList<QString> ret; -#if defined(_WIN32) + std::vector<std::tuple<QString, int>> ret; +#ifdef _WIN32 // Create the System Device Enumerator. HRESULT hr; CoInitialize(nullptr); - ICreateDevEnum *pSysDevEnum = NULL; - hr = CoCreateInstance(CLSID_SystemDeviceEnum, NULL, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); + ICreateDevEnum *pSysDevEnum = nullptr; + hr = CoCreateInstance(CLSID_SystemDeviceEnum, nullptr, CLSCTX_INPROC_SERVER, IID_ICreateDevEnum, (void **)&pSysDevEnum); if (FAILED(hr)) { qDebug() << "failed CLSID_SystemDeviceEnum" << hr; return ret; } // Obtain a class enumerator for the video compressor category. - IEnumMoniker *pEnumCat = NULL; + IEnumMoniker *pEnumCat = nullptr; hr = pSysDevEnum->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, &pEnumCat, 0); if (hr == S_OK) { // Enumerate the monikers. - IMoniker *pMoniker = NULL; + IMoniker *pMoniker = nullptr; ULONG cFetched; while (pEnumCat->Next(1, &pMoniker, &cFetched) == S_OK) { IPropertyBag *pPropBag; - hr = pMoniker->BindToStorage(0, 0, IID_IPropertyBag, (void **)&pPropBag); - if (SUCCEEDED(hr)) { + hr = pMoniker->BindToStorage(nullptr, nullptr, IID_IPropertyBag, (void **)&pPropBag); + if (SUCCEEDED(hr)) { // To retrieve the filter's friendly name, do the following: - VARIANT varName; - VariantInit(&varName); - hr = pPropBag->Read(L"FriendlyName", &varName, 0); if (SUCCEEDED(hr)) { - // Display the name in your UI somehow. - QString str((QChar*)varName.bstrVal, int(std::wcslen(varName.bstrVal))); - ret.append(str); + QString str = prop_to_qstring(pPropBag, L"FriendlyName"); + QString path = device_path_from_qstring(prop_to_qstring(pPropBag, L"DevicePath")); + if (!path.isNull()) + str += QStringLiteral(" [%1]").arg(path); + ret.push_back({ str, (int)ret.size() }); } - VariantClear(&varName); - - ////// To create an instance of the filter, do the following: - ////IBaseFilter *pFilter; - ////hr = pMoniker->BindToObject(NULL, NULL, IID_IBaseFilter, - //// (void**)&pFilter); - // Now add the filter to the graph. - //Remember to release pFilter later. pPropBag->Release(); } pMoniker->Release(); } pEnumCat->Release(); } +#if 0 else qDebug() << "failed CLSID_VideoInputDeviceCategory" << hr; +#endif pSysDevEnum->Release(); #endif -#ifdef __linux + +#ifdef __linux__ for (int i = 0; i < 16; i++) { - char buf[128]; - sprintf(buf, "/dev/video%d", i); - if (access(buf, F_OK) == 0) - ret.append(buf); - else - continue; + char buf[32]; + snprintf(buf, sizeof(buf), "/dev/video%d", i); if (access(buf, R_OK | W_OK) == 0) { int fd = open(buf, O_RDONLY); @@ -102,10 +137,16 @@ OTR_COMPAT_EXPORT QList<QString> get_camera_names() close(fd); continue; } - ret[ret.size()-1] = reinterpret_cast<const char*>(video_cap.card); + ret.push_back({ QString((const char*)video_cap.card), i}); close(fd); } } #endif +#ifdef __APPLE__ + QList<QCameraInfo> cameras = QCameraInfo::availableCameras(); + for (const QCameraInfo &cameraInfo : cameras) + ret.push_back({ cameraInfo.description(), ret.size() }); +#endif + return ret; } |
