Removed virtual input device and using standard input streaming instead. Removed unneeded options related to the input device. Added loglevel and placeholder picture options.
This commit is contained in:
parent
1cea274ccd
commit
e8da748d30
15 changed files with 278 additions and 603 deletions
|
@ -26,6 +26,8 @@
|
||||||
#include "cmdparser.h"
|
#include "cmdparser.h"
|
||||||
#include "VCamUtils/src/ipcbridge.h"
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
#include "VCamUtils/src/image/videoformat.h"
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/image/videoframe.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
#define AKVCAM_BIND_FUNC(member) \
|
#define AKVCAM_BIND_FUNC(member) \
|
||||||
std::bind(&member, this->d, std::placeholders::_1, std::placeholders::_2)
|
std::bind(&member, this->d, std::placeholders::_1, std::placeholders::_2)
|
||||||
|
@ -79,8 +81,6 @@ namespace AkVCam {
|
||||||
int addDevice(const StringMap &flags, const StringVector &args);
|
int addDevice(const StringMap &flags, const StringVector &args);
|
||||||
int removeDevice(const StringMap &flags, const StringVector &args);
|
int removeDevice(const StringMap &flags, const StringVector &args);
|
||||||
int removeDevices(const StringMap &flags, const StringVector &args);
|
int removeDevices(const StringMap &flags, const StringVector &args);
|
||||||
int showDeviceType(const StringMap &flags,
|
|
||||||
const StringVector &args);
|
|
||||||
int showDeviceDescription(const StringMap &flags,
|
int showDeviceDescription(const StringMap &flags,
|
||||||
const StringVector &args);
|
const StringVector &args);
|
||||||
int setDeviceDescription(const StringMap &flags,
|
int setDeviceDescription(const StringMap &flags,
|
||||||
|
@ -93,17 +93,14 @@ namespace AkVCam {
|
||||||
int removeFormats(const StringMap &flags, const StringVector &args);
|
int removeFormats(const StringMap &flags, const StringVector &args);
|
||||||
int update(const StringMap &flags, const StringVector &args);
|
int update(const StringMap &flags, const StringVector &args);
|
||||||
int loadSettings(const StringMap &flags, const StringVector &args);
|
int loadSettings(const StringMap &flags, const StringVector &args);
|
||||||
int showConnections(const StringMap &flags,
|
int stream(const StringMap &flags, const StringVector &args);
|
||||||
const StringVector &args);
|
|
||||||
int connectDevices(const StringMap &flags,
|
|
||||||
const StringVector &args);
|
|
||||||
int disconnectDevices(const StringMap &flags,
|
|
||||||
const StringVector &args);
|
|
||||||
int showBroadcasters(const StringMap &flags,
|
|
||||||
const StringVector &args);
|
|
||||||
int showControls(const StringMap &flags, const StringVector &args);
|
int showControls(const StringMap &flags, const StringVector &args);
|
||||||
int readControl(const StringMap &flags, const StringVector &args);
|
int readControl(const StringMap &flags, const StringVector &args);
|
||||||
int writeControl(const StringMap &flags, const StringVector &args);
|
int writeControl(const StringMap &flags, const StringVector &args);
|
||||||
|
int picture(const StringMap &flags, const StringVector &args);
|
||||||
|
int setPicture(const StringMap &flags, const StringVector &args);
|
||||||
|
int logLevel(const StringMap &flags, const StringVector &args);
|
||||||
|
int setLogLevel(const StringMap &flags, const StringVector &args);
|
||||||
int showClients(const StringMap &flags, const StringVector &args);
|
int showClients(const StringMap &flags, const StringVector &args);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -116,10 +113,10 @@ AkVCam::CmdParser::CmdParser()
|
||||||
this->d->m_commands.push_back({});
|
this->d->m_commands.push_back({});
|
||||||
this->setDefaultFuntion(AKVCAM_BIND_FUNC(CmdParserPrivate::defaultHandler));
|
this->setDefaultFuntion(AKVCAM_BIND_FUNC(CmdParserPrivate::defaultHandler));
|
||||||
this->addFlags("",
|
this->addFlags("",
|
||||||
{"-h", "--help"},
|
{"-h", "--help"},
|
||||||
"Show help.");
|
"Show help.");
|
||||||
this->addFlags("",
|
this->addFlags("",
|
||||||
{"-p", "--parseable"},
|
{"-p", "--parseable"},
|
||||||
"Show parseable output.");
|
"Show parseable output.");
|
||||||
this->addCommand("devices",
|
this->addCommand("devices",
|
||||||
"",
|
"",
|
||||||
|
@ -129,12 +126,6 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"DESCRIPTION",
|
"DESCRIPTION",
|
||||||
"Add a new device.",
|
"Add a new device.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::addDevice));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::addDevice));
|
||||||
this->addFlags("add-device",
|
|
||||||
{"-i", "--input"},
|
|
||||||
"Add an input device.");
|
|
||||||
this->addFlags("add-device",
|
|
||||||
{"-o", "--output"},
|
|
||||||
"Add an output device.");
|
|
||||||
this->addCommand("remove-device",
|
this->addCommand("remove-device",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Remove a device.",
|
"Remove a device.",
|
||||||
|
@ -143,10 +134,6 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"",
|
"",
|
||||||
"Remove all devices.",
|
"Remove all devices.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevices));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevices));
|
||||||
this->addCommand("type",
|
|
||||||
"DEVICE",
|
|
||||||
"Show device type.",
|
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceType));
|
|
||||||
this->addCommand("description",
|
this->addCommand("description",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Show device description.",
|
"Show device description.",
|
||||||
|
@ -160,10 +147,10 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"Show supported formats.",
|
"Show supported formats.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showSupportedFormats));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::showSupportedFormats));
|
||||||
this->addFlags("supported-formats",
|
this->addFlags("supported-formats",
|
||||||
{"-i", "--input"},
|
{"-i", "--input"},
|
||||||
"Show supported input formats.");
|
"Show supported input formats.");
|
||||||
this->addFlags("supported-formats",
|
this->addFlags("supported-formats",
|
||||||
{"-o", "--output"},
|
{"-o", "--output"},
|
||||||
"Show supported output formats.");
|
"Show supported output formats.");
|
||||||
this->addCommand("formats",
|
this->addCommand("formats",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
|
@ -174,7 +161,7 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"Add a new device format.",
|
"Add a new device format.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::addFormat));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::addFormat));
|
||||||
this->addFlags("add-format",
|
this->addFlags("add-format",
|
||||||
{"-i", "--index"},
|
{"-i", "--index"},
|
||||||
"INDEX",
|
"INDEX",
|
||||||
"Add format at INDEX.");
|
"Add format at INDEX.");
|
||||||
this->addCommand("remove-format",
|
this->addCommand("remove-format",
|
||||||
|
@ -193,22 +180,10 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"SETTINGS.INI",
|
"SETTINGS.INI",
|
||||||
"Create devices from a setting file.",
|
"Create devices from a setting file.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
|
||||||
this->addCommand("connections",
|
this->addCommand("stream",
|
||||||
"DEVICE",
|
"DEVICE FORMAT WIDTH HEIGHT",
|
||||||
"Show device connections.",
|
"Read frames from stdin and send them to the device.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showConnections));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::stream));
|
||||||
this->addCommand("connect",
|
|
||||||
"INPUT_DEVICE OUTPUTDEVICE [OUTPUT_DEVICE ...]",
|
|
||||||
"Connect devices.",
|
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::connectDevices));
|
|
||||||
this->addCommand("disconnect",
|
|
||||||
"INPUT_DEVICE OUTPUTDEVICE",
|
|
||||||
"Disconnect devices.",
|
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::disconnectDevices));
|
|
||||||
this->addCommand("broadcasters",
|
|
||||||
"DEVICE",
|
|
||||||
"Show devices that sending frames to the device.",
|
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showBroadcasters));
|
|
||||||
this->addCommand("controls",
|
this->addCommand("controls",
|
||||||
"DEVICE",
|
"DEVICE",
|
||||||
"Show device controls.",
|
"Show device controls.",
|
||||||
|
@ -221,6 +196,22 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"DEVICE CONTROL VALUE",
|
"DEVICE CONTROL VALUE",
|
||||||
"Write device control value.",
|
"Write device control value.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::writeControl));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::writeControl));
|
||||||
|
this->addCommand("picture",
|
||||||
|
"",
|
||||||
|
"Placeholder picture to show when no streaming.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::picture));
|
||||||
|
this->addCommand("set-picture",
|
||||||
|
"FILE",
|
||||||
|
"Set placeholder picture.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::setPicture));
|
||||||
|
this->addCommand("loglevel",
|
||||||
|
"",
|
||||||
|
"Show current debugging level.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::logLevel));
|
||||||
|
this->addCommand("set-loglevel",
|
||||||
|
"LEVEL",
|
||||||
|
"Set debugging level.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::setLogLevel));
|
||||||
this->addCommand("clients",
|
this->addCommand("clients",
|
||||||
"",
|
"",
|
||||||
"Show clients using the camera.",
|
"Show clients using the camera.",
|
||||||
|
@ -619,45 +610,30 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
std::cout << device << std::endl;
|
std::cout << device << std::endl;
|
||||||
} else {
|
} else {
|
||||||
StringVector devicesColumn;
|
StringVector devicesColumn;
|
||||||
StringVector typesColumn;
|
|
||||||
WStringVector descriptionsColumn;
|
WStringVector descriptionsColumn;
|
||||||
|
|
||||||
devicesColumn.push_back("Device");
|
devicesColumn.push_back("Device");
|
||||||
typesColumn.push_back("Type");
|
|
||||||
descriptionsColumn.push_back(L"Description");
|
descriptionsColumn.push_back(L"Description");
|
||||||
|
|
||||||
for (auto &device: devices) {
|
for (auto &device: devices) {
|
||||||
devicesColumn.push_back(device);
|
devicesColumn.push_back(device);
|
||||||
typesColumn.push_back(this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
|
||||||
"Input":
|
|
||||||
"Output");
|
|
||||||
descriptionsColumn.push_back(this->m_ipcBridge.description(device));
|
descriptionsColumn.push_back(this->m_ipcBridge.description(device));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devicesColumnSize = this->maxStringLength(devicesColumn);
|
auto devicesColumnSize = this->maxStringLength(devicesColumn);
|
||||||
auto typesColumnSize = this->maxStringLength(typesColumn);
|
|
||||||
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
||||||
|
|
||||||
std::cout << fill("Device", devicesColumnSize)
|
std::cout << fill("Device", devicesColumnSize)
|
||||||
<< " | "
|
|
||||||
<< fill("Type", typesColumnSize)
|
|
||||||
<< " | "
|
<< " | "
|
||||||
<< fill("Description", descriptionsColumnSize)
|
<< fill("Description", descriptionsColumnSize)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << std::string("-")
|
std::cout << std::string("-")
|
||||||
* (devicesColumnSize
|
* (devicesColumnSize
|
||||||
+ typesColumnSize
|
|
||||||
+ descriptionsColumnSize
|
+ descriptionsColumnSize
|
||||||
+ 6) << std::endl;
|
+ 4) << std::endl;
|
||||||
|
|
||||||
for (auto &device: devices) {
|
for (auto &device: devices) {
|
||||||
std::string type =
|
|
||||||
this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
|
||||||
"Input":
|
|
||||||
"Output";
|
|
||||||
std::cout << fill(device, devicesColumnSize)
|
std::cout << fill(device, devicesColumnSize)
|
||||||
<< " | "
|
|
||||||
<< fill(type, typesColumnSize)
|
|
||||||
<< " | ";
|
<< " | ";
|
||||||
std::wcout << fill(this->m_ipcBridge.description(device),
|
std::wcout << fill(this->m_ipcBridge.description(device),
|
||||||
descriptionsColumnSize)
|
descriptionsColumnSize)
|
||||||
|
@ -671,19 +647,16 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::addDevice(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::addDevice(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
if (args.size() < 2) {
|
if (args.size() < 2) {
|
||||||
std::cerr << "Device description not provided." << std::endl;
|
std::cerr << "Device description not provided." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
IpcBridge::DeviceType type =
|
|
||||||
this->containsFlag(flags, "add-device", "-i")?
|
|
||||||
IpcBridge::DeviceTypeInput:
|
|
||||||
IpcBridge::DeviceTypeOutput;
|
|
||||||
|
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
auto deviceId = this->m_ipcBridge.addDevice(cv.from_bytes(args[1]), type);
|
auto deviceId = this->m_ipcBridge.addDevice(cv.from_bytes(args[1]));
|
||||||
|
|
||||||
if (deviceId.empty()) {
|
if (deviceId.empty()) {
|
||||||
std::cerr << "Failed to create device." << std::endl;
|
std::cerr << "Failed to create device." << std::endl;
|
||||||
|
@ -738,35 +711,6 @@ int AkVCam::CmdParserPrivate::removeDevices(const AkVCam::StringMap &flags,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showDeviceType(const StringMap &flags,
|
|
||||||
const StringVector &args)
|
|
||||||
{
|
|
||||||
UNUSED(flags);
|
|
||||||
|
|
||||||
if (args.size() < 2) {
|
|
||||||
std::cerr << "Device not provided." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto deviceId = args[1];
|
|
||||||
auto devices = this->m_ipcBridge.devices();
|
|
||||||
auto it = std::find(devices.begin(), devices.end(), deviceId);
|
|
||||||
|
|
||||||
if (it == devices.end()) {
|
|
||||||
std::cerr << "'" << deviceId << "' doesn't exists." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(args[1]) == IpcBridge::DeviceTypeInput)
|
|
||||||
std::cout << "Input" << std::endl;
|
|
||||||
else
|
|
||||||
std::cout << "Output" << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showDeviceDescription(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
@ -827,12 +771,12 @@ int AkVCam::CmdParserPrivate::showSupportedFormats(const StringMap &flags,
|
||||||
|
|
||||||
auto type =
|
auto type =
|
||||||
this->containsFlag(flags, "supported-formats", "-i")?
|
this->containsFlag(flags, "supported-formats", "-i")?
|
||||||
IpcBridge::DeviceTypeInput:
|
IpcBridge::StreamTypeInput:
|
||||||
IpcBridge::DeviceTypeOutput;
|
IpcBridge::StreamTypeOutput;
|
||||||
auto formats = this->m_ipcBridge.supportedPixelFormats(type);
|
auto formats = this->m_ipcBridge.supportedPixelFormats(type);
|
||||||
|
|
||||||
if (!this->m_parseable) {
|
if (!this->m_parseable) {
|
||||||
if (type == IpcBridge::DeviceTypeInput)
|
if (type == IpcBridge::StreamTypeInput)
|
||||||
std::cout << "Input formats:" << std::endl;
|
std::cout << "Input formats:" << std::endl;
|
||||||
else
|
else
|
||||||
std::cout << "Output formats:" << std::endl;
|
std::cout << "Output formats:" << std::endl;
|
||||||
|
@ -930,15 +874,11 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto type = this->m_ipcBridge.deviceType(deviceId);
|
auto formats = this->m_ipcBridge.supportedPixelFormats(IpcBridge::StreamTypeOutput);
|
||||||
auto formats = this->m_ipcBridge.supportedPixelFormats(type);
|
|
||||||
auto fit = std::find(formats.begin(), formats.end(), format);
|
auto fit = std::find(formats.begin(), formats.end(), format);
|
||||||
|
|
||||||
if (fit == formats.end()) {
|
if (fit == formats.end()) {
|
||||||
if (type == IpcBridge::DeviceTypeInput)
|
std::cerr << "Format not supported." << std::endl;
|
||||||
std::cerr << "Input format not supported." << std::endl;
|
|
||||||
else
|
|
||||||
std::cerr << "Output format not supported." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
@ -1074,12 +1014,12 @@ int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::stream(const AkVCam::StringMap &flags,
|
||||||
const StringVector &args)
|
const AkVCam::StringVector &args)
|
||||||
{
|
{
|
||||||
UNUSED(flags);
|
UNUSED(flags);
|
||||||
|
|
||||||
if (args.size() < 2) {
|
if (args.size() < 5) {
|
||||||
std::cerr << "Not enough arguments." << std::endl;
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
|
@ -1095,153 +1035,72 @@ int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto &connectedDevice: this->m_ipcBridge.connections(deviceId))
|
auto format = VideoFormat::fourccFromString(args[2]);
|
||||||
std::cout << connectedDevice << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
if (!format) {
|
||||||
}
|
std::cerr << "Invalid pixel format." << std::endl;
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::connectDevices(const StringMap &flags,
|
|
||||||
const StringVector &args)
|
|
||||||
{
|
|
||||||
UNUSED(flags);
|
|
||||||
|
|
||||||
if (args.size() < 3) {
|
|
||||||
std::cerr << "Not enough arguments." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto inputDevice = args[1];
|
auto formats = this->m_ipcBridge.supportedPixelFormats(IpcBridge::StreamTypeOutput);
|
||||||
auto devices = this->m_ipcBridge.devices();
|
auto fit = std::find(formats.begin(), formats.end(), format);
|
||||||
auto it = std::find(devices.begin(), devices.end(), inputDevice);
|
|
||||||
|
|
||||||
if (it == devices.end()) {
|
if (fit == formats.end()) {
|
||||||
std::cerr << inputDevice << " doesn't exists." << std::endl;
|
std::cerr << "Format not supported." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(inputDevice) != IpcBridge::DeviceTypeInput) {
|
char *p = nullptr;
|
||||||
std::cerr << inputDevice << " is not an input." << std::endl;
|
auto width = strtoul(args[3].c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
std::cerr << "Width must be an unsigned integer." << std::endl;
|
||||||
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto outputDevices = this->m_ipcBridge.connections(inputDevice);
|
p = nullptr;
|
||||||
|
auto height = strtoul(args[4].c_str(), &p, 10);
|
||||||
|
|
||||||
for (size_t i = 2; i < args.size(); i++) {
|
if (*p) {
|
||||||
auto &outputDevice = args[i];
|
std::cerr << "Height must be an unsigned integer." << std::endl;
|
||||||
auto it = std::find(devices.begin(), devices.end(), outputDevice);
|
|
||||||
|
|
||||||
if (it == devices.end()) {
|
return -1;
|
||||||
std::cerr << outputDevice << " doesn't exists." << std::endl;
|
}
|
||||||
|
|
||||||
return -1;
|
VideoFormat fmt(format, width, height, {{30, 1}});
|
||||||
|
|
||||||
|
if (!this->m_ipcBridge.deviceStart(deviceId, fmt)) {
|
||||||
|
std::cerr << "Can't start stream." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool exit = false;
|
||||||
|
auto signalHandler = [] (int) {
|
||||||
|
exit = true;
|
||||||
|
};
|
||||||
|
signal(SIGINT, signalHandler);
|
||||||
|
signal(SIGTERM, signalHandler);
|
||||||
|
|
||||||
|
AkVCam::VideoFrame frame(fmt);
|
||||||
|
size_t bufferSize = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
std::cin.read(reinterpret_cast<char *>(frame.data().data()
|
||||||
|
+ bufferSize),
|
||||||
|
frame.data().size() - bufferSize);
|
||||||
|
bufferSize += std::cin.gcount();
|
||||||
|
|
||||||
|
if (bufferSize == frame.data().size()) {
|
||||||
|
this->m_ipcBridge.write(deviceId, frame);
|
||||||
|
bufferSize = 0;
|
||||||
}
|
}
|
||||||
|
} while (!std::cin.eof() && !exit);
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(outputDevice) != IpcBridge::DeviceTypeOutput) {
|
this->m_ipcBridge.deviceStop(deviceId);
|
||||||
std::cerr << outputDevice << " is not an output." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cit = std::find(outputDevices.begin(),
|
|
||||||
outputDevices.end(),
|
|
||||||
outputDevice);
|
|
||||||
|
|
||||||
if (cit == outputDevices.end())
|
|
||||||
outputDevices.push_back(outputDevice);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->m_ipcBridge.setConnections(inputDevice, outputDevices);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::disconnectDevices(const StringMap &flags,
|
|
||||||
const StringVector &args)
|
|
||||||
{
|
|
||||||
UNUSED(flags);
|
|
||||||
|
|
||||||
if (args.size() < 3) {
|
|
||||||
std::cerr << "Not enough arguments." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto inputDevice = args[1];
|
|
||||||
auto devices = this->m_ipcBridge.devices();
|
|
||||||
auto it = std::find(devices.begin(), devices.end(), inputDevice);
|
|
||||||
|
|
||||||
if (it == devices.end()) {
|
|
||||||
std::cerr << inputDevice << " doesn't exists." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(inputDevice) != IpcBridge::DeviceTypeInput) {
|
|
||||||
std::cerr << inputDevice << " is not an input." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto outputDevices = this->m_ipcBridge.connections(inputDevice);
|
|
||||||
auto &outputDevice = args[2];
|
|
||||||
auto dit = std::find(devices.begin(), devices.end(), outputDevice);
|
|
||||||
|
|
||||||
if (dit == devices.end()) {
|
|
||||||
std::cerr << outputDevice << " doesn't exists." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(outputDevice) != IpcBridge::DeviceTypeOutput) {
|
|
||||||
std::cerr << outputDevice << " is not an output." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto cit = std::find(outputDevices.begin(),
|
|
||||||
outputDevices.end(),
|
|
||||||
outputDevice);
|
|
||||||
|
|
||||||
if (cit == outputDevices.end())
|
|
||||||
outputDevices.push_back(outputDevice);
|
|
||||||
|
|
||||||
this->m_ipcBridge.setConnections(inputDevice, outputDevices);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showBroadcasters(const AkVCam::StringMap &flags,
|
|
||||||
const AkVCam::StringVector &args)
|
|
||||||
{
|
|
||||||
UNUSED(flags);
|
|
||||||
|
|
||||||
if (args.size() < 2) {
|
|
||||||
std::cerr << "Not enough arguments." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto ouputDevice = args[1];
|
|
||||||
auto devices = this->m_ipcBridge.devices();
|
|
||||||
auto it = std::find(devices.begin(), devices.end(), ouputDevice);
|
|
||||||
|
|
||||||
if (it == devices.end()) {
|
|
||||||
std::cerr << ouputDevice << " doesn't exists." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this->m_ipcBridge.deviceType(ouputDevice) != IpcBridge::DeviceTypeOutput) {
|
|
||||||
std::cerr << ouputDevice << " is not an output." << std::endl;
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << this->m_ipcBridge.broadcaster(ouputDevice) << std::endl;
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1264,6 +1123,73 @@ int AkVCam::CmdParserPrivate::writeControl(const StringMap &flags,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::picture(const AkVCam::StringMap &flags,
|
||||||
|
const AkVCam::StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
UNUSED(args);
|
||||||
|
|
||||||
|
std::wcout << this->m_ipcBridge.picture() << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::setPicture(const AkVCam::StringMap &flags,
|
||||||
|
const AkVCam::StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
this->m_ipcBridge.setPicture(cv.from_bytes(args[1]));
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::logLevel(const AkVCam::StringMap &flags,
|
||||||
|
const AkVCam::StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
UNUSED(args);
|
||||||
|
|
||||||
|
auto level = this->m_ipcBridge.logLevel();
|
||||||
|
|
||||||
|
if (this->m_parseable)
|
||||||
|
std::cout << level << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << AkVCam::Logger::levelToString(level) << std::endl;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::setLogLevel(const AkVCam::StringMap &flags,
|
||||||
|
const AkVCam::StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto levelStr = args[1];
|
||||||
|
char *p = nullptr;
|
||||||
|
auto level = strtol(levelStr.c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p)
|
||||||
|
level = AkVCam::Logger::levelFromString(levelStr);
|
||||||
|
|
||||||
|
this->m_ipcBridge.setLogLevel(level);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,10 +42,10 @@ namespace AkVCam
|
||||||
ServerStateGone
|
ServerStateGone
|
||||||
};
|
};
|
||||||
|
|
||||||
enum DeviceType
|
enum StreamType
|
||||||
{
|
{
|
||||||
DeviceTypeOutput,
|
StreamTypeOutput,
|
||||||
DeviceTypeInput
|
StreamTypeInput
|
||||||
};
|
};
|
||||||
|
|
||||||
AKVCAM_SIGNAL(ServerStateChanged,
|
AKVCAM_SIGNAL(ServerStateChanged,
|
||||||
|
@ -104,6 +104,11 @@ namespace AkVCam
|
||||||
std::string driver() const;
|
std::string driver() const;
|
||||||
bool setDriver(const std::string &driver);
|
bool setDriver(const std::string &driver);
|
||||||
|
|
||||||
|
std::wstring picture() const;
|
||||||
|
void setPicture(const std::wstring &picture);
|
||||||
|
int logLevel() const;
|
||||||
|
void setLogLevel(int logLevel);
|
||||||
|
|
||||||
// Configure method to be used for executing commands with elevated
|
// Configure method to be used for executing commands with elevated
|
||||||
// privileges.
|
// privileges.
|
||||||
std::vector<std::string> availableRootMethods() const;
|
std::vector<std::string> availableRootMethods() const;
|
||||||
|
@ -129,10 +134,10 @@ namespace AkVCam
|
||||||
const std::wstring &description);
|
const std::wstring &description);
|
||||||
|
|
||||||
// Output pixel formats supported by the driver.
|
// Output pixel formats supported by the driver.
|
||||||
std::vector<PixelFormat> supportedPixelFormats(DeviceType type) const;
|
std::vector<PixelFormat> supportedPixelFormats(StreamType type) const;
|
||||||
|
|
||||||
// Default output pixel format of the driver.
|
// Default output pixel format of the driver.
|
||||||
PixelFormat defaultPixelFormat(DeviceType type) const;
|
PixelFormat defaultPixelFormat(StreamType type) const;
|
||||||
|
|
||||||
// Return supported formats for the device.
|
// Return supported formats for the device.
|
||||||
std::vector<VideoFormat> formats(const std::string &deviceId) const;
|
std::vector<VideoFormat> formats(const std::string &deviceId) const;
|
||||||
|
@ -168,19 +173,13 @@ namespace AkVCam
|
||||||
|
|
||||||
/* Server */
|
/* Server */
|
||||||
|
|
||||||
DeviceType deviceType(const std::string &deviceId);
|
std::string addDevice(const std::wstring &description);
|
||||||
std::string addDevice(const std::wstring &description,
|
|
||||||
DeviceType type);
|
|
||||||
void removeDevice(const std::string &deviceId);
|
void removeDevice(const std::string &deviceId);
|
||||||
void addFormat(const std::string &deviceId,
|
void addFormat(const std::string &deviceId,
|
||||||
const VideoFormat &format,
|
const VideoFormat &format,
|
||||||
int index=-1);
|
int index=-1);
|
||||||
void removeFormat(const std::string &deviceId, int index);
|
void removeFormat(const std::string &deviceId, int index);
|
||||||
void update();
|
void update();
|
||||||
std::vector<std::string> connections(const std::string &deviceId);
|
|
||||||
void setConnections(const std::string &deviceId,
|
|
||||||
const std::vector<std::string> &connectedDevices);
|
|
||||||
|
|
||||||
void updateDevices();
|
void updateDevices();
|
||||||
|
|
||||||
// Start frame transfer to the device.
|
// Start frame transfer to the device.
|
||||||
|
|
|
@ -37,7 +37,7 @@ namespace AkVCam
|
||||||
int logLevel {AKVCAM_LOGLEVEL_DEFAULT};
|
int logLevel {AKVCAM_LOGLEVEL_DEFAULT};
|
||||||
std::fstream stream;
|
std::fstream stream;
|
||||||
|
|
||||||
static std::string logLevelString(int logLevel)
|
static const std::map<int, std::string> &logLevelStrMap()
|
||||||
{
|
{
|
||||||
static std::map<int, std::string> llsMap {
|
static std::map<int, std::string> llsMap {
|
||||||
{AKVCAM_LOGLEVEL_DEFAULT , "default" },
|
{AKVCAM_LOGLEVEL_DEFAULT , "default" },
|
||||||
|
@ -51,10 +51,7 @@ namespace AkVCam
|
||||||
{AKVCAM_LOGLEVEL_DEBUG , "debug" },
|
{AKVCAM_LOGLEVEL_DEBUG , "debug" },
|
||||||
};
|
};
|
||||||
|
|
||||||
if (llsMap.count(logLevel) < 1)
|
return llsMap;
|
||||||
return {};
|
|
||||||
|
|
||||||
return llsMap[logLevel];
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -115,7 +112,7 @@ std::string AkVCam::Logger::header(int logLevel, const std::string file, int lin
|
||||||
<< " ("
|
<< " ("
|
||||||
<< line
|
<< line
|
||||||
<< ")] "
|
<< ")] "
|
||||||
<< LoggerPrivate::logLevelString(logLevel) << ": ";
|
<< levelToString(logLevel) << ": ";
|
||||||
|
|
||||||
return ss.str();
|
return ss.str();
|
||||||
}
|
}
|
||||||
|
@ -139,3 +136,25 @@ std::ostream &AkVCam::Logger::log(int logLevel)
|
||||||
|
|
||||||
return loggerPrivate()->stream;
|
return loggerPrivate()->stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AkVCam::Logger::levelFromString(const std::string &level)
|
||||||
|
{
|
||||||
|
auto &llsMap = LoggerPrivate::logLevelStrMap();
|
||||||
|
|
||||||
|
for (auto it = llsMap.begin(); it != llsMap.end(); it++)
|
||||||
|
if (it->second == level)
|
||||||
|
return it->first;
|
||||||
|
|
||||||
|
return AKVCAM_LOGLEVEL_DEFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::Logger::levelToString(int level)
|
||||||
|
{
|
||||||
|
auto &llsMap = LoggerPrivate::logLevelStrMap();
|
||||||
|
|
||||||
|
for (auto it = llsMap.begin(); it != llsMap.end(); it++)
|
||||||
|
if (it->first == level)
|
||||||
|
return it->second;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ namespace AkVCam
|
||||||
void setLogLevel(int logLevel);
|
void setLogLevel(int logLevel);
|
||||||
std::string header(int logLevel, const std::string file, int line);
|
std::string header(int logLevel, const std::string file, int line);
|
||||||
std::ostream &log(int logLevel);
|
std::ostream &log(int logLevel);
|
||||||
|
int levelFromString(const std::string &level);
|
||||||
|
std::string levelToString(int level);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -39,16 +39,12 @@
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
struct AssistantDevice
|
struct AssistantDevice
|
||||||
{
|
{
|
||||||
std::wstring description;
|
std::wstring description;
|
||||||
std::vector<VideoFormat> formats;
|
std::vector<VideoFormat> formats;
|
||||||
std::vector<std::string> connections;
|
|
||||||
std::string broadcaster;
|
std::string broadcaster;
|
||||||
std::vector<std::string> listeners;
|
std::vector<std::string> listeners;
|
||||||
IpcBridge::DeviceType type;
|
|
||||||
bool horizontalMirror {false};
|
bool horizontalMirror {false};
|
||||||
bool verticalMirror {false};
|
bool verticalMirror {false};
|
||||||
Scaling scaling {ScalingFast};
|
Scaling scaling {ScalingFast};
|
||||||
|
@ -103,8 +99,6 @@ namespace AkVCam
|
||||||
void swapRgb(xpc_connection_t client, xpc_object_t event);
|
void swapRgb(xpc_connection_t client, xpc_object_t event);
|
||||||
void listenerAdd(xpc_connection_t client, xpc_object_t event);
|
void listenerAdd(xpc_connection_t client, xpc_object_t event);
|
||||||
void listenerRemove(xpc_connection_t client, xpc_object_t event);
|
void listenerRemove(xpc_connection_t client, xpc_object_t event);
|
||||||
void connections(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setConnections(xpc_connection_t client, xpc_object_t event);
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,8 +166,6 @@ AkVCam::AssistantPrivate::AssistantPrivate()
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(AssistantPrivate::setAspectRatio) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(AssistantPrivate::setAspectRatio) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB , AKVCAM_BIND_FUNC(AssistantPrivate::swapRgb) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB , AKVCAM_BIND_FUNC(AssistantPrivate::swapRgb) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(AssistantPrivate::setSwapRgb) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(AssistantPrivate::setSwapRgb) },
|
||||||
{AKVCAM_ASSISTANT_MSG_CONNECTIONS , AKVCAM_BIND_FUNC(AssistantPrivate::connections) },
|
|
||||||
{AKVCAM_ASSISTANT_MSG_SETCONNECTIONS , AKVCAM_BIND_FUNC(AssistantPrivate::setConnections) },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this->loadCameras();
|
this->loadCameras();
|
||||||
|
@ -263,8 +255,6 @@ void AkVCam::AssistantPrivate::loadCameras()
|
||||||
this->m_deviceConfigs[path].description =
|
this->m_deviceConfigs[path].description =
|
||||||
Preferences::cameraDescription(i);
|
Preferences::cameraDescription(i);
|
||||||
this->m_deviceConfigs[path].formats = Preferences::cameraFormats(i);
|
this->m_deviceConfigs[path].formats = Preferences::cameraFormats(i);
|
||||||
this->m_deviceConfigs[path].connections =
|
|
||||||
Preferences::cameraConnections(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,12 +409,8 @@ void AkVCam::AssistantPrivate::deviceCreate(xpc_connection_t client,
|
||||||
formats.push_back(VideoFormat {fourcc, width, height, {frameRate}});
|
formats.push_back(VideoFormat {fourcc, width, height, {frameRate}});
|
||||||
}
|
}
|
||||||
|
|
||||||
auto type = xpc_dictionary_get_bool(event, "isinput")?
|
auto deviceId = Preferences::addCamera(description, formats);
|
||||||
IpcBridge::DeviceTypeInput:
|
|
||||||
IpcBridge::DeviceTypeOutput;
|
|
||||||
auto deviceId = Preferences::addCamera(description, formats, type);
|
|
||||||
this->m_deviceConfigs[deviceId] = {};
|
this->m_deviceConfigs[deviceId] = {};
|
||||||
this->m_deviceConfigs[deviceId].type = type;
|
|
||||||
this->m_deviceConfigs[deviceId].description = description;
|
this->m_deviceConfigs[deviceId].description = description;
|
||||||
this->m_deviceConfigs[deviceId].formats = formats;
|
this->m_deviceConfigs[deviceId].formats = formats;
|
||||||
|
|
||||||
|
@ -910,44 +896,3 @@ void AkVCam::AssistantPrivate::listenerRemove(xpc_connection_t client,
|
||||||
xpc_connection_send_message(client, reply);
|
xpc_connection_send_message(client, reply);
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::connections(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
auto listeners = xpc_array_create(nullptr, 0);
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
for (auto &listener: this->m_deviceConfigs[deviceId].connections) {
|
|
||||||
auto listenerObj = xpc_string_create(listener.c_str());
|
|
||||||
xpc_array_append_value(listeners, listenerObj);
|
|
||||||
}
|
|
||||||
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Connections: " << xpc_array_get_count(listeners) << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_value(reply, "connections", listeners);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::setConnections(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
auto connectionsList = xpc_dictionary_get_array(event, "connections");
|
|
||||||
std::vector<std::string> connections;
|
|
||||||
|
|
||||||
for (size_t i = 0; i < xpc_array_get_count(connectionsList); i++)
|
|
||||||
connections.push_back(xpc_array_get_string(connectionsList, i));
|
|
||||||
|
|
||||||
this->m_deviceConfigs[deviceId].connections = connections;
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Connections: " << connections.size() << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "status", true);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
|
@ -30,8 +30,7 @@ GLOBAL_STATIC(AkVCam::Assistant, assistant)
|
||||||
|
|
||||||
int main(int argc, char **argv)
|
int main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
auto loglevel =
|
auto loglevel = AkVCam::Preferences::logLevel();
|
||||||
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
|
||||||
AkVCam::Logger::setLogLevel(loglevel);
|
AkVCam::Logger::setLogLevel(loglevel);
|
||||||
AkLogDebug() << "Creating Service: " << CMIO_ASSISTANT_NAME << std::endl;
|
AkLogDebug() << "Creating Service: " << CMIO_ASSISTANT_NAME << std::endl;
|
||||||
auto server =
|
auto server =
|
||||||
|
|
|
@ -282,8 +282,7 @@ void AkVCam::Preferences::sync()
|
||||||
CFPreferencesAppSynchronize(PREFERENCES_ID);
|
CFPreferencesAppSynchronize(PREFERENCES_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
std::string AkVCam::Preferences::addDevice(const std::wstring &description)
|
||||||
AkVCam::IpcBridge::DeviceType type)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
auto path = createDevicePath();
|
auto path = createDevicePath();
|
||||||
|
@ -293,10 +292,6 @@ std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".description",
|
+ ".description",
|
||||||
description);
|
description);
|
||||||
write("cameras."
|
|
||||||
+ std::to_string(cameraIndex)
|
|
||||||
+ ".isinput",
|
|
||||||
type == IpcBridge::DeviceTypeInput);
|
|
||||||
write("cameras."
|
write("cameras."
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".path",
|
+ ".path",
|
||||||
|
@ -307,16 +302,14 @@ std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::Preferences::addCamera(const std::wstring &description,
|
std::string AkVCam::Preferences::addCamera(const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats)
|
||||||
IpcBridge::DeviceType type)
|
|
||||||
{
|
{
|
||||||
return addCamera("", description, formats, type);
|
return addCamera("", description, formats);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::Preferences::addCamera(const std::string &path,
|
std::string AkVCam::Preferences::addCamera(const std::string &path,
|
||||||
const std::wstring &description,
|
const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats)
|
||||||
IpcBridge::DeviceType type)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
|
@ -330,10 +323,6 @@ std::string AkVCam::Preferences::addCamera(const std::string &path,
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".description",
|
+ ".description",
|
||||||
description);
|
description);
|
||||||
write("cameras."
|
|
||||||
+ std::to_string(cameraIndex)
|
|
||||||
+ ".isinput",
|
|
||||||
type == IpcBridge::DeviceTypeInput);
|
|
||||||
write("cameras."
|
write("cameras."
|
||||||
+ std::to_string(cameraIndex)
|
+ std::to_string(cameraIndex)
|
||||||
+ ".path",
|
+ ".path",
|
||||||
|
@ -442,11 +431,6 @@ bool AkVCam::Preferences::cameraExists(const std::string &path)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::Preferences::cameraIsInput(size_t cameraIndex)
|
|
||||||
{
|
|
||||||
return readBool("cameras." + std::to_string(cameraIndex) + ".isinput");
|
|
||||||
}
|
|
||||||
|
|
||||||
std::wstring AkVCam::Preferences::cameraDescription(size_t cameraIndex)
|
std::wstring AkVCam::Preferences::cameraDescription(size_t cameraIndex)
|
||||||
{
|
{
|
||||||
if (cameraIndex >= camerasCount())
|
if (cameraIndex >= camerasCount())
|
||||||
|
@ -578,9 +562,6 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
if (!cameraIsInput(cameraIndex))
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto formats = cameraFormats(cameraIndex);
|
auto formats = cameraFormats(cameraIndex);
|
||||||
|
|
||||||
if (index < 0 || index >= int(formats.size()))
|
if (index < 0 || index >= int(formats.size()))
|
||||||
|
@ -609,74 +590,22 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
||||||
sync();
|
sync();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraIndex)
|
std::wstring AkVCam::Preferences::picture()
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
return readWString("picture");
|
||||||
std::vector<std::string> cameraConnections;
|
|
||||||
|
|
||||||
if (cameraIsInput(cameraIndex)) {
|
|
||||||
auto connections = readStringList("cameras."
|
|
||||||
+ std::to_string(cameraIndex)
|
|
||||||
+ ".connections");
|
|
||||||
|
|
||||||
for (auto &connection: connections) {
|
|
||||||
if (connection.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t pos = 0;
|
|
||||||
auto outputIndex = std::stoi(connection, &pos);
|
|
||||||
|
|
||||||
if (pos == connection.size())
|
|
||||||
cameraConnections.push_back(cameraPath(outputIndex));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
for (size_t i = 0; i < camerasCount(); i++)
|
|
||||||
if (cameraIsInput(i)) {
|
|
||||||
auto connections = readStringList("cameras."
|
|
||||||
+ std::to_string(i)
|
|
||||||
+ ".connections");
|
|
||||||
|
|
||||||
for (auto &connection: connections) {
|
|
||||||
if (connection.empty())
|
|
||||||
continue;
|
|
||||||
|
|
||||||
size_t pos = 0;
|
|
||||||
auto outputIndex = std::stoi(connection, &pos);
|
|
||||||
|
|
||||||
if (pos == connection.size() && size_t(outputIndex) == cameraIndex)
|
|
||||||
cameraConnections.push_back(cameraPath(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return cameraConnections;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::Preferences::cameraSetConnections(size_t cameraIndex,
|
void AkVCam::Preferences::setPicture(const std::wstring &picture)
|
||||||
const std::vector<std::string> &connectedDevices)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
write("picture", picture);
|
||||||
|
}
|
||||||
if (!cameraIsInput(cameraIndex))
|
|
||||||
return;
|
int AkVCam::Preferences::logLevel()
|
||||||
|
{
|
||||||
std::vector<std::string> connections;
|
return readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
||||||
|
}
|
||||||
for (auto &connection: connectedDevices) {
|
|
||||||
if (connection.empty())
|
void AkVCam::Preferences::setLogLevel(int logLevel)
|
||||||
continue;
|
{
|
||||||
|
write("loglevel", logLevel);
|
||||||
auto outputIndex = cameraFromPath(connection);
|
|
||||||
|
|
||||||
if (outputIndex < 0)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (cameraIsInput(outputIndex))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
connections.push_back(std::to_string(outputIndex));
|
|
||||||
}
|
|
||||||
|
|
||||||
write("cameras." + std::to_string(cameraIndex) + ".connections",
|
|
||||||
connections);
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,8 +24,6 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
|
||||||
#include "VCamUtils/src/ipcbridge.h"
|
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
{
|
{
|
||||||
class VideoFormat;
|
class VideoFormat;
|
||||||
|
@ -55,21 +53,17 @@ namespace AkVCam
|
||||||
void move(const std::string &keyFrom, const std::string &keyTo);
|
void move(const std::string &keyFrom, const std::string &keyTo);
|
||||||
void moveAll(const std::string &keyFrom, const std::string &keyTo);
|
void moveAll(const std::string &keyFrom, const std::string &keyTo);
|
||||||
void sync();
|
void sync();
|
||||||
std::string addDevice(const std::wstring &description,
|
std::string addDevice(const std::wstring &description);
|
||||||
IpcBridge::DeviceType type);
|
|
||||||
std::string addCamera(const std::wstring &description,
|
std::string addCamera(const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats);
|
||||||
IpcBridge::DeviceType type);
|
|
||||||
std::string addCamera(const std::string &path,
|
std::string addCamera(const std::string &path,
|
||||||
const std::wstring &description,
|
const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats);
|
||||||
IpcBridge::DeviceType type);
|
|
||||||
void removeCamera(const std::string &path);
|
void removeCamera(const std::string &path);
|
||||||
size_t camerasCount();
|
size_t camerasCount();
|
||||||
std::string createDevicePath();
|
std::string createDevicePath();
|
||||||
int cameraFromPath(const std::string &path);
|
int cameraFromPath(const std::string &path);
|
||||||
bool cameraExists(const std::string &path);
|
bool cameraExists(const std::string &path);
|
||||||
bool cameraIsInput(size_t cameraIndex);
|
|
||||||
std::wstring cameraDescription(size_t cameraIndex);
|
std::wstring cameraDescription(size_t cameraIndex);
|
||||||
void cameraSetDescription(size_t cameraIndex,
|
void cameraSetDescription(size_t cameraIndex,
|
||||||
const std::wstring &description);
|
const std::wstring &description);
|
||||||
|
@ -85,9 +79,10 @@ namespace AkVCam
|
||||||
const VideoFormat &format,
|
const VideoFormat &format,
|
||||||
int index);
|
int index);
|
||||||
void cameraRemoveFormat(size_t cameraIndex, int index);
|
void cameraRemoveFormat(size_t cameraIndex, int index);
|
||||||
std::vector<std::string> cameraConnections(size_t cameraIndex);
|
std::wstring picture();
|
||||||
void cameraSetConnections(size_t cameraIndex,
|
void setPicture(const std::wstring &picture);
|
||||||
const std::vector<std::string> &connectedDevices);
|
int logLevel();
|
||||||
|
void setLogLevel(int logLevel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -104,6 +104,8 @@ AkVCam::IpcBridge::IpcBridge()
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
this->d = new IpcBridgePrivate(this);
|
this->d = new IpcBridgePrivate(this);
|
||||||
|
auto loglevel = AkVCam::Preferences::logLevel();
|
||||||
|
AkVCam::Logger::setLogLevel(loglevel);
|
||||||
ipcBridgePrivate().add(this);
|
ipcBridgePrivate().add(this);
|
||||||
this->registerPeer();
|
this->registerPeer();
|
||||||
}
|
}
|
||||||
|
@ -159,6 +161,28 @@ bool AkVCam::IpcBridge::setDriver(const std::string &driver)
|
||||||
return driver == "AkVirtualCamera";
|
return driver == "AkVirtualCamera";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
std::wstring AkVCam::IpcBridge::picture() const
|
||||||
|
{
|
||||||
|
return Preferences::picture();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::IpcBridge::setPicture(const std::wstring &picture)
|
||||||
|
{
|
||||||
|
Preferences::setPicture(picture);
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::IpcBridge::logLevel() const
|
||||||
|
{
|
||||||
|
return Preferences::logLevel();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::IpcBridge::setLogLevel(int logLevel)
|
||||||
|
{
|
||||||
|
Preferences::setLogLevel(logLevel);
|
||||||
|
Logger::setLogLevel(logLevel);
|
||||||
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::IpcBridge::availableRootMethods() const
|
std::vector<std::string> AkVCam::IpcBridge::availableRootMethods() const
|
||||||
{
|
{
|
||||||
return {"osascript"};
|
return {"osascript"};
|
||||||
|
@ -356,9 +380,9 @@ void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
|
||||||
return Preferences::cameraSetDescription(cameraIndex, description);
|
return Preferences::cameraSetDescription(cameraIndex, description);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(DeviceType type) const
|
std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(StreamType type) const
|
||||||
{
|
{
|
||||||
if (type == DeviceTypeInput)
|
if (type == StreamTypeInput)
|
||||||
return {PixelFormatRGB24};
|
return {PixelFormatRGB24};
|
||||||
|
|
||||||
return {
|
return {
|
||||||
|
@ -369,9 +393,9 @@ std::vector<AkVCam::PixelFormat> AkVCam::IpcBridge::supportedPixelFormats(Device
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(DeviceType type) const
|
AkVCam::PixelFormat AkVCam::IpcBridge::defaultPixelFormat(StreamType type) const
|
||||||
{
|
{
|
||||||
return type == DeviceTypeInput?
|
return type == StreamTypeInput?
|
||||||
PixelFormatRGB24:
|
PixelFormatRGB24:
|
||||||
PixelFormatYUY2;
|
PixelFormatYUY2;
|
||||||
}
|
}
|
||||||
|
@ -641,19 +665,9 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const
|
||||||
return {path};
|
return {path};
|
||||||
}
|
}
|
||||||
|
|
||||||
AkVCam::IpcBridge::DeviceType AkVCam::IpcBridge::deviceType(const std::string &deviceId)
|
std::string AkVCam::IpcBridge::addDevice(const std::wstring &description)
|
||||||
{
|
{
|
||||||
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
return Preferences::addDevice(description);
|
||||||
|
|
||||||
return Preferences::cameraIsInput(cameraIndex)?
|
|
||||||
DeviceTypeInput:
|
|
||||||
DeviceTypeOutput;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AkVCam::IpcBridge::addDevice(const std::wstring &description,
|
|
||||||
DeviceType type)
|
|
||||||
{
|
|
||||||
return Preferences::addDevice(description, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridge::removeDevice(const std::string &deviceId)
|
void AkVCam::IpcBridge::removeDevice(const std::string &deviceId)
|
||||||
|
@ -693,18 +707,6 @@ void AkVCam::IpcBridge::update()
|
||||||
xpc_release(dictionary);
|
xpc_release(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::IpcBridge::connections(const std::string &deviceId)
|
|
||||||
{
|
|
||||||
return Preferences::cameraConnections(Preferences::cameraFromPath(deviceId));
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setConnections(const std::string &deviceId,
|
|
||||||
const std::vector<std::string> &connectedDevices)
|
|
||||||
{
|
|
||||||
Preferences::cameraSetConnections(Preferences::cameraFromPath(deviceId),
|
|
||||||
connectedDevices);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::updateDevices()
|
void AkVCam::IpcBridge::updateDevices()
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
|
@ -27,9 +27,8 @@ extern "C" void *akPluginMain(CFAllocatorRef allocator,
|
||||||
CFUUIDRef requestedTypeUUID)
|
CFUUIDRef requestedTypeUUID)
|
||||||
{
|
{
|
||||||
UNUSED(allocator);
|
UNUSED(allocator);
|
||||||
auto logLevel =
|
auto loglevel = AkVCam::Preferences::logLevel();
|
||||||
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
AkVCam::Logger::setLogLevel(loglevel);
|
||||||
AkVCam::Logger::setLogLevel(logLevel);
|
|
||||||
|
|
||||||
if (AkVCam::Logger::logLevel() > AKVCAM_LOGLEVEL_DEFAULT) {
|
if (AkVCam::Logger::logLevel() > AKVCAM_LOGLEVEL_DEFAULT) {
|
||||||
// Turn on lights
|
// Turn on lights
|
||||||
|
|
|
@ -269,9 +269,7 @@ void AkVCam::PluginInterface::deviceAdded(void *userData,
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
auto description = self->d->m_ipcBridge.description(deviceId);
|
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||||
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||||
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
self->createDevice(deviceId, description, formats);
|
||||||
|
|
||||||
self->createDevice(deviceId, description, formats, type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::PluginInterface::deviceRemoved(void *userData,
|
void AkVCam::PluginInterface::deviceRemoved(void *userData,
|
||||||
|
@ -304,8 +302,7 @@ void AkVCam::PluginInterface::devicesUpdated(void *userData, void *unused)
|
||||||
for (auto &deviceId: self->d->m_ipcBridge.devices()) {
|
for (auto &deviceId: self->d->m_ipcBridge.devices()) {
|
||||||
auto description = self->d->m_ipcBridge.description(deviceId);
|
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||||
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||||
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
self->createDevice(deviceId, description, formats);
|
||||||
self->createDevice(deviceId, description, formats, type);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -315,13 +312,9 @@ void AkVCam::PluginInterface::frameReady(void *userData,
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
|
||||||
auto connections = Preferences::cameraConnections(cameraIndex);
|
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
for (auto device: self->m_devices)
|
||||||
if (std::find(connections.begin(),
|
if (device->deviceId() == deviceId)
|
||||||
connections.end(),
|
|
||||||
device->deviceId()) != connections.end())
|
|
||||||
device->frameReady(frame);
|
device->frameReady(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -406,8 +399,7 @@ void AkVCam::PluginInterface::removeListener(void *userData,
|
||||||
|
|
||||||
bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||||
const std::wstring &description,
|
const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats)
|
||||||
IpcBridge::DeviceType type)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
StreamPtr stream;
|
StreamPtr stream;
|
||||||
|
@ -460,10 +452,7 @@ bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||||
|
|
||||||
stream->setBridge(&this->d->m_ipcBridge);
|
stream->setBridge(&this->d->m_ipcBridge);
|
||||||
stream->setFormats(formats);
|
stream->setFormats(formats);
|
||||||
stream->properties().setProperty(kCMIOStreamPropertyDirection,
|
stream->properties().setProperty(kCMIOStreamPropertyDirection, 0);
|
||||||
UInt32(type == IpcBridge::DeviceTypeOutput?
|
|
||||||
Stream::Output:
|
|
||||||
Stream::Input));
|
|
||||||
|
|
||||||
if (device->registerStreams() != kCMIOHardwareNoError) {
|
if (device->registerStreams() != kCMIOHardwareNoError) {
|
||||||
device->registerStreams(false);
|
device->registerStreams(false);
|
||||||
|
|
|
@ -80,8 +80,7 @@ namespace AkVCam
|
||||||
const std::string &deviceId);
|
const std::string &deviceId);
|
||||||
bool createDevice(const std::string &deviceId,
|
bool createDevice(const std::string &deviceId,
|
||||||
const std::wstring &description,
|
const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats);
|
||||||
IpcBridge::DeviceType type);
|
|
||||||
void destroyDevice(const std::string &deviceId);
|
void destroyDevice(const std::string &deviceId);
|
||||||
|
|
||||||
friend struct PluginInterfacePrivate;
|
friend struct PluginInterfacePrivate;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <codecvt>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <random>
|
#include <random>
|
||||||
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
||||||
|
@ -24,6 +25,7 @@
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "PlatformUtils/src/preferences.h"
|
||||||
#include "VCamUtils/src/image/videoformat.h"
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
#include "VCamUtils/src/image/videoframe.h"
|
#include "VCamUtils/src/image/videoframe.h"
|
||||||
#include "VCamUtils/src/logger/logger.h"
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
@ -59,7 +61,6 @@ namespace AkVCam
|
||||||
void stopTimer();
|
void stopTimer();
|
||||||
static void streamLoop(CFRunLoopTimerRef timer, void *info);
|
static void streamLoop(CFRunLoopTimerRef timer, void *info);
|
||||||
void sendFrame(const VideoFrame &frame);
|
void sendFrame(const VideoFrame &frame);
|
||||||
void requestFrame();
|
|
||||||
void updateTestFrame();
|
void updateTestFrame();
|
||||||
VideoFrame applyAdjusts(const VideoFrame &frame);
|
VideoFrame applyAdjusts(const VideoFrame &frame);
|
||||||
VideoFrame randomFrame();
|
VideoFrame randomFrame();
|
||||||
|
@ -73,10 +74,12 @@ AkVCam::Stream::Stream(bool registerObject,
|
||||||
this->d = new StreamPrivate(this);
|
this->d = new StreamPrivate(this);
|
||||||
this->m_className = "Stream";
|
this->m_className = "Stream";
|
||||||
this->m_classID = kCMIOStreamClassID;
|
this->m_classID = kCMIOStreamClassID;
|
||||||
this->d->m_testFrame.load(CMIO_PLUGINS_DAL_PATH
|
auto picture = Preferences::picture();
|
||||||
"/"
|
|
||||||
CMIO_PLUGIN_NAME
|
if (!picture.empty()) {
|
||||||
".plugin/Contents/Resources/TestFrame.bmp");
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
this->d->m_testFrame.load(cv.to_bytes(picture));
|
||||||
|
}
|
||||||
|
|
||||||
this->d->m_clock =
|
this->d->m_clock =
|
||||||
std::make_shared<Clock>("CMIO::VirtualCamera::Stream",
|
std::make_shared<Clock>("CMIO::VirtualCamera::Stream",
|
||||||
|
@ -224,29 +227,13 @@ bool AkVCam::Stream::start()
|
||||||
if (this->d->m_running)
|
if (this->d->m_running)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
UInt32 direction = 0;
|
this->d->updateTestFrame();
|
||||||
this->properties().getProperty(kCMIOStreamPropertyDirection, &direction);
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
|
||||||
if (Direction(direction) == Output) {
|
|
||||||
this->d->updateTestFrame();
|
|
||||||
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
|
||||||
}
|
|
||||||
|
|
||||||
this->d->m_sequence = 0;
|
this->d->m_sequence = 0;
|
||||||
memset(&this->d->m_pts, 0, sizeof(CMTime));
|
memset(&this->d->m_pts, 0, sizeof(CMTime));
|
||||||
this->d->m_running = this->d->startTimer();
|
this->d->m_running = this->d->startTimer();
|
||||||
AkLogInfo() << "Running: " << this->d->m_running << std::endl;
|
AkLogInfo() << "Running: " << this->d->m_running << std::endl;
|
||||||
|
|
||||||
if (Direction(direction) == Input) {
|
|
||||||
std::string deviceId;
|
|
||||||
this->m_parent->properties().getProperty(kCMIODevicePropertyDeviceUID,
|
|
||||||
&deviceId);
|
|
||||||
VideoFormat format;
|
|
||||||
this->m_properties.getProperty(kCMIOStreamPropertyFormatDescription,
|
|
||||||
&format);
|
|
||||||
this->d->m_bridge->deviceStart(deviceId, format);
|
|
||||||
}
|
|
||||||
|
|
||||||
return this->d->m_running;
|
return this->d->m_running;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -257,16 +244,6 @@ void AkVCam::Stream::stop()
|
||||||
if (!this->d->m_running)
|
if (!this->d->m_running)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UInt32 direction = 0;
|
|
||||||
this->properties().getProperty(kCMIOStreamPropertyDirection, &direction);
|
|
||||||
|
|
||||||
if (Direction(direction) == Input) {
|
|
||||||
std::string deviceId;
|
|
||||||
this->m_parent->properties().getProperty(kCMIODevicePropertyDeviceUID,
|
|
||||||
&deviceId);
|
|
||||||
this->d->m_bridge->deviceStop(deviceId);
|
|
||||||
}
|
|
||||||
|
|
||||||
this->d->m_running = false;
|
this->d->m_running = false;
|
||||||
this->d->stopTimer();
|
this->d->stopTimer();
|
||||||
this->d->m_currentFrame.clear();
|
this->d->m_currentFrame.clear();
|
||||||
|
@ -491,17 +468,10 @@ void AkVCam::StreamPrivate::streamLoop(CFRunLoopTimerRef timer, void *info)
|
||||||
|
|
||||||
self->m_mutex.lock();
|
self->m_mutex.lock();
|
||||||
|
|
||||||
UInt32 direction = 0;
|
if (self->m_currentFrame.format().size() < 1)
|
||||||
self->self->m_properties.getProperty(kCMIOStreamPropertyDirection, &direction);
|
self->sendFrame(self->randomFrame());
|
||||||
|
else
|
||||||
if (Stream::Direction(direction) == Stream::Output) {
|
self->sendFrame(self->m_currentFrame);
|
||||||
if (self->m_currentFrame.format().size() < 1)
|
|
||||||
self->sendFrame(self->randomFrame());
|
|
||||||
else
|
|
||||||
self->sendFrame(self->m_currentFrame);
|
|
||||||
} else {
|
|
||||||
self->requestFrame();
|
|
||||||
}
|
|
||||||
|
|
||||||
self->m_mutex.unlock();
|
self->m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
@ -599,97 +569,6 @@ void AkVCam::StreamPrivate::sendFrame(const VideoFrame &frame)
|
||||||
this->m_queueAlteredRefCon);
|
this->m_queueAlteredRefCon);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::StreamPrivate::requestFrame()
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (this->m_queue->fullness() >= 1.0f)
|
|
||||||
return;
|
|
||||||
|
|
||||||
bool resync = false;
|
|
||||||
auto hostTime = CFAbsoluteTimeGetCurrent();
|
|
||||||
auto pts = CMTimeMake(int64_t(hostTime), 1e9);
|
|
||||||
auto ptsDiff = CMTimeGetSeconds(CMTimeSubtract(this->m_pts, pts));
|
|
||||||
|
|
||||||
if (CMTimeCompare(pts, this->m_pts) == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
Float64 fps = 0;
|
|
||||||
this->self->m_properties.getProperty(kCMIOStreamPropertyFrameRate, &fps);
|
|
||||||
|
|
||||||
if (CMTIME_IS_INVALID(this->m_pts)
|
|
||||||
|| ptsDiff < 0
|
|
||||||
|| ptsDiff > 2. / fps) {
|
|
||||||
this->m_pts = pts;
|
|
||||||
resync = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CMIOStreamClockPostTimingEvent(this->m_pts,
|
|
||||||
UInt64(hostTime),
|
|
||||||
resync,
|
|
||||||
this->m_clock->ref());
|
|
||||||
|
|
||||||
if (!this->m_queueAltered)
|
|
||||||
return;
|
|
||||||
|
|
||||||
this->m_queueAltered(this->self->m_objectID,
|
|
||||||
nullptr,
|
|
||||||
this->m_queueAlteredRefCon);
|
|
||||||
|
|
||||||
for (;;) {
|
|
||||||
auto videoBuffer = this->m_queue->dequeue();
|
|
||||||
|
|
||||||
if (!videoBuffer)
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Read frame data.
|
|
||||||
auto imageBuffer = CMSampleBufferGetImageBuffer(videoBuffer);
|
|
||||||
auto dataBuffer = CMSampleBufferGetDataBuffer(videoBuffer);
|
|
||||||
auto formatDesc = CMSampleBufferGetFormatDescription(videoBuffer);
|
|
||||||
auto fourCC = CMFormatDescriptionGetMediaSubType(formatDesc);
|
|
||||||
auto size = CMVideoFormatDescriptionGetDimensions(formatDesc);
|
|
||||||
Float64 fps = 0;
|
|
||||||
this->self->m_properties.getProperty(kCMIOStreamPropertyFrameRate, &fps);
|
|
||||||
VideoFormat videoFormat(formatFromCM(fourCC),
|
|
||||||
size.width,
|
|
||||||
size.height,
|
|
||||||
{{int64_t(std::round(fps)), 1}});
|
|
||||||
VideoFrame videoFrame(videoFormat);
|
|
||||||
|
|
||||||
if (imageBuffer) {
|
|
||||||
size_t dataSize = CVPixelBufferGetDataSize(imageBuffer);
|
|
||||||
CVPixelBufferLockBaseAddress(imageBuffer, 0);
|
|
||||||
void *data = CVPixelBufferGetBaseAddress(imageBuffer);
|
|
||||||
memcpy(videoFrame.data().data(),
|
|
||||||
data,
|
|
||||||
std::min(videoFrame.data().size(), dataSize));
|
|
||||||
CVPixelBufferUnlockBaseAddress(imageBuffer, 0);
|
|
||||||
} else if (dataBuffer) {
|
|
||||||
size_t lengthAtOffset = 0;
|
|
||||||
size_t dataSize = 0;
|
|
||||||
char *data = nullptr;
|
|
||||||
CMBlockBufferGetDataPointer(dataBuffer,
|
|
||||||
0,
|
|
||||||
&lengthAtOffset,
|
|
||||||
&dataSize,
|
|
||||||
&data);
|
|
||||||
memcpy(videoFrame.data().data(),
|
|
||||||
data,
|
|
||||||
std::min(videoFrame.data().size(), dataSize));
|
|
||||||
}
|
|
||||||
|
|
||||||
CFRelease(videoBuffer);
|
|
||||||
|
|
||||||
std::string deviceId;
|
|
||||||
this->self->properties().getProperty(kCMIODevicePropertyDeviceUID,
|
|
||||||
&deviceId);
|
|
||||||
this->m_bridge->write(deviceId, videoFrame);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto duration = CMTimeMake(1e3, int32_t(1e3 * fps));
|
|
||||||
this->m_pts = CMTimeAdd(this->m_pts, duration);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::StreamPrivate::updateTestFrame()
|
void AkVCam::StreamPrivate::updateTestFrame()
|
||||||
{
|
{
|
||||||
this->m_testFrameAdapted = this->applyAdjusts(this->m_testFrame);
|
this->m_testFrameAdapted = this->applyAdjusts(this->m_testFrame);
|
||||||
|
|
|
@ -38,12 +38,6 @@ namespace AkVCam
|
||||||
class Stream: public Object
|
class Stream: public Object
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
enum Direction
|
|
||||||
{
|
|
||||||
Output,
|
|
||||||
Input
|
|
||||||
};
|
|
||||||
|
|
||||||
Stream(bool registerObject=false, Object *m_parent=nullptr);
|
Stream(bool registerObject=false, Object *m_parent=nullptr);
|
||||||
Stream(const Stream &other) = delete;
|
Stream(const Stream &other) = delete;
|
||||||
~Stream();
|
~Stream();
|
||||||
|
|
|
@ -658,8 +658,7 @@ bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description,
|
std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description,
|
||||||
const std::vector<VideoFormat> &formats,
|
const std::vector<VideoFormat> &formats)
|
||||||
DeviceType type)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue