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:
Gonzalo Exequiel Pedone 2020-10-07 16:27:38 -03:00
parent 1cf50519bc
commit 7d38a15856
No known key found for this signature in database
GPG key ID: B8B09E63E9B85BAF
8 changed files with 146 additions and 19 deletions

View file

@ -338,11 +338,11 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
CGImageRelease(cgImage);
AkLogDebug() << "Picture loaded as: "
<< VideoFormat::stringFromFourcc(videoFormat.fourcc())
<< VideoFormat::stringFromFourcc(frame.format().fourcc())
<< " "
<< videoFormat.width()
<< frame.format().width()
<< "x"
<< videoFormat.height()
<< frame.format().height()
<< std::endl;
return frame;

View file

@ -45,7 +45,8 @@ LIBS = \
-ladvapi32 \
-lkernel32 \
-lgdi32 \
-lshell32
-lshell32 \
-lwindowscodecs
SOURCES = \
src/messageserver.cpp \

View file

@ -230,10 +230,10 @@ void AkVCam::Preferences::deleteKey(const std::string &key)
splitSubKey(key, subKey, val);
if (val.empty()) {
deleteTree(HKEY_LOCAL_MACHINE, subKey.c_str(), KEY_WOW64_64KEY);
deleteTree(HKEY_CURRENT_USER, subKey.c_str(), KEY_WOW64_64KEY);
} else {
HKEY hkey = nullptr;
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
subKey.c_str(),
0,
KEY_ALL_ACCESS | KEY_WOW64_64KEY,
@ -255,7 +255,7 @@ void AkVCam::Preferences::move(const std::string &keyFrom,
std::string subKeyFrom = REG_PREFIX "\\" + keyFrom;
HKEY hkeyFrom = nullptr;
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
subKeyFrom.c_str(),
0,
KEY_READ | KEY_WOW64_64KEY,
@ -264,7 +264,7 @@ void AkVCam::Preferences::move(const std::string &keyFrom,
if (result == ERROR_SUCCESS) {
std::string subKeyTo = REG_PREFIX "\\" + keyTo;
HKEY hkeyTo = nullptr;
result = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
result = RegCreateKeyExA(HKEY_CURRENT_USER,
subKeyTo.c_str(),
0,
nullptr,
@ -655,7 +655,7 @@ bool AkVCam::Preferences::readValue(const std::string &key,
std::string val;
splitSubKey(key, subKey, val);
HKEY hkey = nullptr;
auto result = RegOpenKeyExA(HKEY_LOCAL_MACHINE,
auto result = RegOpenKeyExA(HKEY_CURRENT_USER,
subKey.c_str(),
0,
KEY_READ | KEY_WOW64_64KEY,
@ -685,7 +685,7 @@ void AkVCam::Preferences::setValue(const std::string &key,
std::string val;
splitSubKey(key, subKey, val);
HKEY hkey = nullptr;
LONG result = RegCreateKeyExA(HKEY_LOCAL_MACHINE,
LONG result = RegCreateKeyExA(HKEY_CURRENT_USER,
subKey.c_str(),
0,
nullptr,

View file

@ -25,6 +25,7 @@
#include <dvdmedia.h>
#include <comdef.h>
#include <shlobj.h>
#include <wincodec.h>
#include "utils.h"
#include "VCamUtils/src/utils.h"
@ -966,8 +967,68 @@ AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
return frame;
}
AkLogDebug() << "Error loading picture: "
<< fileName
IWICImagingFactory *imagingFactory = nullptr;
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;
return frame;

View file

@ -19,6 +19,7 @@
#include <algorithm>
#include <dshow.h>
#include <dbt.h>
#include "basefilter.h"
#include "enumpins.h"
@ -75,6 +76,10 @@ namespace AkVCam
static void frameReady(void *userData,
const std::string &deviceId,
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,
const std::string &deviceId,
const std::string &broadcasting);
@ -357,8 +362,12 @@ AkVCam::BaseFilterPrivate::BaseFilterPrivate(AkVCam::BaseFilter *self,
this->m_ipcBridge.connectServerStateChanged(this,
&BaseFilterPrivate::serverStateChanged);
this->m_ipcBridge.connectDevicesChanged(this,
&BaseFilterPrivate::devicesChanged);
this->m_ipcBridge.connectFrameReady(this,
&BaseFilterPrivate::frameReady);
this->m_ipcBridge.connectPictureChanged(this,
&BaseFilterPrivate::pictureChanged);
this->m_ipcBridge.connectBroadcastingChanged(this,
&BaseFilterPrivate::setBroadcasting);
this->m_ipcBridge.connectControlsChanged(this,
@ -445,6 +454,40 @@ void AkVCam::BaseFilterPrivate::frameReady(void *userData,
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,
const std::string &deviceId,
const std::string &broadcaster)

View file

@ -290,6 +290,20 @@ void AkVCam::Pin::frameReady(const VideoFrame &frame)
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)
{
AkLogFunction();

View file

@ -49,6 +49,7 @@ namespace AkVCam
static HRESULT stateChanged(void *userData, FILTER_STATE state);
void serverStateChanged(IpcBridge::ServerState state);
void frameReady(const VideoFrame &frame);
void setPicture(const std::string &picture);
void setBroadcasting(const std::string &broadcaster);
void setControls(const std::map<std::string, int> &controls);
bool horizontalFlip() const;

View file

@ -26,6 +26,14 @@
#include "PlatformUtils/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
{
class PluginInterfacePrivate
@ -70,11 +78,11 @@ bool AkVCam::PluginInterface::registerServer(const std::string &deviceId,
AkLogInfo() << "Description: " << description << std::endl;
AkLogInfo() << "Filename: " << fileName << std::endl;
auto subkey = "CLSID\\" + clsid;
auto subkey = SUBKEY_PREFIX "\\" + clsid;
HKEY keyCLSID = 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;
if (result != ERROR_SUCCESS)
@ -140,8 +148,8 @@ void AkVCam::PluginInterface::unregisterServer(const CLSID &clsid) const
auto clsidStr = stringFromClsid(clsid);
AkLogInfo() << "CLSID: " << clsidStr << std::endl;
auto subkey = "CLSID\\" + clsidStr;
deleteTree(HKEY_CLASSES_ROOT, subkey.c_str(), 0);
auto subkey = SUBKEY_PREFIX "\\" + clsidStr;
deleteTree(ROOT_HKEY, subkey.c_str(), 0);
}
bool AkVCam::PluginInterface::registerFilter(const std::string &deviceId,
@ -254,15 +262,14 @@ bool AkVCam::PluginInterface::setDevicePath(const std::string &deviceId) const
AkLogFunction();
std::string subKey =
"CLSID\\"
SUBKEY_PREFIX "\\"
+ stringFromIid(CLSID_VideoInputDeviceCategory)
+ "\\Instance\\"
+ createClsidStrFromStr(deviceId);
AkLogInfo() << "Key: HKEY_CLASSES_ROOT" << std::endl;
AkLogInfo() << "SubKey: " << subKey << std::endl;
HKEY hKey = nullptr;
auto result = RegOpenKeyExA(HKEY_CLASSES_ROOT,
auto result = RegOpenKeyExA(ROOT_HKEY,
subKey.c_str(),
0,
KEY_ALL_ACCESS,