summaryrefslogtreecommitdiffhomepage
path: root/compat/camera-names.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'compat/camera-names.cpp')
-rw-r--r--compat/camera-names.cpp117
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;
}