Check that the CLSID is not taken when creating a device path.
This commit is contained in:
parent
5f68d6bfd2
commit
5ba2aba2e7
6 changed files with 196 additions and 170 deletions
|
@ -129,98 +129,6 @@ bool AkVCam::Preferences::readBool(const std::string &key, bool defaultValue)
|
|||
return readInt(key, defaultValue) != 0;
|
||||
}
|
||||
|
||||
std::vector<CLSID> AkVCam::Preferences::listRegisteredCameras(HINSTANCE hinstDLL)
|
||||
{
|
||||
WCHAR *strIID = nullptr;
|
||||
StringFromIID(CLSID_VideoInputDeviceCategory, &strIID);
|
||||
|
||||
std::wstringstream ss;
|
||||
ss << L"CLSID\\"
|
||||
<< strIID
|
||||
<< L"\\Instance";
|
||||
CoTaskMemFree(strIID);
|
||||
|
||||
HKEY key = nullptr;
|
||||
auto result = RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
ss.str().c_str(),
|
||||
0,
|
||||
MAXIMUM_ALLOWED,
|
||||
&key);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return {};
|
||||
|
||||
DWORD subkeys = 0;
|
||||
|
||||
result = RegQueryInfoKey(key,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&subkeys,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<CLSID> cameras;
|
||||
FILETIME lastWrite;
|
||||
|
||||
for (DWORD i = 0; i < subkeys; i++) {
|
||||
WCHAR subKey[MAX_PATH];
|
||||
memset(subKey, 0, MAX_PATH * sizeof(WCHAR));
|
||||
DWORD subKeyLen = MAX_PATH;
|
||||
result = RegEnumKeyExW(key,
|
||||
i,
|
||||
subKey,
|
||||
&subKeyLen,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&lastWrite);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
continue;
|
||||
|
||||
std::wstringstream ss;
|
||||
ss << L"CLSID\\" << subKey << L"\\InprocServer32";
|
||||
WCHAR path[MAX_PATH];
|
||||
memset(path, 0, MAX_PATH * sizeof(WCHAR));
|
||||
DWORD pathSize = MAX_PATH;
|
||||
|
||||
if (RegGetValueW(HKEY_CLASSES_ROOT,
|
||||
ss.str().c_str(),
|
||||
nullptr,
|
||||
RRF_RT_REG_SZ,
|
||||
nullptr,
|
||||
path,
|
||||
&pathSize) == ERROR_SUCCESS) {
|
||||
WCHAR modulePath[MAX_PATH];
|
||||
memset(modulePath, 0, MAX_PATH * sizeof(WCHAR));
|
||||
GetModuleFileNameW(hinstDLL, modulePath, MAX_PATH);
|
||||
|
||||
if (!lstrcmpiW(path, modulePath)) {
|
||||
CLSID clsid;
|
||||
memset(&clsid, 0, sizeof(CLSID));
|
||||
CLSIDFromString(subKey, &clsid);
|
||||
cameras.push_back(clsid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
return cameras;
|
||||
}
|
||||
|
||||
void AkVCam::Preferences::deleteKey(const std::string &key)
|
||||
{
|
||||
AkLogFunction();
|
||||
|
@ -390,6 +298,8 @@ std::string AkVCam::Preferences::createDevicePath()
|
|||
for (size_t i = 0; i < camerasCount(); i++)
|
||||
cameraPaths.push_back(cameraPath(i));
|
||||
|
||||
// List device CLSIDs in use.
|
||||
auto cameraClsids = listAllCameras();
|
||||
const int maxId = 64;
|
||||
|
||||
for (int i = 0; i < maxId; i++) {
|
||||
|
@ -397,11 +307,12 @@ std::string AkVCam::Preferences::createDevicePath()
|
|||
* incremental index to a common prefix.
|
||||
*/
|
||||
auto path = DSHOW_PLUGIN_DEVICE_PREFIX + std::to_string(i);
|
||||
auto clsid = createClsidFromStr(path);
|
||||
auto pit = std::find(cameraPaths.begin(), cameraPaths.end(), path);
|
||||
auto cit = std::find(cameraClsids.begin(), cameraClsids.end(), clsid);
|
||||
|
||||
// Check if the path is being used, if not return it.
|
||||
if (std::find(cameraPaths.begin(),
|
||||
cameraPaths.end(),
|
||||
path) == cameraPaths.end())
|
||||
if (pit == cameraPaths.end() && cit == cameraClsids.end())
|
||||
return path;
|
||||
}
|
||||
|
||||
|
|
|
@ -40,7 +40,6 @@ namespace AkVCam
|
|||
int readInt(const std::string &key, int defaultValue=0);
|
||||
double readDouble(const std::string &key, double defaultValue=0.0);
|
||||
bool readBool(const std::string &key, bool defaultValue=false);
|
||||
std::vector<CLSID> listRegisteredCameras(HINSTANCE hinstDLL);
|
||||
void deleteKey(const std::string &key);
|
||||
void move(const std::string &keyFrom, const std::string &keyTo);
|
||||
std::string addDevice(const std::string &description);
|
||||
|
|
|
@ -43,41 +43,9 @@ namespace AkVCam
|
|||
GUID guid;
|
||||
const DWORD *masks;
|
||||
|
||||
inline static const std::vector<VideoFormatSpecsPrivate> &formats()
|
||||
{
|
||||
static const DWORD bits555[] = {0x007c00, 0x0003e0, 0x00001f};
|
||||
static const DWORD bits565[] = {0x00f800, 0x0007e0, 0x00001f};
|
||||
|
||||
static const std::vector<VideoFormatSpecsPrivate> formats {
|
||||
{PixelFormatRGB32, BI_RGB , MEDIASUBTYPE_RGB32 , nullptr},
|
||||
{PixelFormatRGB24, BI_RGB , MEDIASUBTYPE_RGB24 , nullptr},
|
||||
{PixelFormatRGB16, BI_BITFIELDS , MEDIASUBTYPE_RGB565, bits565},
|
||||
{PixelFormatRGB15, BI_BITFIELDS , MEDIASUBTYPE_RGB555, bits555},
|
||||
{PixelFormatUYVY , MAKEFOURCC('U', 'Y', 'V', 'Y'), MEDIASUBTYPE_UYVY , nullptr},
|
||||
{PixelFormatYUY2 , MAKEFOURCC('Y', 'U', 'Y', '2'), MEDIASUBTYPE_YUY2 , nullptr},
|
||||
{PixelFormatNV12 , MAKEFOURCC('N', 'V', '1', '2'), MEDIASUBTYPE_NV12 , nullptr}
|
||||
};
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
static inline const VideoFormatSpecsPrivate *byGuid(const GUID &guid)
|
||||
{
|
||||
for (auto &format: formats())
|
||||
if (IsEqualGUID(format.guid, guid))
|
||||
return &format;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static inline const VideoFormatSpecsPrivate *byPixelFormat(FourCC pixelFormat)
|
||||
{
|
||||
for (auto &format: formats())
|
||||
if (format.pixelFormat == pixelFormat)
|
||||
return &format;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
inline static const std::vector<VideoFormatSpecsPrivate> &formats();
|
||||
static inline const VideoFormatSpecsPrivate *byGuid(const GUID &guid);
|
||||
static inline const VideoFormatSpecsPrivate *byPixelFormat(FourCC pixelFormat);
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -86,6 +54,26 @@ bool operator <(const CLSID &a, const CLSID &b)
|
|||
return AkVCam::stringFromIid(a) < AkVCam::stringFromIid(b);
|
||||
}
|
||||
|
||||
std::string AkVCam::locatePluginPath()
|
||||
{
|
||||
AkLogFunction();
|
||||
char path[MAX_PATH];
|
||||
memset(path, 0, MAX_PATH);
|
||||
HMODULE hmodule = nullptr;
|
||||
|
||||
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
LPCTSTR(&locatePluginPath),
|
||||
&hmodule)) {
|
||||
GetModuleFileNameA(hmodule, path, MAX_PATH);
|
||||
}
|
||||
|
||||
if (strlen(path) < 1)
|
||||
return {};
|
||||
|
||||
return dirname(path);
|
||||
}
|
||||
|
||||
std::string AkVCam::tempPath()
|
||||
{
|
||||
CHAR tempPath[MAX_PATH];
|
||||
|
@ -104,6 +92,16 @@ std::string AkVCam::moduleFileName(HINSTANCE hinstDLL)
|
|||
return std::string(fileName);
|
||||
}
|
||||
|
||||
std::string AkVCam::dirname(const std::string &path)
|
||||
{
|
||||
return path.substr(0, path.rfind("\\"));
|
||||
}
|
||||
|
||||
bool AkVCam::fileExists(const std::string &path)
|
||||
{
|
||||
return GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
std::string AkVCam::errorToString(DWORD errorCode)
|
||||
{
|
||||
CHAR *errorStr = nullptr;
|
||||
|
@ -1048,3 +1046,150 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
|
|||
|
||||
return frame;
|
||||
}
|
||||
|
||||
std::vector<CLSID> AkVCam::listAllCameras()
|
||||
{
|
||||
WCHAR *strIID = nullptr;
|
||||
StringFromIID(CLSID_VideoInputDeviceCategory, &strIID);
|
||||
|
||||
std::wstringstream ss;
|
||||
ss << L"CLSID\\" << strIID << L"\\Instance";
|
||||
CoTaskMemFree(strIID);
|
||||
|
||||
HKEY key = nullptr;
|
||||
auto result = RegOpenKeyExW(HKEY_CLASSES_ROOT,
|
||||
ss.str().c_str(),
|
||||
0,
|
||||
MAXIMUM_ALLOWED,
|
||||
&key);
|
||||
|
||||
if (result != ERROR_SUCCESS)
|
||||
return {};
|
||||
|
||||
DWORD subkeys = 0;
|
||||
|
||||
result = RegQueryInfoKey(key,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&subkeys,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr);
|
||||
|
||||
if (result != ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<CLSID> cameras;
|
||||
FILETIME lastWrite;
|
||||
|
||||
for (DWORD i = 0; i < subkeys; i++) {
|
||||
WCHAR subKey[MAX_PATH];
|
||||
memset(subKey, 0, MAX_PATH * sizeof(WCHAR));
|
||||
DWORD subKeyLen = MAX_PATH;
|
||||
result = RegEnumKeyExW(key,
|
||||
i,
|
||||
subKey,
|
||||
&subKeyLen,
|
||||
nullptr,
|
||||
nullptr,
|
||||
nullptr,
|
||||
&lastWrite);
|
||||
|
||||
if (result == ERROR_SUCCESS) {
|
||||
CLSID clsid;
|
||||
memset(&clsid, 0, sizeof(CLSID));
|
||||
CLSIDFromString(subKey, &clsid);
|
||||
cameras.push_back(clsid);
|
||||
}
|
||||
}
|
||||
|
||||
RegCloseKey(key);
|
||||
|
||||
return cameras;
|
||||
}
|
||||
|
||||
std::vector<CLSID> AkVCam::listRegisteredCameras()
|
||||
{
|
||||
AkLogFunction();
|
||||
auto pluginFolder = locatePluginPath();
|
||||
AkLogDebug() << "Plugin path: " << pluginFolder << std::endl;
|
||||
|
||||
if (pluginFolder.empty())
|
||||
return {};
|
||||
|
||||
auto pluginPath = pluginFolder + "\\" DSHOW_PLUGIN_NAME ".dll";
|
||||
AkLogDebug() << "Plugin binary: " << pluginPath << std::endl;
|
||||
|
||||
if (!fileExists(pluginPath)) {
|
||||
AkLogError() << "Plugin binary not found: " << pluginPath << std::endl;
|
||||
|
||||
return {};
|
||||
}
|
||||
|
||||
std::vector<CLSID> cameras;
|
||||
|
||||
for (auto &clsid: listAllCameras()) {
|
||||
auto subKey = "CLSID\\" + stringFromIid(clsid) + "\\InprocServer32";
|
||||
CHAR path[MAX_PATH];
|
||||
memset(path, 0, MAX_PATH * sizeof(CHAR));
|
||||
DWORD pathSize = MAX_PATH;
|
||||
|
||||
if (RegGetValueA(HKEY_CLASSES_ROOT,
|
||||
subKey.c_str(),
|
||||
nullptr,
|
||||
RRF_RT_REG_SZ,
|
||||
nullptr,
|
||||
path,
|
||||
&pathSize) == ERROR_SUCCESS) {
|
||||
|
||||
if (path == pluginPath)
|
||||
cameras.push_back(clsid);
|
||||
}
|
||||
}
|
||||
|
||||
return cameras;
|
||||
}
|
||||
|
||||
const std::vector<AkVCam::VideoFormatSpecsPrivate> &AkVCam::VideoFormatSpecsPrivate::formats()
|
||||
{
|
||||
static const DWORD bits555[] = {0x007c00, 0x0003e0, 0x00001f};
|
||||
static const DWORD bits565[] = {0x00f800, 0x0007e0, 0x00001f};
|
||||
|
||||
static const std::vector<VideoFormatSpecsPrivate> formats {
|
||||
{PixelFormatRGB32, BI_RGB , MEDIASUBTYPE_RGB32 , nullptr},
|
||||
{PixelFormatRGB24, BI_RGB , MEDIASUBTYPE_RGB24 , nullptr},
|
||||
{PixelFormatRGB16, BI_BITFIELDS , MEDIASUBTYPE_RGB565, bits565},
|
||||
{PixelFormatRGB15, BI_BITFIELDS , MEDIASUBTYPE_RGB555, bits555},
|
||||
{PixelFormatUYVY , MAKEFOURCC('U', 'Y', 'V', 'Y'), MEDIASUBTYPE_UYVY , nullptr},
|
||||
{PixelFormatYUY2 , MAKEFOURCC('Y', 'U', 'Y', '2'), MEDIASUBTYPE_YUY2 , nullptr},
|
||||
{PixelFormatNV12 , MAKEFOURCC('N', 'V', '1', '2'), MEDIASUBTYPE_NV12 , nullptr}
|
||||
};
|
||||
|
||||
return formats;
|
||||
}
|
||||
|
||||
const AkVCam::VideoFormatSpecsPrivate *AkVCam::VideoFormatSpecsPrivate::byGuid(const GUID &guid)
|
||||
{
|
||||
for (auto &format: formats())
|
||||
if (IsEqualGUID(format.guid, guid))
|
||||
return &format;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const AkVCam::VideoFormatSpecsPrivate *AkVCam::VideoFormatSpecsPrivate::byPixelFormat(FourCC pixelFormat)
|
||||
{
|
||||
for (auto &format: formats())
|
||||
if (format.pixelFormat == pixelFormat)
|
||||
return &format;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -34,8 +34,11 @@ namespace AkVCam
|
|||
class VideoFormat;
|
||||
class VideoFrame;
|
||||
|
||||
std::string locatePluginPath();
|
||||
std::string tempPath();
|
||||
std::string moduleFileName(HINSTANCE hinstDLL);
|
||||
std::string dirname(const std::string &path);
|
||||
bool fileExists(const std::string &path);
|
||||
std::string errorToString(DWORD errorCode);
|
||||
CLSID createClsidFromStr(const std::string &str);
|
||||
std::string createClsidStrFromStr(const std::string &str);
|
||||
|
@ -67,6 +70,8 @@ namespace AkVCam
|
|||
LSTATUS deleteTree(HKEY key, LPCSTR subkey, REGSAM samFlags);
|
||||
LSTATUS copyTree(HKEY src, LPCSTR subkey, HKEY dst, REGSAM samFlags);
|
||||
VideoFrame loadPicture(const std::string &fileName);
|
||||
std::vector<CLSID> listAllCameras();
|
||||
std::vector<CLSID> listRegisteredCameras();
|
||||
}
|
||||
|
||||
#endif // PLATFORM_UTILS_H
|
||||
|
|
|
@ -66,12 +66,9 @@ namespace AkVCam
|
|||
~IpcBridgePrivate();
|
||||
|
||||
inline const std::vector<DeviceControl> &controls() const;
|
||||
static std::string dirname(const std::string &path);
|
||||
void updateDeviceSharedProperties();
|
||||
void updateDeviceSharedProperties(const std::string &deviceId,
|
||||
const std::string &owner);
|
||||
bool fileExists(const std::string &path) const;
|
||||
static std::string locatePluginPath();
|
||||
static void pipeStateChanged(void *userData,
|
||||
MessageServer::PipeState state);
|
||||
|
||||
|
@ -422,7 +419,7 @@ std::vector<std::string> AkVCam::IpcBridge::listeners(const std::string &deviceI
|
|||
std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const
|
||||
{
|
||||
AkLogFunction();
|
||||
auto pluginPath = this->d->locatePluginPath();
|
||||
auto pluginPath = locatePluginPath();
|
||||
AkLogDebug() << "Plugin path: " << pluginPath << std::endl;
|
||||
|
||||
if (pluginPath.empty())
|
||||
|
@ -431,7 +428,7 @@ std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const
|
|||
auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll";
|
||||
AkLogDebug() << "Plugin binary: " << path << std::endl;
|
||||
|
||||
if (!this->d->fileExists(path))
|
||||
if (!fileExists(path))
|
||||
return {};
|
||||
|
||||
std::vector<uint64_t> pids;
|
||||
|
@ -550,7 +547,7 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index)
|
|||
void AkVCam::IpcBridge::updateDevices()
|
||||
{
|
||||
AkLogFunction();
|
||||
auto pluginPath = this->d->locatePluginPath();
|
||||
auto pluginPath = locatePluginPath();
|
||||
AkLogDebug() << "Plugin path: " << pluginPath << std::endl;
|
||||
|
||||
if (pluginPath.empty())
|
||||
|
@ -559,7 +556,7 @@ void AkVCam::IpcBridge::updateDevices()
|
|||
auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll";
|
||||
AkLogDebug() << "Plugin binary: " << path << std::endl;
|
||||
|
||||
if (!this->d->fileExists(path)) {
|
||||
if (!fileExists(path)) {
|
||||
AkLogError() << "Plugin binary not found: " << path << std::endl;
|
||||
|
||||
return;
|
||||
|
@ -800,11 +797,6 @@ const std::vector<AkVCam::DeviceControl> &AkVCam::IpcBridgePrivate::controls() c
|
|||
return controls;
|
||||
}
|
||||
|
||||
std::string AkVCam::IpcBridgePrivate::dirname(const std::string &path)
|
||||
{
|
||||
return path.substr(0, path.rfind("\\"));
|
||||
}
|
||||
|
||||
void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties()
|
||||
{
|
||||
for (size_t i = 0; i < Preferences::camerasCount(); i++) {
|
||||
|
@ -837,31 +829,6 @@ void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties(const std::string &d
|
|||
}
|
||||
}
|
||||
|
||||
bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const
|
||||
{
|
||||
return GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_ARCHIVE;
|
||||
}
|
||||
|
||||
std::string AkVCam::IpcBridgePrivate::locatePluginPath()
|
||||
{
|
||||
AkLogFunction();
|
||||
char path[MAX_PATH];
|
||||
memset(path, 0, MAX_PATH);
|
||||
HMODULE hmodule = nullptr;
|
||||
|
||||
if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS |
|
||||
GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT,
|
||||
LPCTSTR(&AkVCam::IpcBridgePrivate::locatePluginPath),
|
||||
&hmodule)) {
|
||||
GetModuleFileNameA(hmodule, path, MAX_PATH);
|
||||
}
|
||||
|
||||
if (strlen(path) < 1)
|
||||
return {};
|
||||
|
||||
return dirname(path);
|
||||
}
|
||||
|
||||
void AkVCam::IpcBridgePrivate::pipeStateChanged(void *userData,
|
||||
MessageServer::PipeState state)
|
||||
{
|
||||
|
|
|
@ -121,8 +121,7 @@ STDAPI DllUnregisterServer()
|
|||
{
|
||||
pluginInterface()->initializeLogger();
|
||||
AkLogFunction();
|
||||
auto cameras =
|
||||
AkVCam::Preferences::listRegisteredCameras(pluginInterface()->pluginHinstance());
|
||||
auto cameras = AkVCam::listRegisteredCameras();
|
||||
|
||||
for (auto camera: cameras) {
|
||||
AkLogInfo() << "Deleting "
|
||||
|
|
Loading…
Reference in a new issue