Now the Windows plugin can load PNG, JPEG and other image formats as a
place holder picture. Settings moved from HKLM to HKCU, now it should be possible to register the filter per user instead of globally, this way it won't require administrative privileges. Notify to the clients about virtual devices changes.
This commit is contained in:
parent
1cf50519bc
commit
7d38a15856
8 changed files with 146 additions and 19 deletions
|
@ -338,11 +338,11 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
|
||||||
CGImageRelease(cgImage);
|
CGImageRelease(cgImage);
|
||||||
|
|
||||||
AkLogDebug() << "Picture loaded as: "
|
AkLogDebug() << "Picture loaded as: "
|
||||||
<< VideoFormat::stringFromFourcc(videoFormat.fourcc())
|
<< VideoFormat::stringFromFourcc(frame.format().fourcc())
|
||||||
<< " "
|
<< " "
|
||||||
<< videoFormat.width()
|
<< frame.format().width()
|
||||||
<< "x"
|
<< "x"
|
||||||
<< videoFormat.height()
|
<< frame.format().height()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
|
|
|
@ -45,7 +45,8 @@ LIBS = \
|
||||||
-ladvapi32 \
|
-ladvapi32 \
|
||||||
-lkernel32 \
|
-lkernel32 \
|
||||||
-lgdi32 \
|
-lgdi32 \
|
||||||
-lshell32
|
-lshell32 \
|
||||||
|
-lwindowscodecs
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
src/messageserver.cpp \
|
src/messageserver.cpp \
|
||||||
|
|
|
@ -230,10 +230,10 @@ void AkVCam::Preferences::deleteKey(const std::string &key)
|
||||||
splitSubKey(key, subKey, val);
|
splitSubKey(key, subKey, val);
|
||||||
|
|
||||||
if (val.empty()) {
|
if (val.empty()) {
|
||||||
deleteTree(HKEY_LOCAL_MACHINE, subKey.c_str(), KEY_WOW64_64KEY);
|
deleteTree(HKEY_CURRENT_USER, subKey.c_str(), KEY_WOW64_64KEY);
|
||||||
} else {
|
} else {
|
||||||
HKEY hkey = nullptr;
|
HKEY hkey = nullptr;
|
||||||
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
|
||||||
subKey.c_str(),
|
subKey.c_str(),
|
||||||
0,
|
0,
|
||||||
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
|
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
|
||||||
|
@ -255,7 +255,7 @@ void AkVCam::Preferences::move(const std::string &keyFrom,
|
||||||
|
|
||||||
std::string subKeyFrom = REG_PREFIX "\\" + keyFrom;
|
std::string subKeyFrom = REG_PREFIX "\\" + keyFrom;
|
||||||
HKEY hkeyFrom = nullptr;
|
HKEY hkeyFrom = nullptr;
|
||||||
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
|
||||||
subKeyFrom.c_str(),
|
subKeyFrom.c_str(),
|
||||||
0,
|
0,
|
||||||
KEY_READ | KEY_WOW64_64KEY,
|
KEY_READ | KEY_WOW64_64KEY,
|
||||||
|
@ -264,7 +264,7 @@ void AkVCam::Preferences::move(const std::string &keyFrom,
|
||||||
if (result == ERROR_SUCCESS) {
|
if (result == ERROR_SUCCESS) {
|
||||||
std::string subKeyTo = REG_PREFIX "\\" + keyTo;
|
std::string subKeyTo = REG_PREFIX "\\" + keyTo;
|
||||||
HKEY hkeyTo = nullptr;
|
HKEY hkeyTo = nullptr;
|
||||||
result = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
|
result = RegCreateKeyExA(HKEY_CURRENT_USER,
|
||||||
subKeyTo.c_str(),
|
subKeyTo.c_str(),
|
||||||
0,
|
0,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
@ -655,7 +655,7 @@ bool AkVCam::Preferences::readValue(const std::string &key,
|
||||||
std::string val;
|
std::string val;
|
||||||
splitSubKey(key, subKey, val);
|
splitSubKey(key, subKey, val);
|
||||||
HKEY hkey = nullptr;
|
HKEY hkey = nullptr;
|
||||||
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
|
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
|
||||||
subKey.c_str(),
|
subKey.c_str(),
|
||||||
0,
|
0,
|
||||||
KEY_READ | KEY_WOW64_64KEY,
|
KEY_READ | KEY_WOW64_64KEY,
|
||||||
|
@ -685,7 +685,7 @@ void AkVCam::Preferences::setValue(const std::string &key,
|
||||||
std::string val;
|
std::string val;
|
||||||
splitSubKey(key, subKey, val);
|
splitSubKey(key, subKey, val);
|
||||||
HKEY hkey = nullptr;
|
HKEY hkey = nullptr;
|
||||||
LONG result = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
|
LONG result = RegCreateKeyExA(HKEY_CURRENT_USER,
|
||||||
subKey.c_str(),
|
subKey.c_str(),
|
||||||
0,
|
0,
|
||||||
nullptr,
|
nullptr,
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include <dvdmedia.h>
|
#include <dvdmedia.h>
|
||||||
#include <comdef.h>
|
#include <comdef.h>
|
||||||
#include <shlobj.h>
|
#include <shlobj.h>
|
||||||
|
#include <wincodec.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "VCamUtils/src/utils.h"
|
#include "VCamUtils/src/utils.h"
|
||||||
|
@ -966,8 +967,68 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
|
||||||
return frame;
|
return frame;
|
||||||
}
|
}
|
||||||
|
|
||||||
AkLogDebug() << "Error loading picture: "
|
IWICImagingFactory *imagingFactory = nullptr;
|
||||||
<< fileName
|
auto hr = CoCreateInstance(CLSID_WICImagingFactory,
|
||||||
|
NULL,
|
||||||
|
CLSCTX_INPROC_SERVER,
|
||||||
|
IID_PPV_ARGS(&imagingFactory));
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
auto wfileName = stringToWSTR(fileName);
|
||||||
|
IWICBitmapDecoder *decoder = nullptr;
|
||||||
|
hr = imagingFactory->CreateDecoderFromFilename(wfileName,
|
||||||
|
nullptr,
|
||||||
|
GENERIC_READ,
|
||||||
|
WICDecodeMetadataCacheOnLoad,
|
||||||
|
&decoder);
|
||||||
|
CoTaskMemFree(wfileName);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
IWICBitmapFrameDecode *bmpFrame = nullptr;
|
||||||
|
hr = decoder->GetFrame(0, &bmpFrame);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
IWICFormatConverter *formatConverter = nullptr;
|
||||||
|
hr = imagingFactory->CreateFormatConverter(&formatConverter);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
hr = formatConverter->Initialize(bmpFrame,
|
||||||
|
GUID_WICPixelFormat24bppRGB,
|
||||||
|
WICBitmapDitherTypeNone,
|
||||||
|
nullptr,
|
||||||
|
0.0,
|
||||||
|
WICBitmapPaletteTypeMedianCut);
|
||||||
|
|
||||||
|
if (SUCCEEDED(hr)) {
|
||||||
|
UINT width = 0;
|
||||||
|
UINT height = 0;
|
||||||
|
formatConverter->GetSize(&width, &height);
|
||||||
|
VideoFormat videoFormat(PixelFormatRGB24, width, height);
|
||||||
|
frame = VideoFrame(videoFormat);
|
||||||
|
formatConverter->CopyPixels(nullptr,
|
||||||
|
3 * width,
|
||||||
|
frame.data().size(),
|
||||||
|
frame.data().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
formatConverter->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
bmpFrame->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
imagingFactory->Release();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkLogDebug() << "Picture loaded as: "
|
||||||
|
<< VideoFormat::stringFromFourcc(frame.format().fourcc())
|
||||||
|
<< " "
|
||||||
|
<< frame.format().width()
|
||||||
|
<< "x"
|
||||||
|
<< frame.format().height()
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
|
|
||||||
return frame;
|
return frame;
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <dshow.h>
|
#include <dshow.h>
|
||||||
|
#include <dbt.h>
|
||||||
|
|
||||||
#include "basefilter.h"
|
#include "basefilter.h"
|
||||||
#include "enumpins.h"
|
#include "enumpins.h"
|
||||||
|
@ -75,6 +76,10 @@ namespace AkVCam
|
||||||
static void frameReady(void *userData,
|
static void frameReady(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const VideoFrame &frame);
|
const VideoFrame &frame);
|
||||||
|
static void pictureChanged(void *userData,
|
||||||
|
const std::string &picture);
|
||||||
|
static void devicesChanged(void *userData,
|
||||||
|
const std::vector<std::string> &devices);
|
||||||
static void setBroadcasting(void *userData,
|
static void setBroadcasting(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const std::string &broadcasting);
|
const std::string &broadcasting);
|
||||||
|
@ -357,8 +362,12 @@ AkVCam::BaseFilterPrivate::BaseFilterPrivate(AkVCam::BaseFilter *self,
|
||||||
|
|
||||||
this->m_ipcBridge.connectServerStateChanged(this,
|
this->m_ipcBridge.connectServerStateChanged(this,
|
||||||
&BaseFilterPrivate::serverStateChanged);
|
&BaseFilterPrivate::serverStateChanged);
|
||||||
|
this->m_ipcBridge.connectDevicesChanged(this,
|
||||||
|
&BaseFilterPrivate::devicesChanged);
|
||||||
this->m_ipcBridge.connectFrameReady(this,
|
this->m_ipcBridge.connectFrameReady(this,
|
||||||
&BaseFilterPrivate::frameReady);
|
&BaseFilterPrivate::frameReady);
|
||||||
|
this->m_ipcBridge.connectPictureChanged(this,
|
||||||
|
&BaseFilterPrivate::pictureChanged);
|
||||||
this->m_ipcBridge.connectBroadcastingChanged(this,
|
this->m_ipcBridge.connectBroadcastingChanged(this,
|
||||||
&BaseFilterPrivate::setBroadcasting);
|
&BaseFilterPrivate::setBroadcasting);
|
||||||
this->m_ipcBridge.connectControlsChanged(this,
|
this->m_ipcBridge.connectControlsChanged(this,
|
||||||
|
@ -445,6 +454,40 @@ void AkVCam::BaseFilterPrivate::frameReady(void *userData,
|
||||||
AkVCamDevicePinCall(deviceId, self, frameReady, frame);
|
AkVCamDevicePinCall(deviceId, self, frameReady, frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::pictureChanged(void *userData,
|
||||||
|
const std::string &picture)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
auto self = reinterpret_cast<BaseFilterPrivate *>(userData);
|
||||||
|
IEnumPins *pins = nullptr;
|
||||||
|
self->self->EnumPins(&pins);
|
||||||
|
|
||||||
|
if (pins) {
|
||||||
|
AkVCamPinCall(pins, setPicture, picture)
|
||||||
|
pins->Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::BaseFilterPrivate::devicesChanged(void *userData,
|
||||||
|
const std::vector<std::string> &devices)
|
||||||
|
{
|
||||||
|
UNUSED(userData);
|
||||||
|
UNUSED(devices);
|
||||||
|
AkLogFunction();
|
||||||
|
std::vector<HWND> handlers;
|
||||||
|
EnumWindows([] (HWND handler, LPARAM userData) -> BOOL {
|
||||||
|
auto handlers =
|
||||||
|
reinterpret_cast<std::vector<HWND> *>(userData);
|
||||||
|
handlers->push_back(handler);
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
},
|
||||||
|
reinterpret_cast<LPARAM>(&handlers));
|
||||||
|
|
||||||
|
for (auto &handler: handlers)
|
||||||
|
SendMessage(handler, WM_DEVICECHANGE, DBT_DEVNODES_CHANGED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::BaseFilterPrivate::setBroadcasting(void *userData,
|
void AkVCam::BaseFilterPrivate::setBroadcasting(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const std::string &broadcaster)
|
const std::string &broadcaster)
|
||||||
|
|
|
@ -290,6 +290,20 @@ void AkVCam::Pin::frameReady(const VideoFrame &frame)
|
||||||
this->d->m_mutex.unlock();
|
this->d->m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::Pin::setPicture(const std::string &picture)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
AkLogDebug() << "Picture: " << picture;
|
||||||
|
this->d->m_testFrame = loadPicture(picture);
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
|
||||||
|
if (this->d->m_broadcaster.empty())
|
||||||
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::Pin::setBroadcasting(const std::string &broadcaster)
|
void AkVCam::Pin::setBroadcasting(const std::string &broadcaster)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
|
@ -49,6 +49,7 @@ namespace AkVCam
|
||||||
static HRESULT stateChanged(void *userData, FILTER_STATE state);
|
static HRESULT stateChanged(void *userData, FILTER_STATE state);
|
||||||
void serverStateChanged(IpcBridge::ServerState state);
|
void serverStateChanged(IpcBridge::ServerState state);
|
||||||
void frameReady(const VideoFrame &frame);
|
void frameReady(const VideoFrame &frame);
|
||||||
|
void setPicture(const std::string &picture);
|
||||||
void setBroadcasting(const std::string &broadcaster);
|
void setBroadcasting(const std::string &broadcaster);
|
||||||
void setControls(const std::map<std::string, int> &controls);
|
void setControls(const std::map<std::string, int> &controls);
|
||||||
bool horizontalFlip() const;
|
bool horizontalFlip() const;
|
||||||
|
|
|
@ -26,6 +26,14 @@
|
||||||
#include "PlatformUtils/src/utils.h"
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/utils.h"
|
#include "VCamUtils/src/utils.h"
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
#define ROOT_HKEY HKEY_CURRENT_USER
|
||||||
|
#define SUBKEY_PREFIX "Software\\Classes\\CLSID"
|
||||||
|
#else
|
||||||
|
#define ROOT_HKEY HKEY_CLASSES_ROOT
|
||||||
|
#define SUBKEY_PREFIX "CLSID"
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
{
|
{
|
||||||
class PluginInterfacePrivate
|
class PluginInterfacePrivate
|
||||||
|
@ -70,11 +78,11 @@ bool AkVCam::PluginInterface::registerServer(const std::string &deviceId,
|
||||||
AkLogInfo() << "Description: " << description << std::endl;
|
AkLogInfo() << "Description: " << description << std::endl;
|
||||||
AkLogInfo() << "Filename: " << fileName << std::endl;
|
AkLogInfo() << "Filename: " << fileName << std::endl;
|
||||||
|
|
||||||
auto subkey = "CLSID\\" + clsid;
|
auto subkey = SUBKEY_PREFIX "\\" + clsid;
|
||||||
|
|
||||||
HKEY keyCLSID = nullptr;
|
HKEY keyCLSID = nullptr;
|
||||||
HKEY keyServerType = nullptr;
|
HKEY keyServerType = nullptr;
|
||||||
LONG result = RegCreateKeyA(HKEY_CLASSES_ROOT, subkey.c_str(), &keyCLSID);
|
LONG result = RegCreateKeyA(ROOT_HKEY, subkey.c_str(), &keyCLSID);
|
||||||
bool ok = false;
|
bool ok = false;
|
||||||
|
|
||||||
if (result != ERROR_SUCCESS)
|
if (result != ERROR_SUCCESS)
|
||||||
|
@ -140,8 +148,8 @@ void AkVCam::PluginInterface::unregisterServer(const CLSID &clsid) const
|
||||||
|
|
||||||
auto clsidStr = stringFromClsid(clsid);
|
auto clsidStr = stringFromClsid(clsid);
|
||||||
AkLogInfo() << "CLSID: " << clsidStr << std::endl;
|
AkLogInfo() << "CLSID: " << clsidStr << std::endl;
|
||||||
auto subkey = "CLSID\\" + clsidStr;
|
auto subkey = SUBKEY_PREFIX "\\" + clsidStr;
|
||||||
deleteTree(HKEY_CLASSES_ROOT, subkey.c_str(), 0);
|
deleteTree(ROOT_HKEY, subkey.c_str(), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::PluginInterface::registerFilter(const std::string &deviceId,
|
bool AkVCam::PluginInterface::registerFilter(const std::string &deviceId,
|
||||||
|
@ -254,15 +262,14 @@ bool AkVCam::PluginInterface::setDevicePath(const std::string &deviceId) const
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
std::string subKey =
|
std::string subKey =
|
||||||
"CLSID\\"
|
SUBKEY_PREFIX "\\"
|
||||||
+ stringFromIid(CLSID_VideoInputDeviceCategory)
|
+ stringFromIid(CLSID_VideoInputDeviceCategory)
|
||||||
+ "\\Instance\\"
|
+ "\\Instance\\"
|
||||||
+ createClsidStrFromStr(deviceId);
|
+ createClsidStrFromStr(deviceId);
|
||||||
AkLogInfo() << "Key: HKEY_CLASSES_ROOT" << std::endl;
|
|
||||||
AkLogInfo() << "SubKey: " << subKey << std::endl;
|
AkLogInfo() << "SubKey: " << subKey << std::endl;
|
||||||
|
|
||||||
HKEY hKey = nullptr;
|
HKEY hKey = nullptr;
|
||||||
auto result = RegOpenKeyExA(HKEY_CLASSES_ROOT,
|
auto result = RegOpenKeyExA(ROOT_HKEY,
|
||||||
subKey.c_str(),
|
subKey.c_str(),
|
||||||
0,
|
0,
|
||||||
KEY_ALL_ACCESS,
|
KEY_ALL_ACCESS,
|
||||||
|
|
Loading…
Reference in a new issue