Check that the CLSID is not taken when creating a device path.

This commit is contained in:
Gonzalo Exequiel Pedone 2020-10-09 12:01:40 -03:00
parent 5f68d6bfd2
commit 5ba2aba2e7
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
6 changed files with 196 additions and 170 deletions

View file

@ -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;
}

View file

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

View file

@ -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;
}

View file

@ -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

View file

@ -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)
{

View file

@ -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 "