Update uvc-wmf.cc & add xu_control_range
This commit is contained in:
parent
f17eff7e01
commit
3673324079
|
@ -837,6 +837,18 @@ bool Channels::PuControlQuery(
|
||||||
return uvc::pu_control_query(*device_, option, query, value);
|
return uvc::pu_control_query(*device_, option, query, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool Channels::XuControlRange(
|
||||||
|
channel_t channel, int32_t *min, int32_t *max, int32_t *def) const {
|
||||||
|
return XuControlRange(mynteye_xu, channel >> 8, min, max, def);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Channels::XuControlRange(
|
||||||
|
const uvc::xu &xu, uint8_t selector, int32_t *min, int32_t *max,
|
||||||
|
int32_t *def) const {
|
||||||
|
CHECK_NOTNULL(device_);
|
||||||
|
return uvc::xu_control_range(*device_, xu, selector, min, max, def);
|
||||||
|
}
|
||||||
|
|
||||||
bool Channels::XuControlQuery(
|
bool Channels::XuControlQuery(
|
||||||
channel_t channel, uvc::xu_query query, uint16_t size,
|
channel_t channel, uvc::xu_query query, uint16_t size,
|
||||||
uint8_t *data) const {
|
uint8_t *data) const {
|
||||||
|
@ -977,26 +989,11 @@ Channels::control_info_t Channels::XuControlInfo(Option option) const {
|
||||||
return {0, 0, 0};
|
return {0, 0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
control_info_t info{0, 0, 0};
|
int32_t min = 0, max = 0, def = 0;
|
||||||
|
if (!XuControlRange(CHANNEL_CAM_CTRL, &min, &max, &def)) {
|
||||||
data[0] = id & 0xFF;
|
LOG(WARNING) << "Get XuControlInfo of " << option << " failed";
|
||||||
if (XuCamCtrlQuery(uvc::XU_QUERY_MIN, 3, data)) {
|
|
||||||
info.min = (data[1] << 8) | (data[2]);
|
|
||||||
} else {
|
|
||||||
LOG(WARNING) << "Get XuControlInfo.min of " << option << " failed";
|
|
||||||
}
|
}
|
||||||
if (XuCamCtrlQuery(uvc::XU_QUERY_MAX, 3, data)) {
|
return {min, max, def};
|
||||||
info.max = (data[1] << 8) | (data[2]);
|
|
||||||
} else {
|
|
||||||
LOG(WARNING) << "Get XuControlInfo.max of " << option << " failed";
|
|
||||||
}
|
|
||||||
if (XuCamCtrlQuery(uvc::XU_QUERY_DEF, 3, data)) {
|
|
||||||
info.def = (data[1] << 8) | (data[2]);
|
|
||||||
} else {
|
|
||||||
LOG(WARNING) << "Get XuControlInfo.def of " << option << " failed";
|
|
||||||
}
|
|
||||||
|
|
||||||
return info;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
MYNTEYE_END_NAMESPACE
|
MYNTEYE_END_NAMESPACE
|
||||||
|
|
|
@ -97,6 +97,12 @@ class MYNTEYE_API Channels {
|
||||||
Option option, int32_t *min, int32_t *max, int32_t *def) const;
|
Option option, int32_t *min, int32_t *max, int32_t *def) const;
|
||||||
bool PuControlQuery(Option option, uvc::pu_query query, int32_t *value) const;
|
bool PuControlQuery(Option option, uvc::pu_query query, int32_t *value) const;
|
||||||
|
|
||||||
|
bool XuControlRange(
|
||||||
|
channel_t channel, int32_t *min, int32_t *max, int32_t *def) const;
|
||||||
|
bool XuControlRange(
|
||||||
|
const uvc::xu &xu, uint8_t selector, int32_t *min, int32_t *max,
|
||||||
|
int32_t *def) const;
|
||||||
|
|
||||||
bool XuControlQuery(
|
bool XuControlQuery(
|
||||||
channel_t channel, uvc::xu_query query, uint16_t size,
|
channel_t channel, uvc::xu_query query, uint16_t size,
|
||||||
uint8_t *data) const;
|
uint8_t *data) const;
|
||||||
|
|
10
src/uvc/README.md
Normal file
10
src/uvc/README.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
|
||||||
|
## `uvc-v4l2.cc`
|
||||||
|
|
||||||
|
* [Linux Media Subsystem Documentation](https://www.kernel.org/doc/html/latest/media/index.html)
|
||||||
|
* [The Linux USB Video Class (UVC) driver](https://www.kernel.org/doc/html/latest/media/v4l-drivers/uvcvideo.html)
|
||||||
|
|
||||||
|
## `uvc-wmf.cc`
|
||||||
|
|
||||||
|
* [Media Foundation](https://msdn.microsoft.com/en-us/library/ms694197(VS.85).aspx)
|
||||||
|
* [USB Video Class Driver](https://docs.microsoft.com/en-us/windows-hardware/drivers/stream/usb-video-class-driver)
|
|
@ -131,6 +131,19 @@ bool pu_control_query(
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool xu_control_range(
|
||||||
|
const device &device, const xu &xu, uint8_t selector, int32_t *min,
|
||||||
|
int32_t *max, int32_t *def) {
|
||||||
|
// TODO(JohnZhao)
|
||||||
|
UNUSED(device)
|
||||||
|
UNUSED(xu)
|
||||||
|
UNUSED(selector)
|
||||||
|
UNUSED(min)
|
||||||
|
UNUSED(max)
|
||||||
|
UNUSED(def)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
bool xu_control_query(
|
bool xu_control_query(
|
||||||
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
||||||
uint16_t size, uint8_t *data) {
|
uint16_t size, uint8_t *data) {
|
||||||
|
|
|
@ -491,6 +491,32 @@ bool pu_control_query(
|
||||||
return device.pu_control_query(get_cid(option), code, value);
|
return device.pu_control_query(get_cid(option), code, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool xu_control_range(
|
||||||
|
const device &device, const xu &xu, uint8_t selector, int32_t *min,
|
||||||
|
int32_t *max, int32_t *def) {
|
||||||
|
bool ret = true;
|
||||||
|
std::uint8_t data[3]{};
|
||||||
|
if (xu_control_query(device, xu, selcetor, XU_QUERY_MIN, 3, data)) {
|
||||||
|
*min = (data[1] << 8) | (data[2]);
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "xu_control_range query min failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
if (xu_control_query(device, xu, selcetor, XU_QUERY_MAX, 3, data)) {
|
||||||
|
*max = (data[1] << 8) | (data[2]);
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "xu_control_range query max failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
if (xu_control_query(device, xu, selcetor, XU_QUERY_DEF, 3, data)) {
|
||||||
|
*def = (data[1] << 8) | (data[2]);
|
||||||
|
} else {
|
||||||
|
LOG(WARNING) << "xu_control_range query def failed";
|
||||||
|
ret = false;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
bool xu_control_query(
|
bool xu_control_query(
|
||||||
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
||||||
uint16_t size, uint8_t *data) {
|
uint16_t size, uint8_t *data) {
|
||||||
|
|
|
@ -154,9 +154,10 @@ std::vector<std::string> tokenize(std::string string, char separator) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void print_guid(const char *call, GUID guid) {
|
/*
|
||||||
|
static void print_guid(const char *call, int i, GUID guid) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << call << ":";
|
ss << call << "(" << i << ") = ";
|
||||||
ss << "Data1: " << std::hex << guid.Data1 << ", ";
|
ss << "Data1: " << std::hex << guid.Data1 << ", ";
|
||||||
ss << "Data2: " << std::hex << guid.Data2 << ", ";
|
ss << "Data2: " << std::hex << guid.Data2 << ", ";
|
||||||
ss << "Data3: " << std::hex << guid.Data3 << ", ";
|
ss << "Data3: " << std::hex << guid.Data3 << ", ";
|
||||||
|
@ -167,6 +168,7 @@ static void print_guid(const char *call, GUID guid) {
|
||||||
ss << "]";
|
ss << "]";
|
||||||
LOG(INFO) << ss.str();
|
LOG(INFO) << ss.str();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
bool parse_usb_path(int &vid, int &pid, int &mi, std::string &unique_id, const std::string &path) {
|
bool parse_usb_path(int &vid, int &pid, int &mi, std::string &unique_id, const std::string &path) {
|
||||||
auto name = path;
|
auto name = path;
|
||||||
|
@ -322,7 +324,7 @@ struct device {
|
||||||
check("get_NumNodes", ks_topology_info->get_NumNodes(&numberOfNodes));
|
check("get_NumNodes", ks_topology_info->get_NumNodes(&numberOfNodes));
|
||||||
for (int i = 0; i < numberOfNodes; i++) {
|
for (int i = 0; i < numberOfNodes; i++) {
|
||||||
check("get_NodeType", ks_topology_info->get_NodeType(i, &node_type));
|
check("get_NodeType", ks_topology_info->get_NodeType(i, &node_type));
|
||||||
print_guid("node_type", node_type);
|
print_guid("node_type", i, node_type);
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type));
|
check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type));
|
||||||
|
@ -507,22 +509,28 @@ bool pu_control_range(
|
||||||
int32_t *def) {
|
int32_t *def) {
|
||||||
const_cast<uvc::device &>(device).get_media_source();
|
const_cast<uvc::device &>(device).get_media_source();
|
||||||
long minVal = 0, maxVal = 0, steppingDelta = 0, defVal = 0, capsFlag = 0;
|
long minVal = 0, maxVal = 0, steppingDelta = 0, defVal = 0, capsFlag = 0;
|
||||||
check("IAMVideoProcAmp::GetRange", const_cast<uvc::device &>(device).am_video_proc_amp->GetRange(get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag));
|
check("IAMVideoProcAmp::GetRange",
|
||||||
|
const_cast<uvc::device &>(device).am_video_proc_amp->GetRange(
|
||||||
|
get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag));
|
||||||
if (min) *min = static_cast<int>(minVal);
|
if (min) *min = static_cast<int>(minVal);
|
||||||
if (max) *max = static_cast<int>(maxVal);
|
if (max) *max = static_cast<int>(maxVal);
|
||||||
if (def) *def = static_cast<int>(defVal);
|
if (def) *def = static_cast<int>(defVal);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void get_pu_control(const device &device, long property, int32_t *value) {
|
static void pu_control_get(const device &device, long property, int32_t *value) {
|
||||||
long data, flags = 0;
|
long data, flags = 0;
|
||||||
check("IAMVideoProcAmp::Get", const_cast<uvc::device &>(device).am_video_proc_amp->Get(property, &data, &flags));
|
check("IAMVideoProcAmp::Get",
|
||||||
|
const_cast<uvc::device &>(device).am_video_proc_amp->Get(
|
||||||
|
property, &data, &flags));
|
||||||
*value = data;
|
*value = data;
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_pu_control(const device &device, long property, int32_t *value) {
|
static void pu_control_set(const device &device, long property, int32_t *value) {
|
||||||
long data = *value;
|
long data = *value;
|
||||||
check("IAMVideoProcAmp::Set", const_cast<uvc::device &>(device).am_video_proc_amp->Set(property, data, VideoProcAmp_Flags_Auto));
|
check("IAMVideoProcAmp::Set",
|
||||||
|
const_cast<uvc::device &>(device).am_video_proc_amp->Set(
|
||||||
|
property, data, VideoProcAmp_Flags_Auto));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool pu_control_query(
|
bool pu_control_query(
|
||||||
|
@ -531,10 +539,10 @@ bool pu_control_query(
|
||||||
const_cast<uvc::device &>(device).get_media_source();
|
const_cast<uvc::device &>(device).get_media_source();
|
||||||
switch (query) {
|
switch (query) {
|
||||||
case PU_QUERY_SET:
|
case PU_QUERY_SET:
|
||||||
set_pu_control(device, get_cid(option), value);
|
pu_control_set(device, get_cid(option), value);
|
||||||
return true;
|
return true;
|
||||||
case PU_QUERY_GET:
|
case PU_QUERY_GET:
|
||||||
get_pu_control(device, get_cid(option), value);
|
pu_control_get(device, get_cid(option), value);
|
||||||
return true;
|
return true;
|
||||||
default:
|
default:
|
||||||
LOG(ERROR) << "pu_control_query request code is unaccepted";
|
LOG(ERROR) << "pu_control_query request code is unaccepted";
|
||||||
|
@ -542,49 +550,116 @@ bool pu_control_query(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool xu_control_query(
|
static std::vector<BYTE> xu_control_desc(const device &device, const xu &xu, ULONG id, ULONG flags) {
|
||||||
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
|
||||||
uint16_t size, uint8_t *data) {
|
|
||||||
CHECK_NOTNULL(data);
|
|
||||||
int offset = 0;
|
|
||||||
int range_offset = sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
|
|
||||||
|
|
||||||
auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
|
auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
|
||||||
|
|
||||||
|
KSP_NODE node;
|
||||||
|
memset(&node, 0, sizeof(KSP_NODE));
|
||||||
|
node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
|
||||||
|
node.Property.Id = id;
|
||||||
|
node.Property.Flags = flags;
|
||||||
|
node.NodeId = xu.node;
|
||||||
|
|
||||||
|
KSPROPERTY_DESCRIPTION description;
|
||||||
|
ULONG bytes_received = 0;
|
||||||
|
check("IKsControl::KsProperty", ks_control->KsProperty(
|
||||||
|
(PKSPROPERTY)&node,
|
||||||
|
sizeof(node),
|
||||||
|
&description,
|
||||||
|
sizeof(KSPROPERTY_DESCRIPTION),
|
||||||
|
&bytes_received));
|
||||||
|
|
||||||
|
ULONG size = description.DescriptionSize;
|
||||||
|
std::vector<BYTE> buffer(size);
|
||||||
|
|
||||||
|
check("IKsControl::KsProperty", ks_control->KsProperty(
|
||||||
|
(PKSPROPERTY)&node,
|
||||||
|
sizeof(node),
|
||||||
|
buffer.data(),
|
||||||
|
size,
|
||||||
|
&bytes_received));
|
||||||
|
|
||||||
|
if (bytes_received != size) { throw_error() << "wrong data"; }
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xu_control_range(
|
||||||
|
const device &device, const xu &xu, uint8_t selector, int32_t *min,
|
||||||
|
int32_t *max, int32_t *def) {
|
||||||
|
// get step, min and max values
|
||||||
|
{
|
||||||
|
auto &&buffer = xu_control_desc(device, xu, selector,
|
||||||
|
KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY);
|
||||||
|
|
||||||
|
BYTE *values = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
|
||||||
|
|
||||||
|
// *step = static_cast<int32_t>(*values);
|
||||||
|
values++;
|
||||||
|
*min = static_cast<int32_t>(*values);
|
||||||
|
values++;
|
||||||
|
*max = static_cast<int32_t>(*values);
|
||||||
|
}
|
||||||
|
// get def value
|
||||||
|
{
|
||||||
|
auto &&buffer = xu_control_desc(device, xu, selector,
|
||||||
|
KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY);
|
||||||
|
|
||||||
|
BYTE *values = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
|
||||||
|
|
||||||
|
*def = static_cast<int32_t>(*values);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xu_control_get(const device &device, const xu &xu, uint8_t selector, int len, void *data) {
|
||||||
|
auto &&ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
|
||||||
|
|
||||||
KSP_NODE node;
|
KSP_NODE node;
|
||||||
memset(&node, 0, sizeof(KSP_NODE));
|
memset(&node, 0, sizeof(KSP_NODE));
|
||||||
node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
|
node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
|
||||||
node.Property.Id = selector;
|
node.Property.Id = selector;
|
||||||
|
node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
|
||||||
node.NodeId = xu.node;
|
node.NodeId = xu.node;
|
||||||
unsigned long bytes_received = 0;
|
|
||||||
|
ULONG bytes_received = 0;
|
||||||
|
check("IKsControl::KsProperty", ks_control->KsProperty(
|
||||||
|
(PKSPROPERTY)&node, sizeof(node), data, len, &bytes_received));
|
||||||
|
|
||||||
|
if (bytes_received != len)
|
||||||
|
throw_error() << "xu_control_get did not return enough data";
|
||||||
|
}
|
||||||
|
|
||||||
|
static void xu_control_set(const device &device, const xu &xu, uint8_t selector, int len, void *data) {
|
||||||
|
auto &&ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
|
||||||
|
|
||||||
|
KSP_NODE node;
|
||||||
|
memset(&node, 0, sizeof(KSP_NODE));
|
||||||
|
node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
|
||||||
|
node.Property.Id = selector;
|
||||||
|
node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
|
||||||
|
node.NodeId = xu.node;
|
||||||
|
|
||||||
|
ULONG bytes_received = 0;
|
||||||
|
check("IKsControl::KsProperty", ks_control->KsProperty(
|
||||||
|
(PKSPROPERTY)&node, sizeof(node), data, len, &bytes_received));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool xu_control_query(
|
||||||
|
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
||||||
|
uint16_t size, uint8_t *data) {
|
||||||
|
CHECK_NOTNULL(data);
|
||||||
switch (query) {
|
switch (query) {
|
||||||
case XU_QUERY_SET:
|
case XU_QUERY_SET:
|
||||||
node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
|
xu_control_set(device, xu, selector, size, data);
|
||||||
break;
|
return true;
|
||||||
case XU_QUERY_GET:
|
case XU_QUERY_GET:
|
||||||
node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
|
xu_control_get(device, xu, selector, size, data);
|
||||||
break;
|
return true;
|
||||||
case XU_QUERY_MIN:
|
|
||||||
offset = 1;
|
|
||||||
node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
|
|
||||||
break;
|
|
||||||
case XU_QUERY_MAX:
|
|
||||||
offset = 2;
|
|
||||||
node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
|
|
||||||
break;
|
|
||||||
case XU_QUERY_DEF:
|
|
||||||
node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
|
LOG(ERROR) << "xu_control_query request code is unaccepted";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), data, size, &bytes_received));
|
|
||||||
if (bytes_received != size) {
|
|
||||||
throw_error() << "wrong data";
|
|
||||||
}
|
|
||||||
|
|
||||||
*data = (int)*(data + offset);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void set_device_mode(device &device, int width, int height, int fourcc, int fps, video_channel_callback callback) {
|
void set_device_mode(device &device, int width, int height, int fourcc, int fps, video_channel_callback callback) {
|
||||||
|
|
|
@ -72,7 +72,10 @@ MYNTEYE_API bool pu_control_query(
|
||||||
const device &device, Option option, pu_query query, int32_t *value);
|
const device &device, Option option, pu_query query, int32_t *value);
|
||||||
|
|
||||||
// Access XU (Extension Unit) controls
|
// Access XU (Extension Unit) controls
|
||||||
MYNTEYE_API bool xu_control_query(
|
MYNTEYE_API bool xu_control_range(
|
||||||
|
const device &device, const xu &xu, uint8_t selector, int32_t *min,
|
||||||
|
int32_t *max, int32_t *def);
|
||||||
|
MYNTEYE_API bool xu_control_query( // XU_QUERY_SET, XU_QUERY_GET
|
||||||
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
const device &device, const xu &xu, uint8_t selector, xu_query query,
|
||||||
uint16_t size, uint8_t *data);
|
uint16_t size, uint8_t *data);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue
Block a user