From 3673324079c706e098dd0dc43a77a2b63898fcd7 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Fri, 25 May 2018 12:32:58 +0800 Subject: [PATCH] Update uvc-wmf.cc & add xu_control_range --- src/internal/channels.cc | 35 ++++----- src/internal/channels.h | 6 ++ src/uvc/README.md | 10 +++ src/uvc/uvc-libuvc.cc | 13 +++ src/uvc/uvc-v4l2.cc | 26 ++++++ src/uvc/uvc-wmf.cc | 165 ++++++++++++++++++++++++++++----------- src/uvc/uvc.h | 5 +- 7 files changed, 195 insertions(+), 65 deletions(-) create mode 100644 src/uvc/README.md diff --git a/src/internal/channels.cc b/src/internal/channels.cc index ab925c2..de8f255 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -837,6 +837,18 @@ bool Channels::PuControlQuery( 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( channel_t channel, uvc::xu_query query, uint16_t size, uint8_t *data) const { @@ -977,26 +989,11 @@ Channels::control_info_t Channels::XuControlInfo(Option option) const { return {0, 0, 0}; } - control_info_t info{0, 0, 0}; - - data[0] = id & 0xFF; - if (XuCamCtrlQuery(uvc::XU_QUERY_MIN, 3, data)) { - info.min = (data[1] << 8) | (data[2]); - } else { - LOG(WARNING) << "Get XuControlInfo.min of " << option << " failed"; + int32_t min = 0, max = 0, def = 0; + if (!XuControlRange(CHANNEL_CAM_CTRL, &min, &max, &def)) { + LOG(WARNING) << "Get XuControlInfo of " << option << " failed"; } - if (XuCamCtrlQuery(uvc::XU_QUERY_MAX, 3, data)) { - 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; + return {min, max, def}; } MYNTEYE_END_NAMESPACE diff --git a/src/internal/channels.h b/src/internal/channels.h index 8177d22..9feaf32 100644 --- a/src/internal/channels.h +++ b/src/internal/channels.h @@ -97,6 +97,12 @@ class MYNTEYE_API Channels { 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 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( channel_t channel, uvc::xu_query query, uint16_t size, uint8_t *data) const; diff --git a/src/uvc/README.md b/src/uvc/README.md new file mode 100644 index 0000000..f8676b9 --- /dev/null +++ b/src/uvc/README.md @@ -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) diff --git a/src/uvc/uvc-libuvc.cc b/src/uvc/uvc-libuvc.cc index 78fcca8..e3e2c34 100644 --- a/src/uvc/uvc-libuvc.cc +++ b/src/uvc/uvc-libuvc.cc @@ -131,6 +131,19 @@ bool pu_control_query( 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( const device &device, const xu &xu, uint8_t selector, xu_query query, uint16_t size, uint8_t *data) { diff --git a/src/uvc/uvc-v4l2.cc b/src/uvc/uvc-v4l2.cc index 3ae82f1..91b2540 100755 --- a/src/uvc/uvc-v4l2.cc +++ b/src/uvc/uvc-v4l2.cc @@ -491,6 +491,32 @@ bool pu_control_query( 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( const device &device, const xu &xu, uint8_t selector, xu_query query, uint16_t size, uint8_t *data) { diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 9dde416..a5f0c84 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -154,19 +154,21 @@ std::vector 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; - ss << call << ":"; - ss << " Data1: " << std::hex << guid.Data1 << ","; - ss << " Data2: " << std::hex << guid.Data2 << ","; - ss << " Data3: " << std::hex << guid.Data3 << ","; - ss << " Data4: [ "; + ss << call << "(" << i << ") = "; + ss << "Data1: " << std::hex << guid.Data1 << ", "; + ss << "Data2: " << std::hex << guid.Data2 << ", "; + ss << "Data3: " << std::hex << guid.Data3 << ", "; + ss << "Data4: [ "; for (int j = 0; j < 8; j++) { ss << std::hex << (int)guid.Data4[j] << " "; } ss << "]"; LOG(INFO) << ss.str(); } +*/ bool parse_usb_path(int &vid, int &pid, int &mi, std::string &unique_id, const std::string &path) { auto name = path; @@ -322,7 +324,7 @@ struct device { check("get_NumNodes", ks_topology_info->get_NumNodes(&numberOfNodes)); for (int i = 0; i < numberOfNodes; i++) { 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)); @@ -507,22 +509,28 @@ bool pu_control_range( int32_t *def) { const_cast(device).get_media_source(); long minVal = 0, maxVal = 0, steppingDelta = 0, defVal = 0, capsFlag = 0; - check("IAMVideoProcAmp::GetRange", const_cast(device).am_video_proc_amp->GetRange(get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag)); + check("IAMVideoProcAmp::GetRange", + const_cast(device).am_video_proc_amp->GetRange( + get_cid(option), &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag)); if (min) *min = static_cast(minVal); if (max) *max = static_cast(maxVal); if (def) *def = static_cast(defVal); 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; - check("IAMVideoProcAmp::Get", const_cast(device).am_video_proc_amp->Get(property, &data, &flags)); + check("IAMVideoProcAmp::Get", + const_cast(device).am_video_proc_amp->Get( + property, &data, &flags)); *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; - check("IAMVideoProcAmp::Set", const_cast(device).am_video_proc_amp->Set(property, data, VideoProcAmp_Flags_Auto)); + check("IAMVideoProcAmp::Set", + const_cast(device).am_video_proc_amp->Set( + property, data, VideoProcAmp_Flags_Auto)); } bool pu_control_query( @@ -531,10 +539,10 @@ bool pu_control_query( const_cast(device).get_media_source(); switch (query) { case PU_QUERY_SET: - set_pu_control(device, get_cid(option), value); + pu_control_set(device, get_cid(option), value); return true; case PU_QUERY_GET: - get_pu_control(device, get_cid(option), value); + pu_control_get(device, get_cid(option), value); return true; default: LOG(ERROR) << "pu_control_query request code is unaccepted"; @@ -542,49 +550,116 @@ bool pu_control_query( } } -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); - int offset = 0; - int range_offset = sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); - +static std::vector xu_control_desc(const device &device, const xu &xu, ULONG id, ULONG flags) { auto ks_control = const_cast(device).get_ks_control(xu); + + KSP_NODE node; + memset(&node, 0, sizeof(KSP_NODE)); + node.Property.Set = reinterpret_cast(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 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(*values); + values++; + *min = static_cast(*values); + values++; + *max = static_cast(*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(*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(device).get_ks_control(xu); + KSP_NODE node; memset(&node, 0, sizeof(KSP_NODE)); node.Property.Set = reinterpret_cast(xu.id); node.Property.Id = selector; + node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY; 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(device).get_ks_control(xu); + + KSP_NODE node; + memset(&node, 0, sizeof(KSP_NODE)); + node.Property.Set = reinterpret_cast(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) { case XU_QUERY_SET: - node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; - break; + xu_control_set(device, xu, selector, size, data); + return true; case XU_QUERY_GET: - node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY; - break; - 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; + xu_control_get(device, xu, selector, size, data); + return true; default: + LOG(ERROR) << "xu_control_query request code is unaccepted"; 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) { diff --git a/src/uvc/uvc.h b/src/uvc/uvc.h index 94439fd..2f9a970 100644 --- a/src/uvc/uvc.h +++ b/src/uvc/uvc.h @@ -72,7 +72,10 @@ MYNTEYE_API bool pu_control_query( const device &device, Option option, pu_query query, int32_t *value); // 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, uint16_t size, uint8_t *data);