Many improvements:
- Devices controls working. - Placeholder picture now supports PNG and JPEG formats. - Placeholder picture can be updated on fly. - Clients listing working. - Device configurations can be loaded at once. - Print better looking tables in the manager.
This commit is contained in:
parent
39f383560c
commit
39c84d9788
29 changed files with 1315 additions and 902 deletions
|
@ -21,10 +21,12 @@
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
|
#include <locale>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include "cmdparser.h"
|
#include "cmdparser.h"
|
||||||
#include "VCamUtils/src/ipcbridge.h"
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
#include "VCamUtils/src/settings.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"
|
||||||
|
@ -33,6 +35,9 @@
|
||||||
std::bind(&member, this->d, std::placeholders::_1, std::placeholders::_2)
|
std::bind(&member, this->d, std::placeholders::_1, std::placeholders::_2)
|
||||||
|
|
||||||
namespace AkVCam {
|
namespace AkVCam {
|
||||||
|
using StringMatrix = std::vector<StringVector>;
|
||||||
|
using VideoFormatMatrix = std::vector<std::vector<VideoFormat>>;
|
||||||
|
|
||||||
struct CmdParserFlags
|
struct CmdParserFlags
|
||||||
{
|
{
|
||||||
StringVector flags;
|
StringVector flags;
|
||||||
|
@ -56,6 +61,7 @@ namespace AkVCam {
|
||||||
IpcBridge m_ipcBridge;
|
IpcBridge m_ipcBridge;
|
||||||
bool m_parseable {false};
|
bool m_parseable {false};
|
||||||
|
|
||||||
|
static const std::map<ControlType, std::string> &typeStrMap();
|
||||||
std::string basename(const std::string &path);
|
std::string basename(const std::string &path);
|
||||||
void printFlags(const std::vector<CmdParserFlags> &cmdFlags,
|
void printFlags(const std::vector<CmdParserFlags> &cmdFlags,
|
||||||
size_t indent);
|
size_t indent);
|
||||||
|
@ -63,8 +69,13 @@ namespace AkVCam {
|
||||||
size_t maxArgumentsLength();
|
size_t maxArgumentsLength();
|
||||||
size_t maxFlagsLength(const std::vector<CmdParserFlags> &flags);
|
size_t maxFlagsLength(const std::vector<CmdParserFlags> &flags);
|
||||||
size_t maxFlagsValueLength(const std::vector<CmdParserFlags> &flags);
|
size_t maxFlagsValueLength(const std::vector<CmdParserFlags> &flags);
|
||||||
size_t maxStringLength(const StringVector &strings);
|
size_t maxColumnLength(const StringVector &table,
|
||||||
size_t maxStringLength(const WStringVector &strings);
|
size_t width,
|
||||||
|
size_t column);
|
||||||
|
std::vector<size_t> maxColumnsLength(const StringVector &table,
|
||||||
|
size_t width);
|
||||||
|
void drawTableHLine(const std::vector<size_t> &columnsLength);
|
||||||
|
void drawTable(const StringVector &table, size_t width);
|
||||||
CmdParserCommand *parserCommand(const std::string &command);
|
CmdParserCommand *parserCommand(const std::string &command);
|
||||||
const CmdParserFlags *parserFlag(const std::vector<CmdParserFlags> &cmdFlags,
|
const CmdParserFlags *parserFlag(const std::vector<CmdParserFlags> &cmdFlags,
|
||||||
const std::string &flag);
|
const std::string &flag);
|
||||||
|
@ -96,12 +107,26 @@ namespace AkVCam {
|
||||||
int stream(const StringMap &flags, const StringVector &args);
|
int stream(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 writeControls(const StringMap &flags, const StringVector &args);
|
||||||
int picture(const StringMap &flags, const StringVector &args);
|
int picture(const StringMap &flags, const StringVector &args);
|
||||||
int setPicture(const StringMap &flags, const StringVector &args);
|
int setPicture(const StringMap &flags, const StringVector &args);
|
||||||
int logLevel(const StringMap &flags, const StringVector &args);
|
int logLevel(const StringMap &flags, const StringVector &args);
|
||||||
int setLogLevel(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);
|
||||||
|
void loadGenerals(Settings &settings);
|
||||||
|
VideoFormatMatrix readFormats(Settings &settings);
|
||||||
|
std::vector<VideoFormat> readFormat(Settings &settings);
|
||||||
|
StringMatrix matrixCombine(const StringMatrix &matrix);
|
||||||
|
void matrixCombineP(const StringMatrix &matrix,
|
||||||
|
size_t index,
|
||||||
|
StringVector combined,
|
||||||
|
StringMatrix &combinations);
|
||||||
|
void createDevices(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats);
|
||||||
|
void createDevice(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats);
|
||||||
|
std::vector<VideoFormat> readDeviceFormats(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats);
|
||||||
};
|
};
|
||||||
|
|
||||||
std::string operator *(const std::string &str, size_t n);
|
std::string operator *(const std::string &str, size_t n);
|
||||||
|
@ -192,10 +217,31 @@ AkVCam::CmdParser::CmdParser()
|
||||||
"DEVICE CONTROL",
|
"DEVICE CONTROL",
|
||||||
"Read device control.",
|
"Read device control.",
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::readControl));
|
AKVCAM_BIND_FUNC(CmdParserPrivate::readControl));
|
||||||
this->addCommand("set-control",
|
this->addFlags("get-control",
|
||||||
"DEVICE CONTROL VALUE",
|
{"-c", "--description"},
|
||||||
"Write device control value.",
|
"Show control description.");
|
||||||
AKVCAM_BIND_FUNC(CmdParserPrivate::writeControl));
|
this->addFlags("get-control",
|
||||||
|
{"-t", "--type"},
|
||||||
|
"Show control type.");
|
||||||
|
this->addFlags("get-control",
|
||||||
|
{"-m", "--min"},
|
||||||
|
"Show minimum value for the control.");
|
||||||
|
this->addFlags("get-control",
|
||||||
|
{"-M", "--max"},
|
||||||
|
"Show maximum value for the control.");
|
||||||
|
this->addFlags("get-control",
|
||||||
|
{"-s", "--step"},
|
||||||
|
"Show increment/decrement step for the control.");
|
||||||
|
this->addFlags("get-control",
|
||||||
|
{"-d", "--default"},
|
||||||
|
"Show default value for the control.");
|
||||||
|
this->addFlags("get-control",
|
||||||
|
{"-l", "--menu"},
|
||||||
|
"Show options of a memu type control.");
|
||||||
|
this->addCommand("set-controls",
|
||||||
|
"DEVICE CONTROL_1=VALUE CONTROL_2=VALUE...",
|
||||||
|
"Write device controls values.",
|
||||||
|
AKVCAM_BIND_FUNC(CmdParserPrivate::writeControls));
|
||||||
this->addCommand("picture",
|
this->addCommand("picture",
|
||||||
"",
|
"",
|
||||||
"Placeholder picture to show when no streaming.",
|
"Placeholder picture to show when no streaming.",
|
||||||
|
@ -352,6 +398,17 @@ void AkVCam::CmdParser::addFlags(const std::string &command,
|
||||||
this->addFlags(command, flags, "", helpString);
|
this->addFlags(command, flags, "", helpString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::map<AkVCam::ControlType, std::string> &AkVCam::CmdParserPrivate::typeStrMap()
|
||||||
|
{
|
||||||
|
static const std::map<ControlType, std::string> typeStr {
|
||||||
|
{ControlTypeInteger, "Integer"},
|
||||||
|
{ControlTypeBoolean, "Boolean"},
|
||||||
|
{ControlTypeMenu , "Menu" },
|
||||||
|
};
|
||||||
|
|
||||||
|
return typeStr;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AkVCam::CmdParserPrivate::basename(const std::string &path)
|
std::string AkVCam::CmdParserPrivate::basename(const std::string &path)
|
||||||
{
|
{
|
||||||
auto rit =
|
auto rit =
|
||||||
|
@ -393,10 +450,8 @@ void AkVCam::CmdParserPrivate::printFlags(const std::vector<CmdParserFlags> &cmd
|
||||||
std::cout << std::string(spaces.data(), indent)
|
std::cout << std::string(spaces.data(), indent)
|
||||||
<< fill(allFlags, maxFlagsLen);
|
<< fill(allFlags, maxFlagsLen);
|
||||||
|
|
||||||
if (maxFlagsValueLen > 0) {
|
if (maxFlagsValueLen > 0)
|
||||||
std::cout << " "
|
std::cout << " " << fill(flag.value, maxFlagsValueLen);
|
||||||
<< fill(flag.value, maxFlagsValueLen);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::cout << " "
|
std::cout << " "
|
||||||
<< flag.helpString
|
<< flag.helpString
|
||||||
|
@ -444,24 +499,64 @@ size_t AkVCam::CmdParserPrivate::maxFlagsValueLength(const std::vector<CmdParser
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AkVCam::CmdParserPrivate::maxStringLength(const StringVector &strings)
|
size_t AkVCam::CmdParserPrivate::maxColumnLength(const AkVCam::StringVector &table,
|
||||||
|
size_t width,
|
||||||
|
size_t column)
|
||||||
{
|
{
|
||||||
size_t length = 0;
|
size_t length = 0;
|
||||||
|
size_t height = table.size() / width;
|
||||||
|
|
||||||
for (auto &str: strings)
|
for (size_t y = 0; y < height; y++) {
|
||||||
|
auto &str = table[y * width + column];
|
||||||
length = std::max(str.size(), length);
|
length = std::max(str.size(), length);
|
||||||
|
}
|
||||||
|
|
||||||
return length;
|
return length;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t AkVCam::CmdParserPrivate::maxStringLength(const WStringVector &strings)
|
std::vector<size_t> AkVCam::CmdParserPrivate::maxColumnsLength(const AkVCam::StringVector &table,
|
||||||
|
size_t width)
|
||||||
{
|
{
|
||||||
size_t length = 0;
|
std::vector<size_t> lengths;
|
||||||
|
|
||||||
for (auto &str: strings)
|
for (size_t x = 0; x < width; x++)
|
||||||
length = std::max(str.size(), length);
|
lengths.push_back(this->maxColumnLength(table, width, x));
|
||||||
|
|
||||||
return length;
|
return lengths;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::CmdParserPrivate::drawTableHLine(const std::vector<size_t> &columnsLength)
|
||||||
|
{
|
||||||
|
std::cout << '+';
|
||||||
|
|
||||||
|
for (auto &len: columnsLength)
|
||||||
|
std::cout << std::string("-") * (len + 2) << '+';
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::CmdParserPrivate::drawTable(const AkVCam::StringVector &table,
|
||||||
|
size_t width)
|
||||||
|
{
|
||||||
|
size_t height = table.size() / width;
|
||||||
|
auto columnsLength = this->maxColumnsLength(table, width);
|
||||||
|
this->drawTableHLine(columnsLength);
|
||||||
|
|
||||||
|
for (size_t y = 0; y < height; y++) {
|
||||||
|
std::cout << "|";
|
||||||
|
|
||||||
|
for (size_t x = 0; x < width; x++) {
|
||||||
|
auto &element = table[x + y * width];
|
||||||
|
std::cout << " " << fill(element, columnsLength[x]) << " |";
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cout << std::endl;
|
||||||
|
|
||||||
|
if (y == 0 && height > 1)
|
||||||
|
this->drawTableHLine(columnsLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->drawTableHLine(columnsLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
AkVCam::CmdParserCommand *AkVCam::CmdParserPrivate::parserCommand(const std::string &command)
|
AkVCam::CmdParserCommand *AkVCam::CmdParserPrivate::parserCommand(const std::string &command)
|
||||||
|
@ -556,8 +651,8 @@ int AkVCam::CmdParserPrivate::showHelp(const StringMap &flags,
|
||||||
UNUSED(flags);
|
UNUSED(flags);
|
||||||
|
|
||||||
std::cout << args[0]
|
std::cout << args[0]
|
||||||
<< " [OPTIONS...] COMMAND [COMMAND_OPTIONS...] ..."
|
<< " [OPTIONS...] COMMAND [COMMAND_OPTIONS...] ..."
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
std::cout << "AkVirtualCamera virtual device manager." << std::endl;
|
std::cout << "AkVirtualCamera virtual device manager." << std::endl;
|
||||||
std::cout << std::endl;
|
std::cout << std::endl;
|
||||||
|
@ -609,36 +704,21 @@ int AkVCam::CmdParserPrivate::showDevices(const StringMap &flags,
|
||||||
for (auto &device: devices)
|
for (auto &device: devices)
|
||||||
std::cout << device << std::endl;
|
std::cout << device << std::endl;
|
||||||
} else {
|
} else {
|
||||||
StringVector devicesColumn;
|
std::vector<std::string> table {
|
||||||
WStringVector descriptionsColumn;
|
"Device",
|
||||||
|
"Description"
|
||||||
devicesColumn.push_back("Device");
|
};
|
||||||
descriptionsColumn.push_back(L"Description");
|
auto columns = table.size();
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
|
||||||
for (auto &device: devices) {
|
for (auto &device: devices) {
|
||||||
devicesColumn.push_back(device);
|
table.push_back(device);
|
||||||
descriptionsColumn.push_back(this->m_ipcBridge.description(device));
|
auto description =
|
||||||
|
cv.to_bytes(this->m_ipcBridge.description(device));
|
||||||
|
table.push_back(description);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto devicesColumnSize = this->maxStringLength(devicesColumn);
|
this->drawTable(table, columns);
|
||||||
auto descriptionsColumnSize = this->maxStringLength(descriptionsColumn);
|
|
||||||
|
|
||||||
std::cout << fill("Device", devicesColumnSize)
|
|
||||||
<< " | "
|
|
||||||
<< fill("Description", descriptionsColumnSize)
|
|
||||||
<< std::endl;
|
|
||||||
std::cout << std::string("-")
|
|
||||||
* (devicesColumnSize
|
|
||||||
+ descriptionsColumnSize
|
|
||||||
+ 4) << std::endl;
|
|
||||||
|
|
||||||
for (auto &device: devices) {
|
|
||||||
std::cout << fill(device, devicesColumnSize)
|
|
||||||
<< " | ";
|
|
||||||
std::wcout << fill(this->m_ipcBridge.description(device),
|
|
||||||
descriptionsColumnSize)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1003,7 +1083,7 @@ int AkVCam::CmdParserPrivate::update(const StringMap &flags,
|
||||||
{
|
{
|
||||||
UNUSED(flags);
|
UNUSED(flags);
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
this->m_ipcBridge.update();
|
this->m_ipcBridge.updateDevices();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -1011,6 +1091,30 @@ int AkVCam::CmdParserPrivate::update(const StringMap &flags,
|
||||||
int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
|
int AkVCam::CmdParserPrivate::loadSettings(const AkVCam::StringMap &flags,
|
||||||
const AkVCam::StringVector &args)
|
const AkVCam::StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 2) {
|
||||||
|
std::cerr << "Settings file not provided." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
Settings settings;
|
||||||
|
|
||||||
|
if (!settings.load(args[1])) {
|
||||||
|
std::cerr << "Settings file not valid." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
this->loadGenerals(settings);
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
|
||||||
|
for (auto &device: devices)
|
||||||
|
this->m_ipcBridge.removeDevice(device);
|
||||||
|
|
||||||
|
this->createDevices(settings, this->readFormats(settings));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1106,20 +1210,281 @@ int AkVCam::CmdParserPrivate::stream(const AkVCam::StringMap &flags,
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::showControls(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::showControls(const StringMap &flags,
|
||||||
const StringVector &args)
|
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 dit = std::find(devices.begin(), devices.end(), deviceId);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << "'" << deviceId << "' doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->m_parseable) {
|
||||||
|
for (auto &control: this->m_ipcBridge.controls(deviceId))
|
||||||
|
std::cout << control.id << std::endl;
|
||||||
|
} else {
|
||||||
|
auto typeStr = typeStrMap();
|
||||||
|
|
||||||
|
std::vector<std::string> table {
|
||||||
|
"Control",
|
||||||
|
"Description",
|
||||||
|
"Type",
|
||||||
|
"Minimum",
|
||||||
|
"Maximum",
|
||||||
|
"Step",
|
||||||
|
"Default",
|
||||||
|
"Value"
|
||||||
|
};
|
||||||
|
auto columns = table.size();
|
||||||
|
|
||||||
|
for (auto &control: this->m_ipcBridge.controls(deviceId)) {
|
||||||
|
table.push_back(control.id);
|
||||||
|
table.push_back(control.description);
|
||||||
|
table.push_back(typeStr[control.type]);
|
||||||
|
table.push_back(std::to_string(control.minimum));
|
||||||
|
table.push_back(std::to_string(control.maximum));
|
||||||
|
table.push_back(std::to_string(control.step));
|
||||||
|
table.push_back(std::to_string(control.defaultValue));
|
||||||
|
table.push_back(std::to_string(control.value));
|
||||||
|
}
|
||||||
|
|
||||||
|
this->drawTable(table, columns);
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::readControl(const StringMap &flags,
|
int AkVCam::CmdParserPrivate::readControl(const StringMap &flags,
|
||||||
const StringVector &args)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int AkVCam::CmdParserPrivate::writeControl(const StringMap &flags,
|
|
||||||
const StringVector &args)
|
const StringVector &args)
|
||||||
{
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deviceId = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto dit = std::find(devices.begin(), devices.end(), deviceId);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << "'" << deviceId << "' doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &control: this->m_ipcBridge.controls(deviceId))
|
||||||
|
if (control.description == args[2]) {
|
||||||
|
if (flags.empty()) {
|
||||||
|
std::cout << control.value << std::endl;
|
||||||
|
} else {
|
||||||
|
if (this->containsFlag(flags, "get-control", "-c")) {
|
||||||
|
auto typeStr = typeStrMap();
|
||||||
|
std::cout << control.description << std::endl;
|
||||||
|
}
|
||||||
|
if (this->containsFlag(flags, "get-control", "-t")) {
|
||||||
|
auto typeStr = typeStrMap();
|
||||||
|
std::cout << typeStr[control.type] << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->containsFlag(flags, "get-control", "-m")) {
|
||||||
|
std::cout << control.minimum << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->containsFlag(flags, "get-control", "-M")) {
|
||||||
|
std::cout << control.maximum << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->containsFlag(flags, "get-control", "-s")) {
|
||||||
|
std::cout << control.step << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->containsFlag(flags, "get-control", "-d")) {
|
||||||
|
std::cout << control.defaultValue << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this->containsFlag(flags, "get-control", "-l")) {
|
||||||
|
for (size_t i = 0; i< control.menu.size(); i++)
|
||||||
|
if (this->m_parseable)
|
||||||
|
std::cout << control.menu[i] << std::endl;
|
||||||
|
else
|
||||||
|
std::cout << i << ": " << control.menu[i] << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::cerr << "'" << args[2] << "' control not available." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int AkVCam::CmdParserPrivate::writeControls(const StringMap &flags,
|
||||||
|
const StringVector &args)
|
||||||
|
{
|
||||||
|
UNUSED(flags);
|
||||||
|
|
||||||
|
if (args.size() < 3) {
|
||||||
|
std::cerr << "Not enough arguments." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto deviceId = args[1];
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
auto dit = std::find(devices.begin(), devices.end(), deviceId);
|
||||||
|
|
||||||
|
if (dit == devices.end()) {
|
||||||
|
std::cerr << "'" << deviceId << "' doesn't exists." << std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<std::string, int> controls;
|
||||||
|
|
||||||
|
for (size_t i = 2; i < args.size(); i++) {
|
||||||
|
if (args[i].find('=') == std::string::npos) {
|
||||||
|
std::cerr << "Argumment "
|
||||||
|
<< i
|
||||||
|
<< " is not in the form KEY=VALUE."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto pair = splitOnce(args[i], "=");
|
||||||
|
|
||||||
|
if (pair.first.empty()) {
|
||||||
|
std::cerr << "Key for argumment "
|
||||||
|
<< i
|
||||||
|
<< " is emty."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto key = trimmed(pair.first);
|
||||||
|
auto value = trimmed(pair.second);
|
||||||
|
bool found = false;
|
||||||
|
|
||||||
|
for (auto &control: this->m_ipcBridge.controls(deviceId))
|
||||||
|
if (control.id == key) {
|
||||||
|
switch (control.type) {
|
||||||
|
case ControlTypeInteger: {
|
||||||
|
char *p = nullptr;
|
||||||
|
auto val = strtol(value.c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
std::cerr << "Value at argument "
|
||||||
|
<< i
|
||||||
|
<< " must be an integer."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
controls[key] = val;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ControlTypeBoolean: {
|
||||||
|
std::locale loc;
|
||||||
|
std::transform(value.begin(),
|
||||||
|
value.end(),
|
||||||
|
value.begin(),
|
||||||
|
[&loc](char c) {
|
||||||
|
return std::tolower(c, loc);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (value == "0" || value == "false") {
|
||||||
|
controls[key] = 0;
|
||||||
|
} else if (value == "1" || value == "true") {
|
||||||
|
controls[key] = 1;
|
||||||
|
} else {
|
||||||
|
std::cerr << "Value at argument "
|
||||||
|
<< i
|
||||||
|
<< " must be a boolean."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
case ControlTypeMenu: {
|
||||||
|
char *p = nullptr;
|
||||||
|
auto val = strtoul(value.c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p) {
|
||||||
|
auto it = std::find(control.menu.begin(),
|
||||||
|
control.menu.end(),
|
||||||
|
value);
|
||||||
|
|
||||||
|
if (it == control.menu.end()) {
|
||||||
|
std::cerr << "Value at argument "
|
||||||
|
<< i
|
||||||
|
<< " is not valid."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
controls[key] = it - control.menu.begin();
|
||||||
|
} else {
|
||||||
|
if (val >= control.menu.size()) {
|
||||||
|
std::cerr << "Value at argument "
|
||||||
|
<< i
|
||||||
|
<< " is out of range."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
controls[key] = val;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
found = true;
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
std::cerr << "No such '"
|
||||||
|
<< key
|
||||||
|
<< "' control in argument "
|
||||||
|
<< i
|
||||||
|
<< "."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
this->m_ipcBridge.setControls(deviceId, controls);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1195,7 +1560,6 @@ int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
||||||
{
|
{
|
||||||
UNUSED(flags);
|
UNUSED(flags);
|
||||||
UNUSED(args);
|
UNUSED(args);
|
||||||
|
|
||||||
auto clients = this->m_ipcBridge.clientsPids();
|
auto clients = this->m_ipcBridge.clientsPids();
|
||||||
|
|
||||||
if (clients.empty())
|
if (clients.empty())
|
||||||
|
@ -1208,38 +1572,217 @@ int AkVCam::CmdParserPrivate::showClients(const StringMap &flags,
|
||||||
<< this->m_ipcBridge.clientExe(pid)
|
<< this->m_ipcBridge.clientExe(pid)
|
||||||
<< std::endl;
|
<< std::endl;
|
||||||
} else {
|
} else {
|
||||||
StringVector pidsColumn;
|
std::vector<std::string> table {
|
||||||
StringVector exesColumn;
|
"Pid",
|
||||||
|
"Executable"
|
||||||
pidsColumn.push_back("Pid");
|
};
|
||||||
exesColumn.push_back("Executable");
|
auto columns = table.size();
|
||||||
|
|
||||||
for (auto &pid: clients) {
|
for (auto &pid: clients) {
|
||||||
pidsColumn.push_back(std::to_string(pid));
|
table.push_back(std::to_string(pid));
|
||||||
exesColumn.push_back(this->m_ipcBridge.clientExe(pid));
|
table.push_back(this->m_ipcBridge.clientExe(pid));
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pidsColumnSize = this->maxStringLength(pidsColumn);
|
this->drawTable(table, columns);
|
||||||
auto exesColumnSize = this->maxStringLength(exesColumn);
|
|
||||||
|
|
||||||
std::cout << fill("Pid", pidsColumnSize)
|
|
||||||
<< " | "
|
|
||||||
<< fill("Executable", exesColumnSize)
|
|
||||||
<< std::endl;
|
|
||||||
std::cout << std::string("-")
|
|
||||||
* (pidsColumnSize + exesColumnSize + 4)
|
|
||||||
<< std::endl;
|
|
||||||
|
|
||||||
for (auto &pid: clients)
|
|
||||||
std::cout << fill(std::to_string(pid), pidsColumnSize)
|
|
||||||
<< " | "
|
|
||||||
<< fill(this->m_ipcBridge.clientExe(pid), exesColumnSize)
|
|
||||||
<< std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::CmdParserPrivate::loadGenerals(Settings &settings)
|
||||||
|
{
|
||||||
|
settings.beginGroup("General");
|
||||||
|
|
||||||
|
if (settings.contains("default_frame")) {
|
||||||
|
auto defaultFrame = settings.value("default_frame");
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
this->m_ipcBridge.setPicture(cv.from_bytes(defaultFrame));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings.contains("loglevel")) {
|
||||||
|
auto logLevel= settings.value("loglevel");
|
||||||
|
char *p = nullptr;
|
||||||
|
auto level = strtol(logLevel.c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p)
|
||||||
|
level = AkVCam::Logger::levelFromString(logLevel);
|
||||||
|
|
||||||
|
this->m_ipcBridge.setLogLevel(level);
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.endGroup();
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFormatMatrix AkVCam::CmdParserPrivate::readFormats(Settings &settings)
|
||||||
|
{
|
||||||
|
VideoFormatMatrix formatsMatrix;
|
||||||
|
settings.beginGroup("Formats");
|
||||||
|
auto nFormats = settings.beginArray("formats");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nFormats; i++) {
|
||||||
|
settings.setArrayIndex(i);
|
||||||
|
formatsMatrix.push_back(this->readFormat(settings));
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.endArray();
|
||||||
|
settings.endGroup();
|
||||||
|
|
||||||
|
return formatsMatrix;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::VideoFormat> AkVCam::CmdParserPrivate::readFormat(Settings &settings)
|
||||||
|
{
|
||||||
|
std::vector<AkVCam::VideoFormat> formats;
|
||||||
|
|
||||||
|
auto pixFormats = settings.valueList("format", ",");
|
||||||
|
auto widths = settings.valueList("width", ",");
|
||||||
|
auto heights = settings.valueList("height", ",");
|
||||||
|
auto frameRates = settings.valueList("fps", ",");
|
||||||
|
|
||||||
|
if (pixFormats.empty()
|
||||||
|
|| widths.empty()
|
||||||
|
|| heights.empty()
|
||||||
|
|| frameRates.empty()) {
|
||||||
|
std::cerr << "Error reading formats." << std::endl;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
StringMatrix formatMatrix;
|
||||||
|
formatMatrix.push_back(pixFormats);
|
||||||
|
formatMatrix.push_back(widths);
|
||||||
|
formatMatrix.push_back(heights);
|
||||||
|
formatMatrix.push_back(frameRates);
|
||||||
|
|
||||||
|
for (auto &format_list: this->matrixCombine(formatMatrix)) {
|
||||||
|
auto pixFormat = VideoFormat::fourccFromString(format_list[0]);
|
||||||
|
char *p = nullptr;
|
||||||
|
auto width = strtol(format_list[1].c_str(), &p, 10);
|
||||||
|
p = nullptr;
|
||||||
|
auto height = strtol(format_list[2].c_str(), &p, 10);
|
||||||
|
Fraction frame_rate(format_list[3]);
|
||||||
|
VideoFormat format(pixFormat,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
{frame_rate});
|
||||||
|
|
||||||
|
if (format.isValid())
|
||||||
|
formats.push_back(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::StringMatrix AkVCam::CmdParserPrivate::matrixCombine(const StringMatrix &matrix)
|
||||||
|
{
|
||||||
|
StringVector combined;
|
||||||
|
StringMatrix combinations;
|
||||||
|
this->matrixCombineP(matrix, 0, combined, combinations);
|
||||||
|
|
||||||
|
return combinations;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* A matrix is a list of lists where each element in the main list is a row,
|
||||||
|
* and each element in a row is a column. We combine each element in a row with
|
||||||
|
* each element in the next rows.
|
||||||
|
*/
|
||||||
|
void AkVCam::CmdParserPrivate::matrixCombineP(const StringMatrix &matrix,
|
||||||
|
size_t index,
|
||||||
|
StringVector combined,
|
||||||
|
StringMatrix &combinations)
|
||||||
|
{
|
||||||
|
if (index >= matrix.size()) {
|
||||||
|
combinations.push_back(combined);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto &data: matrix[index]) {
|
||||||
|
auto combinedP1 = combined;
|
||||||
|
combinedP1.push_back(data);
|
||||||
|
this->matrixCombineP(matrix, index + 1, combinedP1, combinations);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::CmdParserPrivate::createDevices(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats)
|
||||||
|
{
|
||||||
|
auto devices = this->m_ipcBridge.devices();
|
||||||
|
|
||||||
|
for (auto &device: devices)
|
||||||
|
this->m_ipcBridge.removeDevice(device);
|
||||||
|
|
||||||
|
settings.beginGroup("Cameras");
|
||||||
|
size_t nCameras = settings.beginArray("cameras");
|
||||||
|
|
||||||
|
for (size_t i = 0; i < nCameras; i++) {
|
||||||
|
settings.setArrayIndex(i);
|
||||||
|
this->createDevice(settings, availableFormats);
|
||||||
|
}
|
||||||
|
|
||||||
|
settings.endArray();
|
||||||
|
settings.endGroup();
|
||||||
|
this->m_ipcBridge.updateDevices();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::CmdParserPrivate::createDevice(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats)
|
||||||
|
{
|
||||||
|
auto description = settings.value("description");
|
||||||
|
|
||||||
|
if (description.empty()) {
|
||||||
|
std::cerr << "Device description is empty" << std::endl;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto formats = this->readDeviceFormats(settings, availableFormats);
|
||||||
|
|
||||||
|
if (formats.empty()) {
|
||||||
|
std::cerr << "Can't read device formats" << std::endl;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
auto deviceId = this->m_ipcBridge.addDevice(cv.from_bytes(description));
|
||||||
|
auto supportedFormats = this->m_ipcBridge.supportedPixelFormats(IpcBridge::StreamTypeOutput);
|
||||||
|
|
||||||
|
for (auto &format: formats) {
|
||||||
|
auto it = std::find(supportedFormats.begin(),
|
||||||
|
supportedFormats.end(),
|
||||||
|
format.fourcc());
|
||||||
|
|
||||||
|
if (it != supportedFormats.end())
|
||||||
|
this->m_ipcBridge.addFormat(deviceId, format, -1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<AkVCam::VideoFormat> AkVCam::CmdParserPrivate::readDeviceFormats(Settings &settings,
|
||||||
|
const VideoFormatMatrix &availableFormats)
|
||||||
|
{
|
||||||
|
std::vector<AkVCam::VideoFormat> formats;
|
||||||
|
auto formatsIndex = settings.valueList("formats", ",");
|
||||||
|
|
||||||
|
for (auto &indexStr: formatsIndex) {
|
||||||
|
char *p = nullptr;
|
||||||
|
auto index = strtoul(indexStr.c_str(), &p, 10);
|
||||||
|
|
||||||
|
if (*p)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
index--;
|
||||||
|
|
||||||
|
if (index >= availableFormats.size())
|
||||||
|
continue;
|
||||||
|
|
||||||
|
for (auto &format: availableFormats[index])
|
||||||
|
formats.push_back(format);
|
||||||
|
}
|
||||||
|
|
||||||
|
return formats;
|
||||||
|
}
|
||||||
|
|
||||||
std::string AkVCam::operator *(const std::string &str, size_t n)
|
std::string AkVCam::operator *(const std::string &str, size_t n)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|
|
@ -20,8 +20,9 @@
|
||||||
#ifndef CMDPARSER_H
|
#ifndef CMDPARSER_H
|
||||||
#define CMDPARSER_H
|
#define CMDPARSER_H
|
||||||
|
|
||||||
#include <string>
|
#include <functional>
|
||||||
#include <map>
|
#include <map>
|
||||||
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
namespace AkVCam {
|
namespace AkVCam {
|
||||||
|
|
|
@ -33,6 +33,26 @@ namespace AkVCam
|
||||||
class VideoFormat;
|
class VideoFormat;
|
||||||
class VideoFrame;
|
class VideoFrame;
|
||||||
|
|
||||||
|
enum ControlType
|
||||||
|
{
|
||||||
|
ControlTypeInteger,
|
||||||
|
ControlTypeBoolean,
|
||||||
|
ControlTypeMenu,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DeviceControl
|
||||||
|
{
|
||||||
|
std::string id;
|
||||||
|
std::string description;
|
||||||
|
ControlType type;
|
||||||
|
int minimum;
|
||||||
|
int maximum;
|
||||||
|
int step;
|
||||||
|
int defaultValue;
|
||||||
|
int value;
|
||||||
|
std::vector<std::string> menu;
|
||||||
|
};
|
||||||
|
|
||||||
class IpcBridge
|
class IpcBridge
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -53,6 +73,8 @@ namespace AkVCam
|
||||||
AKVCAM_SIGNAL(FrameReady,
|
AKVCAM_SIGNAL(FrameReady,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const VideoFrame &frame)
|
const VideoFrame &frame)
|
||||||
|
AKVCAM_SIGNAL(PictureChanged,
|
||||||
|
const std::string &picture)
|
||||||
AKVCAM_SIGNAL(DeviceAdded,
|
AKVCAM_SIGNAL(DeviceAdded,
|
||||||
const std::string &deviceId)
|
const std::string &deviceId)
|
||||||
AKVCAM_SIGNAL(DeviceRemoved,
|
AKVCAM_SIGNAL(DeviceRemoved,
|
||||||
|
@ -67,19 +89,9 @@ namespace AkVCam
|
||||||
AKVCAM_SIGNAL(BroadcastingChanged,
|
AKVCAM_SIGNAL(BroadcastingChanged,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const std::string &broadcaster)
|
const std::string &broadcaster)
|
||||||
AKVCAM_SIGNAL(MirrorChanged,
|
AKVCAM_SIGNAL(ControlsChanged,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
bool horizontalMirror,
|
const std::map<std::string, int> &controls)
|
||||||
bool verticalMirror)
|
|
||||||
AKVCAM_SIGNAL(ScalingChanged,
|
|
||||||
const std::string &deviceId,
|
|
||||||
Scaling scaling)
|
|
||||||
AKVCAM_SIGNAL(AspectRatioChanged,
|
|
||||||
const std::string &deviceId,
|
|
||||||
AspectRatio aspectRatio)
|
|
||||||
AKVCAM_SIGNAL(SwapRgbChanged,
|
|
||||||
const std::string &deviceId,
|
|
||||||
bool swap)
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IpcBridge();
|
IpcBridge();
|
||||||
|
@ -147,20 +159,9 @@ namespace AkVCam
|
||||||
// Return return the status of the device.
|
// Return return the status of the device.
|
||||||
std::string broadcaster(const std::string &deviceId) const;
|
std::string broadcaster(const std::string &deviceId) const;
|
||||||
|
|
||||||
// Device is horizontal mirrored,
|
std::vector<DeviceControl> controls(const std::string &deviceId);
|
||||||
bool isHorizontalMirrored(const std::string &deviceId);
|
void setControls(const std::string &deviceId,
|
||||||
|
const std::map<std::string, int> &controls);
|
||||||
// Device is vertical mirrored,
|
|
||||||
bool isVerticalMirrored(const std::string &deviceId);
|
|
||||||
|
|
||||||
// Scaling mode for frames shown in clients.
|
|
||||||
Scaling scalingMode(const std::string &deviceId);
|
|
||||||
|
|
||||||
// Aspect ratio mode for frames shown in clients.
|
|
||||||
AspectRatio aspectRatioMode(const std::string &deviceId);
|
|
||||||
|
|
||||||
// Check if red and blue channels are swapped.
|
|
||||||
bool swapRgb(const std::string &deviceId);
|
|
||||||
|
|
||||||
// Returns the clients that are capturing from a virtual camera.
|
// Returns the clients that are capturing from a virtual camera.
|
||||||
std::vector<std::string> listeners(const std::string &deviceId);
|
std::vector<std::string> listeners(const std::string &deviceId);
|
||||||
|
@ -179,7 +180,6 @@ namespace AkVCam
|
||||||
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 updateDevices();
|
void updateDevices();
|
||||||
|
|
||||||
// Start frame transfer to the device.
|
// Start frame transfer to the device.
|
||||||
|
@ -193,22 +193,6 @@ namespace AkVCam
|
||||||
bool write(const std::string &deviceId,
|
bool write(const std::string &deviceId,
|
||||||
const VideoFrame &frame);
|
const VideoFrame &frame);
|
||||||
|
|
||||||
// Set mirroring options for device,
|
|
||||||
void setMirroring(const std::string &deviceId,
|
|
||||||
bool horizontalMirrored,
|
|
||||||
bool verticalMirrored);
|
|
||||||
|
|
||||||
// Set scaling options for device.
|
|
||||||
void setScaling(const std::string &deviceId,
|
|
||||||
Scaling scaling);
|
|
||||||
|
|
||||||
// Set aspect ratio options for device.
|
|
||||||
void setAspectRatio(const std::string &deviceId,
|
|
||||||
AspectRatio aspectRatio);
|
|
||||||
|
|
||||||
// Swap red and blue channels.
|
|
||||||
void setSwapRgb(const std::string &deviceId, bool swap);
|
|
||||||
|
|
||||||
/* Client */
|
/* Client */
|
||||||
|
|
||||||
// Increment the count of device listeners
|
// Increment the count of device listeners
|
||||||
|
|
|
@ -125,14 +125,14 @@ std::ostream &AkVCam::Logger::log(int logLevel)
|
||||||
return dummy;
|
return dummy;
|
||||||
|
|
||||||
if (loggerPrivate()->fileName.empty())
|
if (loggerPrivate()->fileName.empty())
|
||||||
return std::cout;
|
return std::cerr;
|
||||||
|
|
||||||
if (!loggerPrivate()->stream.is_open())
|
if (!loggerPrivate()->stream.is_open())
|
||||||
loggerPrivate()->stream.open(loggerPrivate()->fileName,
|
loggerPrivate()->stream.open(loggerPrivate()->fileName,
|
||||||
std::ios_base::out | std::ios_base::app);
|
std::ios_base::out | std::ios_base::app);
|
||||||
|
|
||||||
if (!loggerPrivate()->stream.is_open())
|
if (!loggerPrivate()->stream.is_open())
|
||||||
return std::cout;
|
return std::cerr;
|
||||||
|
|
||||||
return loggerPrivate()->stream;
|
return loggerPrivate()->stream;
|
||||||
}
|
}
|
||||||
|
|
|
@ -270,7 +270,7 @@ int32_t AkVCam::Settings::valueInt32(const std::string &key) const
|
||||||
auto value = this->value(key);
|
auto value = this->value(key);
|
||||||
|
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
char *p = nullptr;
|
char *p = nullptr;
|
||||||
|
|
||||||
|
@ -282,7 +282,7 @@ uint32_t AkVCam::Settings::valueUInt32(const std::string &key) const
|
||||||
auto value = this->value(key);
|
auto value = this->value(key);
|
||||||
|
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
return false;
|
return 0;
|
||||||
|
|
||||||
char *p = nullptr;
|
char *p = nullptr;
|
||||||
|
|
||||||
|
@ -297,17 +297,22 @@ std::vector<std::string> AkVCam::Settings::valueList(const std::string &key,
|
||||||
if (value.empty())
|
if (value.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
char *valuePtr = const_cast<char *>(value.c_str());
|
|
||||||
std::vector<std::string> result;
|
std::vector<std::string> result;
|
||||||
|
size_t pos = 0;
|
||||||
|
|
||||||
for (;;) {
|
do {
|
||||||
auto element = strsep(&valuePtr, separators.c_str());
|
auto index = value.size();
|
||||||
|
|
||||||
if (!element)
|
for (auto &separator: separators) {
|
||||||
break;
|
auto it = std::find(value.begin() + pos, value.end(), separator);
|
||||||
|
|
||||||
result.push_back(trimmed(element));
|
if (size_t(it - value.begin()) < index)
|
||||||
}
|
index = it - value.begin();
|
||||||
|
}
|
||||||
|
|
||||||
|
result.push_back(trimmed(value.substr(pos, index - pos)));
|
||||||
|
pos = index + 1;
|
||||||
|
} while (pos < value.size());
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -374,16 +379,15 @@ AkVCam::SettingsElement AkVCam::SettingsPrivate::parse(const std::string &line,
|
||||||
return element;
|
return element;
|
||||||
}
|
}
|
||||||
|
|
||||||
auto pairSep = strchr(line.c_str(), '=');
|
if (line.find('=') == std::string::npos) {
|
||||||
|
|
||||||
if (!pairSep) {
|
|
||||||
if (ok)
|
if (ok)
|
||||||
*ok = false;
|
*ok = false;
|
||||||
|
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
element.key = trimmed(line.substr(0, (size_t) (pairSep - line.c_str())));
|
auto pair = splitOnce(line, "=");
|
||||||
|
element.key = trimmed(pair.first);
|
||||||
std::replace(element.key.begin(), element.key.end(), '\\', '/');
|
std::replace(element.key.begin(), element.key.end(), '\\', '/');
|
||||||
|
|
||||||
if (element.key.empty()) {
|
if (element.key.empty()) {
|
||||||
|
@ -393,8 +397,7 @@ AkVCam::SettingsElement AkVCam::SettingsPrivate::parse(const std::string &line,
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
auto offset = (size_t) (pairSep - line.c_str() + 1);
|
element.value = trimmed(pair.second);
|
||||||
element.value = trimmed(line.substr(offset, line.size() - offset));
|
|
||||||
element.value = this->parseString(element.value);
|
element.value = this->parseString(element.value);
|
||||||
|
|
||||||
if (ok)
|
if (ok)
|
||||||
|
|
|
@ -212,3 +212,17 @@ std::vector<std::string> AkVCam::split(const std::string &str, char separator)
|
||||||
|
|
||||||
return elements;
|
return elements;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<std::string, std::string> AkVCam::splitOnce(const std::string &str,
|
||||||
|
const std::string &separator)
|
||||||
|
{
|
||||||
|
auto pos = str.find(separator);
|
||||||
|
|
||||||
|
if (pos == std::string::npos)
|
||||||
|
return {str, ""};
|
||||||
|
|
||||||
|
auto first = str.substr(0, pos);
|
||||||
|
auto second = pos + 1 < str.size()? str.substr(pos + 1): "";
|
||||||
|
|
||||||
|
return {first, second};
|
||||||
|
}
|
||||||
|
|
|
@ -158,6 +158,8 @@ namespace AkVCam
|
||||||
std::string join(const std::vector<std::string> &strs,
|
std::string join(const std::vector<std::string> &strs,
|
||||||
const std::string &separator);
|
const std::string &separator);
|
||||||
std::vector<std::string> split(const std::string &str, char separator);
|
std::vector<std::string> split(const std::string &str, char separator);
|
||||||
|
std::pair<std::string, std::string> splitOnce(const std::string &str,
|
||||||
|
const std::string &separator);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // AKVCAMUTILS_UTILS_H
|
#endif // AKVCAMUTILS_UTILS_H
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
@ -45,11 +46,6 @@ namespace AkVCam
|
||||||
std::vector<VideoFormat> formats;
|
std::vector<VideoFormat> formats;
|
||||||
std::string broadcaster;
|
std::string broadcaster;
|
||||||
std::vector<std::string> listeners;
|
std::vector<std::string> listeners;
|
||||||
bool horizontalMirror {false};
|
|
||||||
bool verticalMirror {false};
|
|
||||||
Scaling scaling {ScalingFast};
|
|
||||||
AspectRatio aspectRatio {AspectRatioIgnore};
|
|
||||||
bool swapRgb {false};
|
|
||||||
};
|
};
|
||||||
|
|
||||||
using AssistantPeers = std::map<std::string, xpc_connection_t>;
|
using AssistantPeers = std::map<std::string, xpc_connection_t>;
|
||||||
|
@ -82,21 +78,15 @@ namespace AkVCam
|
||||||
void deviceDestroy(xpc_connection_t client, xpc_object_t event);
|
void deviceDestroy(xpc_connection_t client, xpc_object_t event);
|
||||||
void deviceUpdate(xpc_connection_t client, xpc_object_t event);
|
void deviceUpdate(xpc_connection_t client, xpc_object_t event);
|
||||||
void setBroadcasting(xpc_connection_t client, xpc_object_t event);
|
void setBroadcasting(xpc_connection_t client, xpc_object_t event);
|
||||||
void setMirroring(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setScaling(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setAspectRatio(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setSwapRgb(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void frameReady(xpc_connection_t client, xpc_object_t event);
|
void frameReady(xpc_connection_t client, xpc_object_t event);
|
||||||
|
void pictureUpdated(xpc_connection_t client, xpc_object_t event);
|
||||||
void listeners(xpc_connection_t client, xpc_object_t event);
|
void listeners(xpc_connection_t client, xpc_object_t event);
|
||||||
void listener(xpc_connection_t client, xpc_object_t event);
|
void listener(xpc_connection_t client, xpc_object_t event);
|
||||||
void devices(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 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 broadcasting(xpc_connection_t client, xpc_object_t event);
|
||||||
void mirroring(xpc_connection_t client, xpc_object_t event);
|
void controlsUpdated(xpc_connection_t client, xpc_object_t event);
|
||||||
void scaling(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void aspectRatio(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);
|
||||||
};
|
};
|
||||||
|
@ -142,30 +132,24 @@ void AkVCam::Assistant::messageReceived(xpc_connection_t client,
|
||||||
AkVCam::AssistantPrivate::AssistantPrivate()
|
AkVCam::AssistantPrivate::AssistantPrivate()
|
||||||
{
|
{
|
||||||
this->m_messageHandlers = {
|
this->m_messageHandlers = {
|
||||||
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(AssistantPrivate::frameReady) },
|
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(AssistantPrivate::frameReady) },
|
||||||
{AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::requestPort) },
|
{AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(AssistantPrivate::pictureUpdated) },
|
||||||
{AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::addPort) },
|
{AKVCAM_ASSISTANT_MSG_REQUEST_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::requestPort) },
|
||||||
{AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::removePort) },
|
{AKVCAM_ASSISTANT_MSG_ADD_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::addPort) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_CREATE , AKVCAM_BIND_FUNC(AssistantPrivate::deviceCreate) },
|
{AKVCAM_ASSISTANT_MSG_REMOVE_PORT , AKVCAM_BIND_FUNC(AssistantPrivate::removePort) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY , AKVCAM_BIND_FUNC(AssistantPrivate::deviceDestroy) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_CREATE , AKVCAM_BIND_FUNC(AssistantPrivate::deviceCreate) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICES , AKVCAM_BIND_FUNC(AssistantPrivate::devices) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY , AKVCAM_BIND_FUNC(AssistantPrivate::deviceDestroy) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION , AKVCAM_BIND_FUNC(AssistantPrivate::description) },
|
{AKVCAM_ASSISTANT_MSG_DEVICES , AKVCAM_BIND_FUNC(AssistantPrivate::devices) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS , AKVCAM_BIND_FUNC(AssistantPrivate::formats) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION , AKVCAM_BIND_FUNC(AssistantPrivate::description) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(AssistantPrivate::deviceUpdate) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS , AKVCAM_BIND_FUNC(AssistantPrivate::formats) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(AssistantPrivate::listenerAdd) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(AssistantPrivate::deviceUpdate) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(AssistantPrivate::listenerRemove) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(AssistantPrivate::listenerAdd) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(AssistantPrivate::listeners) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(AssistantPrivate::listenerRemove) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(AssistantPrivate::listener) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS , AKVCAM_BIND_FUNC(AssistantPrivate::listeners) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(AssistantPrivate::broadcasting) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER , AKVCAM_BIND_FUNC(AssistantPrivate::listener) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(AssistantPrivate::setBroadcasting)},
|
{AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING , AKVCAM_BIND_FUNC(AssistantPrivate::broadcasting) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING , AKVCAM_BIND_FUNC(AssistantPrivate::mirroring) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(AssistantPrivate::setBroadcasting)},
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(AssistantPrivate::setMirroring) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(AssistantPrivate::controlsUpdated)},
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SCALING , AKVCAM_BIND_FUNC(AssistantPrivate::scaling) },
|
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING , AKVCAM_BIND_FUNC(AssistantPrivate::setScaling) },
|
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO , AKVCAM_BIND_FUNC(AssistantPrivate::aspectRatio) },
|
|
||||||
{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) },
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this->loadCameras();
|
this->loadCameras();
|
||||||
|
@ -500,113 +484,6 @@ void AkVCam::AssistantPrivate::setBroadcasting(xpc_connection_t client,
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::setMirroring(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
bool horizontalMirror = xpc_dictionary_get_bool(event, "hmirror");
|
|
||||||
bool verticalMirror = xpc_dictionary_get_bool(event, "vmirror");
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
if (this->m_deviceConfigs[deviceId].horizontalMirror != horizontalMirror
|
|
||||||
|| this->m_deviceConfigs[deviceId].verticalMirror != verticalMirror) {
|
|
||||||
this->m_deviceConfigs[deviceId].horizontalMirror = horizontalMirror;
|
|
||||||
this->m_deviceConfigs[deviceId].verticalMirror = verticalMirror;
|
|
||||||
auto notification = xpc_copy(event);
|
|
||||||
|
|
||||||
for (auto &client: this->m_clients)
|
|
||||||
xpc_connection_send_message(client.second, notification);
|
|
||||||
|
|
||||||
xpc_release(notification);
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "status", ok);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::setScaling(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
auto scaling = Scaling(xpc_dictionary_get_int64(event, "scaling"));
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
if (this->m_deviceConfigs[deviceId].scaling != scaling) {
|
|
||||||
this->m_deviceConfigs[deviceId].scaling = scaling;
|
|
||||||
auto notification = xpc_copy(event);
|
|
||||||
|
|
||||||
for (auto &client: this->m_clients)
|
|
||||||
xpc_connection_send_message(client.second, notification);
|
|
||||||
|
|
||||||
xpc_release(notification);
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "status", ok);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::setAspectRatio(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
auto aspectRatio = AspectRatio(xpc_dictionary_get_int64(event, "aspect"));
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
if (this->m_deviceConfigs[deviceId].aspectRatio != aspectRatio) {
|
|
||||||
this->m_deviceConfigs[deviceId].aspectRatio = aspectRatio;
|
|
||||||
auto notification = xpc_copy(event);
|
|
||||||
|
|
||||||
for (auto &client: this->m_clients)
|
|
||||||
xpc_connection_send_message(client.second, notification);
|
|
||||||
|
|
||||||
xpc_release(notification);
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "status", ok);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::setSwapRgb(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
auto swapRgb = xpc_dictionary_get_bool(event, "swap");
|
|
||||||
bool ok = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
if (this->m_deviceConfigs[deviceId].swapRgb != swapRgb) {
|
|
||||||
this->m_deviceConfigs[deviceId].swapRgb = swapRgb;
|
|
||||||
auto notification = xpc_copy(event);
|
|
||||||
|
|
||||||
for (auto &client: this->m_clients)
|
|
||||||
xpc_connection_send_message(client.second, notification);
|
|
||||||
|
|
||||||
xpc_release(notification);
|
|
||||||
ok = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "status", ok);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::frameReady(xpc_connection_t client,
|
void AkVCam::AssistantPrivate::frameReady(xpc_connection_t client,
|
||||||
xpc_object_t event)
|
xpc_object_t event)
|
||||||
{
|
{
|
||||||
|
@ -634,6 +511,32 @@ void AkVCam::AssistantPrivate::frameReady(xpc_connection_t client,
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::AssistantPrivate::pictureUpdated(xpc_connection_t client,
|
||||||
|
xpc_object_t event)
|
||||||
|
{
|
||||||
|
UNUSED(client);
|
||||||
|
AkLogFunction();
|
||||||
|
auto reply = xpc_dictionary_create_reply(event);
|
||||||
|
bool ok = true;
|
||||||
|
|
||||||
|
for (auto &client: this->m_clients) {
|
||||||
|
auto reply = xpc_connection_send_message_with_reply_sync(client.second,
|
||||||
|
event);
|
||||||
|
auto replyType = xpc_get_type(reply);
|
||||||
|
bool isOk = false;
|
||||||
|
|
||||||
|
if (replyType == XPC_TYPE_DICTIONARY)
|
||||||
|
isOk = xpc_dictionary_get_bool(reply, "status");
|
||||||
|
|
||||||
|
ok &= isOk;
|
||||||
|
xpc_release(reply);
|
||||||
|
}
|
||||||
|
|
||||||
|
xpc_dictionary_set_bool(reply, "status", ok);
|
||||||
|
xpc_connection_send_message(client, reply);
|
||||||
|
xpc_release(reply);
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::listeners(xpc_connection_t client,
|
void AkVCam::AssistantPrivate::listeners(xpc_connection_t client,
|
||||||
xpc_object_t event)
|
xpc_object_t event)
|
||||||
{
|
{
|
||||||
|
@ -761,78 +664,24 @@ void AkVCam::AssistantPrivate::broadcasting(xpc_connection_t client,
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::mirroring(xpc_connection_t client,
|
void AkVCam::AssistantPrivate::controlsUpdated(xpc_connection_t client, xpc_object_t event)
|
||||||
xpc_object_t event)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
||||||
bool horizontalMirror = false;
|
bool ok = false;
|
||||||
bool verticalMirror = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0) {
|
if (this->m_deviceConfigs.count(deviceId) > 0) {
|
||||||
horizontalMirror = this->m_deviceConfigs[deviceId].horizontalMirror;
|
auto notification = xpc_copy(event);
|
||||||
verticalMirror = this->m_deviceConfigs[deviceId].verticalMirror;
|
|
||||||
|
for (auto &client: this->m_clients)
|
||||||
|
xpc_connection_send_message(client.second, notification);
|
||||||
|
|
||||||
|
xpc_release(notification);
|
||||||
|
ok = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Horizontal mirror: " << horizontalMirror << std::endl;
|
|
||||||
AkLogInfo() << "Vertical mirror: " << verticalMirror << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
auto reply = xpc_dictionary_create_reply(event);
|
||||||
xpc_dictionary_set_bool(reply, "hmirror", horizontalMirror);
|
xpc_dictionary_set_bool(reply, "status", ok);
|
||||||
xpc_dictionary_set_bool(reply, "vmirror", verticalMirror);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::scaling(xpc_connection_t client, xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
Scaling scaling = ScalingFast;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
scaling = this->m_deviceConfigs[deviceId].scaling;
|
|
||||||
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Scaling: " << scaling << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_int64(reply, "scaling", scaling);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::aspectRatio(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
AspectRatio aspectRatio = AspectRatioIgnore;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
aspectRatio = this->m_deviceConfigs[deviceId].aspectRatio;
|
|
||||||
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Aspect ratio: " << aspectRatio << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_int64(reply, "aspect", aspectRatio);
|
|
||||||
xpc_connection_send_message(client, reply);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::AssistantPrivate::swapRgb(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
std::string deviceId = xpc_dictionary_get_string(event, "device");
|
|
||||||
bool swapRgb = false;
|
|
||||||
|
|
||||||
if (this->m_deviceConfigs.count(deviceId) > 0)
|
|
||||||
swapRgb = this->m_deviceConfigs[deviceId].swapRgb;
|
|
||||||
|
|
||||||
AkLogInfo() << "Device: " << deviceId << std::endl;
|
|
||||||
AkLogInfo() << "Swap RGB: " << swapRgb << std::endl;
|
|
||||||
auto reply = xpc_dictionary_create_reply(event);
|
|
||||||
xpc_dictionary_set_bool(reply, "swap", swapRgb);
|
|
||||||
xpc_connection_send_message(client, reply);
|
xpc_connection_send_message(client, reply);
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,44 +26,37 @@
|
||||||
#define AKVCAM_ASSISTANT_CLIENT_NAME "org.webcamoid.cmio.AkVCam.Client"
|
#define AKVCAM_ASSISTANT_CLIENT_NAME "org.webcamoid.cmio.AkVCam.Client"
|
||||||
|
|
||||||
// General messages
|
// General messages
|
||||||
#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000
|
#define AKVCAM_ASSISTANT_MSG_ISALIVE 0x000
|
||||||
#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001
|
#define AKVCAM_ASSISTANT_MSG_FRAME_READY 0x001
|
||||||
|
#define AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED 0x002
|
||||||
|
|
||||||
// Assistant messages
|
// Assistant messages
|
||||||
#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100
|
#define AKVCAM_ASSISTANT_MSG_REQUEST_PORT 0x100
|
||||||
#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101
|
#define AKVCAM_ASSISTANT_MSG_ADD_PORT 0x101
|
||||||
#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102
|
#define AKVCAM_ASSISTANT_MSG_REMOVE_PORT 0x102
|
||||||
|
|
||||||
// Device control and information
|
// Device control and information
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200
|
#define AKVCAM_ASSISTANT_MSG_DEVICES 0x200
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_CREATE 0x201
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY 0x202
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_DESCRIPTION 0x203
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_FORMATS 0x204
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE 0x205
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE 0x205
|
||||||
|
|
||||||
// Device listeners controls
|
// Device listeners controls
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENERS 0x300
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER 0x301
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD 0x302
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE 0x303
|
||||||
|
|
||||||
// Device dynamic properties
|
// Device dynamic properties
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_BROADCASTING 0x400
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING 0x401
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING 0x402
|
#define AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED 0x402
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING 0x403
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SCALING 0x404
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING 0x405
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO 0x406
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO 0x407
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB 0x408
|
|
||||||
#define AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB 0x409
|
|
||||||
|
|
||||||
// Connections
|
// Connections
|
||||||
#define AKVCAM_ASSISTANT_MSG_CONNECTIONS 0x500
|
#define AKVCAM_ASSISTANT_MSG_CONNECTIONS 0x500
|
||||||
#define AKVCAM_ASSISTANT_MSG_SETCONNECTIONS 0x501
|
#define AKVCAM_ASSISTANT_MSG_SETCONNECTIONS 0x501
|
||||||
|
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
{
|
{
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
#include <CoreFoundation/CFRunLoop.h>
|
#include <CoreFoundation/CFRunLoop.h>
|
||||||
#include <xpc/xpc.h>
|
#include <xpc/xpc.h>
|
||||||
#include <xpc/connection.h>
|
#include <xpc/connection.h>
|
||||||
|
|
|
@ -42,7 +42,8 @@ TEMPLATE = lib
|
||||||
|
|
||||||
LIBS = \
|
LIBS = \
|
||||||
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
-framework CoreFoundation
|
-framework CoreFoundation \
|
||||||
|
-framework CoreGraphics
|
||||||
|
|
||||||
SOURCES = \
|
SOURCES = \
|
||||||
src/preferences.cpp \
|
src/preferences.cpp \
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
|
||||||
#include "preferences.h"
|
#include "preferences.h"
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "VCamUtils/src/image/videoformat.h"
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
@ -609,3 +611,16 @@ void AkVCam::Preferences::setLogLevel(int logLevel)
|
||||||
{
|
{
|
||||||
write("loglevel", logLevel);
|
write("loglevel", logLevel);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int AkVCam::Preferences::cameraControlValue(size_t cameraIndex,
|
||||||
|
const std::string &key)
|
||||||
|
{
|
||||||
|
return readInt("cameras." + std::to_string(cameraIndex) + ".controls." + key);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Preferences::cameraSetControlValue(size_t cameraIndex,
|
||||||
|
const std::string &key,
|
||||||
|
int value)
|
||||||
|
{
|
||||||
|
write("cameras." + std::to_string(cameraIndex) + ".controls." + key, value);
|
||||||
|
}
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#ifndef PREFERENCES_H
|
#ifndef PREFERENCES_H
|
||||||
#define PREFERENCES_H
|
#define PREFERENCES_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreFoundation/CoreFoundation.h>
|
||||||
|
@ -79,6 +80,11 @@ 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);
|
||||||
|
int cameraControlValue(size_t cameraIndex,
|
||||||
|
const std::string &key);
|
||||||
|
void cameraSetControlValue(size_t cameraIndex,
|
||||||
|
const std::string &key,
|
||||||
|
int value);
|
||||||
std::wstring picture();
|
std::wstring picture();
|
||||||
void setPicture(const std::wstring &picture);
|
void setPicture(const std::wstring &picture);
|
||||||
int logLevel();
|
int logLevel();
|
||||||
|
|
|
@ -17,7 +17,97 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
#include <sstream>
|
||||||
|
#include <algorithm>
|
||||||
|
#include <unistd.h>
|
||||||
|
#import <CoreGraphics/CGImage.h>
|
||||||
|
#import <CoreGraphics/CGDataProvider.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
#include "VCamUtils/src/image/videoframe.h"
|
||||||
|
|
||||||
|
namespace AkVCam {
|
||||||
|
namespace Utils {
|
||||||
|
struct RGB24
|
||||||
|
{
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t r;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RGB32
|
||||||
|
{
|
||||||
|
uint8_t b;
|
||||||
|
uint8_t g;
|
||||||
|
uint8_t r;
|
||||||
|
uint8_t x;
|
||||||
|
};
|
||||||
|
|
||||||
|
inline const std::map<AkVCam::PixelFormat, FourCharCode> *formatsTable()
|
||||||
|
{
|
||||||
|
static const std::map<AkVCam::PixelFormat, FourCharCode> formatsTable {
|
||||||
|
{AkVCam::PixelFormatRGB32, kCMPixelFormat_32ARGB },
|
||||||
|
{AkVCam::PixelFormatRGB24, kCMPixelFormat_24RGB },
|
||||||
|
{AkVCam::PixelFormatRGB16, kCMPixelFormat_16LE565 },
|
||||||
|
{AkVCam::PixelFormatRGB15, kCMPixelFormat_16LE555 },
|
||||||
|
{AkVCam::PixelFormatUYVY , kCMPixelFormat_422YpCbCr8 },
|
||||||
|
{AkVCam::PixelFormatYUY2 , kCMPixelFormat_422YpCbCr8_yuvs}
|
||||||
|
};
|
||||||
|
|
||||||
|
return &formatsTable;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AkVCam::uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2)
|
||||||
|
{
|
||||||
|
auto iid2 = CFUUIDGetUUIDBytes(uuid2);
|
||||||
|
auto puuid1 = reinterpret_cast<const UInt8 *>(&uuid1);
|
||||||
|
auto puuid2 = reinterpret_cast<const UInt8 *>(&iid2);
|
||||||
|
|
||||||
|
for (int i = 0; i < 16; i++)
|
||||||
|
if (puuid1[i] != puuid2[i])
|
||||||
|
return false;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::enumToString(UInt32 value)
|
||||||
|
{
|
||||||
|
auto valueChr = reinterpret_cast<char *>(&value);
|
||||||
|
std::stringstream ss;
|
||||||
|
|
||||||
|
for (int i = 3; i >= 0; i--)
|
||||||
|
if (valueChr[i] < 0)
|
||||||
|
ss << std::hex << valueChr[i];
|
||||||
|
else if (valueChr[i] < 32)
|
||||||
|
ss << int(valueChr[i]);
|
||||||
|
else
|
||||||
|
ss << valueChr[i];
|
||||||
|
|
||||||
|
return "'" + ss.str() + "'";
|
||||||
|
}
|
||||||
|
|
||||||
|
FourCharCode AkVCam::formatToCM(PixelFormat format)
|
||||||
|
{
|
||||||
|
for (auto &fmt: *Utils::formatsTable())
|
||||||
|
if (fmt.first == format)
|
||||||
|
return fmt.second;
|
||||||
|
|
||||||
|
return FourCharCode(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::PixelFormat AkVCam::formatFromCM(FourCharCode format)
|
||||||
|
{
|
||||||
|
for (auto &fmt: *Utils::formatsTable())
|
||||||
|
if (fmt.second == format)
|
||||||
|
return fmt.first;
|
||||||
|
|
||||||
|
return PixelFormat(0);
|
||||||
|
}
|
||||||
|
|
||||||
std::shared_ptr<CFTypeRef> AkVCam::cfTypeFromStd(const std::string &str)
|
std::shared_ptr<CFTypeRef> AkVCam::cfTypeFromStd(const std::string &str)
|
||||||
{
|
{
|
||||||
|
@ -135,3 +225,174 @@ std::wstring AkVCam::wstringFromCFType(CFTypeRef cfType)
|
||||||
|
|
||||||
return std::wstring(cstr, size_t(len));
|
return std::wstring(cstr, size_t(len));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string AkVCam::realPath(const std::string &path)
|
||||||
|
{
|
||||||
|
char resolvedPath[PATH_MAX];
|
||||||
|
memset(resolvedPath, 0, PATH_MAX);
|
||||||
|
::realpath(path.c_str(), resolvedPath);
|
||||||
|
|
||||||
|
char realPath[PATH_MAX];
|
||||||
|
memset(realPath, 0, PATH_MAX);
|
||||||
|
readlink(resolvedPath, realPath, PATH_MAX);
|
||||||
|
|
||||||
|
if (strlen(realPath) < 1)
|
||||||
|
return {resolvedPath};
|
||||||
|
|
||||||
|
return {realPath};
|
||||||
|
}
|
||||||
|
|
||||||
|
AkVCam::VideoFrame AkVCam::loadPicture(const std::string &fileName)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
VideoFrame frame;
|
||||||
|
|
||||||
|
if (frame.load(fileName)) {
|
||||||
|
AkLogInfo() << "Picture loaded as BMP" << std::endl;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto fileDataProvider = CGDataProviderCreateWithFilename(fileName.c_str());
|
||||||
|
|
||||||
|
if (!fileDataProvider) {
|
||||||
|
AkLogError() << "Can't create a data provider for '"
|
||||||
|
<< fileName
|
||||||
|
<< "'"
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if the file is a PNG and open it.
|
||||||
|
auto cgImage = CGImageCreateWithPNGDataProvider(fileDataProvider,
|
||||||
|
nullptr,
|
||||||
|
true,
|
||||||
|
kCGRenderingIntentDefault);
|
||||||
|
|
||||||
|
// If the file is not a PNG, try opening as JPEG.
|
||||||
|
if (!cgImage) {
|
||||||
|
AkLogWarning() << "Can't read '"
|
||||||
|
<< fileName
|
||||||
|
<< "' as a PNG image."
|
||||||
|
<< std::endl;
|
||||||
|
cgImage = CGImageCreateWithJPEGDataProvider(fileDataProvider,
|
||||||
|
nullptr,
|
||||||
|
true,
|
||||||
|
kCGRenderingIntentDefault);
|
||||||
|
}
|
||||||
|
|
||||||
|
CGDataProviderRelease(fileDataProvider);
|
||||||
|
|
||||||
|
// The file format is not supported, fail.
|
||||||
|
if (!cgImage) {
|
||||||
|
AkLogError() << "Can't read '"
|
||||||
|
<< fileName
|
||||||
|
<< "' as a JPEG image."
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
FourCC format = 0;
|
||||||
|
|
||||||
|
if (CGImageGetBitsPerComponent(cgImage) == 8) {
|
||||||
|
if (CGImageGetBitsPerPixel(cgImage) == 24)
|
||||||
|
format = PixelFormatRGB24;
|
||||||
|
else if (CGImageGetBitsPerPixel(cgImage) == 32) {
|
||||||
|
format = PixelFormatRGB32;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto width = CGImageGetWidth(cgImage);
|
||||||
|
auto height = CGImageGetHeight(cgImage);
|
||||||
|
|
||||||
|
if (format == 0 || width < 1 || height < 1) {
|
||||||
|
AkLogError() << "Invalid picture format: "
|
||||||
|
<< "BPC="
|
||||||
|
<< CGImageGetBitsPerComponent(cgImage)
|
||||||
|
<< "BPP="
|
||||||
|
<< CGImageGetBitsPerPixel(cgImage)
|
||||||
|
<< " "
|
||||||
|
<< width
|
||||||
|
<< "x"
|
||||||
|
<< height
|
||||||
|
<< std::endl;
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
VideoFormat videoFormat(PixelFormatRGB24, width, height);
|
||||||
|
frame = VideoFrame(videoFormat);
|
||||||
|
|
||||||
|
auto imageDataProvider = CGImageGetDataProvider(cgImage);
|
||||||
|
|
||||||
|
if (!imageDataProvider) {
|
||||||
|
AkLogError() << "Can't get data provider for picture." << std::endl;
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto data = CGDataProviderCopyData(imageDataProvider);
|
||||||
|
|
||||||
|
if (!data) {
|
||||||
|
AkLogError() << "Can't copy data from image provider." << std::endl;
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
auto lineSize = CGImageGetBytesPerRow(cgImage);
|
||||||
|
|
||||||
|
if (CGImageGetBitsPerPixel(cgImage) == 24) {
|
||||||
|
for (int y = 0; y < videoFormat.height(); y++) {
|
||||||
|
auto srcLine = reinterpret_cast<const Utils::RGB24 *>(CFDataGetBytePtr(data) + y * lineSize);
|
||||||
|
auto dstLine = reinterpret_cast<Utils::RGB24 *>(frame.line(0, y));
|
||||||
|
|
||||||
|
for (int x = 0; x < videoFormat.height(); x++) {
|
||||||
|
dstLine[x].r = srcLine[x].r;
|
||||||
|
dstLine[x].g = srcLine[x].g;
|
||||||
|
dstLine[x].b = srcLine[x].b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (CGImageGetBitsPerPixel(cgImage) == 32) {
|
||||||
|
if (CGImageGetAlphaInfo(cgImage) == kCGImageAlphaNone) {
|
||||||
|
for (int y = 0; y < videoFormat.height(); y++) {
|
||||||
|
auto srcLine = reinterpret_cast<const Utils::RGB32 *>(CFDataGetBytePtr(data) + y * lineSize);
|
||||||
|
auto dstLine = reinterpret_cast<Utils::RGB24 *>(frame.line(0, y));
|
||||||
|
|
||||||
|
for (int x = 0; x < videoFormat.height(); x++) {
|
||||||
|
dstLine[x].r = srcLine[x].r;
|
||||||
|
dstLine[x].g = srcLine[x].g;
|
||||||
|
dstLine[x].b = srcLine[x].b;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (int y = 0; y < videoFormat.height(); y++) {
|
||||||
|
auto srcLine = reinterpret_cast<const Utils::RGB32 *>(CFDataGetBytePtr(data) + y * lineSize);
|
||||||
|
auto dstLine = reinterpret_cast<Utils::RGB24 *>(frame.line(0, y));
|
||||||
|
|
||||||
|
for (int x = 0; x < videoFormat.width(); x++) {
|
||||||
|
dstLine[x].r = srcLine[x].r * srcLine[x].x / 255;
|
||||||
|
dstLine[x].g = srcLine[x].g * srcLine[x].x / 255;
|
||||||
|
dstLine[x].b = srcLine[x].b * srcLine[x].x / 255;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CFRelease(data);
|
||||||
|
CGImageRelease(cgImage);
|
||||||
|
|
||||||
|
AkLogDebug() << "Picture loaded as: "
|
||||||
|
<< VideoFormat::stringFromFourcc(videoFormat.fourcc())
|
||||||
|
<< " "
|
||||||
|
<< videoFormat.width()
|
||||||
|
<< "x"
|
||||||
|
<< videoFormat.height()
|
||||||
|
<< std::endl;
|
||||||
|
|
||||||
|
return frame;
|
||||||
|
}
|
||||||
|
|
|
@ -20,19 +20,29 @@
|
||||||
#ifndef PLATFORM_UTILS_H
|
#ifndef PLATFORM_UTILS_H
|
||||||
#define PLATFORM_UTILS_H
|
#define PLATFORM_UTILS_H
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <CoreFoundation/CoreFoundation.h>
|
#include <CoreMediaIO/CMIOHardwarePlugIn.h>
|
||||||
|
#include <CoreMedia/CMFormatDescription.h>
|
||||||
|
|
||||||
|
#include "VCamUtils/src/image/videoformattypes.h"
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
{
|
{
|
||||||
class VideoFormat;
|
class VideoFrame;
|
||||||
|
|
||||||
|
bool uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2);
|
||||||
|
std::string enumToString(UInt32 value);
|
||||||
|
FourCharCode formatToCM(PixelFormat format);
|
||||||
|
PixelFormat formatFromCM(FourCharCode format);
|
||||||
std::shared_ptr<CFTypeRef> cfTypeFromStd(const std::string &str);
|
std::shared_ptr<CFTypeRef> cfTypeFromStd(const std::string &str);
|
||||||
std::shared_ptr<CFTypeRef> cfTypeFromStd(const std::wstring &str);
|
std::shared_ptr<CFTypeRef> cfTypeFromStd(const std::wstring &str);
|
||||||
std::shared_ptr<CFTypeRef> cfTypeFromStd(int num);
|
std::shared_ptr<CFTypeRef> cfTypeFromStd(int num);
|
||||||
std::shared_ptr<CFTypeRef> cfTypeFromStd(double num);
|
std::shared_ptr<CFTypeRef> cfTypeFromStd(double num);
|
||||||
std::string stringFromCFType(CFTypeRef cfType);
|
std::string stringFromCFType(CFTypeRef cfType);
|
||||||
std::wstring wstringFromCFType(CFTypeRef cfType);
|
std::wstring wstringFromCFType(CFTypeRef cfType);
|
||||||
|
std::string realPath(const std::string &path);
|
||||||
|
VideoFrame loadPicture(const std::string &fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // PLATFORM_UTILS_H
|
#endif // PLATFORM_UTILS_H
|
||||||
|
|
|
@ -17,12 +17,16 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <codecvt>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <locale>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <algorithm>
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <dirent.h>
|
#include <dirent.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
#include <libgen.h>
|
||||||
#include <Foundation/Foundation.h>
|
#include <Foundation/Foundation.h>
|
||||||
#include <IOSurface/IOSurface.h>
|
#include <IOSurface/IOSurface.h>
|
||||||
#include <CoreMedia/CMFormatDescription.h>
|
#include <CoreMedia/CMFormatDescription.h>
|
||||||
|
@ -31,6 +35,7 @@
|
||||||
|
|
||||||
#include "Assistant/src/assistantglobals.h"
|
#include "Assistant/src/assistantglobals.h"
|
||||||
#include "PlatformUtils/src/preferences.h"
|
#include "PlatformUtils/src/preferences.h"
|
||||||
|
#include "PlatformUtils/src/utils.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/ipcbridge.h"
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
|
@ -61,6 +66,7 @@ namespace AkVCam
|
||||||
inline void add(IpcBridge *bridge);
|
inline void add(IpcBridge *bridge);
|
||||||
void remove(IpcBridge *bridge);
|
void remove(IpcBridge *bridge);
|
||||||
inline std::vector<IpcBridge *> &bridges();
|
inline std::vector<IpcBridge *> &bridges();
|
||||||
|
inline const std::vector<DeviceControl> &controls() const;
|
||||||
|
|
||||||
// Message handling methods
|
// Message handling methods
|
||||||
void isAlive(xpc_connection_t client, xpc_object_t event);
|
void isAlive(xpc_connection_t client, xpc_object_t event);
|
||||||
|
@ -68,12 +74,9 @@ namespace AkVCam
|
||||||
void deviceDestroy(xpc_connection_t client, xpc_object_t event);
|
void deviceDestroy(xpc_connection_t client, xpc_object_t event);
|
||||||
void deviceUpdate(xpc_connection_t client, xpc_object_t event);
|
void deviceUpdate(xpc_connection_t client, xpc_object_t event);
|
||||||
void frameReady(xpc_connection_t client, xpc_object_t event);
|
void frameReady(xpc_connection_t client, xpc_object_t event);
|
||||||
void setBroadcasting(xpc_connection_t client,
|
void pictureUpdated(xpc_connection_t client, xpc_object_t event);
|
||||||
xpc_object_t event);
|
void setBroadcasting(xpc_connection_t client, xpc_object_t event);
|
||||||
void setMirror(xpc_connection_t client, xpc_object_t event);
|
void controlsUpdated(xpc_connection_t client, xpc_object_t event);
|
||||||
void setScaling(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setAspectRatio(xpc_connection_t client, xpc_object_t event);
|
|
||||||
void setSwapRgb(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 messageReceived(xpc_connection_t client, xpc_object_t event);
|
void messageReceived(xpc_connection_t client, xpc_object_t event);
|
||||||
|
@ -83,10 +86,9 @@ namespace AkVCam
|
||||||
std::string homePath() const;
|
std::string homePath() const;
|
||||||
bool fileExists(const std::wstring &path) const;
|
bool fileExists(const std::wstring &path) const;
|
||||||
bool fileExists(const std::string &path) const;
|
bool fileExists(const std::string &path) const;
|
||||||
std::wstring fileName(const std::wstring &path) const;
|
|
||||||
bool mkpath(const std::string &path) const;
|
bool mkpath(const std::string &path) const;
|
||||||
bool rm(const std::string &path) const;
|
bool rm(const std::string &path) const;
|
||||||
std::wstring locateDriverPath() const;
|
static std::string locatePluginPath();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::vector<IpcBridge *> m_bridges;
|
std::vector<IpcBridge *> m_bridges;
|
||||||
|
@ -169,7 +171,18 @@ std::wstring AkVCam::IpcBridge::picture() const
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setPicture(const std::wstring &picture)
|
void AkVCam::IpcBridge::setPicture(const std::wstring &picture)
|
||||||
{
|
{
|
||||||
|
AkLogFunction();
|
||||||
Preferences::setPicture(picture);
|
Preferences::setPicture(picture);
|
||||||
|
|
||||||
|
if (!this->d->m_serverMessagePort)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
|
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
||||||
|
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED);
|
||||||
|
xpc_dictionary_set_string(dictionary, "picture", cv.to_bytes(picture).c_str());
|
||||||
|
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
|
||||||
|
xpc_release(dictionary);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AkVCam::IpcBridge::logLevel() const
|
int AkVCam::IpcBridge::logLevel() const
|
||||||
|
@ -446,139 +459,62 @@ std::string AkVCam::IpcBridge::broadcaster(const std::string &deviceId) const
|
||||||
return broadcaster;
|
return broadcaster;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::isHorizontalMirrored(const std::string &deviceId)
|
std::vector<AkVCam::DeviceControl> AkVCam::IpcBridge::controls(const std::string &deviceId)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
if (cameraIndex < 0)
|
||||||
return false;
|
return {};
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
std::vector<DeviceControl> controls;
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
for (auto &control: this->d->controls()) {
|
||||||
xpc_release(reply);
|
controls.push_back(control);
|
||||||
|
controls.back().value =
|
||||||
return false;
|
Preferences::cameraControlValue(cameraIndex, control.id);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool horizontalMirror = xpc_dictionary_get_bool(reply, "hmirror");
|
return controls;
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return horizontalMirror;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::isVerticalMirrored(const std::string &deviceId)
|
void AkVCam::IpcBridge::setControls(const std::string &deviceId,
|
||||||
|
const std::map<std::string, int> &controls)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
if (cameraIndex < 0)
|
||||||
return false;
|
return;
|
||||||
|
|
||||||
|
bool updated = false;
|
||||||
|
|
||||||
|
for (auto &control: this->d->controls()) {
|
||||||
|
auto oldValue =
|
||||||
|
Preferences::cameraControlValue(cameraIndex, control.id);
|
||||||
|
|
||||||
|
if (controls.count(control.id)) {
|
||||||
|
auto newValue = controls.at(control.id);
|
||||||
|
|
||||||
|
if (newValue != oldValue) {
|
||||||
|
Preferences::cameraSetControlValue(cameraIndex,
|
||||||
|
control.id,
|
||||||
|
newValue);
|
||||||
|
updated = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this->d->m_serverMessagePort || !updated)
|
||||||
|
return;
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_MIRRORING);
|
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED);
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
||||||
dictionary);
|
dictionary);
|
||||||
xpc_release(dictionary);
|
xpc_release(dictionary);
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool verticalMirror = xpc_dictionary_get_bool(reply, "vmirror");
|
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
|
|
||||||
return verticalMirror;
|
|
||||||
}
|
|
||||||
|
|
||||||
AkVCam::Scaling AkVCam::IpcBridge::scalingMode(const std::string &deviceId)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return ScalingFast;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SCALING);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return ScalingFast;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto scaling = Scaling(xpc_dictionary_get_int64(reply, "scaling"));
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return scaling;
|
|
||||||
}
|
|
||||||
|
|
||||||
AkVCam::AspectRatio AkVCam::IpcBridge::aspectRatioMode(const std::string &deviceId)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return AspectRatioIgnore;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_ASPECTRATIO);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return AspectRatioIgnore;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto aspectRatio = AspectRatio(xpc_dictionary_get_int64(reply, "aspect"));
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return aspectRatio;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::swapRgb(const std::string &deviceId)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SWAPRGB);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
auto replyType = xpc_get_type(reply);
|
|
||||||
|
|
||||||
if (replyType != XPC_TYPE_DICTIONARY) {
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto swap = xpc_dictionary_get_bool(reply, "swap");
|
|
||||||
xpc_release(reply);
|
|
||||||
|
|
||||||
return swap;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<std::string> AkVCam::IpcBridge::listeners(const std::string &deviceId)
|
std::vector<std::string> AkVCam::IpcBridge::listeners(const std::string &deviceId)
|
||||||
|
@ -618,17 +554,19 @@ std::vector<std::string> AkVCam::IpcBridge::listeners(const std::string &deviceI
|
||||||
|
|
||||||
std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const
|
std::vector<uint64_t> AkVCam::IpcBridge::clientsPids() const
|
||||||
{
|
{
|
||||||
auto driverPath = this->d->locateDriverPath();
|
AkLogFunction();
|
||||||
|
auto driverPath = this->d->locatePluginPath();
|
||||||
|
AkLogDebug() << "Plugin path: " << driverPath << std::endl;
|
||||||
|
|
||||||
if (driverPath.empty())
|
if (driverPath.empty())
|
||||||
return {};
|
return {};
|
||||||
|
|
||||||
auto plugin = this->d->fileName(driverPath);
|
auto path = driverPath + "/Contents/MacOS/" CMIO_PLUGIN_NAME;
|
||||||
std::wstring pluginPath =
|
AkLogDebug() << "Plugin binary: " << path << std::endl;
|
||||||
CMIO_PLUGINS_DAL_PATH_L L"/"
|
|
||||||
+ plugin
|
if (!this->d->fileExists(path))
|
||||||
+ L"/Contents/MacOS/" CMIO_PLUGIN_NAME_L;
|
return {};
|
||||||
std::string path(pluginPath.begin(), pluginPath.end());
|
|
||||||
auto npids = proc_listpidspath(PROC_ALL_PIDS,
|
auto npids = proc_listpidspath(PROC_ALL_PIDS,
|
||||||
0,
|
0,
|
||||||
path.c_str(),
|
path.c_str(),
|
||||||
|
@ -692,7 +630,7 @@ void AkVCam::IpcBridge::removeFormat(const std::string &deviceId, int index)
|
||||||
index);
|
index);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridge::update()
|
void AkVCam::IpcBridge::updateDevices()
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
|
@ -705,19 +643,6 @@ void AkVCam::IpcBridge::update()
|
||||||
AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
|
AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
|
||||||
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
|
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
|
||||||
xpc_release(dictionary);
|
xpc_release(dictionary);
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::updateDevices()
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE);
|
|
||||||
xpc_connection_send_message(this->d->m_serverMessagePort, dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -856,79 +781,6 @@ bool AkVCam::IpcBridge::write(const std::string &deviceId,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setMirroring(const std::string &deviceId,
|
|
||||||
bool horizontalMirrored,
|
|
||||||
bool verticalMirrored)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
xpc_dictionary_set_bool(dictionary, "hmirror", horizontalMirrored);
|
|
||||||
xpc_dictionary_set_bool(dictionary, "vmirror", verticalMirrored);
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setScaling(const std::string &deviceId,
|
|
||||||
Scaling scaling)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
xpc_dictionary_set_int64(dictionary, "scaling", scaling);
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setAspectRatio(const std::string &deviceId,
|
|
||||||
AspectRatio aspectRatio)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
xpc_dictionary_set_int64(dictionary, "aspect", aspectRatio);
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridge::setSwapRgb(const std::string &deviceId, bool swap)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
if (!this->d->m_serverMessagePort)
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto dictionary = xpc_dictionary_create(nullptr, nullptr, 0);
|
|
||||||
xpc_dictionary_set_int64(dictionary, "message", AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB);
|
|
||||||
xpc_dictionary_set_string(dictionary, "device", deviceId.c_str());
|
|
||||||
xpc_dictionary_set_bool(dictionary, "swap", swap);
|
|
||||||
auto reply = xpc_connection_send_message_with_reply_sync(this->d->m_serverMessagePort,
|
|
||||||
dictionary);
|
|
||||||
xpc_release(dictionary);
|
|
||||||
xpc_release(reply);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridge::addListener(const std::string &deviceId)
|
bool AkVCam::IpcBridge::addListener(const std::string &deviceId)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
@ -991,18 +843,16 @@ AkVCam::IpcBridgePrivate::IpcBridgePrivate(IpcBridge *self):
|
||||||
m_serverMessagePort(nullptr)
|
m_serverMessagePort(nullptr)
|
||||||
{
|
{
|
||||||
this->m_messageHandlers = {
|
this->m_messageHandlers = {
|
||||||
{AKVCAM_ASSISTANT_MSG_ISALIVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::isAlive) },
|
{AKVCAM_ASSISTANT_MSG_ISALIVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::isAlive) },
|
||||||
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(IpcBridgePrivate::frameReady) },
|
{AKVCAM_ASSISTANT_MSG_FRAME_READY , AKVCAM_BIND_FUNC(IpcBridgePrivate::frameReady) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_CREATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceCreate) },
|
{AKVCAM_ASSISTANT_MSG_PICTURE_UPDATED , AKVCAM_BIND_FUNC(IpcBridgePrivate::pictureUpdated) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceDestroy) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_CREATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceCreate) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceUpdate) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_DESTROY , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceDestroy) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerAdd) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_UPDATE , AKVCAM_BIND_FUNC(IpcBridgePrivate::deviceUpdate) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE, AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerRemove) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_ADD , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerAdd) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING, AKVCAM_BIND_FUNC(IpcBridgePrivate::setBroadcasting)},
|
{AKVCAM_ASSISTANT_MSG_DEVICE_LISTENER_REMOVE , AKVCAM_BIND_FUNC(IpcBridgePrivate::listenerRemove) },
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETMIRRORING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setMirror) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_SETBROADCASTING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setBroadcasting)},
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSCALING , AKVCAM_BIND_FUNC(IpcBridgePrivate::setScaling) },
|
{AKVCAM_ASSISTANT_MSG_DEVICE_CONTROLS_UPDATED, AKVCAM_BIND_FUNC(IpcBridgePrivate::controlsUpdated)},
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETASPECTRATIO , AKVCAM_BIND_FUNC(IpcBridgePrivate::setAspectRatio) },
|
|
||||||
{AKVCAM_ASSISTANT_MSG_DEVICE_SETSWAPRGB , AKVCAM_BIND_FUNC(IpcBridgePrivate::setSwapRgb) },
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1038,6 +888,31 @@ std::vector<AkVCam::IpcBridge *> &AkVCam::IpcBridgePrivate::bridges()
|
||||||
return this->m_bridges;
|
return this->m_bridges;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const std::vector<AkVCam::DeviceControl> &AkVCam::IpcBridgePrivate::controls() const
|
||||||
|
{
|
||||||
|
static const std::vector<std::string> scalingMenu {
|
||||||
|
"Fast",
|
||||||
|
"Linear"
|
||||||
|
};
|
||||||
|
static const std::vector<std::string> aspectRatioMenu {
|
||||||
|
"Ignore",
|
||||||
|
"Keep",
|
||||||
|
"Expanding"
|
||||||
|
};
|
||||||
|
static const auto scalingMax = int(scalingMenu.size()) - 1;
|
||||||
|
static const auto aspectRatioMax = int(aspectRatioMenu.size()) - 1;
|
||||||
|
|
||||||
|
static const std::vector<DeviceControl> controls {
|
||||||
|
{"hflip" , "Horizontal Mirror", ControlTypeBoolean, 0, 1 , 1, 0, 0, {} },
|
||||||
|
{"vflip" , "Vertical Mirror" , ControlTypeBoolean, 0, 1 , 1, 0, 0, {} },
|
||||||
|
{"scaling" , "Scaling" , ControlTypeMenu , 0, scalingMax , 1, 0, 0, scalingMenu },
|
||||||
|
{"aspect_ratio", "Aspect Ratio" , ControlTypeMenu , 0, aspectRatioMax, 1, 0, 0, aspectRatioMenu},
|
||||||
|
{"swap_rgb" , "Swap RGB" , ControlTypeBoolean, 0, 1 , 1, 0, 0, {} },
|
||||||
|
};
|
||||||
|
|
||||||
|
return controls;
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::isAlive(xpc_connection_t client,
|
void AkVCam::IpcBridgePrivate::isAlive(xpc_connection_t client,
|
||||||
xpc_object_t event)
|
xpc_object_t event)
|
||||||
{
|
{
|
||||||
|
@ -1118,6 +993,18 @@ void AkVCam::IpcBridgePrivate::frameReady(xpc_connection_t client,
|
||||||
xpc_release(reply);
|
xpc_release(reply);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::IpcBridgePrivate::pictureUpdated(xpc_connection_t client,
|
||||||
|
xpc_object_t event)
|
||||||
|
{
|
||||||
|
UNUSED(client);
|
||||||
|
AkLogFunction();
|
||||||
|
|
||||||
|
std::string picture = xpc_dictionary_get_string(event, "picture");
|
||||||
|
|
||||||
|
for (auto bridge: this->m_bridges)
|
||||||
|
AKVCAM_EMIT(bridge, PictureChanged, picture)
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::setBroadcasting(xpc_connection_t client,
|
void AkVCam::IpcBridgePrivate::setBroadcasting(xpc_connection_t client,
|
||||||
xpc_object_t event)
|
xpc_object_t event)
|
||||||
{
|
{
|
||||||
|
@ -1133,69 +1020,31 @@ void AkVCam::IpcBridgePrivate::setBroadcasting(xpc_connection_t client,
|
||||||
AKVCAM_EMIT(bridge, BroadcastingChanged, deviceId, broadcaster)
|
AKVCAM_EMIT(bridge, BroadcastingChanged, deviceId, broadcaster)
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::setMirror(xpc_connection_t client,
|
void AkVCam::IpcBridgePrivate::controlsUpdated(xpc_connection_t client,
|
||||||
xpc_object_t event)
|
xpc_object_t event)
|
||||||
{
|
{
|
||||||
UNUSED(client);
|
UNUSED(client);
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
std::string deviceId =
|
std::string deviceId =
|
||||||
xpc_dictionary_get_string(event, "device");
|
xpc_dictionary_get_string(event, "device");
|
||||||
bool horizontalMirror =
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
xpc_dictionary_get_bool(event, "hmirror");
|
std::map<std::string, int> controls;
|
||||||
bool verticalMirror =
|
|
||||||
xpc_dictionary_get_bool(event, "vmirror");
|
for (auto &control: this->controls())
|
||||||
|
controls[control.id] =
|
||||||
|
Preferences::cameraControlValue(cameraIndex, control.id);
|
||||||
|
|
||||||
for (auto bridge: this->m_bridges)
|
for (auto bridge: this->m_bridges)
|
||||||
AKVCAM_EMIT(bridge,
|
AKVCAM_EMIT(bridge,
|
||||||
MirrorChanged,
|
ControlsChanged,
|
||||||
deviceId,
|
deviceId,
|
||||||
horizontalMirror,
|
controls)
|
||||||
verticalMirror)
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::setScaling(xpc_connection_t client,
|
auto reply = xpc_dictionary_create_reply(event);
|
||||||
xpc_object_t event)
|
xpc_dictionary_set_bool(reply, "status", cameraIndex >= 0);
|
||||||
{
|
xpc_connection_send_message(client, reply);
|
||||||
UNUSED(client);
|
xpc_release(reply);
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
std::string deviceId =
|
|
||||||
xpc_dictionary_get_string(event, "device");
|
|
||||||
auto scaling =
|
|
||||||
Scaling(xpc_dictionary_get_int64(event, "scaling"));
|
|
||||||
|
|
||||||
for (auto bridge: this->m_bridges)
|
|
||||||
AKVCAM_EMIT(bridge, ScalingChanged, deviceId, scaling)
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::setAspectRatio(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
UNUSED(client);
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
std::string deviceId =
|
|
||||||
xpc_dictionary_get_string(event, "device");
|
|
||||||
auto aspectRatio =
|
|
||||||
AspectRatio(xpc_dictionary_get_int64(event, "aspect"));
|
|
||||||
|
|
||||||
for (auto bridge: this->m_bridges)
|
|
||||||
AKVCAM_EMIT(bridge, AspectRatioChanged, deviceId, aspectRatio)
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::setSwapRgb(xpc_connection_t client,
|
|
||||||
xpc_object_t event)
|
|
||||||
{
|
|
||||||
UNUSED(client);
|
|
||||||
AkLogFunction();
|
|
||||||
|
|
||||||
std::string deviceId =
|
|
||||||
xpc_dictionary_get_string(event, "device");
|
|
||||||
auto swap = xpc_dictionary_get_bool(event, "swap");
|
|
||||||
|
|
||||||
for (auto bridge: this->m_bridges)
|
|
||||||
AKVCAM_EMIT(bridge, SwapRgbChanged, deviceId, swap)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::IpcBridgePrivate::listenerAdd(xpc_connection_t client,
|
void AkVCam::IpcBridgePrivate::listenerAdd(xpc_connection_t client,
|
||||||
|
@ -1280,11 +1129,6 @@ bool AkVCam::IpcBridgePrivate::fileExists(const std::string &path) const
|
||||||
return stat(path.c_str(), &stats) == 0;
|
return stat(path.c_str(), &stats) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring AkVCam::IpcBridgePrivate::fileName(const std::wstring &path) const
|
|
||||||
{
|
|
||||||
return path.substr(path.rfind(L'/') + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::IpcBridgePrivate::mkpath(const std::string &path) const
|
bool AkVCam::IpcBridgePrivate::mkpath(const std::string &path) const
|
||||||
{
|
{
|
||||||
if (path.empty())
|
if (path.empty())
|
||||||
|
@ -1341,32 +1185,14 @@ bool AkVCam::IpcBridgePrivate::rm(const std::string &path) const
|
||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::wstring AkVCam::IpcBridgePrivate::locateDriverPath() const
|
std::string AkVCam::IpcBridgePrivate::locatePluginPath()
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
std::wstring driverPath;
|
Dl_info info;
|
||||||
|
memset(&info, 0, sizeof(Dl_info));
|
||||||
|
dladdr(reinterpret_cast<void *>(&AkVCam::IpcBridgePrivate::locatePluginPath),
|
||||||
|
&info);
|
||||||
|
std::string dirName = dirname(const_cast<char *>(info.dli_fname));
|
||||||
|
|
||||||
for (auto it = this->driverPaths()->rbegin();
|
return realPath(dirName + "/../..");
|
||||||
it != this->driverPaths()->rend();
|
|
||||||
it++) {
|
|
||||||
auto path = *it;
|
|
||||||
path = replace(path, L"\\", L"/");
|
|
||||||
|
|
||||||
if (path.back() != L'/')
|
|
||||||
path += L'/';
|
|
||||||
|
|
||||||
path += CMIO_PLUGIN_NAME_L L".plugin";
|
|
||||||
|
|
||||||
if (!this->fileExists(path + L"/Contents/MacOS/" CMIO_PLUGIN_NAME_L))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
if (!this->fileExists(path + L"/Contents/Resources/" CMIO_PLUGIN_ASSISTANT_NAME_L))
|
|
||||||
continue;
|
|
||||||
|
|
||||||
driverPath = path;
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
return driverPath;
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,7 @@ LIBS = \
|
||||||
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
-L$${OUT_PWD}/../../VCamUtils/$${BIN_DIR} -lVCamUtils \
|
||||||
-L$${OUT_PWD}/../VCamIPC/$${BIN_DIR} -lVCamIPC \
|
-L$${OUT_PWD}/../VCamIPC/$${BIN_DIR} -lVCamIPC \
|
||||||
-framework CoreFoundation \
|
-framework CoreFoundation \
|
||||||
|
-framework CoreGraphics \
|
||||||
-framework CoreMedia \
|
-framework CoreMedia \
|
||||||
-framework CoreMediaIO \
|
-framework CoreMediaIO \
|
||||||
-framework CoreVideo \
|
-framework CoreVideo \
|
||||||
|
@ -57,7 +58,6 @@ TEMPLATE = lib
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
src/plugin.h \
|
src/plugin.h \
|
||||||
src/plugininterface.h \
|
src/plugininterface.h \
|
||||||
src/utils.h \
|
|
||||||
src/device.h \
|
src/device.h \
|
||||||
src/object.h \
|
src/object.h \
|
||||||
src/stream.h \
|
src/stream.h \
|
||||||
|
@ -69,7 +69,6 @@ HEADERS += \
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
src/plugin.cpp \
|
src/plugin.cpp \
|
||||||
src/plugininterface.cpp \
|
src/plugininterface.cpp \
|
||||||
src/utils.cpp \
|
|
||||||
src/device.cpp \
|
src/device.cpp \
|
||||||
src/object.cpp \
|
src/object.cpp \
|
||||||
src/stream.cpp \
|
src/stream.cpp \
|
||||||
|
@ -88,8 +87,7 @@ RESOURCESPATH = $${CONTENTSPATH}/Resources
|
||||||
|
|
||||||
INSTALLS += \
|
INSTALLS += \
|
||||||
targetLib \
|
targetLib \
|
||||||
infoPlist \
|
infoPlist
|
||||||
resources
|
|
||||||
|
|
||||||
targetLib.files = $$shell_path($${OUT_PWD}/../../$${MACBINPATH}/$${CMIO_PLUGIN_NAME})
|
targetLib.files = $$shell_path($${OUT_PWD}/../../$${MACBINPATH}/$${CMIO_PLUGIN_NAME})
|
||||||
targetLib.path = $${PREFIX}/$${MACBINPATH}
|
targetLib.path = $${PREFIX}/$${MACBINPATH}
|
||||||
|
@ -99,12 +97,7 @@ infoPlist.files = $$shell_path($${OUT_PWD}/Info.plist)
|
||||||
infoPlist.path = $${PREFIX}/$${CONTENTSPATH}
|
infoPlist.path = $${PREFIX}/$${CONTENTSPATH}
|
||||||
infoPlist.CONFIG += no_check_exist
|
infoPlist.CONFIG += no_check_exist
|
||||||
|
|
||||||
resources.files = ../../share/TestFrame/TestFrame.bmp
|
|
||||||
resources.path = $${PREFIX}/$${RESOURCESPATH}
|
|
||||||
|
|
||||||
QMAKE_POST_LINK = \
|
QMAKE_POST_LINK = \
|
||||||
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../../$${MACBINPATH})) $${CMD_SEP} \
|
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../../$${MACBINPATH})) $${CMD_SEP} \
|
||||||
$$sprintf($$QMAKE_MKDIR_CMD, $$shell_path($${OUT_PWD}/../../$${RESOURCESPATH})) $${CMD_SEP} \
|
|
||||||
$(COPY) $$shell_path($${OUT_PWD}/Info.plist) $$shell_path($${OUT_PWD}/../../$${CONTENTSPATH}) $${CMD_SEP} \
|
$(COPY) $$shell_path($${OUT_PWD}/Info.plist) $$shell_path($${OUT_PWD}/../../$${CONTENTSPATH}) $${CMD_SEP} \
|
||||||
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/lib$${CMIO_PLUGIN_NAME}.$${QMAKE_EXTENSION_SHLIB}) $$shell_path($${OUT_PWD}/../../$${MACBINPATH}/$${CMIO_PLUGIN_NAME}) $${CMD_SEP} \
|
$(COPY) $$shell_path($${OUT_PWD}/$${BIN_DIR}/lib$${CMIO_PLUGIN_NAME}.$${QMAKE_EXTENSION_SHLIB}) $$shell_path($${OUT_PWD}/../../$${MACBINPATH}/$${CMIO_PLUGIN_NAME}) $${CMD_SEP}
|
||||||
$(COPY) $$shell_path($${PWD}/../../share/TestFrame/TestFrame.bmp) $$shell_path($${OUT_PWD}/../../$${RESOURCESPATH})
|
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "device.h"
|
#include "device.h"
|
||||||
#include "utils.h"
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/logger/logger.h"
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
AkVCam::Device::Device(CMIOHardwarePlugInRef pluginInterface,
|
AkVCam::Device::Device(CMIOHardwarePlugInRef pluginInterface,
|
||||||
|
@ -194,16 +194,28 @@ void AkVCam::Device::frameReady(const AkVCam::VideoFrame &frame)
|
||||||
stream.second->frameReady(frame);
|
stream.second->frameReady(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setPicture(const std::string &picture)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setPicture(picture);
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::Device::setBroadcasting(const std::string &broadcaster)
|
void AkVCam::Device::setBroadcasting(const std::string &broadcaster)
|
||||||
{
|
{
|
||||||
for (auto &stream: this->m_streams)
|
for (auto &stream: this->m_streams)
|
||||||
stream.second->setBroadcasting(broadcaster);
|
stream.second->setBroadcasting(broadcaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::Device::setMirror(bool horizontalMirror, bool verticalMirror)
|
void AkVCam::Device::setHorizontalMirror(bool horizontalMirror)
|
||||||
{
|
{
|
||||||
for (auto &stream: this->m_streams)
|
for (auto &stream: this->m_streams)
|
||||||
stream.second->setMirror(horizontalMirror, verticalMirror);
|
stream.second->setHorizontalMirror(horizontalMirror);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Device::setVerticalMirror(bool verticalMirror)
|
||||||
|
{
|
||||||
|
for (auto &stream: this->m_streams)
|
||||||
|
stream.second->setVerticalMirror(verticalMirror);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::Device::setScaling(Scaling scaling)
|
void AkVCam::Device::setScaling(Scaling scaling)
|
||||||
|
|
|
@ -52,8 +52,10 @@ namespace AkVCam
|
||||||
|
|
||||||
void serverStateChanged(IpcBridge::ServerState state);
|
void serverStateChanged(IpcBridge::ServerState state);
|
||||||
void frameReady(const VideoFrame &frame);
|
void frameReady(const VideoFrame &frame);
|
||||||
|
void setPicture(const std::string &picture);
|
||||||
void setBroadcasting(const std::string &broadcaster);
|
void setBroadcasting(const std::string &broadcaster);
|
||||||
void setMirror(bool horizontalMirror, bool verticalMirror);
|
void setHorizontalMirror(bool horizontalMirror);
|
||||||
|
void setVerticalMirror(bool verticalMirror);
|
||||||
void setScaling(Scaling scaling);
|
void setScaling(Scaling scaling);
|
||||||
void setAspectRatio(AspectRatio aspectRatio);
|
void setAspectRatio(AspectRatio aspectRatio);
|
||||||
void setSwapRgb(bool swap);
|
void setSwapRgb(bool swap);
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "utils.h"
|
#include "PlatformUtils/src/utils.h"
|
||||||
|
|
||||||
AkVCam::Object::Object(CMIOHardwarePlugInRef pluginInterface,
|
AkVCam::Object::Object(CMIOHardwarePlugInRef pluginInterface,
|
||||||
Object *parent):
|
Object *parent):
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "objectinterface.h"
|
#include "objectinterface.h"
|
||||||
#include "utils.h"
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/logger/logger.h"
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
AkVCam::ObjectInterface::ObjectInterface():
|
AkVCam::ObjectInterface::ObjectInterface():
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
#include <map>
|
#include <map>
|
||||||
|
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "utils.h"
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/image/videoformat.h"
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
|
|
||||||
namespace AkVCam
|
namespace AkVCam
|
||||||
|
|
|
@ -18,8 +18,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "plugin.h"
|
#include "plugin.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "PlatformUtils/src/preferences.h"
|
#include "PlatformUtils/src/preferences.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/ipcbridge.h"
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
#include "VCamUtils/src/logger/logger.h"
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
|
||||||
|
|
|
@ -23,9 +23,9 @@
|
||||||
#include <IOKit/audio/IOAudioTypes.h>
|
#include <IOKit/audio/IOAudioTypes.h>
|
||||||
|
|
||||||
#include "plugininterface.h"
|
#include "plugininterface.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "Assistant/src/assistantglobals.h"
|
#include "Assistant/src/assistantglobals.h"
|
||||||
#include "PlatformUtils/src/preferences.h"
|
#include "PlatformUtils/src/preferences.h"
|
||||||
|
#include "PlatformUtils/src/utils.h"
|
||||||
#include "VCamUtils/src/image/videoformat.h"
|
#include "VCamUtils/src/image/videoformat.h"
|
||||||
#include "VCamUtils/src/ipcbridge.h"
|
#include "VCamUtils/src/ipcbridge.h"
|
||||||
#include "VCamUtils/src/logger/logger.h"
|
#include "VCamUtils/src/logger/logger.h"
|
||||||
|
@ -163,11 +163,9 @@ AkVCam::PluginInterface::PluginInterface():
|
||||||
this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved);
|
this->d->m_ipcBridge.connectDeviceRemoved(this, &PluginInterface::deviceRemoved);
|
||||||
this->d->m_ipcBridge.connectDevicesUpdated(this, &PluginInterface::devicesUpdated);
|
this->d->m_ipcBridge.connectDevicesUpdated(this, &PluginInterface::devicesUpdated);
|
||||||
this->d->m_ipcBridge.connectFrameReady(this, &PluginInterface::frameReady);
|
this->d->m_ipcBridge.connectFrameReady(this, &PluginInterface::frameReady);
|
||||||
|
this->d->m_ipcBridge.connectPictureChanged(this, &PluginInterface::pictureChanged);
|
||||||
this->d->m_ipcBridge.connectBroadcastingChanged(this, &PluginInterface::setBroadcasting);
|
this->d->m_ipcBridge.connectBroadcastingChanged(this, &PluginInterface::setBroadcasting);
|
||||||
this->d->m_ipcBridge.connectMirrorChanged(this, &PluginInterface::setMirror);
|
this->d->m_ipcBridge.connectControlsChanged(this, &PluginInterface::controlsChanged);
|
||||||
this->d->m_ipcBridge.connectScalingChanged(this, &PluginInterface::setScaling);
|
|
||||||
this->d->m_ipcBridge.connectAspectRatioChanged(this, &PluginInterface::setAspectRatio);
|
|
||||||
this->d->m_ipcBridge.connectSwapRgbChanged(this, &PluginInterface::setSwapRgb);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
AkVCam::PluginInterface::~PluginInterface()
|
AkVCam::PluginInterface::~PluginInterface()
|
||||||
|
@ -318,6 +316,16 @@ void AkVCam::PluginInterface::frameReady(void *userData,
|
||||||
device->frameReady(frame);
|
device->frameReady(frame);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::PluginInterface::pictureChanged(void *userData,
|
||||||
|
const std::string &picture)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
|
for (auto device: self->m_devices)
|
||||||
|
device->setPicture(picture);
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::PluginInterface::setBroadcasting(void *userData,
|
void AkVCam::PluginInterface::setBroadcasting(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const std::string &broadcaster)
|
const std::string &broadcaster)
|
||||||
|
@ -332,53 +340,31 @@ void AkVCam::PluginInterface::setBroadcasting(void *userData,
|
||||||
device->setBroadcasting(broadcaster);
|
device->setBroadcasting(broadcaster);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::PluginInterface::setMirror(void *userData,
|
void AkVCam::PluginInterface::controlsChanged(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
bool horizontalMirror,
|
const std::map<std::string, int> &controls)
|
||||||
bool verticalMirror)
|
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
AkLogInfo() << "Device: " << deviceId << std::endl;
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
auto self = reinterpret_cast<PluginInterface *>(userData);
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
for (auto device: self->m_devices)
|
||||||
if (device->deviceId() == deviceId)
|
if (device->deviceId() == deviceId) {
|
||||||
device->setMirror(horizontalMirror, verticalMirror);
|
if (controls.count("hflip"))
|
||||||
}
|
device->setHorizontalMirror(controls.at("hflip"));
|
||||||
|
|
||||||
void AkVCam::PluginInterface::setScaling(void *userData,
|
if (controls.count("vflip"))
|
||||||
const std::string &deviceId,
|
device->setHorizontalMirror(controls.at("vflip"));
|
||||||
Scaling scaling)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
if (controls.count("scaling"))
|
||||||
if (device->deviceId() == deviceId)
|
device->setScaling(Scaling(controls.at("scaling")));
|
||||||
device->setScaling(scaling);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::PluginInterface::setAspectRatio(void *userData,
|
if (controls.count("aspect_ratio"))
|
||||||
const std::string &deviceId,
|
device->setAspectRatio(AspectRatio(controls.at("aspect_ratio")));
|
||||||
AspectRatio aspectRatio)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
if (controls.count("swap_rgb"))
|
||||||
if (device->deviceId() == deviceId)
|
device->setSwapRgb(controls.at("swap_rgb"));
|
||||||
device->setAspectRatio(aspectRatio);
|
}
|
||||||
}
|
|
||||||
|
|
||||||
void AkVCam::PluginInterface::setSwapRgb(void *userData,
|
|
||||||
const std::string &deviceId,
|
|
||||||
bool swap)
|
|
||||||
{
|
|
||||||
AkLogFunction();
|
|
||||||
auto self = reinterpret_cast<PluginInterface *>(userData);
|
|
||||||
|
|
||||||
for (auto device: self->m_devices)
|
|
||||||
if (device->deviceId() == deviceId)
|
|
||||||
device->setSwapRgb(swap);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::PluginInterface::addListener(void *userData,
|
void AkVCam::PluginInterface::addListener(void *userData,
|
||||||
|
@ -412,6 +398,13 @@ bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||||
device->connectRemoveListener(this, &PluginInterface::removeListener);
|
device->connectRemoveListener(this, &PluginInterface::removeListener);
|
||||||
this->m_devices.push_back(device);
|
this->m_devices.push_back(device);
|
||||||
|
|
||||||
|
auto cameraIndex = Preferences::cameraFromPath(deviceId);
|
||||||
|
auto hflip = Preferences::cameraControlValue(cameraIndex, "hflip");
|
||||||
|
auto vflip = Preferences::cameraControlValue(cameraIndex, "vflip");
|
||||||
|
auto scaling = Preferences::cameraControlValue(cameraIndex, "scaling");
|
||||||
|
auto aspectRatio = Preferences::cameraControlValue(cameraIndex, "aspect_ratio");
|
||||||
|
auto swapRgb = Preferences::cameraControlValue(cameraIndex, "swap_rgb");
|
||||||
|
|
||||||
// Define device properties.
|
// Define device properties.
|
||||||
device->properties().setProperty(kCMIOObjectPropertyName,
|
device->properties().setProperty(kCMIOObjectPropertyName,
|
||||||
description);
|
description);
|
||||||
|
@ -469,11 +462,11 @@ bool AkVCam::PluginInterface::createDevice(const std::string &deviceId,
|
||||||
}
|
}
|
||||||
|
|
||||||
device->setBroadcasting(this->d->m_ipcBridge.broadcaster(deviceId));
|
device->setBroadcasting(this->d->m_ipcBridge.broadcaster(deviceId));
|
||||||
device->setMirror(this->d->m_ipcBridge.isHorizontalMirrored(deviceId),
|
device->setHorizontalMirror(hflip);
|
||||||
this->d->m_ipcBridge.isVerticalMirrored(deviceId));
|
device->setVerticalMirror(vflip);
|
||||||
device->setScaling(this->d->m_ipcBridge.scalingMode(deviceId));
|
device->setScaling(Scaling(scaling));
|
||||||
device->setAspectRatio(this->d->m_ipcBridge.aspectRatioMode(deviceId));
|
device->setAspectRatio(AspectRatio(aspectRatio));
|
||||||
device->setSwapRgb(this->d->m_ipcBridge.swapRgb(deviceId));
|
device->setSwapRgb(swapRgb);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -509,11 +502,17 @@ void AkVCam::PluginInterfacePrivate::updateDevices()
|
||||||
{
|
{
|
||||||
for (auto &device: this->self->m_devices) {
|
for (auto &device: this->self->m_devices) {
|
||||||
device->setBroadcasting(this->m_ipcBridge.broadcaster(device->deviceId()));
|
device->setBroadcasting(this->m_ipcBridge.broadcaster(device->deviceId()));
|
||||||
device->setMirror(this->m_ipcBridge.isHorizontalMirrored(device->deviceId()),
|
auto cameraIndex = Preferences::cameraFromPath(device->deviceId());
|
||||||
this->m_ipcBridge.isVerticalMirrored(device->deviceId()));
|
auto hflip = Preferences::cameraControlValue(cameraIndex, "hflip");
|
||||||
device->setScaling(this->m_ipcBridge.scalingMode(device->deviceId()));
|
auto vflip = Preferences::cameraControlValue(cameraIndex, "vflip");
|
||||||
device->setAspectRatio(this->m_ipcBridge.aspectRatioMode(device->deviceId()));
|
auto scaling = Preferences::cameraControlValue(cameraIndex, "scaling");
|
||||||
device->setSwapRgb(this->m_ipcBridge.swapRgb(device->deviceId()));
|
auto aspectRatio = Preferences::cameraControlValue(cameraIndex, "aspect_ratio");
|
||||||
|
auto swapRgb = Preferences::cameraControlValue(cameraIndex, "swap_rgb");
|
||||||
|
device->setHorizontalMirror(hflip);
|
||||||
|
device->setVerticalMirror(vflip);
|
||||||
|
device->setScaling(Scaling(scaling));
|
||||||
|
device->setAspectRatio(AspectRatio(aspectRatio));
|
||||||
|
device->setSwapRgb(swapRgb);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -58,22 +58,14 @@ namespace AkVCam
|
||||||
static void frameReady(void *userData,
|
static void frameReady(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const VideoFrame &frame);
|
const VideoFrame &frame);
|
||||||
|
static void pictureChanged(void *userData,
|
||||||
|
const std::string &picture);
|
||||||
static void setBroadcasting(void *userData,
|
static void setBroadcasting(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
const std::string &broadcaster);
|
const std::string &broadcaster);
|
||||||
static void setMirror(void *userData,
|
static void controlsChanged(void *userData,
|
||||||
const std::string &deviceId,
|
const std::string &deviceId,
|
||||||
bool horizontalMirror,
|
const std::map<std::string, int> &controls);
|
||||||
bool verticalMirror);
|
|
||||||
static void setScaling(void *userData,
|
|
||||||
const std::string &deviceId,
|
|
||||||
Scaling scaling);
|
|
||||||
static void setAspectRatio(void *userData,
|
|
||||||
const std::string &deviceId,
|
|
||||||
AspectRatio aspectRatio);
|
|
||||||
static void setSwapRgb(void *userData,
|
|
||||||
const std::string &deviceId,
|
|
||||||
bool swap);
|
|
||||||
static void addListener(void *userData,
|
static void addListener(void *userData,
|
||||||
const std::string &deviceId);
|
const std::string &deviceId);
|
||||||
static void removeListener(void *userData,
|
static void removeListener(void *userData,
|
||||||
|
|
|
@ -17,15 +17,18 @@
|
||||||
* Web-Site: http://webcamoid.github.io/
|
* Web-Site: http://webcamoid.github.io/
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
#include <codecvt>
|
#include <codecvt>
|
||||||
#include <thread>
|
#include <locale>
|
||||||
|
#include <mutex>
|
||||||
#include <random>
|
#include <random>
|
||||||
|
#include <thread>
|
||||||
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
#include <CoreMediaIO/CMIOSampleBuffer.h>
|
||||||
|
|
||||||
#include "stream.h"
|
#include "stream.h"
|
||||||
#include "clock.h"
|
#include "clock.h"
|
||||||
#include "utils.h"
|
|
||||||
#include "PlatformUtils/src/preferences.h"
|
#include "PlatformUtils/src/preferences.h"
|
||||||
|
#include "PlatformUtils/src/utils.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"
|
||||||
|
@ -78,7 +81,7 @@ AkVCam::Stream::Stream(bool registerObject,
|
||||||
|
|
||||||
if (!picture.empty()) {
|
if (!picture.empty()) {
|
||||||
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> cv;
|
||||||
this->d->m_testFrame.load(cv.to_bytes(picture));
|
this->d->m_testFrame = loadPicture(cv.to_bytes(picture));
|
||||||
}
|
}
|
||||||
|
|
||||||
this->d->m_clock =
|
this->d->m_clock =
|
||||||
|
@ -158,6 +161,20 @@ OSStatus AkVCam::Stream::registerObject(bool regist)
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setPicture(const std::string &picture)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
AkLogDebug() << "Picture: " << picture;
|
||||||
|
this->d->m_testFrame = loadPicture(picture);
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
this->d->m_mutex.lock();
|
||||||
|
|
||||||
|
if (this->d->m_broadcaster.empty())
|
||||||
|
this->d->m_currentFrame = this->d->m_testFrameAdapted;
|
||||||
|
|
||||||
|
this->d->m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
void AkVCam::Stream::setBridge(IpcBridge *bridge)
|
void AkVCam::Stream::setBridge(IpcBridge *bridge)
|
||||||
{
|
{
|
||||||
this->d->m_bridge = bridge;
|
this->d->m_bridge = bridge;
|
||||||
|
@ -307,15 +324,24 @@ void AkVCam::Stream::setBroadcasting(const std::string &broadcaster)
|
||||||
this->d->m_mutex.unlock();
|
this->d->m_mutex.unlock();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AkVCam::Stream::setMirror(bool horizontalMirror, bool verticalMirror)
|
void AkVCam::Stream::setHorizontalMirror(bool horizontalMirror)
|
||||||
{
|
{
|
||||||
AkLogFunction();
|
AkLogFunction();
|
||||||
|
|
||||||
if (this->d->m_horizontalMirror == horizontalMirror
|
if (this->d->m_horizontalMirror == horizontalMirror)
|
||||||
&& this->d->m_verticalMirror == verticalMirror)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
this->d->m_horizontalMirror = horizontalMirror;
|
this->d->m_horizontalMirror = horizontalMirror;
|
||||||
|
this->d->updateTestFrame();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AkVCam::Stream::setVerticalMirror(bool verticalMirror)
|
||||||
|
{
|
||||||
|
AkLogFunction();
|
||||||
|
|
||||||
|
if (this->d->m_verticalMirror == verticalMirror)
|
||||||
|
return;
|
||||||
|
|
||||||
this->d->m_verticalMirror = verticalMirror;
|
this->d->m_verticalMirror = verticalMirror;
|
||||||
this->d->updateTestFrame();
|
this->d->updateTestFrame();
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,8 +54,10 @@ namespace AkVCam
|
||||||
|
|
||||||
void serverStateChanged(IpcBridge::ServerState state);
|
void serverStateChanged(IpcBridge::ServerState state);
|
||||||
void frameReady(const VideoFrame &frame);
|
void frameReady(const VideoFrame &frame);
|
||||||
|
void setPicture(const std::string &picture);
|
||||||
void setBroadcasting(const std::string &broadcaster);
|
void setBroadcasting(const std::string &broadcaster);
|
||||||
void setMirror(bool horizontalMirror, bool verticalMirror);
|
void setHorizontalMirror(bool horizontalMirror);
|
||||||
|
void setVerticalMirror(bool verticalMirror);
|
||||||
void setScaling(Scaling scaling);
|
void setScaling(Scaling scaling);
|
||||||
void setAspectRatio(AspectRatio aspectRatio);
|
void setAspectRatio(AspectRatio aspectRatio);
|
||||||
void setSwapRgb(bool swap);
|
void setSwapRgb(bool swap);
|
||||||
|
|
|
@ -1,85 +0,0 @@
|
||||||
/* akvirtualcamera, virtual camera for Mac and Windows.
|
|
||||||
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
|
||||||
*
|
|
||||||
* akvirtualcamera is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* akvirtualcamera is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Web-Site: http://webcamoid.github.io/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#include <map>
|
|
||||||
#include <sstream>
|
|
||||||
#include <algorithm>
|
|
||||||
|
|
||||||
#include "utils.h"
|
|
||||||
|
|
||||||
inline const std::map<AkVCam::PixelFormat, FourCharCode> *formatsTable()
|
|
||||||
{
|
|
||||||
static const std::map<AkVCam::PixelFormat, FourCharCode> formatsTable {
|
|
||||||
{AkVCam::PixelFormatRGB32, kCMPixelFormat_32ARGB },
|
|
||||||
{AkVCam::PixelFormatRGB24, kCMPixelFormat_24RGB },
|
|
||||||
{AkVCam::PixelFormatRGB16, kCMPixelFormat_16LE565 },
|
|
||||||
{AkVCam::PixelFormatRGB15, kCMPixelFormat_16LE555 },
|
|
||||||
{AkVCam::PixelFormatUYVY , kCMPixelFormat_422YpCbCr8 },
|
|
||||||
{AkVCam::PixelFormatYUY2 , kCMPixelFormat_422YpCbCr8_yuvs}
|
|
||||||
};
|
|
||||||
|
|
||||||
return &formatsTable;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AkVCam::uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2)
|
|
||||||
{
|
|
||||||
auto iid2 = CFUUIDGetUUIDBytes(uuid2);
|
|
||||||
auto puuid1 = reinterpret_cast<const UInt8 *>(&uuid1);
|
|
||||||
auto puuid2 = reinterpret_cast<const UInt8 *>(&iid2);
|
|
||||||
|
|
||||||
for (int i = 0; i < 16; i++)
|
|
||||||
if (puuid1[i] != puuid2[i])
|
|
||||||
return false;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string AkVCam::enumToString(UInt32 value)
|
|
||||||
{
|
|
||||||
auto valueChr = reinterpret_cast<char *>(&value);
|
|
||||||
std::stringstream ss;
|
|
||||||
|
|
||||||
for (int i = 3; i >= 0; i--)
|
|
||||||
if (valueChr[i] < 0)
|
|
||||||
ss << std::hex << valueChr[i];
|
|
||||||
else if (valueChr[i] < 32)
|
|
||||||
ss << int(valueChr[i]);
|
|
||||||
else
|
|
||||||
ss << valueChr[i];
|
|
||||||
|
|
||||||
return "'" + ss.str() + "'";
|
|
||||||
}
|
|
||||||
|
|
||||||
FourCharCode AkVCam::formatToCM(PixelFormat format)
|
|
||||||
{
|
|
||||||
for (auto &fmt: *formatsTable())
|
|
||||||
if (fmt.first == format)
|
|
||||||
return fmt.second;
|
|
||||||
|
|
||||||
return FourCharCode(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
AkVCam::PixelFormat AkVCam::formatFromCM(FourCharCode format)
|
|
||||||
{
|
|
||||||
for (auto &fmt: *formatsTable())
|
|
||||||
if (fmt.second == format)
|
|
||||||
return fmt.first;
|
|
||||||
|
|
||||||
return PixelFormat(0);
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/* akvirtualcamera, virtual camera for Mac and Windows.
|
|
||||||
* Copyright (C) 2020 Gonzalo Exequiel Pedone
|
|
||||||
*
|
|
||||||
* akvirtualcamera is free software: you can redistribute it and/or modify
|
|
||||||
* it under the terms of the GNU General Public License as published by
|
|
||||||
* the Free Software Foundation, either version 3 of the License, or
|
|
||||||
* (at your option) any later version.
|
|
||||||
*
|
|
||||||
* akvirtualcamera is distributed in the hope that it will be useful,
|
|
||||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
||||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
||||||
* GNU General Public License for more details.
|
|
||||||
*
|
|
||||||
* You should have received a copy of the GNU General Public License
|
|
||||||
* along with akvirtualcamera. If not, see <http://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* Web-Site: http://webcamoid.github.io/
|
|
||||||
*/
|
|
||||||
|
|
||||||
#ifndef UTILS_H
|
|
||||||
#define UTILS_H
|
|
||||||
|
|
||||||
#include <string>
|
|
||||||
#include <CoreMediaIO/CMIOHardwarePlugIn.h>
|
|
||||||
#include <CoreMedia/CMFormatDescription.h>
|
|
||||||
|
|
||||||
#include "VCamUtils/src/image/videoformattypes.h"
|
|
||||||
|
|
||||||
namespace AkVCam
|
|
||||||
{
|
|
||||||
bool uuidEqual(const REFIID &uuid1, const CFUUIDRef uuid2);
|
|
||||||
std::string enumToString(UInt32 value);
|
|
||||||
FourCharCode formatToCM(PixelFormat format);
|
|
||||||
PixelFormat formatFromCM(FourCharCode format);
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif // UTILS_H
|
|
Loading…
Reference in a new issue