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 "VCamUtils/src/ipcbridge.h"
|
||||
#include "VCamUtils/src/image/videoformat.h"
|
||||
#include "VCamUtils/src/image/videoframe.h"
|
||||
#include "VCamUtils/src/logger/logger.h"
|
||||
|
||||
#define AKVCAM_BIND_FUNC(member) \
|
||||
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 removeDevice(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,
|
||||
const StringVector &args);
|
||||
int setDeviceDescription(const StringMap &flags,
|
||||
|
@ -93,17 +93,14 @@ namespace AkVCam {
|
|||
int removeFormats(const StringMap &flags, const StringVector &args);
|
||||
int update(const StringMap &flags, const StringVector &args);
|
||||
int loadSettings(const StringMap &flags, const StringVector &args);
|
||||
int showConnections(const StringMap &flags,
|
||||
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 stream(const StringMap &flags, const StringVector &args);
|
||||
int showControls(const StringMap &flags, const StringVector &args);
|
||||
int readControl(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);
|
||||
};
|
||||
|
||||
|
@ -116,10 +113,10 @@ AkVCam::CmdParser::CmdParser()
|
|||
this->d->m_commands.push_back({});
|
||||
this->setDefaultFuntion(AKVCAM_BIND_FUNC(CmdParserPrivate::defaultHandler));
|
||||
this->addFlags("",
|
||||
{"-h", "--help"},
|
||||
{"-h", "--help"},
|
||||
"Show help.");
|
||||
this->addFlags("",
|
||||
{"-p", "--parseable"},
|
||||
{"-p", "--parseable"},
|
||||
"Show parseable output.");
|
||||
this->addCommand("devices",
|
||||
"",
|
||||
|
@ -129,12 +126,6 @@ AkVCam::CmdParser::CmdParser()
|
|||
"DESCRIPTION",
|
||||
"Add a new device.",
|
||||
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",
|
||||
"DEVICE",
|
||||
"Remove a device.",
|
||||
|
@ -143,10 +134,6 @@ AkVCam::CmdParser::CmdParser()
|
|||
"",
|
||||
"Remove all devices.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::removeDevices));
|
||||
this->addCommand("type",
|
||||
"DEVICE",
|
||||
"Show device type.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showDeviceType));
|
||||
this->addCommand("description",
|
||||
"DEVICE",
|
||||
"Show device description.",
|
||||
|
@ -160,10 +147,10 @@ AkVCam::CmdParser::CmdParser()
|
|||
"Show supported formats.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showSupportedFormats));
|
||||
this->addFlags("supported-formats",
|
||||
{"-i", "--input"},
|
||||
{"-i", "--input"},
|
||||
"Show supported input formats.");
|
||||
this->addFlags("supported-formats",
|
||||
{"-o", "--output"},
|
||||
{"-o", "--output"},
|
||||
"Show supported output formats.");
|
||||
this->addCommand("formats",
|
||||
"DEVICE",
|
||||
|
@ -174,7 +161,7 @@ AkVCam::CmdParser::CmdParser()
|
|||
"Add a new device format.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::addFormat));
|
||||
this->addFlags("add-format",
|
||||
{"-i", "--index"},
|
||||
{"-i", "--index"},
|
||||
"INDEX",
|
||||
"Add format at INDEX.");
|
||||
this->addCommand("remove-format",
|
||||
|
@ -193,22 +180,10 @@ AkVCam::CmdParser::CmdParser()
|
|||
"SETTINGS.INI",
|
||||
"Create devices from a setting file.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::loadSettings));
|
||||
this->addCommand("connections",
|
||||
"DEVICE",
|
||||
"Show device connections.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::showConnections));
|
||||
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("stream",
|
||||
"DEVICE FORMAT WIDTH HEIGHT",
|
||||
"Read frames from stdin and send them to the device.",
|
||||
AKVCAM_BIND_FUNC(CmdParserPrivate::stream));
|
||||
this->addCommand("controls",
|
||||
"DEVICE",
|
||||
"Show device controls.",
|
||||
|
@ -221,6 +196,22 @@ AkVCam::CmdParser::CmdParser()
|
|||
"DEVICE CONTROL VALUE",
|
||||
"Write device control value.",
|
||||
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",
|
||||
"",
|
||||
"Show clients using the camera.",
|
||||
|
@ -619,45 +610,30 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
|||
std::cout << device << std::endl;
|
||||
} else {
|
||||
StringVector devicesColumn;
|
||||
StringVector typesColumn;
|
||||
WStringVector descriptionsColumn;
|
||||
|
||||
devicesColumn.push_back("Device");
|
||||
typesColumn.push_back("Type");
|
||||
descriptionsColumn.push_back(L"Description");
|
||||
|
||||
for (auto &device: devices) {
|
||||
devicesColumn.push_back(device);
|
||||
typesColumn.push_back(this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
||||
"Input":
|
||||
"Output");
|
||||
descriptionsColumn.push_back(this->m_ipcBridge.description(device));
|
||||
}
|
||||
|
||||
auto devicesColumnSize = this->maxStringLength(devicesColumn);
|
||||
auto typesColumnSize = this->maxStringLength(typesColumn);
|
||||
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
||||
|
||||
std::cout << fill("Device", devicesColumnSize)
|
||||
<< " | "
|
||||
<< fill("Type", typesColumnSize)
|
||||
<< " | "
|
||||
<< fill("Description", descriptionsColumnSize)
|
||||
<< std::endl;
|
||||
std::cout << std::string("-")
|
||||
* (devicesColumnSize
|
||||
+ typesColumnSize
|
||||
+ descriptionsColumnSize
|
||||
+ 6) << std::endl;
|
||||
+ 4) << std::endl;
|
||||
|
||||
for (auto &device: devices) {
|
||||
std::string type =
|
||||
this->m_ipcBridge.deviceType(device) == IpcBridge::DeviceTypeInput?
|
||||
"Input":
|
||||
"Output";
|
||||
std::cout << fill(device, devicesColumnSize)
|
||||
<< " | "
|
||||
<< fill(type, typesColumnSize)
|
||||
<< " | ";
|
||||
std::wcout << fill(this->m_ipcBridge.description(device),
|
||||
descriptionsColumnSize)
|
||||
|
@ -671,19 +647,16 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
|||
int AkVCam::CmdParserPrivate::addDevice(const StringMap &flags,
|
||||
const StringVector &args)
|
||||
{
|
||||
UNUSED(flags);
|
||||
|
||||
if (args.size() < 2) {
|
||||
std::cerr << "Device description not provided." << std::endl;
|
||||
|
||||
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;
|
||||
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()) {
|
||||
std::cerr << "Failed to create device." << std::endl;
|
||||
|
@ -738,35 +711,6 @@ int AkVCam::CmdParserPrivate::removeDevices(const AkVCam::StringMap &flags,
|
|||
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,
|
||||
const StringVector &args)
|
||||
{
|
||||
|
@ -827,12 +771,12 @@ int AkVCam::CmdParserPrivate::showSupportedFormats(const StringMap &flags,
|
|||
|
||||
auto type =
|
||||
this->containsFlag(flags, "supported-formats", "-i")?
|
||||
IpcBridge::DeviceTypeInput:
|
||||
IpcBridge::DeviceTypeOutput;
|
||||
IpcBridge::StreamTypeInput:
|
||||
IpcBridge::StreamTypeOutput;
|
||||
auto formats = this->m_ipcBridge.supportedPixelFormats(type);
|
||||
|
||||
if (!this->m_parseable) {
|
||||
if (type == IpcBridge::DeviceTypeInput)
|
||||
if (type == IpcBridge::StreamTypeInput)
|
||||
std::cout << "Input formats:" << std::endl;
|
||||
else
|
||||
std::cout << "Output formats:" << std::endl;
|
||||
|
@ -930,15 +874,11 @@ int AkVCam::CmdParserPrivate::addFormat(const StringMap &flags,
|
|||
return -1;
|
||||
}
|
||||
|
||||
auto type = this->m_ipcBridge.deviceType(deviceId);
|
||||
auto formats = this->m_ipcBridge.supportedPixelFormats(type);
|
||||
auto formats = this->m_ipcBridge.supportedPixelFormats(IpcBridge::StreamTypeOutput);
|
||||
auto fit = std::find(formats.begin(), formats.end(), format);
|
||||
|
||||
if (fit == formats.end()) {
|
||||
if (type == IpcBridge::DeviceTypeInput)
|
||||
std::cerr << "Input format not supported." << std::endl;
|
||||
else
|
||||
std::cerr << "Output format not supported." << std::endl;
|
||||
std::cerr << "Format not supported." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
@ -1074,12 +1014,12 @@ int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
|
|||
return 0;
|
||||
}
|
||||
|
||||
int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
||||
const StringVector &args)
|
||||
int AkVCam::CmdParserPrivate::stream(const AkVCam::StringMap &flags,
|
||||
const AkVCam::StringVector &args)
|
||||
{
|
||||
UNUSED(flags);
|
||||
|
||||
if (args.size() < 2) {
|
||||
if (args.size() < 5) {
|
||||
std::cerr << "Not enough arguments." << std::endl;
|
||||
|
||||
return -1;
|
||||
|
@ -1095,153 +1035,72 @@ int AkVCam::CmdParserPrivate::showConnections(const StringMap &flags,
|
|||
return -1;
|
||||
}
|
||||
|
||||
for (auto &connectedDevice: this->m_ipcBridge.connections(deviceId))
|
||||
std::cout << connectedDevice << std::endl;
|
||||
auto format = VideoFormat::fourccFromString(args[2]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int AkVCam::CmdParserPrivate::connectDevices(const StringMap &flags,
|
||||
const StringVector &args)
|
||||
{
|
||||
UNUSED(flags);
|
||||
|
||||
if (args.size() < 3) {
|
||||
std::cerr << "Not enough arguments." << std::endl;
|
||||
if (!format) {
|
||||
std::cerr << "Invalid pixel format." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
auto inputDevice = args[1];
|
||||
auto devices = this->m_ipcBridge.devices();
|
||||
auto it = std::find(devices.begin(), devices.end(), inputDevice);
|
||||
auto formats = this->m_ipcBridge.supportedPixelFormats(IpcBridge::StreamTypeOutput);
|
||||
auto fit = std::find(formats.begin(), formats.end(), format);
|
||||
|
||||
if (it == devices.end()) {
|
||||
std::cerr << inputDevice << " doesn't exists." << std::endl;
|
||||
if (fit == formats.end()) {
|
||||
std::cerr << "Format not supported." << std::endl;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (this->m_ipcBridge.deviceType(inputDevice) != IpcBridge::DeviceTypeInput) {
|
||||
std::cerr << inputDevice << " is not an input." << std::endl;
|
||||
char *p = nullptr;
|
||||
auto width = strtoul(args[3].c_str(), &p, 10);
|
||||
|
||||
if (*p) {
|
||||
std::cerr << "Width must be an unsigned integer." << std::endl;
|
||||
|
||||
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++) {
|
||||
auto &outputDevice = args[i];
|
||||
auto it = std::find(devices.begin(), devices.end(), outputDevice);
|
||||
if (*p) {
|
||||
std::cerr << "Height must be an unsigned integer." << std::endl;
|
||||
|
||||
if (it == devices.end()) {
|
||||
std::cerr << outputDevice << " doesn't exists." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
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) {
|
||||
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;
|
||||
this->m_ipcBridge.deviceStop(deviceId);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1264,6 +1123,73 @@ int AkVCam::CmdParserPrivate::writeControl(const StringMap &flags,
|
|||
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,
|
||||
const StringVector &args)
|
||||
{
|
||||
|
|
|
@ -42,10 +42,10 @@ namespace AkVCam
|
|||
ServerStateGone
|
||||
};
|
||||
|
||||
enum DeviceType
|
||||
enum StreamType
|
||||
{
|
||||
DeviceTypeOutput,
|
||||
DeviceTypeInput
|
||||
StreamTypeOutput,
|
||||
StreamTypeInput
|
||||
};
|
||||
|
||||
AKVCAM_SIGNAL(ServerStateChanged,
|
||||
|
@ -104,6 +104,11 @@ namespace AkVCam
|
|||
std::string driver() const;
|
||||
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
|
||||
// privileges.
|
||||
std::vector<std::string> availableRootMethods() const;
|
||||
|
@ -129,10 +134,10 @@ namespace AkVCam
|
|||
const std::wstring &description);
|
||||
|
||||
// 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.
|
||||
PixelFormat defaultPixelFormat(DeviceType type) const;
|
||||
PixelFormat defaultPixelFormat(StreamType type) const;
|
||||
|
||||
// Return supported formats for the device.
|
||||
std::vector<VideoFormat> formats(const std::string &deviceId) const;
|
||||
|
@ -168,19 +173,13 @@ namespace AkVCam
|
|||
|
||||
/* Server */
|
||||
|
||||
DeviceType deviceType(const std::string &deviceId);
|
||||
std::string addDevice(const std::wstring &description,
|
||||
DeviceType type);
|
||||
std::string addDevice(const std::wstring &description);
|
||||
void removeDevice(const std::string &deviceId);
|
||||
void addFormat(const std::string &deviceId,
|
||||
const VideoFormat &format,
|
||||
int index=-1);
|
||||
void removeFormat(const std::string &deviceId, int index);
|
||||
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();
|
||||
|
||||
// Start frame transfer to the device.
|
||||
|
|
|
@ -37,7 +37,7 @@ namespace AkVCam
|
|||
int logLevel {AKVCAM_LOGLEVEL_DEFAULT};
|
||||
std::fstream stream;
|
||||
|
||||
static std::string logLevelString(int logLevel)
|
||||
static const std::map<int, std::string> &logLevelStrMap()
|
||||
{
|
||||
static std::map<int, std::string> llsMap {
|
||||
{AKVCAM_LOGLEVEL_DEFAULT , "default" },
|
||||
|
@ -51,10 +51,7 @@ namespace AkVCam
|
|||
{AKVCAM_LOGLEVEL_DEBUG , "debug" },
|
||||
};
|
||||
|
||||
if (llsMap.count(logLevel) < 1)
|
||||
return {};
|
||||
|
||||
return llsMap[logLevel];
|
||||
return llsMap;
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -115,7 +112,7 @@ std::string AkVCam::Logger::header(int logLevel, const std::string file, int lin
|
|||
<< " ("
|
||||
<< line
|
||||
<< ")] "
|
||||
<< LoggerPrivate::logLevelString(logLevel) << ": ";
|
||||
<< levelToString(logLevel) << ": ";
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
@ -139,3 +136,25 @@ std::ostream &AkVCam::Logger::log(int logLevel)
|
|||
|
||||
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);
|
||||
std::string header(int logLevel, const std::string file, int line);
|
||||
std::ostream &log(int logLevel);
|
||||
int levelFromString(const std::string &level);
|
||||
std::string levelToString(int level);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -39,20 +39,16 @@
|
|||
|
||||
namespace AkVCam
|
||||
{
|
||||
|
||||
|
||||
struct AssistantDevice
|
||||
{
|
||||
std::wstring description;
|
||||
std::vector<VideoFormat> formats;
|
||||
std::vector<std::string> connections;
|
||||
std::string broadcaster;
|
||||
std::vector<std::string> listeners;
|
||||
IpcBridge::DeviceType type;
|
||||
bool horizontalMirror {false};
|
||||
bool verticalMirror {false};
|
||||
Scaling scaling {ScalingFast};
|
||||
AspectRatio aspectRatio {AspectRatioIgnore};
|
||||
AspectRatio aspectRatio {AspectRatioIgnore};
|
||||
bool swapRgb {false};
|
||||
};
|
||||
|
||||
|
@ -95,7 +91,7 @@ namespace AkVCam
|
|||
void listener(xpc_connection_t client, xpc_object_t event);
|
||||
void devices(xpc_connection_t client, xpc_object_t event);
|
||||
void description(xpc_connection_t client, xpc_object_t event);
|
||||
void formats(xpc_connection_t client, xpc_object_t event);
|
||||
void formats(xpc_connection_t client, xpc_object_t event);
|
||||
void broadcasting(xpc_connection_t client, xpc_object_t event);
|
||||
void mirroring(xpc_connection_t client, xpc_object_t event);
|
||||
void scaling(xpc_connection_t client, xpc_object_t event);
|
||||
|
@ -103,8 +99,6 @@ namespace AkVCam
|
|||
void swapRgb(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 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_SWAPRGB , AKVCAM_BIND_FUNC(AssistantPrivate::swapRgb) },
|
||||
{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();
|
||||
|
@ -263,8 +255,6 @@ void AkVCam::AssistantPrivate::loadCameras()
|
|||
this->m_deviceConfigs[path].description =
|
||||
Preferences::cameraDescription(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}});
|
||||
}
|
||||
|
||||
auto type = xpc_dictionary_get_bool(event, "isinput")?
|
||||
IpcBridge::DeviceTypeInput:
|
||||
IpcBridge::DeviceTypeOutput;
|
||||
auto deviceId = Preferences::addCamera(description, formats, type);
|
||||
auto deviceId = Preferences::addCamera(description, formats);
|
||||
this->m_deviceConfigs[deviceId] = {};
|
||||
this->m_deviceConfigs[deviceId].type = type;
|
||||
this->m_deviceConfigs[deviceId].description = description;
|
||||
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_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)
|
||||
{
|
||||
auto loglevel =
|
||||
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
||||
auto loglevel = AkVCam::Preferences::logLevel();
|
||||
AkVCam::Logger::setLogLevel(loglevel);
|
||||
AkLogDebug() << "Creating Service: " << CMIO_ASSISTANT_NAME << std::endl;
|
||||
auto server =
|
||||
|
|
|
@ -282,8 +282,7 @@ void AkVCam::Preferences::sync()
|
|||
CFPreferencesAppSynchronize(PREFERENCES_ID);
|
||||
}
|
||||
|
||||
std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
||||
AkVCam::IpcBridge::DeviceType type)
|
||||
std::string AkVCam::Preferences::addDevice(const std::wstring &description)
|
||||
{
|
||||
AkLogFunction();
|
||||
auto path = createDevicePath();
|
||||
|
@ -293,10 +292,6 @@ std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
|||
+ std::to_string(cameraIndex)
|
||||
+ ".description",
|
||||
description);
|
||||
write("cameras."
|
||||
+ std::to_string(cameraIndex)
|
||||
+ ".isinput",
|
||||
type == IpcBridge::DeviceTypeInput);
|
||||
write("cameras."
|
||||
+ std::to_string(cameraIndex)
|
||||
+ ".path",
|
||||
|
@ -307,16 +302,14 @@ std::string AkVCam::Preferences::addDevice(const std::wstring &description,
|
|||
}
|
||||
|
||||
std::string AkVCam::Preferences::addCamera(const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type)
|
||||
const std::vector<VideoFormat> &formats)
|
||||
{
|
||||
return addCamera("", description, formats, type);
|
||||
return addCamera("", description, formats);
|
||||
}
|
||||
|
||||
std::string AkVCam::Preferences::addCamera(const std::string &path,
|
||||
const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type)
|
||||
const std::vector<VideoFormat> &formats)
|
||||
{
|
||||
AkLogFunction();
|
||||
|
||||
|
@ -330,10 +323,6 @@ std::string AkVCam::Preferences::addCamera(const std::string &path,
|
|||
+ std::to_string(cameraIndex)
|
||||
+ ".description",
|
||||
description);
|
||||
write("cameras."
|
||||
+ std::to_string(cameraIndex)
|
||||
+ ".isinput",
|
||||
type == IpcBridge::DeviceTypeInput);
|
||||
write("cameras."
|
||||
+ std::to_string(cameraIndex)
|
||||
+ ".path",
|
||||
|
@ -442,11 +431,6 @@ bool AkVCam::Preferences::cameraExists(const std::string &path)
|
|||
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)
|
||||
{
|
||||
if (cameraIndex >= camerasCount())
|
||||
|
@ -578,9 +562,6 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
|||
{
|
||||
AkLogFunction();
|
||||
|
||||
if (!cameraIsInput(cameraIndex))
|
||||
return;
|
||||
|
||||
auto formats = cameraFormats(cameraIndex);
|
||||
|
||||
if (index < 0 || index >= int(formats.size()))
|
||||
|
@ -609,74 +590,22 @@ void AkVCam::Preferences::cameraRemoveFormat(size_t cameraIndex, int index)
|
|||
sync();
|
||||
}
|
||||
|
||||
std::vector<std::string> AkVCam::Preferences::cameraConnections(size_t cameraIndex)
|
||||
std::wstring AkVCam::Preferences::picture()
|
||||
{
|
||||
AkLogFunction();
|
||||
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;
|
||||
return readWString("picture");
|
||||
}
|
||||
|
||||
void AkVCam::Preferences::cameraSetConnections(size_t cameraIndex,
|
||||
const std::vector<std::string> &connectedDevices)
|
||||
void AkVCam::Preferences::setPicture(const std::wstring &picture)
|
||||
{
|
||||
AkLogFunction();
|
||||
|
||||
if (!cameraIsInput(cameraIndex))
|
||||
return;
|
||||
|
||||
std::vector<std::string> connections;
|
||||
|
||||
for (auto &connection: connectedDevices) {
|
||||
if (connection.empty())
|
||||
continue;
|
||||
|
||||
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);
|
||||
write("picture", picture);
|
||||
}
|
||||
|
||||
int AkVCam::Preferences::logLevel()
|
||||
{
|
||||
return readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
||||
}
|
||||
|
||||
void AkVCam::Preferences::setLogLevel(int logLevel)
|
||||
{
|
||||
write("loglevel", logLevel);
|
||||
}
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <vector>
|
||||
#include <CoreFoundation/CoreFoundation.h>
|
||||
|
||||
#include "VCamUtils/src/ipcbridge.h"
|
||||
|
||||
namespace AkVCam
|
||||
{
|
||||
class VideoFormat;
|
||||
|
@ -55,21 +53,17 @@ namespace AkVCam
|
|||
void move(const std::string &keyFrom, const std::string &keyTo);
|
||||
void moveAll(const std::string &keyFrom, const std::string &keyTo);
|
||||
void sync();
|
||||
std::string addDevice(const std::wstring &description,
|
||||
IpcBridge::DeviceType type);
|
||||
std::string addDevice(const std::wstring &description);
|
||||
std::string addCamera(const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type);
|
||||
const std::vector<VideoFormat> &formats);
|
||||
std::string addCamera(const std::string &path,
|
||||
const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type);
|
||||
const std::vector<VideoFormat> &formats);
|
||||
void removeCamera(const std::string &path);
|
||||
size_t camerasCount();
|
||||
std::string createDevicePath();
|
||||
int cameraFromPath(const std::string &path);
|
||||
bool cameraExists(const std::string &path);
|
||||
bool cameraIsInput(size_t cameraIndex);
|
||||
std::wstring cameraDescription(size_t cameraIndex);
|
||||
void cameraSetDescription(size_t cameraIndex,
|
||||
const std::wstring &description);
|
||||
|
@ -85,9 +79,10 @@ namespace AkVCam
|
|||
const VideoFormat &format,
|
||||
int index);
|
||||
void cameraRemoveFormat(size_t cameraIndex, int index);
|
||||
std::vector<std::string> cameraConnections(size_t cameraIndex);
|
||||
void cameraSetConnections(size_t cameraIndex,
|
||||
const std::vector<std::string> &connectedDevices);
|
||||
std::wstring picture();
|
||||
void setPicture(const std::wstring &picture);
|
||||
int logLevel();
|
||||
void setLogLevel(int logLevel);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -104,6 +104,8 @@ AkVCam::IpcBridge::IpcBridge()
|
|||
{
|
||||
AkLogFunction();
|
||||
this->d = new IpcBridgePrivate(this);
|
||||
auto loglevel = AkVCam::Preferences::logLevel();
|
||||
AkVCam::Logger::setLogLevel(loglevel);
|
||||
ipcBridgePrivate().add(this);
|
||||
this->registerPeer();
|
||||
}
|
||||
|
@ -159,6 +161,28 @@ bool AkVCam::IpcBridge::setDriver(const std::string &driver)
|
|||
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
|
||||
{
|
||||
return {"osascript"};
|
||||
|
@ -356,9 +380,9 @@ void AkVCam::IpcBridge::setDescription(const std::string &deviceId,
|
|||
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 {
|
||||
|
@ -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:
|
||||
PixelFormatYUY2;
|
||||
}
|
||||
|
@ -641,19 +665,9 @@ std::string AkVCam::IpcBridge::clientExe(uint64_t pid) const
|
|||
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::cameraIsInput(cameraIndex)?
|
||||
DeviceTypeInput:
|
||||
DeviceTypeOutput;
|
||||
}
|
||||
|
||||
std::string AkVCam::IpcBridge::addDevice(const std::wstring &description,
|
||||
DeviceType type)
|
||||
{
|
||||
return Preferences::addDevice(description, type);
|
||||
return Preferences::addDevice(description);
|
||||
}
|
||||
|
||||
void AkVCam::IpcBridge::removeDevice(const std::string &deviceId)
|
||||
|
@ -693,18 +707,6 @@ void AkVCam::IpcBridge::update()
|
|||
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()
|
||||
{
|
||||
AkLogFunction();
|
||||
|
|
|
@ -27,9 +27,8 @@ extern "C" void *akPluginMain(CFAllocatorRef allocator,
|
|||
CFUUIDRef requestedTypeUUID)
|
||||
{
|
||||
UNUSED(allocator);
|
||||
auto logLevel =
|
||||
AkVCam::Preferences::readInt("loglevel", AKVCAM_LOGLEVEL_DEFAULT);
|
||||
AkVCam::Logger::setLogLevel(logLevel);
|
||||
auto loglevel = AkVCam::Preferences::logLevel();
|
||||
AkVCam::Logger::setLogLevel(loglevel);
|
||||
|
||||
if (AkVCam::Logger::logLevel() > AKVCAM_LOGLEVEL_DEFAULT) {
|
||||
// Turn on lights
|
||||
|
|
|
@ -269,9 +269,7 @@ void AkVCam::PluginInterface::deviceAdded(void *userData,
|
|||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
||||
|
||||
self->createDevice(deviceId, description, formats, type);
|
||||
self->createDevice(deviceId, description, formats);
|
||||
}
|
||||
|
||||
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()) {
|
||||
auto description = self->d->m_ipcBridge.description(deviceId);
|
||||
auto formats = self->d->m_ipcBridge.formats(deviceId);
|
||||
auto type = self->d->m_ipcBridge.deviceType(deviceId);
|
||||
self->createDevice(deviceId, description, formats, type);
|
||||
self->createDevice(deviceId, description, formats);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -315,13 +312,9 @@ void AkVCam::PluginInterface::frameReady(void *userData,
|
|||
{
|
||||
AkLogFunction();
|
||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||
auto connections = Preferences::cameraConnections(cameraIndex);
|
||||
|
||||
for (auto device: self->m_devices)
|
||||
if (std::find(connections.begin(),
|
||||
connections.end(),
|
||||
device->deviceId()) != connections.end())
|
||||
if (device->deviceId() == deviceId)
|
||||
device->frameReady(frame);
|
||||
}
|
||||
|
||||
|
@ -406,8 +399,7 @@ void AkVCam::PluginInterface::removeListener(void *userData,
|
|||
|
||||
bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||
const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type)
|
||||
const std::vector<VideoFormat> &formats)
|
||||
{
|
||||
AkLogFunction();
|
||||
StreamPtr stream;
|
||||
|
@ -460,10 +452,7 @@ bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
|||
|
||||
stream->setBridge(&this->d->m_ipcBridge);
|
||||
stream->setFormats(formats);
|
||||
stream->properties().setProperty(kCMIOStreamPropertyDirection,
|
||||
UInt32(type == IpcBridge::DeviceTypeOutput?
|
||||
Stream::Output:
|
||||
Stream::Input));
|
||||
stream->properties().setProperty(kCMIOStreamPropertyDirection, 0);
|
||||
|
||||
if (device->registerStreams() != kCMIOHardwareNoError) {
|
||||
device->registerStreams(false);
|
||||
|
|
|
@ -80,8 +80,7 @@ namespace AkVCam
|
|||
const std::string &deviceId);
|
||||
bool createDevice(const std::string &deviceId,
|
||||
const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
IpcBridge::DeviceType type);
|
||||
const std::vector<VideoFormat> &formats);
|
||||
void destroyDevice(const std::string &deviceId);
|
||||
|
||||
friend struct PluginInterfacePrivate;
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
* Web-Site: http://webcamoid.github.io/
|
||||
*/
|
||||
|
||||
#include <codecvt>
|
||||
#include <thread>
|
||||
#include <random>
|
||||
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
||||
|
@ -24,6 +25,7 @@
|
|||
#include "stream.h"
|
||||
#include "clock.h"
|
||||
#include "utils.h"
|
||||
#include "PlatformUtils/src/preferences.h"
|
||||
#include "VCamUtils/src/image/videoformat.h"
|
||||
#include "VCamUtils/src/image/videoframe.h"
|
||||
#include "VCamUtils/src/logger/logger.h"
|
||||
|
@ -59,7 +61,6 @@ namespace AkVCam
|
|||
void stopTimer();
|
||||
static void streamLoop(CFRunLoopTimerRef timer, void *info);
|
||||
void sendFrame(const VideoFrame &frame);
|
||||
void requestFrame();
|
||||
void updateTestFrame();
|
||||
VideoFrame applyAdjusts(const VideoFrame &frame);
|
||||
VideoFrame randomFrame();
|
||||
|
@ -73,10 +74,12 @@ AkVCam::Stream::Stream(bool registerObject,
|
|||
this->d = new StreamPrivate(this);
|
||||
this->m_className = "Stream";
|
||||
this->m_classID = kCMIOStreamClassID;
|
||||
this->d->m_testFrame.load(CMIO_PLUGINS_DAL_PATH
|
||||
"/"
|
||||
CMIO_PLUGIN_NAME
|
||||
".plugin/Contents/Resources/TestFrame.bmp");
|
||||
auto picture = Preferences::picture();
|
||||
|
||||
if (!picture.empty()) {
|
||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||
this->d->m_testFrame.load(cv.to_bytes(picture));
|
||||
}
|
||||
|
||||
this->d->m_clock =
|
||||
std::make_shared<Clock>("CMIO::VirtualCamera::Stream",
|
||||
|
@ -224,29 +227,13 @@ bool AkVCam::Stream::start()
|
|||
if (this->d->m_running)
|
||||
return false;
|
||||
|
||||
UInt32 direction = 0;
|
||||
this->properties().getProperty(kCMIOStreamPropertyDirection, &direction);
|
||||
|
||||
if (Direction(direction) == Output) {
|
||||
this->d->updateTestFrame();
|
||||
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||
}
|
||||
|
||||
this->d->updateTestFrame();
|
||||
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||
this->d->m_sequence = 0;
|
||||
memset(&this->d->m_pts, 0, sizeof(CMTime));
|
||||
this->d->m_running = this->d->startTimer();
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -257,16 +244,6 @@ void AkVCam::Stream::stop()
|
|||
if (!this->d->m_running)
|
||||
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->stopTimer();
|
||||
this->d->m_currentFrame.clear();
|
||||
|
@ -491,17 +468,10 @@ void AkVCam::StreamPrivate::streamLoop(CFRunLoopTimerRef timer, void *info)
|
|||
|
||||
self->m_mutex.lock();
|
||||
|
||||
UInt32 direction = 0;
|
||||
self->self->m_properties.getProperty(kCMIOStreamPropertyDirection, &direction);
|
||||
|
||||
if (Stream::Direction(direction) == Stream::Output) {
|
||||
if (self->m_currentFrame.format().size() < 1)
|
||||
self->sendFrame(self->randomFrame());
|
||||
else
|
||||
self->sendFrame(self->m_currentFrame);
|
||||
} else {
|
||||
self->requestFrame();
|
||||
}
|
||||
if (self->m_currentFrame.format().size() < 1)
|
||||
self->sendFrame(self->randomFrame());
|
||||
else
|
||||
self->sendFrame(self->m_currentFrame);
|
||||
|
||||
self->m_mutex.unlock();
|
||||
}
|
||||
|
@ -599,97 +569,6 @@ void AkVCam::StreamPrivate::sendFrame(const VideoFrame &frame)
|
|||
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()
|
||||
{
|
||||
this->m_testFrameAdapted = this->applyAdjusts(this->m_testFrame);
|
||||
|
|
|
@ -38,12 +38,6 @@ namespace AkVCam
|
|||
class Stream: public Object
|
||||
{
|
||||
public:
|
||||
enum Direction
|
||||
{
|
||||
Output,
|
||||
Input
|
||||
};
|
||||
|
||||
Stream(bool registerObject=false, Object *m_parent=nullptr);
|
||||
Stream(const Stream &other) = delete;
|
||||
~Stream();
|
||||
|
|
|
@ -658,8 +658,7 @@ bool AkVCam::IpcBridge::canApply(AkVCam::IpcBridge::Operation operation) const
|
|||
}
|
||||
|
||||
std::string AkVCam::IpcBridge::deviceCreate(const std::wstring &description,
|
||||
const std::vector<VideoFormat> &formats,
|
||||
DeviceType type)
|
||||
const std::vector<VideoFormat> &formats)
|
||||
{
|
||||
AkLogFunction();
|
||||
|
||||
|
|
Loading…
Reference in a new issue