diff --git a/Manager/src/cmdparser.cpp b/Manager/src/cmdparser.cpp index bf9f1e2..3075e05 100644 --- a/Manager/src/cmdparser.cpp +++ b/Manager/src/cmdparser.cpp @@ -262,12 +262,10 @@ AkVCam::CmdParser::CmdParser() "", "Show clients using the camera.", AKVCAM_BIND_FUNC(CmdParserPrivate::showClients)); - this->d->m_ipcBridge.connectService(); } AkVCam::CmdParser::~CmdParser() { - this->d->m_ipcBridge.disconnectService(); delete this->d; } diff --git a/VCamUtils/src/ipcbridge.h b/VCamUtils/src/ipcbridge.h index c650055..4420820 100644 --- a/VCamUtils/src/ipcbridge.h +++ b/VCamUtils/src/ipcbridge.h @@ -104,10 +104,6 @@ namespace AkVCam int logLevel() const; void setLogLevel(int logLevel); - // Manage main service connection. - void connectService(); - void disconnectService(); - // Register the peer to the global server. bool registerPeer(); diff --git a/cmio/Assistant/src/assistantglobals.h b/cmio/Assistant/src/assistantglobals.h index 58bcf2a..4ada9e8 100644 --- a/cmio/Assistant/src/assistantglobals.h +++ b/cmio/Assistant/src/assistantglobals.h @@ -54,10 +54,6 @@ #define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 #define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402 -// Connections -#define AKVCAM_ASSISTANT_MSG_CONNECTIONS 0x500 -#define AKVCAM_ASSISTANT_MSG_SETCONNECTIONS 0x501 - namespace AkVCam { using XpcMessage = std::function; diff --git a/cmio/PlatformUtils/src/preferences.cpp b/cmio/PlatformUtils/src/preferences.cpp index 4a8f858..1ead2fb 100644 --- a/cmio/PlatformUtils/src/preferences.cpp +++ b/cmio/PlatformUtils/src/preferences.cpp @@ -361,7 +361,7 @@ void AkVCam::Preferences::removeCamera(const std::string &path) if (cameraIndex < 0) return; - cameraSetFormats(cameraIndex, {}); + cameraSetFormats(size_t(cameraIndex), {}); auto nCameras = camerasCount(); deleteAllKeys("cameras." + std::to_string(cameraIndex)); @@ -451,6 +451,7 @@ void AkVCam::Preferences::cameraSetDescription(size_t cameraIndex, write("cameras." + std::to_string(cameraIndex) + ".description", description); + sync(); } std::string AkVCam::Preferences::cameraPath(size_t cameraIndex) @@ -536,7 +537,7 @@ void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex, auto formats = cameraFormats(cameraIndex); if (index < 0 || index > int(formats.size())) - index = formats.size(); + index = int(formats.size()); formats.insert(formats.begin() + index, format); write("cameras." @@ -563,7 +564,6 @@ void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex, void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index) { AkLogFunction(); - auto formats = cameraFormats(cameraIndex); if (index < 0 || index >= int(formats.size())) @@ -592,26 +592,6 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index) sync(); } -std::wstring AkVCam::Preferences::picture() -{ - return readWString("picture"); -} - -void AkVCam::Preferences::setPicture(const std::wstring &picture) -{ - write("picture", picture); -} - -int AkVCam::Preferences::logLevel() -{ - return readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); -} - -void AkVCam::Preferences::setLogLevel(int logLevel) -{ - write("loglevel", logLevel); -} - int AkVCam::Preferences::cameraControlValue(size_t cameraIndex, const std::string &key) { @@ -623,4 +603,27 @@ void AkVCam::Preferences::cameraSetControlValue(size_t cameraIndex, int value) { write("cameras." + std::to_string(cameraIndex) + ".controls." + key, value); + sync(); +} + +std::wstring AkVCam::Preferences::picture() +{ + return readWString("picture"); +} + +void AkVCam::Preferences::setPicture(const std::wstring &picture) +{ + write("picture", picture); + sync(); +} + +int AkVCam::Preferences::logLevel() +{ + return readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); +} + +void AkVCam::Preferences::setLogLevel(int logLevel) +{ + write("loglevel", logLevel); + sync(); } diff --git a/cmio/PlatformUtils/src/preferences.h b/cmio/PlatformUtils/src/preferences.h index ee046fb..1d20852 100644 --- a/cmio/PlatformUtils/src/preferences.h +++ b/cmio/PlatformUtils/src/preferences.h @@ -74,8 +74,6 @@ namespace AkVCam std::vector cameraFormats(size_t cameraIndex); void cameraSetFormats(size_t cameraIndex, const std::vector &formats); - void cameraFormats(size_t cameraIndex, - const std::vector &formats); void cameraAddFormat(size_t cameraIndex, const VideoFormat &format, int index); diff --git a/cmio/VCamIPC/src/ipcbridge.mm b/cmio/VCamIPC/src/ipcbridge.mm index 4c596bf..39b0705 100644 --- a/cmio/VCamIPC/src/ipcbridge.mm +++ b/cmio/VCamIPC/src/ipcbridge.mm @@ -80,11 +80,7 @@ namespace AkVCam void connectionInterrupted(); // Utility methods - std::string homePath() const; - bool fileExists(const std::wstring &path) const; bool fileExists(const std::string &path) const; - bool mkpath(const std::string &path) const; - bool rm(const std::string &path) const; static std::string locatePluginPath(); private: @@ -148,30 +144,10 @@ void AkVCam::IpcBridge::setLogLevel(int logLevel) Logger::setLogLevel(logLevel); } -void AkVCam::IpcBridge::connectService() -{ - AkLogFunction(); - this->registerPeer(); -} - -void AkVCam::IpcBridge::disconnectService() -{ - AkLogFunction(); - this->unregisterPeer(); -} - bool AkVCam::IpcBridge::registerPeer() { AkLogFunction(); - std::string plistFile = - CMIO_DAEMONS_PATH "/" CMIO_ASSISTANT_NAME ".plist"; - - auto daemon = replace(plistFile, "~", this->d->homePath()); - - if (!this->d->fileExists(daemon)) - return false; - if (this->d->m_serverMessagePort) return true; @@ -318,7 +294,10 @@ std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const AkLogFunction(); auto cameraIndex = Preferences::cameraFromPath(deviceId); - return Preferences::cameraDescription(cameraIndex); + if (cameraIndex < 0) + return {}; + + return Preferences::cameraDescription(size_t(cameraIndex)); } void AkVCam::IpcBridge::setDescription(const std::string &deviceId, @@ -327,7 +306,8 @@ void AkVCam::IpcBridge::setDescription(const std::string &deviceId, AkLogFunction(); auto cameraIndex = Preferences::cameraFromPath(deviceId); - return Preferences::cameraSetDescription(cameraIndex, description); + if (cameraIndex >= 0) + Preferences::cameraSetDescription(size_t(cameraIndex), description); } std::vector AkVCam::IpcBridge::supportedPixelFormats(StreamType type) const @@ -355,7 +335,10 @@ std::vector AkVCam::IpcBridge::formats(const std::string &d AkLogFunction(); auto cameraIndex = Preferences::cameraFromPath(deviceId); - return Preferences::cameraFormats(cameraIndex); + if (cameraIndex < 0) + return {}; + + return Preferences::cameraFormats(size_t(cameraIndex)); } void AkVCam::IpcBridge::setFormats(const std::string &deviceId, @@ -363,7 +346,8 @@ void AkVCam::IpcBridge::setFormats(const std::string &deviceId, { auto cameraIndex = Preferences::cameraFromPath(deviceId); - return Preferences::cameraSetFormats(cameraIndex, formats); + if (cameraIndex >= 0) + Preferences::cameraSetFormats(size_t(cameraIndex), formats); } std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const @@ -409,7 +393,7 @@ std::vector AkVCam::IpcBridge::controls(const std::string for (auto &control: this->d->controls()) { controls.push_back(control); controls.back().value = - Preferences::cameraControlValue(cameraIndex, control.id); + Preferences::cameraControlValue(size_t(cameraIndex), control.id); } return controls; @@ -428,13 +412,14 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId, for (auto &control: this->d->controls()) { auto oldValue = - Preferences::cameraControlValue(cameraIndex, control.id); + Preferences::cameraControlValue(size_t(cameraIndex), + control.id); if (controls.count(control.id)) { auto newValue = controls.at(control.id); if (newValue != oldValue) { - Preferences::cameraSetControlValue(cameraIndex, + Preferences::cameraSetControlValue(size_t(cameraIndex), control.id, newValue); updated = true; @@ -490,13 +475,13 @@ std::vector AkVCam::IpcBridge::listeners(const std::string &deviceI std::vector AkVCam::IpcBridge::clientsPids() const { AkLogFunction(); - auto driverPath = this->d->locatePluginPath(); - AkLogDebug() << "Plugin path: " << driverPath << std::endl; + auto pluginPath = this->d->locatePluginPath(); + AkLogDebug() << "Plugin path: " << pluginPath << std::endl; - if (driverPath.empty()) + if (pluginPath.empty()) return {}; - auto path = driverPath + "/Contents/MacOS/" CMIO_PLUGIN_NAME; + auto path = pluginPath + "/Contents/MacOS/" CMIO_PLUGIN_NAME; AkLogDebug() << "Plugin binary: " << path << std::endl; if (!this->d->fileExists(path)) @@ -553,16 +538,22 @@ void AkVCam::IpcBridge::addFormat(const std::string &deviceId, int index) { AkLogFunction(); - Preferences::cameraAddFormat(Preferences::cameraFromPath(deviceId), - format, - index); + auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex >= 0) + Preferences::cameraAddFormat(size_t(cameraIndex), + format, + index); } void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index) { AkLogFunction(); - Preferences::cameraRemoveFormat(Preferences::cameraFromPath(deviceId), - index); + auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex >= 0) + Preferences::cameraRemoveFormat(size_t(cameraIndex), + index); } void AkVCam::IpcBridge::updateDevices() @@ -578,7 +569,6 @@ void AkVCam::IpcBridge::updateDevices() AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE); xpc_connection_send_message(this->d->m_serverMessagePort, dictionary); xpc_release(dictionary); - } bool AkVCam::IpcBridge::deviceStart(const std::string &deviceId, @@ -957,11 +947,15 @@ void AkVCam::IpcBridgePrivate::controlsUpdated(xpc_connection_t client, std::string deviceId = xpc_dictionary_get_string(event, "device"); auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex < 0) + return; + std::map controls; for (auto &control: this->controls()) controls[control.id] = - Preferences::cameraControlValue(cameraIndex, control.id); + Preferences::cameraControlValue(size_t(cameraIndex), control.id); for (auto bridge: this->m_bridges) AKVCAM_EMIT(bridge, @@ -1029,21 +1023,6 @@ void AkVCam::IpcBridgePrivate::connectionInterrupted() } } -std::string AkVCam::IpcBridgePrivate::homePath() const -{ - auto homePath = NSHomeDirectory(); - - if (!homePath) - return {}; - - return std::string(homePath.UTF8String); -} - -bool AkVCam::IpcBridgePrivate::fileExists(const std::wstring &path) const -{ - return this->fileExists(std::string(path.begin(), path.end())); -} - bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const { struct stat stats; @@ -1052,62 +1031,6 @@ bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const return stat(path.c_str(), &stats) == 0; } -bool AkVCam::IpcBridgePrivate::mkpath(const std::string &path) const -{ - if (path.empty()) - return false; - - if (this->fileExists(path)) - return true; - - // Create parent folders - for (auto pos = path.find('/'); - pos != std::string::npos; - pos = path.find('/', pos + 1)) { - auto path_ = path.substr(0, pos); - - if (path_.empty() || this->fileExists(path_)) - continue; - - if (mkdir(path_.c_str(), - S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH)) - return false; - } - - return !mkdir(path.c_str(), - S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH); -} - -bool AkVCam::IpcBridgePrivate::rm(const std::string &path) const -{ - if (path.empty()) - return false; - - struct stat stats; - memset(&stats, 0, sizeof(struct stat)); - - if (stat(path.c_str(), &stats)) - return false; - - bool ok = true; - - if (S_ISDIR(stats.st_mode)) { - auto dir = opendir(path.c_str()); - - while (auto entry = readdir(dir)) - if (strcmp(entry->d_name, ".") && strcmp(entry->d_name, "..")) - this->rm(entry->d_name); - - closedir(dir); - - ok &= !rmdir(path.c_str()); - } else { - ok &= !::remove(path.c_str()); - } - - return ok; -} - std::string AkVCam::IpcBridgePrivate::locatePluginPath() { AkLogFunction(); diff --git a/cmio/VirtualCamera/src/plugininterface.cpp b/cmio/VirtualCamera/src/plugininterface.cpp index d36a3f3..92c8d95 100644 --- a/cmio/VirtualCamera/src/plugininterface.cpp +++ b/cmio/VirtualCamera/src/plugininterface.cpp @@ -157,7 +157,6 @@ AkVCam::PluginInterface::PluginInterface(): this->d->m_ref = 0; this->d->m_reserved = 0; - this->d->m_ipcBridge.connectService(); this->d->m_ipcBridge.connectServerStateChanged(this, &PluginInterface::serverStateChanged); this->d->m_ipcBridge.connectDeviceAdded(this, &PluginInterface::deviceAdded); this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved); @@ -170,7 +169,6 @@ AkVCam::PluginInterface::PluginInterface(): AkVCam::PluginInterface::~PluginInterface() { - this->d->m_ipcBridge.disconnectService(); delete this->d->pluginInterface; delete this->d; } diff --git a/dshow/Assistant/src/main.cpp b/dshow/Assistant/src/main.cpp index 58590b7..8e32d75 100644 --- a/dshow/Assistant/src/main.cpp +++ b/dshow/Assistant/src/main.cpp @@ -21,18 +21,17 @@ #include #include "service.h" +#include "PlatformUtils/src/preferences.h" #include "PlatformUtils/src/utils.h" #include "VCamUtils/src/logger/logger.h" int main(int argc, char **argv) { - auto loglevel = AkVCam::regReadInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); + auto loglevel = AkVCam::Preferences::logLevel(); AkVCam::Logger::setLogLevel(loglevel); - auto temp = AkVCam::tempPath(); - auto logFile = - AkVCam::regReadString("logfile", - std::string(temp.begin(), temp.end()) - + "\\" DSHOW_PLUGIN_ASSISTANT_NAME ".log"); + auto defaultLogFile = AkVCam::tempPath() + + "\\" DSHOW_PLUGIN_ASSISTANT_NAME ".log"; + auto logFile = AkVCam::Preferences::readString("logfile", defaultLogFile); AkVCam::Logger::setLogFile(logFile); AkVCam::Service service; diff --git a/dshow/Assistant/src/service.cpp b/dshow/Assistant/src/service.cpp index bd99368..40646e2 100644 --- a/dshow/Assistant/src/service.cpp +++ b/dshow/Assistant/src/service.cpp @@ -42,20 +42,6 @@ namespace AkVCam { std::string broadcaster; std::vector listeners; - bool horizontalMirror; - bool verticalMirror; - Scaling scaling; - AspectRatio aspectRatio; - bool swapRgb; - - AssistantDevice(): - horizontalMirror(false), - verticalMirror(false), - scaling(ScalingFast), - aspectRatio(AspectRatioIgnore), - swapRgb(false) - { - } }; typedef std::map AssistantPeers; @@ -85,20 +71,15 @@ namespace AkVCam void addPort(Message *message); void removePort(Message *message); void setBroadCasting(Message *message); - void setMirroring(Message *message); - void setScaling(Message *message); - void setAspectRatio(Message *message); - void setSwapRgb(Message *message); void frameReady(Message *message); + void pictureUpdated(Message *message); + void deviceUpdate(Message *message); void listeners(Message *message); void listener(Message *message); void broadcasting(Message *message); - void mirroring(Message *message); - void scaling(Message *message); - void aspectRatio(Message *message); - void swapRgb(Message *message); void listenerAdd(Message *message); void listenerRemove(Message *message); + void controlsUpdated(Message *message); }; GLOBAL_STATIC(ServicePrivate, servicePrivate) @@ -245,7 +226,7 @@ void AkVCam::Service::debug() void AkVCam::Service::showHelp(int argc, char **argv) { AkLogFunction(); - UNUSED(argc) + UNUSED(argc); auto programName = strrchr(argv[0], '\\'); @@ -285,24 +266,19 @@ AkVCam::ServicePrivate::ServicePrivate() this->m_statusHandler = nullptr; this->m_messageServer.setPipeName(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L); this->m_messageServer.setHandlers({ - {AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) }, - {AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) }, - {AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) }, - {AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)}, - {AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::mirroring) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::setMirroring) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SCALING , AKVCAM_BIND_FUNC(ServicePrivate::scaling) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING , AKVCAM_BIND_FUNC(ServicePrivate::setScaling) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO , AKVCAM_BIND_FUNC(ServicePrivate::aspectRatio) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(ServicePrivate::setAspectRatio) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB , AKVCAM_BIND_FUNC(ServicePrivate::swapRgb) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(ServicePrivate::setSwapRgb) }, + {AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) }, + {AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(ServicePrivate::pictureUpdated) }, + {AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) }, + {AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) }, + {AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(ServicePrivate::deviceUpdate) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)}, + {AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(ServicePrivate::controlsUpdated)}, }); this->m_timer.setInterval(60000); this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers); @@ -311,7 +287,7 @@ AkVCam::ServicePrivate::ServicePrivate() void AkVCam::ServicePrivate::stateChanged(void *userData, MessageServer::State state) { - UNUSED(userData) + UNUSED(userData); switch (state) { case MessageServer::StateAboutToStart: @@ -368,7 +344,6 @@ void AkVCam::ServicePrivate::sendStatus(DWORD currentState, DWORD wait) { AkLogFunction(); - this->m_status.dwControlsAccepted = currentState == SERVICE_START_PENDING? 0: SERVICE_ACCEPT_STOP; this->m_status.dwCurrentState = currentState; @@ -460,11 +435,8 @@ void AkVCam::ServicePrivate::requestPort(AkVCam::Message *message) AkLogFunction(); auto data = messageData(message); - std::string portName = data->client? - AKVCAM_ASSISTANT_CLIENT_NAME: - AKVCAM_ASSISTANT_SERVER_NAME; + std::string portName = AKVCAM_ASSISTANT_CLIENT_NAME; portName += std::to_string(this->id()); - AkLogInfo() << "Returning Port: " << portName << std::endl; memcpy(data->port, portName.c_str(), @@ -547,112 +519,6 @@ void AkVCam::ServicePrivate::setBroadCasting(AkVCam::Message *message) this->m_peerMutex.unlock(); } -void AkVCam::ServicePrivate::setMirroring(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - data->status = false; - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - if (this->m_deviceConfigs[deviceId].horizontalMirror == data->hmirror - && this->m_deviceConfigs[deviceId].verticalMirror == data->vmirror) - return; - - this->m_deviceConfigs[deviceId].horizontalMirror = data->hmirror; - this->m_deviceConfigs[deviceId].verticalMirror = data->vmirror; - data->status = true; - - this->m_peerMutex.lock(); - - for (auto &client: this->m_clients) { - Message msg(message); - MessageServer::sendMessage(client.second, &msg); - } - - this->m_peerMutex.unlock(); -} - -void AkVCam::ServicePrivate::setScaling(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - data->status = false; - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - if (this->m_deviceConfigs[deviceId].scaling == data->scaling) - return; - - this->m_deviceConfigs[deviceId].scaling = data->scaling; - data->status = true; - - this->m_peerMutex.lock(); - - for (auto &client: this->m_clients) { - Message msg(message); - MessageServer::sendMessage(client.second, &msg); - } - - this->m_peerMutex.unlock(); -} - -void AkVCam::ServicePrivate::setAspectRatio(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - data->status = false; - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - if (this->m_deviceConfigs[deviceId].aspectRatio == data->aspect) - return; - - this->m_deviceConfigs[deviceId].aspectRatio = data->aspect; - data->status = true; - - this->m_peerMutex.lock(); - - for (auto &client: this->m_clients) { - Message msg(message); - MessageServer::sendMessage(client.second, &msg); - } - - this->m_peerMutex.unlock(); -} - -void AkVCam::ServicePrivate::setSwapRgb(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - data->status = false; - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - if (this->m_deviceConfigs[deviceId].swapRgb == data->swap) - return; - - this->m_deviceConfigs[deviceId].swapRgb = data->swap; - data->status = true; - - this->m_peerMutex.lock(); - - for (auto &client: this->m_clients) { - Message msg(message); - MessageServer::sendMessage(client.second, &msg); - } - - this->m_peerMutex.unlock(); -} - void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message) { AkLogFunction(); @@ -664,6 +530,28 @@ void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message) this->m_peerMutex.unlock(); } +void AkVCam::ServicePrivate::pictureUpdated(AkVCam::Message *message) +{ + AkLogFunction(); + this->m_peerMutex.lock(); + + for (auto &client: this->m_clients) + MessageServer::sendMessage(client.second, message); + + this->m_peerMutex.unlock(); +} + +void AkVCam::ServicePrivate::deviceUpdate(AkVCam::Message *message) +{ + AkLogFunction(); + this->m_peerMutex.lock(); + + for (auto &client: this->m_clients) + MessageServer::sendMessage(client.second, message); + + this->m_peerMutex.unlock(); +} + void AkVCam::ServicePrivate::listeners(AkVCam::Message *message) { AkLogFunction(); @@ -726,59 +614,6 @@ void AkVCam::ServicePrivate::broadcasting(AkVCam::Message *message) data->status = true; } -void AkVCam::ServicePrivate::mirroring(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - data->hmirror = this->m_deviceConfigs[deviceId].horizontalMirror; - data->vmirror = this->m_deviceConfigs[deviceId].verticalMirror; - data->status = true; -} - -void AkVCam::ServicePrivate::scaling(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - data->scaling = this->m_deviceConfigs[deviceId].scaling; - data->status = true; -} - -void AkVCam::ServicePrivate::aspectRatio(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - data->aspect = this->m_deviceConfigs[deviceId].aspectRatio; - data->status = true; -} - -void AkVCam::ServicePrivate::swapRgb(AkVCam::Message *message) -{ - AkLogFunction(); - auto data = messageData(message); - std::string deviceId(data->device); - - if (this->m_deviceConfigs.count(deviceId) < 1) - this->m_deviceConfigs[deviceId] = {}; - - data->swap = this->m_deviceConfigs[deviceId].swapRgb; - data->status = true; -} - void AkVCam::ServicePrivate::listenerAdd(AkVCam::Message *message) { AkLogFunction(); @@ -843,14 +678,25 @@ void AkVCam::ServicePrivate::listenerRemove(AkVCam::Message *message) } } +void AkVCam::ServicePrivate::controlsUpdated(AkVCam::Message *message) +{ + AkLogFunction(); + this->m_peerMutex.lock(); + + for (auto &client: this->m_clients) + MessageServer::sendMessage(client.second, message); + + this->m_peerMutex.unlock(); +} + DWORD WINAPI controlHandler(DWORD control, DWORD eventType, LPVOID eventData, LPVOID context) { - UNUSED(eventType) - UNUSED(eventData) - UNUSED(context) + UNUSED(eventType); + UNUSED(eventData); + UNUSED(context); AkLogFunction(); DWORD result = ERROR_CALL_NOT_IMPLEMENTED; @@ -896,8 +742,8 @@ BOOL WINAPI controlDebugHandler(DWORD control) void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv) { - UNUSED(dwArgc) - UNUSED(lpszArgv) + UNUSED(dwArgc); + UNUSED(lpszArgv); AkLogFunction(); AkLogInfo() << "Setting service control handler" << std::endl; diff --git a/dshow/PlatformUtils/PlatformUtils.pro b/dshow/PlatformUtils/PlatformUtils.pro index c93e097..49af419 100644 --- a/dshow/PlatformUtils/PlatformUtils.pro +++ b/dshow/PlatformUtils/PlatformUtils.pro @@ -50,6 +50,7 @@ LIBS = \ SOURCES = \ src/messageserver.cpp \ src/mutex.cpp \ + src/preferences.cpp \ src/utils.cpp \ src/sharedmemory.cpp @@ -57,6 +58,7 @@ HEADERS = \ src/messagecommons.h \ src/messageserver.h \ src/mutex.h \ + src/preferences.h \ src/utils.h \ src/sharedmemory.h diff --git a/dshow/PlatformUtils/src/messagecommons.h b/dshow/PlatformUtils/src/messagecommons.h index 93b9b67..1e1853e 100644 --- a/dshow/PlatformUtils/src/messagecommons.h +++ b/dshow/PlatformUtils/src/messagecommons.h @@ -30,38 +30,33 @@ #define AKVCAM_ASSISTANT_SERVER_NAME "AkVCam_Server" // General messages -#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000 -#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001 +#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000 +#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001 +#define AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED 0x002 // Assistant messages -#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100 -#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101 -#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102 +#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100 +#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101 +#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102 // Device control and information -#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200 -#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201 -#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202 -#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203 -#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204 +#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200 +#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201 +#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202 +#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203 +#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204 +#define AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE 0x205 // Device listeners controls -#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300 -#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301 -#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302 -#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303 +#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300 +#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301 +#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302 +#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303 // Device dynamic properties -#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 -#define AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING 0x402 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING 0x403 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SCALING 0x404 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING 0x405 -#define AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO 0x406 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO 0x407 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB 0x408 -#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB 0x409 +#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400 +#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 +#define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402 #define MSG_BUFFER_SIZE 4096 #define MAX_STRING 1024 @@ -136,7 +131,6 @@ namespace AkVCam struct MsgRequestPort { - bool client; char port[MAX_STRING]; }; @@ -152,6 +146,16 @@ namespace AkVCam char port[MAX_STRING]; }; + struct MsgDeviceAdded + { + char device[MAX_STRING]; + }; + + struct MsgDeviceRemoved + { + char device[MAX_STRING]; + }; + struct MsgBroadcasting { char device[MAX_STRING]; @@ -159,35 +163,6 @@ namespace AkVCam bool status; }; - struct MsgMirroring - { - char device[MAX_STRING]; - bool hmirror; - bool vmirror; - bool status; - }; - - struct MsgScaling - { - char device[MAX_STRING]; - Scaling scaling; - bool status; - }; - - struct MsgAspectRatio - { - char device[MAX_STRING]; - AspectRatio aspect; - bool status; - }; - - struct MsgSwapRgb - { - char device[MAX_STRING]; - bool swap; - bool status; - }; - struct MsgListeners { char device[MAX_STRING]; @@ -206,6 +181,16 @@ namespace AkVCam char device[MAX_STRING]; char port[MAX_STRING]; }; + + struct MsgPictureUpdated + { + char picture[MAX_STRING]; + }; + + struct MsgControlsUpdated + { + char device[MAX_STRING]; + }; } #endif // MESSAGECOMMONS_H diff --git a/dshow/PlatformUtils/src/messageserver.cpp b/dshow/PlatformUtils/src/messageserver.cpp index 8a0a15d..c1563a4 100644 --- a/dshow/PlatformUtils/src/messageserver.cpp +++ b/dshow/PlatformUtils/src/messageserver.cpp @@ -375,7 +375,7 @@ void AkVCam::MessageServerPrivate::checkLoop() this->m_pipeName.end()) << std::endl; this->m_pipeState = AkVCam::MessageServer::PipeStateAvailable; - AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState); + AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState) } else if (!result && this->m_pipeState != AkVCam::MessageServer::PipeStateGone && GetLastError() != ERROR_SEM_TIMEOUT) { @@ -384,7 +384,7 @@ void AkVCam::MessageServerPrivate::checkLoop() this->m_pipeName.end()) << std::endl; this->m_pipeState = AkVCam::MessageServer::PipeStateGone; - AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState); + AKVCAM_EMIT(this->self, PipeStateChanged, this->m_pipeState) } if (!this->m_running) diff --git a/dshow/PlatformUtils/src/preferences.cpp b/dshow/PlatformUtils/src/preferences.cpp new file mode 100644 index 0000000..9cb7c6a --- /dev/null +++ b/dshow/PlatformUtils/src/preferences.cpp @@ -0,0 +1,792 @@ +/* akvirtualcamera, virtual camera for Mac and Windows. + * Copyright (C) 2020 Gonzalo Exequiel Pedone + * + * akvirtualcamera is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * akvirtualcamera is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with akvirtualcamera. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "preferences.h" +#include "utils.h" +#include "VCamUtils/src/image/videoformat.h" +#include "VCamUtils/src/logger/logger.h" + +#define REG_PREFIX "SOFTWARE\\Webcamoid\\VirtualCamera\\" + +namespace AkVCam +{ + namespace Preferences + { + void splitSubKey(const std::string &key, + std::string &subKey, + std::string &value); + bool valueA(const std::string &key, + DWORD dataTypeFlags, + PVOID data, + LPDWORD dataSize); + bool valueW(const std::string &key, + DWORD dataTypeFlags, + PVOID data, + LPDWORD dataSize); + void setValueA(const std::string &key, + DWORD dataType, + LPCSTR data, + DWORD dataSize); + void setValueW(const std::string &key, + DWORD dataType, + LPCWSTR data, + DWORD dataSize); + } +} + +void AkVCam::Preferences::write(const std::string &key, + const std::string &value) +{ + AkLogFunction(); + AkLogInfo() << "Writing: " << key << " = " << value << std::endl; + setValueA(key, REG_SZ, value.c_str(), DWORD(value.size())); +} + +void AkVCam::Preferences::write(const std::string &key, + const std::wstring &value) +{ + AkLogFunction(); + AkLogInfo() << "Writing: " + << key + << " = " + << std::string(value.begin(), value.end()) << std::endl; + setValueW(key, REG_SZ, value.c_str(), DWORD(value.size())); +} + +void AkVCam::Preferences::write(const std::string &key, int value) +{ + AkLogFunction(); + AkLogInfo() << "Writing: " << key << " = " << value << std::endl; + setValueA(key, + REG_DWORD, + reinterpret_cast(&value), + DWORD(sizeof(int))); +} + +void AkVCam::Preferences::write(const std::string &key, double value) +{ + AkLogFunction(); + AkLogInfo() << "Writing: " << key << " = " << value << std::endl; + auto val = std::to_string(value); + setValueA(key, + REG_SZ, + val.c_str(), + DWORD(val.size())); +} + +void AkVCam::Preferences::write(const std::string &key, + std::vector &value) +{ + AkLogFunction(); + write(key, join(value, ",")); +} + +std::string AkVCam::Preferences::readString(const std::string &key, + const std::string &defaultValue) +{ + AkLogFunction(); + char value[MAX_PATH]; + memset(value, 0, MAX_PATH * sizeof(char)); + DWORD valueSize = MAX_PATH; + + if (!valueA(key, RRF_RT_REG_SZ, &value, &valueSize)) + return defaultValue; + + return {value}; +} + +std::wstring AkVCam::Preferences::readWString(const std::string &key, + const std::wstring &defaultValue) +{ + AkLogFunction(); + TCHAR value[MAX_PATH]; + memset(value, 0, MAX_PATH * sizeof(TCHAR)); + DWORD valueSize = MAX_PATH; + + if (!valueW(key, RRF_RT_REG_SZ, &value, &valueSize)) + return defaultValue; + + return {value}; +} + +int AkVCam::Preferences::readInt(const std::string &key, int defaultValue) +{ + AkLogFunction(); + DWORD value = 0; + DWORD valueSize = sizeof(DWORD); + + if (!valueA(key, RRF_RT_REG_DWORD, &value, &valueSize)) + return defaultValue; + + return int(value); +} + +double AkVCam::Preferences::readDouble(const std::string &key, + double defaultValue) +{ + AkLogFunction(); + auto value = readString(key, std::to_string(defaultValue)); + std::string::size_type sz; + + return std::stod(value, &sz); +} + +bool AkVCam::Preferences::readBool(const std::string &key, bool defaultValue) +{ + AkLogFunction(); + + return readInt(key, defaultValue) != 0; +} + +std::vector 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 = RegOpenKeyEx(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 cameras; + FILETIME lastWrite; + + for (DWORD i = 0; i < subkeys; i++) { + TCHAR subKey[MAX_PATH]; + memset(subKey, 0, MAX_PATH * sizeof(TCHAR)); + DWORD subKeyLen = MAX_PATH; + result = RegEnumKeyEx(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 (RegGetValue(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)); + GetModuleFileName(hinstDLL, modulePath, MAX_PATH); + + if (!lstrcmpi(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(); + AkLogInfo() << "Deleting " << key << std::endl; + std::string subKey; + std::string val; + splitSubKey(key, subKey, val); + HKEY hkey = nullptr; + auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + subKey.c_str(), + 0, + KEY_ALL_ACCESS | KEY_WOW64_64KEY, + &hkey); + + if (result != ERROR_SUCCESS) + return; + + if (val.empty()) + RegDeleteTreeA(hkey, nullptr); + else + RegDeleteValueA(hkey, val.c_str()); + + RegCloseKey(hkey); +} + +void AkVCam::Preferences::move(const std::string &keyFrom, + const std::string &keyTo) +{ + AkLogFunction(); + AkLogInfo() << "From: " << keyFrom << std::endl; + AkLogInfo() << "To: " << keyTo << std::endl; + + std::string subKeyFrom = REG_PREFIX "\\" + keyFrom; + HKEY hkeyFrom = nullptr; + auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + subKeyFrom.c_str(), + 0, + KEY_READ | KEY_WOW64_64KEY, + &hkeyFrom); + + if (result == ERROR_SUCCESS) { + std::string subKeyTo = REG_PREFIX "\\" + keyTo; + HKEY hkeyTo = nullptr; + result = RegCreateKeyExA(HKEY_LOCAL_MACHINE, + subKeyTo.c_str(), + 0, + nullptr, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + nullptr, + &hkeyTo, + nullptr); + + if (result == ERROR_SUCCESS) { + result = RegCopyTree(hkeyFrom, nullptr, hkeyTo); + + if (result == ERROR_SUCCESS) + deleteKey(keyFrom); + + RegCloseKey(hkeyTo); + } + + RegCloseKey(hkeyFrom); + } +} + +std::string AkVCam::Preferences::addDevice(const std::wstring &description) +{ + AkLogFunction(); + auto path = createDevicePath(); + int cameraIndex = readInt("Cameras\\size") + 1; + write("Cameras\\size", cameraIndex); + write("Cameras\\" + std::to_string(cameraIndex) + "\\description", + description); + write("Cameras\\" + std::to_string(cameraIndex) + "\\path", path); + + return path; +} + +std::string AkVCam::Preferences::addCamera(const std::wstring &description, + const std::vector &formats) +{ + return addCamera("", description, formats); +} + +std::string AkVCam::Preferences::addCamera(const std::string &path, + const std::wstring &description, + const std::vector &formats) +{ + AkLogFunction(); + + if (!path.empty() && cameraExists(path)) + return {}; + + auto path_ = path.empty()? createDevicePath(): path; + int cameraIndex = readInt("Cameras\\") + 1; + write("Cameras\\size", cameraIndex); + write("Cameras\\" + + std::to_string(cameraIndex) + + "\\description", + description); + write("Cameras\\" + + std::to_string(cameraIndex) + + "\\path", + path_); + write("Cameras\\" + + std::to_string(cameraIndex) + + "\\Formats\\size", + int(formats.size())); + + for (size_t i = 0; i < formats.size(); i++) { + auto &format = formats[i]; + auto prefix = "Cameras\\" + + std::to_string(cameraIndex) + + "\\Formats\\" + + std::to_string(i + 1); + auto formatStr = VideoFormat::stringFromFourcc(format.fourcc()); + write(prefix + "\\format", formatStr); + write(prefix + "\\width", format.width()); + write(prefix + "\\height", format.height()); + write(prefix + "\\fps", format.minimumFrameRate().toString()); + } + + return path_; +} + +void AkVCam::Preferences::removeCamera(const std::string &path) +{ + AkLogFunction(); + AkLogInfo() << "Device: " << path << std::endl; + int cameraIndex = cameraFromPath(path); + + if (cameraIndex < 0) + return; + + cameraSetFormats(size_t(cameraIndex), {}); + + auto nCameras = camerasCount(); + deleteKey("Cameras\\" + std::to_string(cameraIndex + 1) + '\\'); + + for (auto i = size_t(cameraIndex + 1); i < nCameras; i++) + move("Cameras\\" + std::to_string(i + 1), + "Cameras\\" + std::to_string(i)); + + if (nCameras > 1) + write("Cameras\\size", int(nCameras - 1)); + else + deleteKey("Cameras\\"); +} + +size_t AkVCam::Preferences::camerasCount() +{ + AkLogFunction(); + int nCameras = readInt("Cameras\\size"); + AkLogInfo() << "Cameras: " << nCameras << std::endl; + + return size_t(nCameras); +} + +std::string AkVCam::Preferences::createDevicePath() +{ + AkLogFunction(); + + // List device paths in use. + std::vector cameraPaths; + + for (size_t i = 0; i < camerasCount(); i++) + cameraPaths.push_back(cameraPath(i)); + + const int maxId = 64; + + for (int i = 0; i < maxId; i++) { + /* There are no rules for device paths in Windows. Just append an + * incremental index to a common prefix. + */ + auto path = DSHOW_PLUGIN_DEVICE_PREFIX + std::to_string(i); + + // Check if the path is being used, if not return it. + if (std::find(cameraPaths.begin(), + cameraPaths.end(), + path) == cameraPaths.end()) + return path; + } + + return {}; +} + +int AkVCam::Preferences::cameraFromPath(const std::string &path) +{ + for (size_t i = 0; i < camerasCount(); i++) + if (cameraPath(i) == path) + return int(i); + + return -1; +} + +bool AkVCam::Preferences::cameraExists(const std::string &path) +{ + for (DWORD i = 0; i < camerasCount(); i++) + if (cameraPath(i) == path) + return true; + + return false; +} + +std::wstring AkVCam::Preferences::cameraDescription(size_t cameraIndex) +{ + if (cameraIndex >= camerasCount()) + return {}; + + return readWString("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\description"); +} + +void AkVCam::Preferences::cameraSetDescription(size_t cameraIndex, + const std::wstring &description) +{ + if (cameraIndex >= camerasCount()) + return; + + write("Cameras\\" + std::to_string(cameraIndex + 1) + "\\description", + description); +} + +std::string AkVCam::Preferences::cameraPath(size_t cameraIndex) +{ + return readString("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\path"); +} + +size_t AkVCam::Preferences::formatsCount(size_t cameraIndex) +{ + return size_t(readInt("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\size")); +} + +AkVCam::VideoFormat AkVCam::Preferences::cameraFormat(size_t cameraIndex, + size_t formatIndex) +{ + AkLogFunction(); + auto prefix = "Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\" + + std::to_string(formatIndex + 1); + auto format = readString(prefix + "\\format"); + auto fourcc = VideoFormat::fourccFromString(format); + int width = readInt(prefix + "\\width"); + int height = readInt(prefix + "\\height"); + auto fps = Fraction(readString(prefix + "\\fps")); + + return VideoFormat(fourcc, width, height, {fps}); +} + +std::vector AkVCam::Preferences::cameraFormats(size_t cameraIndex) +{ + AkLogFunction(); + std::vector formats; + + for (size_t i = 0; i < formatsCount(cameraIndex); i++) { + auto videoFormat = cameraFormat(cameraIndex, i); + + if (videoFormat) + formats.push_back(videoFormat); + } + + return formats; +} + +void AkVCam::Preferences::cameraSetFormats(size_t cameraIndex, + const std::vector &formats) +{ + AkLogFunction(); + + if (cameraIndex >= camerasCount()) + return; + + write("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\size", + int(formats.size())); + + for (size_t i = 0; i < formats.size(); i++) { + auto &format = formats[i]; + auto prefix = "Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\" + + std::to_string(i + 1); + auto formatStr = VideoFormat::stringFromFourcc(format.fourcc()); + write(prefix + "\\format", formatStr); + write(prefix + "\\width", format.width()); + write(prefix + "\\height", format.height()); + write(prefix + "\\fps", format.minimumFrameRate().toString()); + } +} + +void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex, + const AkVCam::VideoFormat &format, + int index) +{ + AkLogFunction(); + auto formats = cameraFormats(cameraIndex); + + if (index < 0 || index > int(formats.size())) + index = int(formats.size()); + + formats.insert(formats.begin() + index, format); + write("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\size", + int(formats.size())); + + for (size_t i = 0; i < formats.size(); i++) { + auto &format = formats[i]; + auto prefix = "Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\" + + std::to_string(i + 1); + auto formatStr = VideoFormat::stringFromFourcc(format.fourcc()); + write(prefix + "\\format", formatStr); + write(prefix + "\\width", format.width()); + write(prefix + "\\height", format.height()); + write(prefix + "\\fps", format.minimumFrameRate().toString()); + } +} + +void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index) +{ + AkLogFunction(); + auto formats = cameraFormats(cameraIndex); + + if (index < 0 || index >= int(formats.size())) + return; + + formats.erase(formats.begin() + index); + write("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Formats\\size", + int(formats.size())); + + for (size_t i = 0; i < formats.size(); i++) { + auto &format = formats[i]; + auto prefix = "Cameras\\" + + std::to_string(cameraIndex) + + "\\Formats\\" + + std::to_string(i + 1); + auto formatStr = VideoFormat::stringFromFourcc(format.fourcc()); + write(prefix + "\\format", formatStr); + write(prefix + "\\width", format.width()); + write(prefix + "\\height", format.height()); + write(prefix + "\\fps", format.minimumFrameRate().toString()); + } +} + +int AkVCam::Preferences::cameraControlValue(size_t cameraIndex, + const std::string &key) +{ + return readInt("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Controls\\" + + key); +} + +void AkVCam::Preferences::cameraSetControlValue(size_t cameraIndex, + const std::string &key, + int value) +{ + write("Cameras\\" + + std::to_string(cameraIndex + 1) + + "\\Controls\\" + + key, + value); +} + +std::wstring AkVCam::Preferences::picture() +{ + return readWString("picture"); +} + +void AkVCam::Preferences::setPicture(const std::wstring &picture) +{ + write("picture", picture); +} + +int AkVCam::Preferences::logLevel() +{ + return readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); +} + +void AkVCam::Preferences::setLogLevel(int logLevel) +{ + write("loglevel", logLevel); +} + +void AkVCam::Preferences::splitSubKey(const std::string &key, + std::string &subKey, + std::string &value) +{ + subKey = REG_PREFIX; + auto separator = key.rfind('\\'); + + if (separator == std::string::npos) { + value = key; + } else { + subKey += '\\' + key.substr(0, separator); + + if (separator + 1 < key.size()) + value = key.substr(separator + 1); + } +} + +bool AkVCam::Preferences::valueA(const std::string &key, + DWORD dataTypeFlags, + PVOID data, + LPDWORD dataSize) +{ + std::string subKey; + std::string val; + splitSubKey(key, subKey, val); + HKEY hkey = nullptr; + auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + subKey.c_str(), + 0, + KEY_READ | KEY_WOW64_64KEY, + &hkey); + + if (result != ERROR_SUCCESS) + return false; + + result = RegGetValueA(hkey, + nullptr, + val.c_str(), + dataTypeFlags, + nullptr, + data, + dataSize); + RegCloseKey(hkey); + + return result == ERROR_SUCCESS; +} + +bool AkVCam::Preferences::valueW(const std::string &key, + DWORD dataTypeFlags, + PVOID data, + LPDWORD dataSize) +{ + std::string subKey; + std::string val; + splitSubKey(key, subKey, val); + HKEY hkey = nullptr; + auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE, + subKey.c_str(), + 0, + KEY_READ | KEY_WOW64_64KEY, + &hkey); + + if (result != ERROR_SUCCESS) + return false; + + std::wstring_convert> cv; + auto wval = cv.from_bytes(val); + result = RegGetValueW(hkey, + nullptr, + wval.c_str(), + dataTypeFlags, + nullptr, + data, + dataSize); + RegCloseKey(hkey); + + return result == ERROR_SUCCESS; +} + +void AkVCam::Preferences::setValueA(const std::string &key, + DWORD dataType, + LPCSTR data, + DWORD dataSize) +{ + std::string subKey; + std::string val; + splitSubKey(key, subKey, val); + HKEY hkey = nullptr; + LONG result = RegCreateKeyExA(HKEY_LOCAL_MACHINE, + subKey.c_str(), + 0, + nullptr, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + nullptr, + &hkey, + nullptr); + + if (result != ERROR_SUCCESS) + return; + + RegSetValueA(hkey, + val.c_str(), + dataType, + data, + dataSize); + RegCloseKey(hkey); +} + +void AkVCam::Preferences::setValueW(const std::string &key, + DWORD dataType, + LPCWSTR data, + DWORD dataSize) +{ + std::string subKey; + std::string val; + splitSubKey(key, subKey, val); + HKEY hkey = nullptr; + LONG result = RegCreateKeyExA(HKEY_LOCAL_MACHINE, + subKey.c_str(), + 0, + nullptr, + REG_OPTION_NON_VOLATILE, + KEY_WRITE | KEY_WOW64_64KEY, + nullptr, + &hkey, + nullptr); + + if (result != ERROR_SUCCESS) + return; + + std::wstring_convert> cv; + auto wval = cv.from_bytes(val); + RegSetValueW(hkey, + wval.c_str(), + dataType, + data, + dataSize); + RegCloseKey(hkey); +} diff --git a/dshow/PlatformUtils/src/preferences.h b/dshow/PlatformUtils/src/preferences.h new file mode 100644 index 0000000..e4350d5 --- /dev/null +++ b/dshow/PlatformUtils/src/preferences.h @@ -0,0 +1,85 @@ +/* akvirtualcamera, virtual camera for Mac and Windows. + * Copyright (C) 2020 Gonzalo Exequiel Pedone + * + * akvirtualcamera is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * akvirtualcamera is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with akvirtualcamera. If not, see . + * + * Web-Site: http://webcamoid.github.io/ + */ + +#ifndef PREFERENCES_H +#define PREFERENCES_H + +#include +#include +#include +#include + +namespace AkVCam +{ + class VideoFormat; + + namespace Preferences + { + void write(const std::string &key, const std::string &value); + void write(const std::string &key, const std::wstring &value); + void write(const std::string &key, int value); + void write(const std::string &key, double value); + void write(const std::string &key, std::vector &value); + std::string readString(const std::string &key, + const std::string &defaultValue={}); + std::wstring readWString(const std::string &key, + const std::wstring &defaultValue={}); + 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 listRegisteredCameras(HINSTANCE hinstDLL); + void deleteKey(const std::string &key); + void move(const std::string &keyFrom, const std::string &keyTo); + std::string addDevice(const std::wstring &description); + std::string addCamera(const std::wstring &description, + const std::vector &formats); + std::string addCamera(const std::string &path, + const std::wstring &description, + const std::vector &formats); + void removeCamera(const std::string &path); + size_t camerasCount(); + std::string createDevicePath(); + int cameraFromPath(const std::string &path); + bool cameraExists(const std::string &path); + std::wstring cameraDescription(size_t cameraIndex); + void cameraSetDescription(size_t cameraIndex, + const std::wstring &description); + std::string cameraPath(size_t cameraIndex); + size_t formatsCount(size_t cameraIndex); + VideoFormat cameraFormat(size_t cameraIndex, size_t formatIndex); + std::vector cameraFormats(size_t cameraIndex); + void cameraSetFormats(size_t cameraIndex, + const std::vector &formats); + void cameraAddFormat(size_t cameraIndex, + const VideoFormat &format, + int index); + void cameraRemoveFormat(size_t cameraIndex, int index); + int cameraControlValue(size_t cameraIndex, + const std::string &key); + void cameraSetControlValue(size_t cameraIndex, + const std::string &key, + int value); + std::wstring picture(); + void setPicture(const std::wstring &picture); + int logLevel(); + void setLogLevel(int logLevel); + } +} + +#endif // PREFERENCES_H diff --git a/dshow/PlatformUtils/src/utils.cpp b/dshow/PlatformUtils/src/utils.cpp index b0d266b..44e9968 100644 --- a/dshow/PlatformUtils/src/utils.cpp +++ b/dshow/PlatformUtils/src/utils.cpp @@ -95,31 +95,41 @@ BOOL AkVCam::isWow64() return isWow64; } -std::wstring AkVCam::tempPath() +std::string AkVCam::tempPath() { - WCHAR tempPath[MAX_PATH]; - memset(tempPath, 0, MAX_PATH * sizeof(WCHAR)); - GetTempPath(MAX_PATH, tempPath); + CHAR tempPath[MAX_PATH]; + memset(tempPath, 0, MAX_PATH * sizeof(CHAR)); + GetTempPathA(MAX_PATH, tempPath); - return std::wstring(tempPath); + return std::string(tempPath); } std::wstring AkVCam::programFilesPath() { - WCHAR programFiles[MAX_PATH]; - DWORD programFilesSize = MAX_PATH * sizeof(WCHAR); - memset(programFiles, 0, programFilesSize); bool ok = false; + TCHAR programFiles[MAX_PATH]; + DWORD programFilesSize = MAX_PATH * sizeof(TCHAR); + memset(programFiles, 0, programFilesSize); + HKEY hkey = nullptr; + auto result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, + L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", + 0, + KEY_READ | KEY_WOW64_64KEY, + &hkey); - if (isWow64() - && regGetValue(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", - L"ProgramFilesDir", - RRF_RT_REG_SZ, - nullptr, - &programFiles, - &programFilesSize) == ERROR_SUCCESS) - ok = true; + if (result == ERROR_SUCCESS) { + result = RegGetValue(hkey, + nullptr, + L"ProgramFilesDir", + RRF_RT_REG_SZ, + nullptr, + &programFiles, + &programFilesSize); + if (isWow64()) + ok = true; + + RegCloseKey(hkey); + } if (!ok) SHGetSpecialFolderPath(nullptr, @@ -391,16 +401,15 @@ AM_MEDIA_TYPE *AkVCam::mediaTypeFromFormat(const AkVCam::VideoFormat &format) memset(videoInfo, 0, sizeof(VIDEOINFO)); auto fps = format.minimumFrameRate(); + // Initialize info header. videoInfo->rcSource = {0, 0, 0, 0}; videoInfo->rcTarget = videoInfo->rcSource; videoInfo->dwBitRate = DWORD(8 * frameSize - * fps.num() - / fps.den()); - videoInfo->AvgTimePerFrame = REFERENCE_TIME(TIME_BASE - * fps.den() - / fps.num()); + * size_t(fps.num()) + / size_t(fps.den())); + videoInfo->AvgTimePerFrame = REFERENCE_TIME(TIME_BASE / fps.value()); // Initialize bitmap header. videoInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); @@ -783,405 +792,3 @@ std::string AkVCam::stringFromMediaSample(IMediaSample *mediaSample) return ss.str(); } - -LONG AkVCam::regGetValue(HKEY hkey, - LPCWSTR lpSubKey, - LPCWSTR lpValue, - DWORD dwFlags, - LPDWORD pdwType, - PVOID pvData, - LPDWORD pcbData) -{ - HKEY key = nullptr; - auto result = RegOpenKeyEx(hkey, - lpSubKey, - 0, - KEY_READ | KEY_WOW64_64KEY, - &key); - - if (result != ERROR_SUCCESS) - return result; - - result = RegGetValue(key, - nullptr, - lpValue, - dwFlags, - pdwType, - pvData, - pcbData); - RegCloseKey(key); - - return result; -} - -std::string AkVCam::regReadString(const std::string &key, const std::string &defaultValue) -{ - auto wkey = std::wstring(key.begin(), key.end()); - WCHAR value[MAX_PATH]; - memset(value, 0, MAX_PATH * sizeof(WCHAR)); - DWORD valueSize = MAX_PATH; - if (FAILED(regGetValue(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Webcamoid\\VirtualCamera", - wkey.c_str(), - RRF_RT_REG_SZ, - nullptr, - &value, - &valueSize))) - return defaultValue; - - char str[MAX_PATH]; - char defaultChar = '?'; - WideCharToMultiByte(CP_ACP, - 0, - value, - -1, - str, - MAX_PATH, - &defaultChar, - nullptr); - - return std::string(str); -} - -int AkVCam::regReadInt(const std::string &key, int defaultValue) -{ - auto wkey = std::wstring(key.begin(), key.end()); - DWORD value = 0; - DWORD valueSize = sizeof(DWORD); - - if (FAILED(regGetValue(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Webcamoid\\VirtualCamera", - wkey.c_str(), - RRF_RT_REG_DWORD, - nullptr, - &value, - &valueSize))) - return defaultValue; - - return value; -} - -std::vector AkVCam::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 = RegOpenKeyEx(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 cameras; - FILETIME lastWrite; - - for (DWORD i = 0; i < subkeys; i++) { - TCHAR subKey[MAX_PATH]; - memset(subKey, 0, MAX_PATH * sizeof(TCHAR)); - DWORD subKeyLen = MAX_PATH; - result = RegEnumKeyEx(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 (RegGetValue(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)); - GetModuleFileName(hinstDLL, modulePath, MAX_PATH); - - if (!lstrcmpi(path, modulePath)) { - CLSID clsid; - memset(&clsid, 0, sizeof(CLSID)); - CLSIDFromString(subKey, &clsid); - cameras.push_back(clsid); - } - } - } - - RegCloseKey(key); - - return cameras; -} - -DWORD AkVCam::camerasCount() -{ - DWORD nCameras = 0; - DWORD nCamerasSize = sizeof(DWORD); - - regGetValue(HKEY_LOCAL_MACHINE, - L"SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras", - L"size", - RRF_RT_REG_DWORD, - nullptr, - &nCameras, - &nCamerasSize); - - return nCameras; -} - -std::wstring AkVCam::createDevicePath() -{ - // List device paths in use. - std::vector cameraPaths; - - for (DWORD i = 0; i < camerasCount(); i++) - cameraPaths.push_back(cameraPath(i)); - - const int maxId = 64; - - for (int i = 0; i < maxId; i++) { - /* There are no rules for device paths in Windows. Just append an - * incremental index to a common prefix. - */ - auto path = DSHOW_PLUGIN_DEVICE_PREFIX_L + std::to_wstring(i); - - // Check if the path is being used, if not return it. - if (std::find(cameraPaths.begin(), - cameraPaths.end(), - path) == cameraPaths.end()) - return path; - } - - return {}; -} - -int AkVCam::cameraFromId(const std::wstring &path) -{ - auto clsid = createClsidFromStr(path); - - return cameraFromId(clsid); -} - -int AkVCam::cameraFromId(const CLSID &clsid) -{ - for (DWORD i = 0; i < camerasCount(); i++) { - auto cameraClsid = createClsidFromStr(cameraPath(i)); - - if (IsEqualCLSID(cameraClsid, clsid) && !cameraFormats(i).empty()) - return int(i); - } - - return -1; -} - -bool AkVCam::cameraExists(const std::string &path) -{ - return cameraExists(std::wstring(path.begin(), path.end())); -} - -bool AkVCam::cameraExists(const std::wstring &path) -{ - for (DWORD i = 0; i < camerasCount(); i++) - if (cameraPath(i) == path) - return true; - - return false; -} - -std::wstring AkVCam::cameraDescription(DWORD cameraIndex) -{ - std::wstringstream ss; - ss << L"SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - << cameraIndex + 1; - - WCHAR description[1024]; - DWORD descriptionSize = 1024 * sizeof(WCHAR); - memset(description, 0, descriptionSize); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"description", - RRF_RT_REG_SZ, - nullptr, - &description, - &descriptionSize) != ERROR_SUCCESS) - return std::wstring(); - - return std::wstring(description); -} - -std::wstring AkVCam::cameraPath(DWORD cameraIndex) -{ - std::wstringstream ss; - ss << L"SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - << cameraIndex + 1; - - WCHAR path[1024]; - DWORD pathSize = 1024 * sizeof(WCHAR); - memset(path, 0, pathSize); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"path", - RRF_RT_REG_SZ, - nullptr, - &path, - &pathSize) != ERROR_SUCCESS) - return std::wstring(); - - return std::wstring(path); -} - -std::wstring AkVCam::cameraPath(const CLSID &clsid) -{ - auto camera = cameraFromId(clsid); - - if (camera < 0) - return {}; - - return cameraPath(DWORD(camera)); -} - -DWORD AkVCam::formatsCount(DWORD cameraIndex) -{ - std::wstringstream ss; - ss << L"SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - << cameraIndex + 1 - << L"\\Formats"; - - DWORD nFormats; - DWORD nFormatsSize = sizeof(DWORD); - memset(&nFormats, 0, nFormatsSize); - - regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"size", - RRF_RT_REG_DWORD, - nullptr, - &nFormats, - &nFormatsSize); - - return nFormats; -} - -AkVCam::VideoFormat AkVCam::cameraFormat(DWORD cameraIndex, DWORD formatIndex) -{ - std::wstringstream ss; - ss << L"SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - << cameraIndex + 1 - << L"\\Formats\\" - << formatIndex + 1; - - WCHAR formatStr[1024]; - DWORD variableSize = 1024 * sizeof(WCHAR); - memset(formatStr, 0, variableSize); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"format", - RRF_RT_REG_SZ, - nullptr, - &formatStr, - &variableSize) != ERROR_SUCCESS) - return {}; - - DWORD width = 0; - variableSize = sizeof(DWORD); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"width", - RRF_RT_REG_DWORD, - nullptr, - &width, - &variableSize) != ERROR_SUCCESS) - return {}; - - DWORD height = 0; - variableSize = sizeof(DWORD); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"height", - RRF_RT_REG_DWORD, - nullptr, - &height, - &variableSize) != ERROR_SUCCESS) - return {}; - - WCHAR fpsStr[1024]; - variableSize = 1024 * sizeof(WCHAR); - memset(fpsStr, 0, variableSize); - - if (regGetValue(HKEY_LOCAL_MACHINE, - ss.str().c_str(), - L"fps", - RRF_RT_REG_SZ, - nullptr, - &fpsStr, - &variableSize) != ERROR_SUCCESS) - return {}; - - std::wstring format(formatStr); - auto fourcc = VideoFormat::fourccFromString(std::string(format.begin(), - format.end())); - - return VideoFormat(fourcc, - int(width), - int(height), - {Fraction(fpsStr)}); -} - -std::vector AkVCam::cameraFormats(DWORD cameraIndex) -{ - std::vector formats; - - for (DWORD i = 0; i < formatsCount(cameraIndex); i++) { - auto videoFormat = cameraFormat(cameraIndex, i); - - if (videoFormat) - formats.push_back(videoFormat); - } - - return formats; -} diff --git a/dshow/PlatformUtils/src/utils.h b/dshow/PlatformUtils/src/utils.h index dbf0b95..a54940f 100644 --- a/dshow/PlatformUtils/src/utils.h +++ b/dshow/PlatformUtils/src/utils.h @@ -34,7 +34,7 @@ namespace AkVCam class VideoFormat; BOOL isWow64(); - std::wstring tempPath(); + std::string tempPath(); std::wstring programFilesPath(); std::wstring moduleFileNameW(HINSTANCE hinstDLL); std::string moduleFileName(HINSTANCE hinstDLL); @@ -69,29 +69,6 @@ namespace AkVCam std::string stringFromFormatType(const GUID &formatType); std::string stringFromMediaType(const AM_MEDIA_TYPE *mediaType); std::string stringFromMediaSample(IMediaSample *mediaSample); - LONG regGetValue(HKEY hkey, - LPCWSTR lpSubKey, - LPCWSTR lpValue, - DWORD dwFlags, - LPDWORD pdwType, - PVOID pvData, - LPDWORD pcbData); - std::string regReadString(const std::string &key, - const std::string &defaultValue={}); - int regReadInt(const std::string &key, int defaultValue=0); - std::vector listRegisteredCameras(HINSTANCE hinstDLL); - DWORD camerasCount(); - std::wstring createDevicePath(); - int cameraFromId(const std::wstring &path); - int cameraFromId(const CLSID &clsid); - bool cameraExists(const std::string &path); - bool cameraExists(const std::wstring &path); - std::wstring cameraDescription(DWORD cameraIndex); - std::wstring cameraPath(DWORD cameraIndex); - std::wstring cameraPath(const CLSID &clsid); - DWORD formatsCount(DWORD cameraIndex); - VideoFormat cameraFormat(DWORD cameraIndex, DWORD formatIndex); - std::vector cameraFormats(DWORD cameraIndex); } #endif // PLATFORM_UTILS_H diff --git a/dshow/VCamIPC/src/ipcbridge.cpp b/dshow/VCamIPC/src/ipcbridge.cpp index 283dd09..bbfb250 100644 --- a/dshow/VCamIPC/src/ipcbridge.cpp +++ b/dshow/VCamIPC/src/ipcbridge.cpp @@ -18,17 +18,20 @@ */ #include -#include #include +#include +#include +#include #include #include #include #include -#include +#include #include #include "PlatformUtils/src/messageserver.h" #include "PlatformUtils/src/mutex.h" +#include "PlatformUtils/src/preferences.h" #include "PlatformUtils/src/sharedmemory.h" #include "PlatformUtils/src/utils.h" #include "VCamUtils/src/image/videoformat.h" @@ -38,11 +41,7 @@ namespace AkVCam { - typedef std::shared_ptr MonikerPtr; - typedef std::shared_ptr BaseFilterPtr; - typedef std::shared_ptr PropertyBagPtr; - typedef std::shared_ptr PinPtr; - typedef std::shared_ptr MediaTypePtr; + using RegisterServerFunc = HRESULT (WINAPI *)(); struct DeviceSharedProperties { @@ -54,77 +53,39 @@ namespace AkVCam { public: IpcBridge *self; + std::string m_portName; std::map m_devices; std::map m_messageHandlers; std::vector m_broadcasting; - std::map m_options; MessageServer m_messageServer; MessageServer m_mainServer; SharedMemory m_sharedMemory; Mutex m_globalMutex; - std::string m_portName; - std::wstring m_error; - bool m_asClient; explicit IpcBridgePrivate(IpcBridge *self); ~IpcBridgePrivate(); - static inline std::vector *driverPaths(); - std::vector listCameras() const; - BaseFilterPtr filter(IMoniker *moniker) const; - PropertyBagPtr propertyBag(IMoniker *moniker) const; - bool isVirtualCamera(const MonikerPtr &moniker) const; - bool isVirtualCamera(IBaseFilter *baseFilter) const; - std::string cameraPath(const MonikerPtr &moniker) const; - std::string cameraPath(IPropertyBag *propertyBag) const; - std::wstring cameraDescription(const MonikerPtr &moniker) const; - std::wstring cameraDescription(IPropertyBag *propertyBag) const; - std::vector enumPins(IBaseFilter *baseFilter) const; - std::vector enumVideoFormats(IPin *pin) const; - std::vector findFiles(const std::wstring &path) const; - std::vector findFiles(const std::string &path, - const std::string &fileName) const; - std::vector findFiles(const std::wstring &path, - const std::wstring &fileName) const; - std::wstring regAddLine(const std::wstring &key, - const std::wstring &value, - const std::wstring &data, - BOOL wow=false) const; - std::wstring regAddLine(const std::wstring &key, - const std::wstring &value, - int data, - BOOL wow=false) const; - std::wstring regDeleteLine(const std::wstring &key, - BOOL wow=false) const; - std::wstring regDeleteLine(const std::wstring &key, - const std::wstring &value, - BOOL wow=false) const; - std::wstring regMoveLine(const std::wstring &fromKey, - const std::wstring &toKey, - BOOL wow=false) const; - std::wstring dirname(const std::wstring &path) const; + inline const std::vector &controls() const; + static std::string dirname(const std::string &path); void updateDeviceSharedProperties(); void updateDeviceSharedProperties(const std::string &deviceId, const std::string &owner); - std::wstring locateDriverPath() const; + bool fileExists(const std::string &path) const; + static std::string locatePluginPath(); static void pipeStateChanged(void *userData, MessageServer::PipeState state); // Message handling methods void isAlive(Message *message); void frameReady(Message *message); - void setBroadcasting(Message *message); - void setMirror(Message *message); - void setScaling(Message *message); - void setAspectRatio(Message *message); - void setSwapRgb(Message *message); + void pictureUpdated(Message *message); + void deviceCreate(Message *message); + void deviceDestroy(Message *message); + void deviceUpdate(Message *message); void listenerAdd(Message *message); - void listenerRemove(Message *message); - - // Execute commands with elevated privileges. - int sudo(const std::vector ¶meters, - const std::wstring &directory={}, - bool show=false); + void listenerRemove (Message *message); + void setBroadcasting(Message *message); + void controlsUpdated(Message *message); }; static const int maxFrameWidth = 1920; @@ -137,86 +98,51 @@ AkVCam::IpcBridge::IpcBridge() { AkLogFunction(); this->d = new IpcBridgePrivate(this); + auto loglevel = AkVCam::Preferences::logLevel(); + AkVCam::Logger::setLogLevel(loglevel); + this->d->m_mainServer.start(); + this->registerPeer(); } AkVCam::IpcBridge::~IpcBridge() { + this->unregisterPeer(); + this->d->m_mainServer.stop(true); delete this->d; } -std::wstring AkVCam::IpcBridge::errorMessage() const +std::wstring AkVCam::IpcBridge::picture() const { - return this->d->m_error; + return Preferences::picture(); } -void AkVCam::IpcBridge::setOption(const std::string &key, const std::string &value) +void AkVCam::IpcBridge::setPicture(const std::wstring &picture) { - AkLogFunction(); - - if (value.empty()) - this->d->m_options.erase(key); - else - this->d->m_options[key] = value; + Preferences::setPicture(picture); + std::wstring_convert> cv; + auto picture_ = cv.to_bytes(picture); + Message message; + message.messageId = AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED; + message.dataSize = sizeof(MsgPictureUpdated); + auto data = messageData(&message); + memcpy(data->picture, + picture_.c_str(), + (std::min)(picture_.size(), MAX_STRING)); + this->d->m_mainServer.sendMessage(&message); } -std::vector AkVCam::IpcBridge::driverPaths() const +int AkVCam::IpcBridge::logLevel() const { - AkLogFunction(); - - return *this->d->driverPaths(); + return Preferences::logLevel(); } -void AkVCam::IpcBridge::setDriverPaths(const std::vector &driverPaths) +void AkVCam::IpcBridge::setLogLevel(int logLevel) { - AkLogFunction(); - *this->d->driverPaths() = driverPaths; + Preferences::setLogLevel(logLevel); + Logger::setLogLevel(logLevel); } -std::vector AkVCam::IpcBridge::availableDrivers() const -{ - return {"AkVirtualCamera"}; -} - -std::string AkVCam::IpcBridge::driver() const -{ - return {"AkVirtualCamera"}; -} - -bool AkVCam::IpcBridge::setDriver(const std::string &driver) -{ - return driver == "AkVirtualCamera"; -} - -std::vector AkVCam::IpcBridge::availableRootMethods() const -{ - return {"runas"}; -} - -std::string AkVCam::IpcBridge::rootMethod() const -{ - return {"runas"}; -} - -bool AkVCam::IpcBridge::setRootMethod(const std::string &rootMethod) -{ - return rootMethod == "runas"; -} - -void AkVCam::IpcBridge::connectService(bool asClient) -{ - AkLogFunction(); - this->d->m_asClient = asClient; - this->d->m_mainServer.start(); -} - -void AkVCam::IpcBridge::disconnectService() -{ - AkLogFunction(); - this->d->m_mainServer.stop(true); - this->d->m_asClient = false; -} - -bool AkVCam::IpcBridge::registerPeer(bool asClient) +bool AkVCam::IpcBridge::registerPeer() { AkLogFunction(); @@ -224,7 +150,6 @@ bool AkVCam::IpcBridge::registerPeer(bool asClient) message.messageId = AKVCAM_ASSISTANT_MSG_REQUEST_PORT; message.dataSize = sizeof(MsgRequestPort); auto requestData = messageData(&message); - requestData->client = asClient; if (!MessageServer::sendMessage(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L, &message)) @@ -306,16 +231,15 @@ void AkVCam::IpcBridge::unregisterPeer() std::vector AkVCam::IpcBridge::devices() const { AkLogFunction(); + auto nCameras = Preferences::camerasCount(); std::vector devices; - - for (auto camera: this->d->listCameras()) - if (this->d->isVirtualCamera(camera)) - devices.push_back(this->d->cameraPath(camera)); - AkLogInfo() << "Devices:" << std::endl; - for (auto &device: devices) - AkLogInfo() << " " << device << std::endl; + for (size_t i = 0; i < nCameras; i++) { + auto deviceId = Preferences::cameraPath(i); + devices.push_back(deviceId); + AkLogInfo() << " " << deviceId << std::endl; + } return devices; } @@ -323,20 +247,29 @@ std::vector AkVCam::IpcBridge::devices() const std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); - for (auto camera: this->d->listCameras()) { - auto propertyBag = this->d->propertyBag(camera.get()); + if (cameraIndex < 0) + return {}; - if (this->d->isVirtualCamera(camera) - && this->d->cameraPath(propertyBag.get()) == deviceId) - return this->d->cameraDescription(propertyBag.get()); - } - - return {}; + return Preferences::cameraDescription(size_t(cameraIndex)); } -std::vector AkVCam::IpcBridge::supportedPixelFormats() const +void AkVCam::IpcBridge::setDescription(const std::string &deviceId, + const std::wstring &description) { + AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex >= 0) + Preferences::cameraSetDescription(size_t(cameraIndex), description); +} + +std::vector AkVCam::IpcBridge::supportedPixelFormats(StreamType type) const +{ + if (type == StreamTypeInput) + return {PixelFormatRGB24}; + return { PixelFormatRGB32, PixelFormatRGB24, @@ -348,32 +281,30 @@ std::vector AkVCam::IpcBridge::supportedPixelFormats() cons }; } -AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat() const +AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(StreamType type) const { - return PixelFormatYUY2; + return type == StreamTypeInput? + PixelFormatRGB24: + PixelFormatYUY2; } std::vector AkVCam::IpcBridge::formats(const std::string &deviceId) const { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); - std::vector formats; + if (cameraIndex < 0) + return {}; - for (auto camera: this->d->listCameras()) { - auto baseFilter = this->d->filter(camera.get()); + return Preferences::cameraFormats(size_t(cameraIndex)); +} +void AkVCam::IpcBridge::setFormats(const std::string &deviceId, + const std::vector &formats) +{ + auto cameraIndex = Preferences::cameraFromPath(deviceId); - if (this->d->isVirtualCamera(baseFilter.get()) - && this->d->cameraPath(camera) == deviceId) { - auto pins = this->d->enumPins(baseFilter.get()); - - if (!pins.empty()) - formats = this->d->enumVideoFormats(pins[0].get()); - - break; - } - } - - return formats; + if (cameraIndex >= 0) + Preferences::cameraSetFormats(size_t(cameraIndex), formats); } std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const @@ -402,109 +333,64 @@ std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const return broadcaster; } -bool AkVCam::IpcBridge::isHorizontalMirrored(const std::string &deviceId) +std::vector AkVCam::IpcBridge::controls(const std::string &deviceId) { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING; - message.dataSize = sizeof(MsgMirroring); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); + if (cameraIndex < 0) + return {}; - if (!this->d->m_mainServer.sendMessage(&message)) - return false; + std::vector controls; - if (!data->status) - return false; + for (auto &control: this->d->controls()) { + controls.push_back(control); + controls.back().value = + Preferences::cameraControlValue(size_t(cameraIndex), control.id); + } - return data->hmirror; + return controls; } -bool AkVCam::IpcBridge::isVerticalMirrored(const std::string &deviceId) +void AkVCam::IpcBridge::setControls(const std::string &deviceId, + const std::map &controls) { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex < 0) + return; + + bool updated = false; + + for (auto &control: this->d->controls()) { + auto oldValue = + Preferences::cameraControlValue(size_t(cameraIndex), + control.id); + + if (controls.count(control.id)) { + auto newValue = controls.at(control.id); + + if (newValue != oldValue) { + Preferences::cameraSetControlValue(size_t(cameraIndex), + control.id, + newValue); + updated = true; + } + } + } + + if (!updated) + return; Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING; - message.dataSize = sizeof(MsgMirroring); - auto data = messageData(&message); + message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED; + message.dataSize = sizeof(MsgControlsUpdated); + auto data = messageData(&message); memcpy(data->device, deviceId.c_str(), (std::min)(deviceId.size(), MAX_STRING)); - - if (!this->d->m_mainServer.sendMessage(&message)) - return false; - - if (!data->status) - return false; - - return data->vmirror; -} - -AkVCam::Scaling AkVCam::IpcBridge::scalingMode(const std::string &deviceId) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SCALING; - message.dataSize = sizeof(MsgScaling); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - - if (!this->d->m_mainServer.sendMessage(&message)) - return ScalingFast; - - if (!data->status) - return ScalingFast; - - return data->scaling; -} - -AkVCam::AspectRatio AkVCam::IpcBridge::aspectRatioMode(const std::string &deviceId) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO; - message.dataSize = sizeof(MsgAspectRatio); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - - if (!this->d->m_mainServer.sendMessage(&message)) - return AspectRatioIgnore; - - if (!data->status) - return AspectRatioIgnore; - - return data->aspect; -} - -bool AkVCam::IpcBridge::swapRgb(const std::string &deviceId) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB; - message.dataSize = sizeof(MsgSwapRgb); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - - if (!this->d->m_mainServer.sendMessage(&message)) - return false; - - if (!data->status) - return false; - - return data->swap; + this->d->m_mainServer.sendMessage(&message); } std::vector AkVCam::IpcBridge::listeners(const std::string &deviceId) @@ -545,21 +431,18 @@ std::vector AkVCam::IpcBridge::listeners(const std::string &deviceI std::vector AkVCam::IpcBridge::clientsPids() const { - auto driverPath = this->d->locateDriverPath(); + AkLogFunction(); + auto pluginPath = this->d->locatePluginPath(); + AkLogDebug() << "Plugin path: " << pluginPath << std::endl; - if (driverPath.empty()) + if (pluginPath.empty()) return {}; - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; + auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll"; + AkLogDebug() << "Plugin binary: " << path << std::endl; - std::vector pluginsPaths; - - for (auto path: this->d->findFiles(driverPath, - DSHOW_PLUGIN_NAME_L L".dll")) { - auto pluginPath = replace(path, driverPath, driverInstallPath); - pluginsPaths.push_back(pluginPath); - } + if (!this->d->fileExists(path)) + return {}; std::vector pids; @@ -593,18 +476,14 @@ std::vector AkVCam::IpcBridge::clientsPids() const std::min(needed / sizeof(HMODULE), nElements); for (size_t j = 0; j < nModules; j++) { - WCHAR moduleName[MAX_PATH]; - memset(moduleName, 0, MAX_PATH * sizeof(WCHAR)); + CHAR moduleName[MAX_PATH]; + memset(moduleName, 0, MAX_PATH * sizeof(CHAR)); - if (GetModuleFileNameExW(processHnd, + if (GetModuleFileNameExA(processHnd, modules[j], moduleName, MAX_PATH)) { - auto pluginsIt = std::find(pluginsPaths.begin(), - pluginsPaths.end(), - std::wstring(moduleName)); - - if (pluginsIt != pluginsPaths.end()) { + if (moduleName == path) { auto pidsIt = std::find(pids.begin(), pids.end(), process[i]); @@ -645,634 +524,75 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const return exe; } -bool AkVCam::IpcBridge::needsRestart(Operation operation) const +std::string AkVCam::IpcBridge::addDevice(const std::wstring &description) { - return operation == OperationDestroyAll - || (operation == OperationDestroy - && this->devices().size() == 1); + return Preferences::addDevice(description); } -bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const +void AkVCam::IpcBridge::removeDevice(const std::string &deviceId) { - return this->clientsPids().empty() && !this->needsRestart(operation); + Preferences::removeCamera(deviceId); } -std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description, - const std::vector &formats) +void AkVCam::IpcBridge::addFormat(const std::string &deviceId, + const VideoFormat &format, + int index) { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); - if (!this->canApply(OperationCreate)) { - this->d->m_error = L"The driver is in use"; - - return {}; - } - - auto driverPath = this->d->locateDriverPath(); - - if (driverPath.empty()) { - this->d->m_error = L"Driver not found"; - - return {}; - } - - // Create a device path for the new device and add it's entry. - auto devicePath = createDevicePath(); - - if (devicePath.empty()) { - this->d->m_error = L"Can't create a device"; - - return {}; - } - - std::wstringstream ss; - ss << L"@echo off" << std::endl; - ss << L"chcp " << GetACP() << std::endl; - - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; - - // Copy all plugins - std::vector installPaths; - - for (auto path: this->d->findFiles(driverPath, - DSHOW_PLUGIN_NAME_L L".dll")) { - auto installPath = replace(path, driverPath, driverInstallPath); - - if (!isEqualFile(path, installPath)) - ss << L"mkdir \"" - << this->d->dirname(installPath) - << L"\"" - << std::endl - << L"copy /y \"" - << path - << L"\" \"" - << installPath - << L"\"" - << std::endl; - - installPaths.push_back(installPath); - } - - // Copy all services - std::vector assistantInstallPaths; - - for (auto path: this->d->findFiles(driverPath, - DSHOW_PLUGIN_ASSISTANT_NAME_L L".exe")) { - auto installPath = replace(path, driverPath, driverInstallPath); - - if (!isEqualFile(path, installPath)) - ss << L"mkdir \"" - << this->d->dirname(installPath) - << L"\"" - << std::endl - << L"copy /y \"" - << path - << L"\" \"" - << installPath - << L"\"" - << std::endl; - - assistantInstallPaths.push_back(installPath); - } - - // Copy shared files - for (auto path: this->d->findFiles(driverPath + L"/share")) { - auto installPath = replace(path, driverPath, driverInstallPath); - - if (!isEqualFile(path, installPath)) - ss << L"mkdir \"" - << this->d->dirname(installPath) - << L"\"" - << std::endl - << L"copy /y \"" - << path - << L"\" \"" - << installPath - << L"\"" - << std::endl; - } - - BOOL wow = isWow64(); - - // List cameras and create a line with the number of cameras. - auto nCameras = camerasCount(); - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras", - L"size", - int(nCameras + 1), - wow) - << std::endl; - - // Set camera path. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1), - L"path", - devicePath, - wow) - << std::endl; - - // Set description. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1), - L"description", - description, - wow) - << std::endl; - - // Set number of formats. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1) - + L"\\Formats", - L"size", - int(formats.size()), - wow) - << std::endl; - - // Setup formats. - for (size_t i = 0; i < formats.size(); i++) { - auto videoFormat = formats[i]; - auto format = VideoFormat::wstringFromFourcc(videoFormat.fourcc()); - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"format", - format, - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"width", - videoFormat.width(), - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"height", - videoFormat.height(), - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(nCameras + 1) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"fps", - videoFormat.minimumFrameRate().toWString(), - wow) - << std::endl; - } - - for (auto path: installPaths) - ss << L"regsvr32 /s \"" << path << L"\"" << std::endl; - - std::vector preferredArch; - - if (wow) - preferredArch.push_back(L"x64"); - - preferredArch.push_back(DSHOW_PLUGIN_ARCH_L); - - if (wcscmp(DSHOW_PLUGIN_ARCH_L, L"x64") == 0) - preferredArch.push_back(L"x32"); - - for (auto &arch: preferredArch) { - auto assistantPath = driverInstallPath - + L"\\" - + arch - + L"\\" DSHOW_PLUGIN_ASSISTANT_NAME_L L".exe"; - - if (std::find(assistantInstallPaths.begin(), - assistantInstallPaths.end(), - assistantPath) != assistantInstallPaths.end()) { - ss << "\"" << assistantPath << "\" --install" << std::endl; - - break; - } - } - - // Create the script. - auto temp = tempPath(); - auto scriptPath = std::string(temp.begin(), temp.end()) - + "\\device_create_" - + timeStamp() - + ".bat"; - std::wfstream script; - script.imbue(std::locale("")); - script.open(scriptPath, std::ios_base::out | std::ios_base::trunc); - - if (script.is_open()) { - script << ss.str(); - script.close(); - - // Execute the script with elevated privileges. - if (this->d->sudo({"cmd", "/c", scriptPath})) - devicePath.clear(); - - std::wstring wScriptPath(scriptPath.begin(), scriptPath.end()); - DeleteFile(wScriptPath.c_str()); - } else { - devicePath.clear(); - } - - return std::string(devicePath.begin(), devicePath.end()); + if (cameraIndex >= 0) + Preferences::cameraAddFormat(size_t(cameraIndex), + format, + index); } -bool AkVCam::IpcBridge::deviceEdit(const std::string &deviceId, - const std::wstring &description, - const std::vector &formats) +void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index) { AkLogFunction(); + auto cameraIndex = Preferences::cameraFromPath(deviceId); - if (!this->canApply(OperationEdit)) { - this->d->m_error = L"The driver is in use"; - - return {}; - } - - auto camera = cameraFromId(std::wstring(deviceId.begin(), deviceId.end())); - - if (camera < 0) - return false; - - auto driverPath = this->d->locateDriverPath(); - - if (driverPath.empty()) { - this->d->m_error = L"Driver not found"; - - return false; - } - - std::wstringstream ss; - ss << L"@echo off" << std::endl; - ss << L"chcp " << GetACP() << std::endl; - - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; - std::vector installPaths; - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_NAME_L L".dll")) { - auto installPath = replace(path, driverPath, driverInstallPath); - installPaths.push_back(installPath); - } - - BOOL wow = isWow64(); - - // Set camera path. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera), - L"path", - std::wstring(deviceId.begin(), deviceId.end()), - wow) - << std::endl; - - // Set description. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera), - L"description", - description, - wow) - << std::endl; - - // Set number of formats. - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera) - + L"\\Formats", - L"size", - int(formats.size()), - wow) - << std::endl; - - // Setup formats. - for (size_t i = 0; i < formats.size(); i++) { - auto videoFormat = formats[i]; - auto format = VideoFormat::wstringFromFourcc(videoFormat.fourcc()); - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"format", - format, - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"width", - videoFormat.width(), - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"height", - videoFormat.height(), - wow) - << std::endl; - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera) - + L"\\Formats\\" - + std::to_wstring(i + 1), - L"fps", - videoFormat.minimumFrameRate().toWString(), - wow) - << std::endl; - } - - for (auto path: installPaths) - ss << L"regsvr32 /s \"" << path << L"\"" << std::endl; - - // Create the script. - auto temp = tempPath(); - auto scriptPath = std::string(temp.begin(), temp.end()) - + "\\device_create_" - + timeStamp() - + ".bat"; - std::wfstream script; - script.imbue(std::locale("")); - script.open(scriptPath, std::ios_base::out | std::ios_base::trunc); - bool ok = false; - - if (script.is_open()) { - script << ss.str(); - script.close(); - ok = this->d->sudo({"cmd", "/c", scriptPath}) == 0; - std::wstring wScriptPath(scriptPath.begin(), scriptPath.end()); - DeleteFile(wScriptPath.c_str()); - } - - return ok; + if (cameraIndex >= 0) + Preferences::cameraRemoveFormat(size_t(cameraIndex), + index); } -bool AkVCam::IpcBridge::changeDescription(const std::string &deviceId, - const std::wstring &description) +void AkVCam::IpcBridge::updateDevices() { AkLogFunction(); + auto pluginPath = this->d->locatePluginPath(); + AkLogDebug() << "Plugin path: " << pluginPath << std::endl; - if (!this->canApply(OperationEdit)) { - this->d->m_error = L"The driver is in use"; + if (pluginPath.empty()) + return; - return false; - } + auto path = pluginPath + "\\" DSHOW_PLUGIN_NAME ".dll"; + AkLogDebug() << "Plugin binary: " << path << std::endl; - auto camera = cameraFromId(std::wstring(deviceId.begin(), deviceId.end())); + if (!this->d->fileExists(path)) + return; - if (camera < 0) - return false; + if (auto hmodule = LoadLibraryA(path.c_str())) { + auto registerServer = + RegisterServerFunc(GetProcAddress(hmodule, "DllRegisterServer")); - auto driverPath = this->d->locateDriverPath(); + if (registerServer) { + (*registerServer)(); - if (driverPath.empty()) { - this->d->m_error = L"Driver not found"; - - return false; - } - - std::wstringstream ss; - ss << L"@echo off" << std::endl; - ss << L"chcp " << GetACP() << std::endl; - - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; - std::vector installPaths; - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_NAME_L L".dll")) { - auto installPath = replace(path, driverPath, driverInstallPath); - installPaths.push_back(installPath); - } - - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera + 1), - L"description", - description, - isWow64()) - << std::endl; - - for (auto path: installPaths) - ss << L"regsvr32 /s \"" << path << L"\"" << std::endl; - - auto temp = tempPath(); - auto scriptPath = std::string(temp.begin(), temp.end()) - + "\\device_change_description_" - + timeStamp() - + ".bat"; - std::wfstream script; - script.imbue(std::locale("")); - script.open(scriptPath, std::ios_base::out | std::ios_base::trunc); - bool ok = false; - - if (script.is_open()) { - script << ss.str(); - script.close(); - ok = this->d->sudo({"cmd", "/c", scriptPath}) == 0; - std::wstring wScriptPath(scriptPath.begin(), scriptPath.end()); - DeleteFile(wScriptPath.c_str()); - } - - return ok; -} - -bool AkVCam::IpcBridge::deviceDestroy(const std::string &deviceId) -{ - AkLogFunction(); - - if (!this->canApply(OperationDestroy)) { - this->d->m_error = L"The driver is in use"; - - return false; - } - - auto camera = cameraFromId(std::wstring(deviceId.begin(), deviceId.end())); - - if (camera < 0) - return false; - - auto driverPath = this->d->locateDriverPath(); - - if (driverPath.empty()) { - this->d->m_error = L"Driver not found"; - - return false; - } - - std::wstringstream ss; - ss << L"@echo off" << std::endl; - ss << L"chcp " << GetACP() << std::endl; - - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; - std::vector installPaths; - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_NAME_L L".dll")) { - auto installPath = replace(path, driverPath, driverInstallPath); - - installPaths.push_back(installPath); - } - - std::vector assistantInstallPaths; - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_ASSISTANT_NAME_L L".exe")) { - auto installPath = replace(path, driverPath, driverInstallPath); - - assistantInstallPaths.push_back(installPath); - } - - BOOL wow = isWow64(); - - // List cameras and create a line with the number of cameras. - auto nCameras = camerasCount(); - - if (nCameras > 1) { - ss << this->d->regAddLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras", - L"size", - int(nCameras - 1), - wow) - << std::endl; - - ss << this->d->regDeleteLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(camera + 1), - wow) - << std::endl; - - for (DWORD i = DWORD(camera + 1); i < nCameras; i++) { - ss << this->d->regMoveLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(i + 1), - L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras\\" - + std::to_wstring(i), - wow) - << std::endl; + Message message; + message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE; + message.dataSize = 0; + this->d->m_mainServer.sendMessage(&message); } - for (auto path: installPaths) - ss << L"regsvr32 /s \"" << path << L"\"" << std::endl; - } else { - for (auto path: installPaths) - ss << L"regsvr32 /s /u \"" << path << L"\"" << std::endl; - - for (auto path: assistantInstallPaths) - ss << L"\"" << path << L"\" --uninstall" << std::endl; - - ss << this->d->regDeleteLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras", - wow) - << std::endl; - - if (lstrcmpi(driverPath.c_str(), driverInstallPath.c_str())) - ss << L"rmdir /s /q \"" << driverInstallPath << L"\"" << std::endl; + FreeLibrary(hmodule); } - - auto temp = tempPath(); - auto scriptPath = std::string(temp.begin(), temp.end()) - + "\\device_destroy_" - + timeStamp() - + ".bat"; - std::wfstream script; - script.imbue(std::locale("")); - script.open(scriptPath, std::ios_base::out | std::ios_base::trunc); - - if (script.is_open()) { - script << ss.str(); - script.close(); - this->d->sudo({"cmd", "/c", scriptPath}); - std::wstring wScriptPath(scriptPath.begin(), scriptPath.end()); - DeleteFile(wScriptPath.c_str()); - } - - return true; -} - -bool AkVCam::IpcBridge::destroyAllDevices() -{ - AkLogFunction(); - - if (!this->canApply(OperationDestroyAll)) { - this->d->m_error = L"The driver is in use"; - - return false; - } - - auto driverPath = this->d->locateDriverPath(); - - if (driverPath.empty()) { - this->d->m_error = L"Driver not found"; - - return false; - } - - std::wstringstream ss; - ss << L"@echo off" << std::endl; - ss << L"chcp " << GetACP() << std::endl; - - auto driverInstallPath = - programFilesPath() + L"\\" DSHOW_PLUGIN_NAME_L L".plugin"; - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_NAME_L L".dll")) { - auto installPath = replace(path, driverPath, driverInstallPath); - ss << L"regsvr32 /s /u \"" << installPath << L"\"" << std::endl; - } - - for (auto path: this->d->findFiles(std::wstring(driverPath.begin(), - driverPath.end()), - DSHOW_PLUGIN_ASSISTANT_NAME_L L".exe")) { - auto installPath = replace(path, driverPath, driverInstallPath); - ss << L"\"" << installPath << L"\" --uninstall" << std::endl; - } - - ss << this->d->regDeleteLine(L"HKLM\\SOFTWARE\\Webcamoid\\VirtualCamera\\Cameras", - isWow64()) - << std::endl; - - if (lstrcmpi(driverPath.c_str(), driverInstallPath.c_str())) - ss << "rmdir /s /q \"" << driverInstallPath << L"\"" << std::endl; - - auto temp = tempPath(); - auto scriptPath = std::string(temp.begin(), temp.end()) - + "\\device_remove_all_" - + timeStamp() - + ".bat"; - std::wfstream script; - script.imbue(std::locale("")); - script.open(scriptPath, std::ios_base::out | std::ios_base::trunc); - bool ok = false; - - if (script.is_open()) { - script << ss.str(); - script.close(); - ok = this->d->sudo({"cmd", "/c", scriptPath}) == 0; - std::wstring wScriptPath(scriptPath.begin(), scriptPath.end()); - DeleteFile(wScriptPath.c_str()); - } - - return ok; } bool AkVCam::IpcBridge::deviceStart(const std::string &deviceId, const VideoFormat &format) { - UNUSED(format) + UNUSED(format); AkLogFunction(); auto it = std::find(this->d->m_broadcasting.begin(), this->d->m_broadcasting.end(), @@ -1387,75 +707,9 @@ bool AkVCam::IpcBridge::write(const std::string &deviceId, return this->d->m_mainServer.sendMessage(&message) == TRUE; } -void AkVCam::IpcBridge::setMirroring(const std::string &deviceId, - bool horizontalMirrored, - bool verticalMirrored) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING; - message.dataSize = sizeof(MsgMirroring); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - data->hmirror = horizontalMirrored; - data->vmirror = verticalMirrored; - this->d->m_mainServer.sendMessage(&message); -} - -void AkVCam::IpcBridge::setScaling(const std::string &deviceId, - Scaling scaling) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING; - message.dataSize = sizeof(MsgScaling); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - data->scaling = scaling; - this->d->m_mainServer.sendMessage(&message); -} - -void AkVCam::IpcBridge::setAspectRatio(const std::string &deviceId, - AspectRatio aspectRatio) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO; - message.dataSize = sizeof(MsgAspectRatio); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - data->aspect = aspectRatio; - this->d->m_mainServer.sendMessage(&message); -} - -void AkVCam::IpcBridge::setSwapRgb(const std::string &deviceId, bool swap) -{ - AkLogFunction(); - - Message message; - message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB; - message.dataSize = sizeof(MsgSwapRgb); - auto data = messageData(&message); - memcpy(data->device, - deviceId.c_str(), - (std::min)(deviceId.size(), MAX_STRING)); - data->swap = swap; - this->d->m_mainServer.sendMessage(&message); -} - bool AkVCam::IpcBridge::addListener(const std::string &deviceId) { AkLogFunction(); - Message message; message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD; message.dataSize = sizeof(MsgListeners); @@ -1476,7 +730,6 @@ bool AkVCam::IpcBridge::addListener(const std::string &deviceId) bool AkVCam::IpcBridge::removeListener(const std::string &deviceId) { AkLogFunction(); - Message message; message.messageId = AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE; message.dataSize = sizeof(MsgListeners); @@ -1495,8 +748,7 @@ bool AkVCam::IpcBridge::removeListener(const std::string &deviceId) } AkVCam::IpcBridgePrivate::IpcBridgePrivate(IpcBridge *self): - self(self), - m_asClient(false) + self(self) { this->m_mainServer.setPipeName(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L); this->m_mainServer.setMode(MessageServer::ServerModeSend); @@ -1505,15 +757,16 @@ AkVCam::IpcBridgePrivate::IpcBridgePrivate(IpcBridge *self): this->updateDeviceSharedProperties(); this->m_messageHandlers = std::map { - {AKVCAM_ASSISTANT_MSG_ISALIVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::isAlive) }, - {AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(IpcBridgePrivate::frameReady) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(IpcBridgePrivate::setBroadcasting)}, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setMirror) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setScaling) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(IpcBridgePrivate::setAspectRatio) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(IpcBridgePrivate::setSwapRgb) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerAdd) }, - {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerRemove) }, + {AKVCAM_ASSISTANT_MSG_ISALIVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::isAlive) }, + {AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(IpcBridgePrivate::frameReady) }, + {AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(IpcBridgePrivate::pictureUpdated) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_CREATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceCreate) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceDestroy) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceUpdate) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerAdd) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerRemove) }, + {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setBroadcasting)}, + {AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(IpcBridgePrivate::controlsUpdated)}, }; } @@ -1522,368 +775,40 @@ AkVCam::IpcBridgePrivate::~IpcBridgePrivate() this->m_mainServer.stop(true); } -std::vector *AkVCam::IpcBridgePrivate::driverPaths() +const std::vector &AkVCam::IpcBridgePrivate::controls() const { - static std::vector paths; + static const std::vector scalingMenu { + "Fast", + "Linear" + }; + static const std::vector aspectRatioMenu { + "Ignore", + "Keep", + "Expanding" + }; + static const auto scalingMax = int(scalingMenu.size()) - 1; + static const auto aspectRatioMax = int(aspectRatioMenu.size()) - 1; - return &paths; + static const std::vector controls { + {"hflip" , "Horizontal Mirror", ControlTypeBoolean, 0, 1 , 1, 0, 0, {} }, + {"vflip" , "Vertical Mirror" , ControlTypeBoolean, 0, 1 , 1, 0, 0, {} }, + {"scaling" , "Scaling" , ControlTypeMenu , 0, scalingMax , 1, 0, 0, scalingMenu }, + {"aspect_ratio", "Aspect Ratio" , ControlTypeMenu , 0, aspectRatioMax, 1, 0, 0, aspectRatioMenu}, + {"swap_rgb" , "Swap RGB" , ControlTypeBoolean, 0, 1 , 1, 0, 0, {} }, + }; + + return controls; } -std::vector AkVCam::IpcBridgePrivate::listCameras() const +std::string AkVCam::IpcBridgePrivate::dirname(const std::string &path) { - std::vector cameras; - - // Create the System Device Enumerator. - ICreateDevEnum *deviceEnumerator = nullptr; - HRESULT hr = CoCreateInstance(CLSID_SystemDeviceEnum, - nullptr, - CLSCTX_INPROC_SERVER, - IID_ICreateDevEnum, - reinterpret_cast(&deviceEnumerator)); - - if (FAILED(hr)) - return cameras; - - // Create an enumerator for the category. - IEnumMoniker *enumMoniker = nullptr; - - if (deviceEnumerator->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, - &enumMoniker, - 0) == S_OK) { - enumMoniker->Reset(); - IMoniker *moniker = nullptr; - - while (enumMoniker->Next(1, &moniker, nullptr) == S_OK) - cameras.push_back(MonikerPtr(moniker, [](IMoniker *moniker) { - moniker->Release(); - })); - - enumMoniker->Release(); - } - - deviceEnumerator->Release(); - - return cameras; -} - -AkVCam::BaseFilterPtr AkVCam::IpcBridgePrivate::filter(IMoniker *moniker) const -{ - if (!moniker) - return {}; - - IBaseFilter *baseFilter = nullptr; - - if (FAILED(moniker->BindToObject(nullptr, - nullptr, - IID_IBaseFilter, - reinterpret_cast(&baseFilter)))) { - return {}; - } - - return BaseFilterPtr(baseFilter, [] (IBaseFilter *baseFilter) { - baseFilter->Release(); - }); -} - -AkVCam::PropertyBagPtr AkVCam::IpcBridgePrivate::propertyBag(IMoniker *moniker) const -{ - if (!moniker) - return {}; - - IPropertyBag *propertyBag = nullptr; - - if (FAILED(moniker->BindToStorage(nullptr, - nullptr, - IID_IPropertyBag, - reinterpret_cast(&propertyBag)))) { - return {}; - } - - return PropertyBagPtr(propertyBag, [] (IPropertyBag *propertyBag) { - propertyBag->Release(); - }); -} - -bool AkVCam::IpcBridgePrivate::isVirtualCamera(const MonikerPtr &moniker) const -{ - auto baseFilter = this->filter(moniker.get()); - - if (!baseFilter) - return false; - - return this->isVirtualCamera(baseFilter.get()); -} - -bool AkVCam::IpcBridgePrivate::isVirtualCamera(IBaseFilter *baseFilter) const -{ - if (!baseFilter) - return false; - - CLSID clsid; - memset(&clsid, 0, sizeof(CLSID)); - baseFilter->GetClassID(&clsid); - - return cameraFromId(clsid) >= 0; -} - -std::string AkVCam::IpcBridgePrivate::cameraPath(const MonikerPtr &moniker) const -{ - auto propertyBag = this->propertyBag(moniker.get()); - - return this->cameraPath(propertyBag.get()); -} - -std::string AkVCam::IpcBridgePrivate::cameraPath(IPropertyBag *propertyBag) const -{ - VARIANT var; - VariantInit(&var); - - if (FAILED(propertyBag->Read(L"DevicePath", &var, nullptr))) - return std::string(); - - std::wstring wstr(var.bstrVal); - std::string devicePath(wstr.begin(), wstr.end()); - VariantClear(&var); - - return devicePath; -} - -std::wstring AkVCam::IpcBridgePrivate::cameraDescription(const MonikerPtr &moniker) const -{ - auto propertyBag = this->propertyBag(moniker.get()); - - return this->cameraDescription(propertyBag.get()); -} - -std::wstring AkVCam::IpcBridgePrivate::cameraDescription(IPropertyBag *propertyBag) const -{ - VARIANT var; - VariantInit(&var); - - if (FAILED(propertyBag->Read(L"Description", &var, nullptr))) - if (FAILED(propertyBag->Read(L"FriendlyName", &var, nullptr))) - return {}; - - std::wstring wstr(var.bstrVal); - VariantClear(&var); - - return wstr; -} - -std::vector AkVCam::IpcBridgePrivate::enumPins(IBaseFilter *baseFilter) const -{ - std::vector pins; - IEnumPins *enumPins = nullptr; - - if (SUCCEEDED(baseFilter->EnumPins(&enumPins))) { - enumPins->Reset(); - IPin *pin = nullptr; - - while (enumPins->Next(1, &pin, nullptr) == S_OK) { - PIN_DIRECTION direction = PINDIR_INPUT; - - if (SUCCEEDED(pin->QueryDirection(&direction)) - && direction == PINDIR_OUTPUT) { - pins.push_back(PinPtr(pin, [] (IPin *pin) { - pin->Release(); - })); - - continue; - } - - pin->Release(); - } - - enumPins->Release(); - } - - return pins; -} - -std::vector AkVCam::IpcBridgePrivate::enumVideoFormats(IPin *pin) const -{ - std::vector mediaTypes; - IEnumMediaTypes *pEnum = nullptr; - - if (FAILED(pin->EnumMediaTypes(&pEnum))) - return mediaTypes; - - pEnum->Reset(); - AM_MEDIA_TYPE *mediaType = nullptr; - - while (pEnum->Next(1, &mediaType, nullptr) == S_OK) { - auto format = formatFromMediaType(mediaType); - deleteMediaType(&mediaType); - - if (format.size() > 0) - mediaTypes.push_back(format); - } - - pEnum->Release(); - - return mediaTypes; -} - -std::vector AkVCam::IpcBridgePrivate::findFiles(const std::wstring &path) const -{ - std::wstring path_ = path; - - auto attributes = GetFileAttributes(path.c_str()); - - if (attributes & FILE_ATTRIBUTE_DIRECTORY) - path_ += L"\\*"; - - WIN32_FIND_DATA data; - memset(&data, 0, sizeof(WIN32_FIND_DATA)); - auto find = FindFirstFile(path_.c_str(), &data); - - if (find == INVALID_HANDLE_VALUE) - return {}; - - std::vector paths; - - do { - std::wstring fileName(data.cFileName); - - if (fileName == L"." || fileName == L"..") - continue; - - std::wstring filePath = path + L"\\" + fileName; - - if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) - for (auto path: this->findFiles(filePath)) - paths.push_back(path); - else - paths.push_back(filePath); - } while (FindNextFile(find, &data)); - - FindClose(find); - - return paths; -} - -std::vector AkVCam::IpcBridgePrivate::findFiles(const std::string &path, - const std::string &fileName) const -{ - auto wfiles = - this->findFiles(std::wstring(path.begin(), path.end()), - std::wstring(fileName.begin(), fileName.end())); - - std::vector files; - - for (auto &file: wfiles) - files.push_back(std::string(file.begin(), file.end())); - - return files; -} - -std::vector AkVCam::IpcBridgePrivate::findFiles(const std::wstring &path, - const std::wstring &fileName) const -{ - std::vector plugins; - - for (auto file: this->findFiles(path)) { - auto pos = file.rfind(L"\\"); - auto fName = file.substr(pos + 1); - - if (!lstrcmpi(fName.c_str(), fileName.c_str())) - plugins.push_back(file); - } - - return plugins; -} - -std::wstring AkVCam::IpcBridgePrivate::regAddLine(const std::wstring &key, - const std::wstring &value, - const std::wstring &data, - BOOL wow) const -{ - std::wstringstream ss; - ss << L"reg add \"" - << key - << L"\" /v " - << value - << L" /d \"" - << data - << L"\" /f"; - - if (wow) - ss << L" /reg:64"; - - return ss.str(); -} - -std::wstring AkVCam::IpcBridgePrivate::regAddLine(const std::wstring &key, - const std::wstring &value, - int data, - BOOL wow) const -{ - std::wstringstream ss; - ss << L"reg add \"" - << key - << L"\" /v " - << value - << L" /t REG_DWORD" - << L" /d " - << data - << L" /f"; - - if (wow) - ss << L" /reg:64"; - - return ss.str(); -} - -std::wstring AkVCam::IpcBridgePrivate::regDeleteLine(const std::wstring &key, - BOOL wow) const -{ - std::wstringstream ss; - ss << L"reg delete \"" + key + L"\" /f"; - - if (wow) - ss << L" /reg:64"; - - return ss.str(); -} - -std::wstring AkVCam::IpcBridgePrivate::regDeleteLine(const std::wstring &key, - const std::wstring &value, - BOOL wow) const -{ - std::wstringstream ss; - ss << L"reg delete \"" + key + L"\" /v \"" + value + L"\" /f"; - - if (wow) - ss << L" /reg:64"; - - return ss.str(); -} - -std::wstring AkVCam::IpcBridgePrivate::regMoveLine(const std::wstring &fromKey, - const std::wstring &toKey, - BOOL wow) const -{ - std::wstringstream ss; - ss << L"reg copy \"" << fromKey << L"\" \"" << toKey << L"\" /s /f"; - - if (wow) - ss << L" /reg:64"; - - ss << std::endl - << regDeleteLine(fromKey, wow); - - return ss.str(); -} - -std::wstring AkVCam::IpcBridgePrivate::dirname(const std::wstring &path) const -{ - return path.substr(0, path.rfind(L"\\")); + return path.substr(0, path.rfind("\\")); } void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties() { - for (DWORD i = 0; i < camerasCount(); i++) { - auto cameraPath = AkVCam::cameraPath(i); + for (size_t i = 0; i < Preferences::camerasCount(); i++) { + auto cameraPath = Preferences::cameraPath(i); std::string deviceId(cameraPath.begin(), cameraPath.end()); Message message; @@ -1916,33 +841,29 @@ void AkVCam::IpcBridgePrivate::updateDeviceSharedProperties(const std::string &d } } -std::wstring AkVCam::IpcBridgePrivate::locateDriverPath() const +bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const { - std::wstring driverPath; + return GetFileAttributesA(path.c_str()) & FILE_ATTRIBUTE_ARCHIVE; +} - for (auto it = this->driverPaths()->rbegin(); - it != this->driverPaths()->rend(); - it++) { - auto path = *it; - path = replace(path, L"/", L"\\"); +std::string AkVCam::IpcBridgePrivate::locatePluginPath() +{ + AkLogFunction(); + char path[MAX_PATH]; + memset(path, 0, MAX_PATH); + HMODULE hmodule = nullptr; - if (path.back() != L'\\') - path += L'\\'; - - path += DSHOW_PLUGIN_NAME_L L".plugin"; - - if (this->findFiles(path, DSHOW_PLUGIN_NAME_L L".dll").empty()) - continue; - - if (this->findFiles(path, DSHOW_PLUGIN_ASSISTANT_NAME_L L".exe").empty()) - continue; - - driverPath = path; - - break; + 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); } - return driverPath; + if (strlen(path) < 1) + return {}; + + return dirname(path); } void AkVCam::IpcBridgePrivate::pipeStateChanged(void *userData, @@ -1955,7 +876,7 @@ void AkVCam::IpcBridgePrivate::pipeStateChanged(void *userData, case MessageServer::PipeStateAvailable: AkLogInfo() << "Server Available" << std::endl; - if (self->self->registerPeer(self->m_asClient)) { + if (self->self->registerPeer()) { AKVCAM_EMIT(self->self, ServerStateChanged, IpcBridge::ServerStateAvailable) @@ -1976,12 +897,14 @@ void AkVCam::IpcBridgePrivate::pipeStateChanged(void *userData, void AkVCam::IpcBridgePrivate::isAlive(Message *message) { + AkLogFunction(); auto data = messageData(message); data->alive = true; } void AkVCam::IpcBridgePrivate::frameReady(Message *message) { + AkLogFunction(); auto data = messageData(message); std::string deviceId(data->device); @@ -2006,8 +929,59 @@ void AkVCam::IpcBridgePrivate::frameReady(Message *message) AKVCAM_EMIT(this->self, FrameReady, deviceId, videoFrame) } +void AkVCam::IpcBridgePrivate::pictureUpdated(Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + AKVCAM_EMIT(this->self, + PictureChanged, + std::string(data->picture)) +} + +void AkVCam::IpcBridgePrivate::deviceCreate(Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + AKVCAM_EMIT(this->self, DeviceAdded, std::string(data->device)) +} + +void AkVCam::IpcBridgePrivate::deviceDestroy(Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + AKVCAM_EMIT(this->self, DeviceAdded, std::string(data->device)) +} + +void AkVCam::IpcBridgePrivate::deviceUpdate(Message *message) +{ + UNUSED(message); + AkLogFunction(); + AKVCAM_EMIT(this->self, DevicesUpdated, nullptr) +} + +void AkVCam::IpcBridgePrivate::listenerAdd(Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + AKVCAM_EMIT(this->self, + ListenerAdded, + std::string(data->device), + std::string(data->listener)) +} + +void AkVCam::IpcBridgePrivate::listenerRemove(Message *message) +{ + AkLogFunction(); + auto data = messageData(message); + AKVCAM_EMIT(this->self, + ListenerRemoved, + std::string(data->device), + std::string(data->listener)) +} + void AkVCam::IpcBridgePrivate::setBroadcasting(Message *message) { + AkLogFunction(); auto data = messageData(message); std::string deviceId(data->device); std::string broadcaster(data->broadcaster); @@ -2015,105 +989,21 @@ void AkVCam::IpcBridgePrivate::setBroadcasting(Message *message) AKVCAM_EMIT(this->self, BroadcastingChanged, deviceId, broadcaster) } -void AkVCam::IpcBridgePrivate::setMirror(Message *message) +void AkVCam::IpcBridgePrivate::controlsUpdated(Message *message) { - auto data = messageData(message); + AkLogFunction(); + auto data = messageData(message); std::string deviceId(data->device); - AKVCAM_EMIT(this->self, - MirrorChanged, - deviceId, - data->hmirror, - data->vmirror) -} - -void AkVCam::IpcBridgePrivate::setScaling(Message *message) -{ - auto data = messageData(message); - std::string deviceId(data->device); - AKVCAM_EMIT(this->self, ScalingChanged, deviceId, data->scaling) -} - -void AkVCam::IpcBridgePrivate::setAspectRatio(Message *message) -{ - auto data = messageData(message); - std::string deviceId(data->device); - AKVCAM_EMIT(this->self, AspectRatioChanged, deviceId, data->aspect) -} - -void AkVCam::IpcBridgePrivate::setSwapRgb(Message *message) -{ - auto data = messageData(message); - std::string deviceId(data->device); - AKVCAM_EMIT(this->self, SwapRgbChanged, deviceId, data->swap) -} - -void AkVCam::IpcBridgePrivate::listenerAdd(Message *message) -{ - auto data = messageData(message); - std::string deviceId(data->device); - AKVCAM_EMIT(this->self, - ListenerAdded, - deviceId, - std::string(data->listener)) -} - -void AkVCam::IpcBridgePrivate::listenerRemove(Message *message) -{ - auto data = messageData(message); - std::string deviceId(data->device); - AKVCAM_EMIT(this->self, - ListenerRemoved, - deviceId, - std::string(data->listener)) -} - -int AkVCam::IpcBridgePrivate::sudo(const std::vector ¶meters, - const std::wstring &directory, - bool show) -{ - if (parameters.size() < 1) - return E_FAIL; - - auto command = parameters[0]; - std::wstring wcommand(command.begin(), command.end()); - std::wstring wparameters; - - for (size_t i = 1; i < parameters.size(); i++) { - auto param = parameters[i]; - - if (i > 1) - wparameters += L" "; - - wparameters += std::wstring(param.begin(), param.end()); - } - - SHELLEXECUTEINFO execInfo; - memset(&execInfo, 0, sizeof(SHELLEXECUTEINFO)); - execInfo.cbSize = sizeof(SHELLEXECUTEINFO); - execInfo.fMask = SEE_MASK_NOCLOSEPROCESS; - execInfo.hwnd = nullptr; - execInfo.lpVerb = L"runas"; - execInfo.lpFile = wcommand.data(); - execInfo.lpParameters = wparameters.data(); - execInfo.lpDirectory = directory.data(); - execInfo.nShow = show? SW_SHOWNORMAL: SW_HIDE; - execInfo.hInstApp = nullptr; - ShellExecuteEx(&execInfo); - - if (!execInfo.hProcess) { - this->m_error = L"Failed executing script"; - - return E_FAIL; - } - - WaitForSingleObject(execInfo.hProcess, INFINITE); - - DWORD exitCode; - GetExitCodeProcess(execInfo.hProcess, &exitCode); - CloseHandle(execInfo.hProcess); - - if (FAILED(exitCode)) - this->m_error = L"Script failed with code " + std::to_wstring(exitCode); - - return int(exitCode); + auto cameraIndex = Preferences::cameraFromPath(deviceId); + + if (cameraIndex < 0) + return; + + std::map controls; + + for (auto &control: this->controls()) + controls[control.id] = + Preferences::cameraControlValue(size_t(cameraIndex), control.id); + + AKVCAM_EMIT(this->self, ControlsChanged, deviceId, controls) } diff --git a/dshow/VirtualCamera/VirtualCamera.pro b/dshow/VirtualCamera/VirtualCamera.pro index 8216252..a720f51 100644 --- a/dshow/VirtualCamera/VirtualCamera.pro +++ b/dshow/VirtualCamera/VirtualCamera.pro @@ -52,7 +52,6 @@ LIBS += \ -lwinmm TARGET = $${DSHOW_PLUGIN_NAME} - TEMPLATE = lib HEADERS += \ diff --git a/dshow/VirtualCamera/src/basefilter.cpp b/dshow/VirtualCamera/src/basefilter.cpp index e0b445e..fd83684 100644 --- a/dshow/VirtualCamera/src/basefilter.cpp +++ b/dshow/VirtualCamera/src/basefilter.cpp @@ -113,15 +113,11 @@ void AkVCam::BaseFilter::addPin(const std::vector &formats, { AkLogFunction(); this->d->m_pins->addPin(new Pin(this, formats, pinName), changed); - - if (this->d->m_pins->count() == 1) - this->d->m_ipcBridge.connectService(true); } void AkVCam::BaseFilter::removePin(IPin *pin, bool changed) { AkLogFunction(); - this->d->m_ipcBridge.disconnectService(); this->d->m_pins->removePin(pin, changed); } diff --git a/dshow/VirtualCamera/src/plugin.cpp b/dshow/VirtualCamera/src/plugin.cpp index c4e5956..8cbdb91 100644 --- a/dshow/VirtualCamera/src/plugin.cpp +++ b/dshow/VirtualCamera/src/plugin.cpp @@ -20,6 +20,7 @@ #include "plugin.h" #include "plugininterface.h" #include "classfactory.h" +#include "PlatformUtils/src/preferences.h" #include "PlatformUtils/src/utils.h" #include "VCamUtils/src/utils.h" @@ -33,24 +34,20 @@ inline AkVCam::PluginInterface *pluginInterface() // Filter entry point BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) { - UNUSED(lpvReserved) - AkLogFunction(); - auto logLevel = - AkVCam::regReadInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); - AkVCam::Logger::setLogLevel(logLevel); + UNUSED(lpvReserved); + AkLogFunction(); + auto loglevel = AkVCam::Preferences::logLevel(); + AkVCam::Logger::setLogLevel(loglevel); - if (AkVCam::Logger::logLevel() > AKVCAM_LOGLEVEL_DEFAULT) { + if (loglevel > AKVCAM_LOGLEVEL_DEFAULT) { // Turn on lights freopen("CONOUT$", "a", stdout); freopen("CONOUT$", "a", stderr); setbuf(stdout, nullptr); } - auto temp = AkVCam::tempPath(); - auto logFile = - AkVCam::regReadString("logfile", - std::string(temp.begin(), temp.end()) - + "\\" DSHOW_PLUGIN_NAME ".log"); + auto defaultLogFile = AkVCam::tempPath() + "\\" DSHOW_PLUGIN_NAME ".log"; + auto logFile = AkVCam::Preferences::readString("logfile", defaultLogFile); AkVCam::Logger::setLogFile(logFile); switch (fdwReason) {