Working in the DirectShow plugin.

This commit is contained in:
Gonzalo Exequiel Pedone 2020-10-02 12:58:39 -03:00
parent 1ce2384623
commit bd5e1d4e94
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
20 changed files with 1382 additions and 2295 deletions

View file

@ -262,12 +262,10 @@ AkVCam::CmdParser::CmdParser()
"", "",
"Show clients using the camera.", "Show clients using the camera.",
AKVCAM_BIND_FUNC(CmdParserPrivate::showClients)); AKVCAM_BIND_FUNC(CmdParserPrivate::showClients));
this->d->m_ipcBridge.connectService();
} }
AkVCam::CmdParser::~CmdParser() AkVCam::CmdParser::~CmdParser()
{ {
this->d->m_ipcBridge.disconnectService();
delete this->d; delete this->d;
} }

View file

@ -104,10 +104,6 @@ namespace AkVCam
int logLevel() const; int logLevel() const;
void setLogLevel(int logLevel); void setLogLevel(int logLevel);
// Manage main service connection.
void connectService();
void disconnectService();
// Register the peer to the global server. // Register the peer to the global server.
bool registerPeer(); bool registerPeer();

View file

@ -54,10 +54,6 @@
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 #define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
#define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402 #define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402
// Connections
#define AKVCAM_ASSISTANT_MSG_CONNECTIONS 0x500
#define AKVCAM_ASSISTANT_MSG_SETCONNECTIONS 0x501
namespace AkVCam namespace AkVCam
{ {
using XpcMessage = std::function<void (xpc_connection_t, xpc_object_t)>; using XpcMessage = std::function<void (xpc_connection_t, xpc_object_t)>;

View file

@ -361,7 +361,7 @@ void AkVCam::Preferences::removeCamera(const std::string &path)
if (cameraIndex < 0) if (cameraIndex < 0)
return; return;
cameraSetFormats(cameraIndex, {}); cameraSetFormats(size_t(cameraIndex), {});
auto nCameras = camerasCount(); auto nCameras = camerasCount();
deleteAllKeys("cameras." + std::to_string(cameraIndex)); deleteAllKeys("cameras." + std::to_string(cameraIndex));
@ -451,6 +451,7 @@ void AkVCam::Preferences::cameraSetDescription(size_t cameraIndex,
write("cameras." + std::to_string(cameraIndex) + ".description", write("cameras." + std::to_string(cameraIndex) + ".description",
description); description);
sync();
} }
std::string AkVCam::Preferences::cameraPath(size_t cameraIndex) std::string AkVCam::Preferences::cameraPath(size_t cameraIndex)
@ -536,7 +537,7 @@ void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex,
auto formats = cameraFormats(cameraIndex); auto formats = cameraFormats(cameraIndex);
if (index < 0 || index > int(formats.size())) if (index < 0 || index > int(formats.size()))
index = formats.size(); index = int(formats.size());
formats.insert(formats.begin() + index, format); formats.insert(formats.begin() + index, format);
write("cameras." write("cameras."
@ -563,7 +564,6 @@ void AkVCam::Preferences::cameraAddFormat(size_t cameraIndex,
void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index) void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
{ {
AkLogFunction(); AkLogFunction();
auto formats = cameraFormats(cameraIndex); auto formats = cameraFormats(cameraIndex);
if (index < 0 || index >= int(formats.size())) if (index < 0 || index >= int(formats.size()))
@ -592,26 +592,6 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
sync(); 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, int AkVCam::Preferences::cameraControlValue(size_t cameraIndex,
const std::string &key) const std::string &key)
{ {
@ -623,4 +603,27 @@ void AkVCam::Preferences::cameraSetControlValue(size_t cameraIndex,
int value) int value)
{ {
write("cameras." + std::to_string(cameraIndex) + ".controls." + key, 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();
} }

View file

@ -74,8 +74,6 @@ namespace AkVCam
std::vector<VideoFormat> cameraFormats(size_t cameraIndex); std::vector<VideoFormat> cameraFormats(size_t cameraIndex);
void cameraSetFormats(size_t cameraIndex, void cameraSetFormats(size_t cameraIndex,
const std::vector<VideoFormat> &formats); const std::vector<VideoFormat> &formats);
void cameraFormats(size_t cameraIndex,
const std::vector<VideoFormat> &formats);
void cameraAddFormat(size_t cameraIndex, void cameraAddFormat(size_t cameraIndex,
const VideoFormat &format, const VideoFormat &format,
int index); int index);

View file

@ -80,11 +80,7 @@ namespace AkVCam
void connectionInterrupted(); void connectionInterrupted();
// Utility methods // Utility methods
std::string homePath() const;
bool fileExists(const std::wstring &path) const;
bool fileExists(const std::string &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(); static std::string locatePluginPath();
private: private:
@ -148,30 +144,10 @@ void AkVCam::IpcBridge::setLogLevel(int logLevel)
Logger::setLogLevel(logLevel); Logger::setLogLevel(logLevel);
} }
void AkVCam::IpcBridge::connectService()
{
AkLogFunction();
this->registerPeer();
}
void AkVCam::IpcBridge::disconnectService()
{
AkLogFunction();
this->unregisterPeer();
}
bool AkVCam::IpcBridge::registerPeer() bool AkVCam::IpcBridge::registerPeer()
{ {
AkLogFunction(); 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) if (this->d->m_serverMessagePort)
return true; return true;
@ -318,7 +294,10 @@ std::wstring AkVCam::IpcBridge::description(const std::string &deviceId) const
AkLogFunction(); AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId); 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, void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
@ -327,7 +306,8 @@ void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
AkLogFunction(); AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId); auto cameraIndex = Preferences::cameraFromPath(deviceId);
return Preferences::cameraSetDescription(cameraIndex, description); if (cameraIndex >= 0)
Preferences::cameraSetDescription(size_t(cameraIndex), description);
} }
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(StreamType type) const std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(StreamType type) const
@ -355,7 +335,10 @@ std::vector<AkVCam::VideoFormat> AkVCam::IpcBridge::formats(const std::string &d
AkLogFunction(); AkLogFunction();
auto cameraIndex = Preferences::cameraFromPath(deviceId); 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, 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); 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 std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const
@ -409,7 +393,7 @@ std::vector<AkVCam::DeviceControl> AkVCam::IpcBridge::controls(const std::string
for (auto &control: this->d->controls()) { for (auto &control: this->d->controls()) {
controls.push_back(control); controls.push_back(control);
controls.back().value = controls.back().value =
Preferences::cameraControlValue(cameraIndex, control.id); Preferences::cameraControlValue(size_t(cameraIndex), control.id);
} }
return controls; return controls;
@ -428,13 +412,14 @@ void AkVCam::IpcBridge::setControls(const std::string &deviceId,
for (auto &control: this->d->controls()) { for (auto &control: this->d->controls()) {
auto oldValue = auto oldValue =
Preferences::cameraControlValue(cameraIndex, control.id); Preferences::cameraControlValue(size_t(cameraIndex),
control.id);
if (controls.count(control.id)) { if (controls.count(control.id)) {
auto newValue = controls.at(control.id); auto newValue = controls.at(control.id);
if (newValue != oldValue) { if (newValue != oldValue) {
Preferences::cameraSetControlValue(cameraIndex, Preferences::cameraSetControlValue(size_t(cameraIndex),
control.id, control.id,
newValue); newValue);
updated = true; updated = true;
@ -490,13 +475,13 @@ std::vector<std::string> AkVCam::IpcBridge::listeners(const std::string &deviceI
std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const
{ {
AkLogFunction(); AkLogFunction();
auto driverPath = this->d->locatePluginPath(); auto pluginPath = this->d->locatePluginPath();
AkLogDebug() << "Plugin path: " << driverPath << std::endl; AkLogDebug() << "Plugin path: " << pluginPath << std::endl;
if (driverPath.empty()) if (pluginPath.empty())
return {}; return {};
auto path = driverPath + "/Contents/MacOS/" CMIO_PLUGIN_NAME; auto path = pluginPath + "/Contents/MacOS/" CMIO_PLUGIN_NAME;
AkLogDebug() << "Plugin binary: " << path << std::endl; AkLogDebug() << "Plugin binary: " << path << std::endl;
if (!this->d->fileExists(path)) if (!this->d->fileExists(path))
@ -553,16 +538,22 @@ void AkVCam::IpcBridge::addFormat(const std::string &deviceId,
int index) int index)
{ {
AkLogFunction(); AkLogFunction();
Preferences::cameraAddFormat(Preferences::cameraFromPath(deviceId), auto cameraIndex = Preferences::cameraFromPath(deviceId);
format,
index); if (cameraIndex >= 0)
Preferences::cameraAddFormat(size_t(cameraIndex),
format,
index);
} }
void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index) void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index)
{ {
AkLogFunction(); AkLogFunction();
Preferences::cameraRemoveFormat(Preferences::cameraFromPath(deviceId), auto cameraIndex = Preferences::cameraFromPath(deviceId);
index);
if (cameraIndex >= 0)
Preferences::cameraRemoveFormat(size_t(cameraIndex),
index);
} }
void AkVCam::IpcBridge::updateDevices() void AkVCam::IpcBridge::updateDevices()
@ -578,7 +569,6 @@ void AkVCam::IpcBridge::updateDevices()
AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE); AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary); xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
xpc_release(dictionary); xpc_release(dictionary);
} }
bool AkVCam::IpcBridge::deviceStart(const std::string &deviceId, bool AkVCam::IpcBridge::deviceStart(const std::string &deviceId,
@ -957,11 +947,15 @@ void AkVCam::IpcBridgePrivate::controlsUpdated(xpc_connection_t client,
std::string deviceId = std::string deviceId =
xpc_dictionary_get_string(event, "device"); xpc_dictionary_get_string(event, "device");
auto cameraIndex = Preferences::cameraFromPath(deviceId); auto cameraIndex = Preferences::cameraFromPath(deviceId);
if (cameraIndex < 0)
return;
std::map<std::string, int> controls; std::map<std::string, int> controls;
for (auto &control: this->controls()) for (auto &control: this->controls())
controls[control.id] = controls[control.id] =
Preferences::cameraControlValue(cameraIndex, control.id); Preferences::cameraControlValue(size_t(cameraIndex), control.id);
for (auto bridge: this->m_bridges) for (auto bridge: this->m_bridges)
AKVCAM_EMIT(bridge, 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 bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const
{ {
struct stat stats; struct stat stats;
@ -1052,62 +1031,6 @@ bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const
return stat(path.c_str(), &stats) == 0; 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() std::string AkVCam::IpcBridgePrivate::locatePluginPath()
{ {
AkLogFunction(); AkLogFunction();

View file

@ -157,7 +157,6 @@ AkVCam::PluginInterface::PluginInterface():
this->d->m_ref = 0; this->d->m_ref = 0;
this->d->m_reserved = 0; this->d->m_reserved = 0;
this->d->m_ipcBridge.connectService();
this->d->m_ipcBridge.connectServerStateChanged(this, &PluginInterface::serverStateChanged); this->d->m_ipcBridge.connectServerStateChanged(this, &PluginInterface::serverStateChanged);
this->d->m_ipcBridge.connectDeviceAdded(this, &PluginInterface::deviceAdded); this->d->m_ipcBridge.connectDeviceAdded(this, &PluginInterface::deviceAdded);
this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved); this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved);
@ -170,7 +169,6 @@ AkVCam::PluginInterface::PluginInterface():
AkVCam::PluginInterface::~PluginInterface() AkVCam::PluginInterface::~PluginInterface()
{ {
this->d->m_ipcBridge.disconnectService();
delete this->d->pluginInterface; delete this->d->pluginInterface;
delete this->d; delete this->d;
} }

View file

@ -21,18 +21,17 @@
#include <windows.h> #include <windows.h>
#include "service.h" #include "service.h"
#include "PlatformUtils/src/preferences.h"
#include "PlatformUtils/src/utils.h" #include "PlatformUtils/src/utils.h"
#include "VCamUtils/src/logger/logger.h" #include "VCamUtils/src/logger/logger.h"
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
auto loglevel = AkVCam::regReadInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); auto loglevel = AkVCam::Preferences::logLevel();
AkVCam::Logger::setLogLevel(loglevel); AkVCam::Logger::setLogLevel(loglevel);
auto temp = AkVCam::tempPath(); auto defaultLogFile = AkVCam::tempPath()
auto logFile = + "\\" DSHOW_PLUGIN_ASSISTANT_NAME ".log";
AkVCam::regReadString("logfile", auto logFile = AkVCam::Preferences::readString("logfile", defaultLogFile);
std::string(temp.begin(), temp.end())
+ "\\" DSHOW_PLUGIN_ASSISTANT_NAME ".log");
AkVCam::Logger::setLogFile(logFile); AkVCam::Logger::setLogFile(logFile);
AkVCam::Service service; AkVCam::Service service;

View file

@ -42,20 +42,6 @@ namespace AkVCam
{ {
std::string broadcaster; std::string broadcaster;
std::vector<std::string> listeners; std::vector<std::string> 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<std::string, std::string> AssistantPeers; typedef std::map<std::string, std::string> AssistantPeers;
@ -85,20 +71,15 @@ namespace AkVCam
void addPort(Message *message); void addPort(Message *message);
void removePort(Message *message); void removePort(Message *message);
void setBroadCasting(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 frameReady(Message *message);
void pictureUpdated(Message *message);
void deviceUpdate(Message *message);
void listeners(Message *message); void listeners(Message *message);
void listener(Message *message); void listener(Message *message);
void broadcasting(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 listenerAdd(Message *message);
void listenerRemove(Message *message); void listenerRemove(Message *message);
void controlsUpdated(Message *message);
}; };
GLOBAL_STATIC(ServicePrivate, servicePrivate) GLOBAL_STATIC(ServicePrivate, servicePrivate)
@ -245,7 +226,7 @@ void AkVCam::Service::debug()
void AkVCam::Service::showHelp(int argc, char **argv) void AkVCam::Service::showHelp(int argc, char **argv)
{ {
AkLogFunction(); AkLogFunction();
UNUSED(argc) UNUSED(argc);
auto programName = strrchr(argv[0], '\\'); auto programName = strrchr(argv[0], '\\');
@ -285,24 +266,19 @@ AkVCam::ServicePrivate::ServicePrivate()
this->m_statusHandler = nullptr; this->m_statusHandler = nullptr;
this->m_messageServer.setPipeName(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L); this->m_messageServer.setPipeName(L"\\\\.\\pipe\\" DSHOW_PLUGIN_ASSISTANT_NAME_L);
this->m_messageServer.setHandlers({ this->m_messageServer.setHandlers({
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) }, {AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(ServicePrivate::frameReady) },
{AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) }, {AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(ServicePrivate::pictureUpdated) },
{AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) }, {AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(ServicePrivate::requestPort) },
{AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) }, {AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(ServicePrivate::addPort) },
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) }, {AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(ServicePrivate::removePort) },
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) }, {AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(ServicePrivate::deviceUpdate) },
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) }, {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(ServicePrivate::listenerAdd) },
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) }, {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(ServicePrivate::listenerRemove) },
{AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) }, {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(ServicePrivate::listeners) },
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)}, {AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(ServicePrivate::listener) },
{AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::mirroring) }, {AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::broadcasting) },
{AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(ServicePrivate::setMirroring) }, {AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(ServicePrivate::setBroadCasting)},
{AKVCAM_ASSISTANT_MSG_DEVICE_SCALING , AKVCAM_BIND_FUNC(ServicePrivate::scaling) }, {AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(ServicePrivate::controlsUpdated)},
{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) },
}); });
this->m_timer.setInterval(60000); this->m_timer.setInterval(60000);
this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers); this->m_timer.connectTimeout(this, &ServicePrivate::checkPeers);
@ -311,7 +287,7 @@ AkVCam::ServicePrivate::ServicePrivate()
void AkVCam::ServicePrivate::stateChanged(void *userData, void AkVCam::ServicePrivate::stateChanged(void *userData,
MessageServer::State state) MessageServer::State state)
{ {
UNUSED(userData) UNUSED(userData);
switch (state) { switch (state) {
case MessageServer::StateAboutToStart: case MessageServer::StateAboutToStart:
@ -368,7 +344,6 @@ void AkVCam::ServicePrivate::sendStatus(DWORD currentState,
DWORD wait) DWORD wait)
{ {
AkLogFunction(); AkLogFunction();
this->m_status.dwControlsAccepted = this->m_status.dwControlsAccepted =
currentState == SERVICE_START_PENDING? 0: SERVICE_ACCEPT_STOP; currentState == SERVICE_START_PENDING? 0: SERVICE_ACCEPT_STOP;
this->m_status.dwCurrentState = currentState; this->m_status.dwCurrentState = currentState;
@ -460,11 +435,8 @@ void AkVCam::ServicePrivate::requestPort(AkVCam::Message *message)
AkLogFunction(); AkLogFunction();
auto data = messageData<MsgRequestPort>(message); auto data = messageData<MsgRequestPort>(message);
std::string portName = data->client? std::string portName = AKVCAM_ASSISTANT_CLIENT_NAME;
AKVCAM_ASSISTANT_CLIENT_NAME:
AKVCAM_ASSISTANT_SERVER_NAME;
portName += std::to_string(this->id()); portName += std::to_string(this->id());
AkLogInfo() << "Returning Port: " << portName << std::endl; AkLogInfo() << "Returning Port: " << portName << std::endl;
memcpy(data->port, memcpy(data->port,
portName.c_str(), portName.c_str(),
@ -547,112 +519,6 @@ void AkVCam::ServicePrivate::setBroadCasting(AkVCam::Message *message)
this->m_peerMutex.unlock(); this->m_peerMutex.unlock();
} }
void AkVCam::ServicePrivate::setMirroring(AkVCam::Message *message)
{
AkLogFunction();
auto data = messageData<MsgMirroring>(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<MsgScaling>(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<MsgAspectRatio>(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<MsgSwapRgb>(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) void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message)
{ {
AkLogFunction(); AkLogFunction();
@ -664,6 +530,28 @@ void AkVCam::ServicePrivate::frameReady(AkVCam::Message *message)
this->m_peerMutex.unlock(); 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) void AkVCam::ServicePrivate::listeners(AkVCam::Message *message)
{ {
AkLogFunction(); AkLogFunction();
@ -726,59 +614,6 @@ void AkVCam::ServicePrivate::broadcasting(AkVCam::Message *message)
data->status = true; data->status = true;
} }
void AkVCam::ServicePrivate::mirroring(AkVCam::Message *message)
{
AkLogFunction();
auto data = messageData<MsgMirroring>(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<MsgScaling>(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<MsgAspectRatio>(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<MsgSwapRgb>(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) void AkVCam::ServicePrivate::listenerAdd(AkVCam::Message *message)
{ {
AkLogFunction(); 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 WINAPI controlHandler(DWORD control,
DWORD eventType, DWORD eventType,
LPVOID eventData, LPVOID eventData,
LPVOID context) LPVOID context)
{ {
UNUSED(eventType) UNUSED(eventType);
UNUSED(eventData) UNUSED(eventData);
UNUSED(context) UNUSED(context);
AkLogFunction(); AkLogFunction();
DWORD result = ERROR_CALL_NOT_IMPLEMENTED; DWORD result = ERROR_CALL_NOT_IMPLEMENTED;
@ -896,8 +742,8 @@ BOOL WINAPI controlDebugHandler(DWORD control)
void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv) void WINAPI serviceMain(DWORD dwArgc, LPTSTR *lpszArgv)
{ {
UNUSED(dwArgc) UNUSED(dwArgc);
UNUSED(lpszArgv) UNUSED(lpszArgv);
AkLogFunction(); AkLogFunction();
AkLogInfo() << "Setting service control handler" << std::endl; AkLogInfo() << "Setting service control handler" << std::endl;

View file

@ -50,6 +50,7 @@ LIBS = \
SOURCES = \ SOURCES = \
src/messageserver.cpp \ src/messageserver.cpp \
src/mutex.cpp \ src/mutex.cpp \
src/preferences.cpp \
src/utils.cpp \ src/utils.cpp \
src/sharedmemory.cpp src/sharedmemory.cpp
@ -57,6 +58,7 @@ HEADERS = \
src/messagecommons.h \ src/messagecommons.h \
src/messageserver.h \ src/messageserver.h \
src/mutex.h \ src/mutex.h \
src/preferences.h \
src/utils.h \ src/utils.h \
src/sharedmemory.h src/sharedmemory.h

View file

@ -30,38 +30,33 @@
#define AKVCAM_ASSISTANT_SERVER_NAME "AkVCam_Server" #define AKVCAM_ASSISTANT_SERVER_NAME "AkVCam_Server"
// General messages // General messages
#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000 #define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000
#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001 #define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001
#define AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED 0x002
// Assistant messages // Assistant messages
#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100 #define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100
#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101 #define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101
#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102 #define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102
// Device control and information // Device control and information
#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200 #define AKVCAM_ASSISTANT_MSG_DEVICES 0x200
#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201 #define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202 #define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203 #define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203
#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204 #define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204
#define AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE 0x205
// Device listeners controls // Device listeners controls
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300 #define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301 #define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302 #define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303 #define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303
// Device dynamic properties // Device dynamic properties
#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400 #define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401 #define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
#define AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING 0x402 #define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 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 MSG_BUFFER_SIZE 4096 #define MSG_BUFFER_SIZE 4096
#define MAX_STRING 1024 #define MAX_STRING 1024
@ -136,7 +131,6 @@ namespace AkVCam
struct MsgRequestPort struct MsgRequestPort
{ {
bool client;
char port[MAX_STRING]; char port[MAX_STRING];
}; };
@ -152,6 +146,16 @@ namespace AkVCam
char port[MAX_STRING]; char port[MAX_STRING];
}; };
struct MsgDeviceAdded
{
char device[MAX_STRING];
};
struct MsgDeviceRemoved
{
char device[MAX_STRING];
};
struct MsgBroadcasting struct MsgBroadcasting
{ {
char device[MAX_STRING]; char device[MAX_STRING];
@ -159,35 +163,6 @@ namespace AkVCam
bool status; 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 struct MsgListeners
{ {
char device[MAX_STRING]; char device[MAX_STRING];
@ -206,6 +181,16 @@ namespace AkVCam
char device[MAX_STRING]; char device[MAX_STRING];
char port[MAX_STRING]; char port[MAX_STRING];
}; };
struct MsgPictureUpdated
{
char picture[MAX_STRING];
};
struct MsgControlsUpdated
{
char device[MAX_STRING];
};
} }
#endif // MESSAGECOMMONS_H #endif // MESSAGECOMMONS_H

View file

@ -375,7 +375,7 @@ void AkVCam::MessageServerPrivate::checkLoop()
this->m_pipeName.end()) this->m_pipeName.end())
<< std::endl; << std::endl;
this->m_pipeState = AkVCam::MessageServer::PipeStateAvailable; 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 } else if (!result
&& this->m_pipeState != AkVCam::MessageServer::PipeStateGone && this->m_pipeState != AkVCam::MessageServer::PipeStateGone
&& GetLastError() != ERROR_SEM_TIMEOUT) { && GetLastError() != ERROR_SEM_TIMEOUT) {
@ -384,7 +384,7 @@ void AkVCam::MessageServerPrivate::checkLoop()
this->m_pipeName.end()) this->m_pipeName.end())
<< std::endl; << std::endl;
this->m_pipeState = AkVCam::MessageServer::PipeStateGone; 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) if (!this->m_running)

View file

@ -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 <http://www.gnu.org/licenses/>.
*
* Web-Site: http://webcamoid.github.io/
*/
#include <algorithm>
#include <codecvt>
#include <locale>
#include <sstream>
#include <windows.h>
#include <winreg.h>
#include <uuids.h>
#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<const char *>(&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<std::string> &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<CLSID> AkVCam::Preferences::listRegisteredCameras(HINSTANCE hinstDLL)
{
WCHAR *strIID = nullptr;
StringFromIID(CLSID_VideoInputDeviceCategory, &strIID);
std::wstringstream ss;
ss << L"CLSID\\"
<< strIID
<< L"\\Instance";
CoTaskMemFree(strIID);
HKEY key = nullptr;
auto result = 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<CLSID> 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<VideoFormat> &formats)
{
return addCamera("", description, formats);
}
std::string AkVCam::Preferences::addCamera(const std::string &path,
const std::wstring &description,
const std::vector<VideoFormat> &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<std::string> 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::VideoFormat> AkVCam::Preferences::cameraFormats(size_t cameraIndex)
{
AkLogFunction();
std::vector<AkVCam::VideoFormat> 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<AkVCam::VideoFormat> &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<std::codecvt_utf8_utf16<wchar_t>> 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<std::codecvt_utf8_utf16<wchar_t>> cv;
auto wval = cv.from_bytes(val);
RegSetValueW(hkey,
wval.c_str(),
dataType,
data,
dataSize);
RegCloseKey(hkey);
}

View file

@ -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 <http://www.gnu.org/licenses/>.
*
* Web-Site: http://webcamoid.github.io/
*/
#ifndef PREFERENCES_H
#define PREFERENCES_H
#include <memory>
#include <string>
#include <vector>
#include <strmif.h>
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<std::string> &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<CLSID> listRegisteredCameras(HINSTANCE hinstDLL);
void deleteKey(const std::string &key);
void move(const std::string &keyFrom, const std::string &keyTo);
std::string addDevice(const std::wstring &description);
std::string addCamera(const std::wstring &description,
const std::vector<VideoFormat> &formats);
std::string addCamera(const std::string &path,
const std::wstring &description,
const std::vector<VideoFormat> &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<VideoFormat> cameraFormats(size_t cameraIndex);
void cameraSetFormats(size_t cameraIndex,
const std::vector<VideoFormat> &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

View file

@ -95,31 +95,41 @@ BOOL AkVCam::isWow64()
return isWow64; return isWow64;
} }
std::wstring AkVCam::tempPath() std::string AkVCam::tempPath()
{ {
WCHAR tempPath[MAX_PATH]; CHAR tempPath[MAX_PATH];
memset(tempPath, 0, MAX_PATH * sizeof(WCHAR)); memset(tempPath, 0, MAX_PATH * sizeof(CHAR));
GetTempPath(MAX_PATH, tempPath); GetTempPathA(MAX_PATH, tempPath);
return std::wstring(tempPath); return std::string(tempPath);
} }
std::wstring AkVCam::programFilesPath() std::wstring AkVCam::programFilesPath()
{ {
WCHAR programFiles[MAX_PATH];
DWORD programFilesSize = MAX_PATH * sizeof(WCHAR);
memset(programFiles, 0, programFilesSize);
bool ok = false; 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() if (result == ERROR_SUCCESS) {
&& regGetValue(HKEY_LOCAL_MACHINE, result = RegGetValue(hkey,
L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion", nullptr,
L"ProgramFilesDir", L"ProgramFilesDir",
RRF_RT_REG_SZ, RRF_RT_REG_SZ,
nullptr, nullptr,
&programFiles, &programFiles,
&programFilesSize) == ERROR_SUCCESS) &programFilesSize);
ok = true; if (isWow64())
ok = true;
RegCloseKey(hkey);
}
if (!ok) if (!ok)
SHGetSpecialFolderPath(nullptr, SHGetSpecialFolderPath(nullptr,
@ -391,16 +401,15 @@ AM_MEDIA_TYPE *AkVCam::mediaTypeFromFormat(const AkVCam::VideoFormat &format)
memset(videoInfo, 0, sizeof(VIDEOINFO)); memset(videoInfo, 0, sizeof(VIDEOINFO));
auto fps = format.minimumFrameRate(); auto fps = format.minimumFrameRate();
// Initialize info header. // Initialize info header.
videoInfo->rcSource = {0, 0, 0, 0}; videoInfo->rcSource = {0, 0, 0, 0};
videoInfo->rcTarget = videoInfo->rcSource; videoInfo->rcTarget = videoInfo->rcSource;
videoInfo->dwBitRate = DWORD(8 videoInfo->dwBitRate = DWORD(8
* frameSize * frameSize
* fps.num() * size_t(fps.num())
/ fps.den()); / size_t(fps.den()));
videoInfo->AvgTimePerFrame = REFERENCE_TIME(TIME_BASE videoInfo->AvgTimePerFrame = REFERENCE_TIME(TIME_BASE / fps.value());
* fps.den()
/ fps.num());
// Initialize bitmap header. // Initialize bitmap header.
videoInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); videoInfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
@ -783,405 +792,3 @@ std::string AkVCam::stringFromMediaSample(IMediaSample *mediaSample)
return ss.str(); 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<CLSID> 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<CLSID> 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<std::wstring> 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::VideoFormat> AkVCam::cameraFormats(DWORD cameraIndex)
{
std::vector<AkVCam::VideoFormat> formats;
for (DWORD i = 0; i < formatsCount(cameraIndex); i++) {
auto videoFormat = cameraFormat(cameraIndex, i);
if (videoFormat)
formats.push_back(videoFormat);
}
return formats;
}

View file

@ -34,7 +34,7 @@ namespace AkVCam
class VideoFormat; class VideoFormat;
BOOL isWow64(); BOOL isWow64();
std::wstring tempPath(); std::string tempPath();
std::wstring programFilesPath(); std::wstring programFilesPath();
std::wstring moduleFileNameW(HINSTANCE hinstDLL); std::wstring moduleFileNameW(HINSTANCE hinstDLL);
std::string moduleFileName(HINSTANCE hinstDLL); std::string moduleFileName(HINSTANCE hinstDLL);
@ -69,29 +69,6 @@ namespace AkVCam
std::string stringFromFormatType(const GUID &formatType); std::string stringFromFormatType(const GUID &formatType);
std::string stringFromMediaType(const AM_MEDIA_TYPE *mediaType); std::string stringFromMediaType(const AM_MEDIA_TYPE *mediaType);
std::string stringFromMediaSample(IMediaSample *mediaSample); 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<CLSID> 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<VideoFormat> cameraFormats(DWORD cameraIndex);
} }
#endif // PLATFORM_UTILS_H #endif // PLATFORM_UTILS_H

File diff suppressed because it is too large Load diff

View file

@ -52,7 +52,6 @@ LIBS += \
-lwinmm -lwinmm
TARGET = $${DSHOW_PLUGIN_NAME} TARGET = $${DSHOW_PLUGIN_NAME}
TEMPLATE = lib TEMPLATE = lib
HEADERS += \ HEADERS += \

View file

@ -113,15 +113,11 @@ void AkVCam::BaseFilter::addPin(const std::vector<AkVCam::VideoFormat> &formats,
{ {
AkLogFunction(); AkLogFunction();
this->d->m_pins->addPin(new Pin(this, formats, pinName), changed); 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) void AkVCam::BaseFilter::removePin(IPin *pin, bool changed)
{ {
AkLogFunction(); AkLogFunction();
this->d->m_ipcBridge.disconnectService();
this->d->m_pins->removePin(pin, changed); this->d->m_pins->removePin(pin, changed);
} }

View file

@ -20,6 +20,7 @@
#include "plugin.h" #include "plugin.h"
#include "plugininterface.h" #include "plugininterface.h"
#include "classfactory.h" #include "classfactory.h"
#include "PlatformUtils/src/preferences.h"
#include "PlatformUtils/src/utils.h" #include "PlatformUtils/src/utils.h"
#include "VCamUtils/src/utils.h" #include "VCamUtils/src/utils.h"
@ -33,24 +34,20 @@ inline AkVCam::PluginInterface *pluginInterface()
// Filter entry point // Filter entry point
BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{ {
UNUSED(lpvReserved) UNUSED(lpvReserved);
AkLogFunction(); AkLogFunction();
auto logLevel = auto loglevel = AkVCam::Preferences::logLevel();
AkVCam::regReadInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT); AkVCam::Logger::setLogLevel(loglevel);
AkVCam::Logger::setLogLevel(logLevel);
if (AkVCam::Logger::logLevel() > AKVCAM_LOGLEVEL_DEFAULT) { if (loglevel > AKVCAM_LOGLEVEL_DEFAULT) {
// Turn on lights // Turn on lights
freopen("CONOUT$", "a", stdout); freopen("CONOUT$", "a", stdout);
freopen("CONOUT$", "a", stderr); freopen("CONOUT$", "a", stderr);
setbuf(stdout, nullptr); setbuf(stdout, nullptr);
} }
auto temp = AkVCam::tempPath(); auto defaultLogFile = AkVCam::tempPath() + "\\" DSHOW_PLUGIN_NAME ".log";
auto logFile = auto logFile = AkVCam::Preferences::readString("logfile", defaultLogFile);
AkVCam::regReadString("logfile",
std::string(temp.begin(), temp.end())
+ "\\" DSHOW_PLUGIN_NAME ".log");
AkVCam::Logger::setLogFile(logFile); AkVCam::Logger::setLogFile(logFile);
switch (fdwReason) { switch (fdwReason) {