From 8d017f5e2dd31ade50e609fa98a74203d4f5189e Mon Sep 17 00:00:00 2001 From: kalman Date: Sat, 5 May 2018 16:27:05 +0800 Subject: [PATCH 01/19] add code in uvc-wmf.cc --- src/uvc/uvc-wmf.cc | 810 ++++++++++++++++++++++++++++++++++++++------- src/uvc/uvc.h | 4 + 2 files changed, 698 insertions(+), 116 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 8200e7d..ccb7dda 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -1,116 +1,694 @@ -#include "uvc/uvc.h" // NOLINT - -#include - -MYNTEYE_BEGIN_NAMESPACE - -namespace uvc { - -struct context { - context() { - VLOG(2) << __func__; - } - - ~context() { - VLOG(2) << __func__; - } -}; - -struct device { - const std::shared_ptr parent; - - int vid, pid; - - device(std::shared_ptr parent) : parent(parent) { - VLOG(2) << __func__; - } - - ~device() { - VLOG(2) << __func__; - } -}; - -std::shared_ptr create_context() { - return std::make_shared(); -} - -std::vector> query_devices( - std::shared_ptr context) { - std::vector> devices; - UNUSED(context) - return devices; -} - -int get_vendor_id(const device &device) { - return device.vid; -} - -int get_product_id(const device &device) { - return device.pid; -} - -std::string get_name(const device &device) { - UNUSED(device) - return ""; -} - -std::string get_video_name(const device &device) { - UNUSED(device) - return ""; -} - -bool pu_control_range( - const device &device, Option option, int32_t *min, int32_t *max, - int32_t *def) { - UNUSED(device) - UNUSED(option) - UNUSED(min) - UNUSED(max) - UNUSED(def) - return false; -} - -bool pu_control_query( - const device &device, Option option, pu_query query, int32_t *value) { - UNUSED(device) - UNUSED(option) - UNUSED(query) - UNUSED(value) - return false; -} - -bool xu_control_query( - const device &device, const xu &xu, uint8_t selector, xu_query query, - uint16_t size, uint8_t *data) { - UNUSED(device) - UNUSED(xu) - UNUSED(selector) - UNUSED(query) - UNUSED(size) - UNUSED(data) - return false; -} - -void set_device_mode( - device &device, int width, int height, int fourcc, int fps, // NOLINT - video_channel_callback callback) { - UNUSED(device) - UNUSED(width) - UNUSED(height) - UNUSED(fourcc) - UNUSED(fps) - UNUSED(callback) -} - -void start_streaming(device &device, int num_transfer_bufs) { // NOLINT - UNUSED(device) - UNUSED(num_transfer_bufs) -} - -void stop_streaming(device &device) { // NOLINT - UNUSED(device) -} - -} // namespace uvc - -MYNTEYE_END_NAMESPACE +#include "uvc/uvc.h" // NOLINT + +#include + +#include +#include + +#include +#include +#include + +#include "uvc.h" + +#include // For QISearch, etc. +#include // For MFStartup, etc. +#include // For MF_DEVSOURCE_*, etc. +#include // MFCreateSourceReaderFromMediaSource +#include + +#pragma comment(lib, "Shlwapi.lib") +#pragma comment(lib, "mf.lib") +#pragma comment(lib, "mfplat.lib") +#pragma comment(lib, "mfreadwrite.lib") +#pragma comment(lib, "mfuuid.lib") + +#pragma comment(lib, "setupapi.lib") +#pragma comment(lib, "winusb.lib") + +#include +#include +#include +#include + +#include + +#pragma comment(lib, "cfgmgr32.lib") + +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +MYNTEYE_BEGIN_NAMESPACE + +namespace uvc { + +const std::map fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */ + +#define LOG_ERROR(severity, str) \ + do { \ + LOG(severity) << str << " error " << errno << ", " << strerror(errno); \ + } while (0) + +struct throw_error { + throw_error() = default; + + explicit throw_error(const std::string &s) { + ss << s; + } + + ~throw_error() noexcept(false) { + throw std::runtime_error(ss.str()); + // throw device_error(ss.str()); + } + + template + throw_error &operator<<(const T &val) { + ss << val; + return *this; + } + + std::ostringstream ss; +}; + +template class com_ptr +{ + T * p; + void ref(T * new_p) + { + if(p == new_p) return; + unref(); + p = new_p; + if(p) p->AddRef(); + } + + void unref() + { + if(p) + { + p->Release(); + p = nullptr; + } + } +public: + com_ptr() : p() {} + com_ptr(T * p) : com_ptr() { ref(p); } + com_ptr(const com_ptr & r) : com_ptr(r.p) {} + ~com_ptr() { unref(); } + + operator T * () const { return p; } + T & operator * () const { return *p; } + T * operator -> () const { return p; } + + T ** operator & () { unref(); return &p; } + com_ptr & operator = (const com_ptr & r) { ref(r.p); return *this; } + }; + +static std::string win_to_utf(const WCHAR * s) +{ + int len = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, NULL, NULL); + if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); + std::string buffer(len-1, ' '); + len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL); + if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); + return buffer; +} + +static void check(const char *call, HRESULT hr) { + if (FAILED(hr)) { + std::cout << call << "(...) returned 0x" << std::hex << (uint32_t)hr << std::endl; + throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; + } + std::cout << call << " SUCCESSED " << std::endl; +} + +std::vector tokenize(std::string string, char separator) +{ + std::vector tokens; + std::string::size_type i1 = 0; + while(true) + { + auto i2 = string.find(separator, i1); + if(i2 == std::string::npos) + { + tokens.push_back(string.substr(i1)); + return tokens; + } + tokens.push_back(string.substr(i1, i2-i1)); + i1 = i2+1; + } +} + +bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path) +{ + auto name = path; + std::transform(begin(name), end(name), begin(name), ::tolower); + auto tokens = tokenize(name, '#'); + if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device + if(tokens.size() < 3) + { + //LOG_ERROR("malformed usb device path: " + name); + return false; + } + + auto ids = tokenize(tokens[1], '&'); + if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) + { + //LOG_ERROR("malformed vid string: " + tokens[1]); + return false; + } + + if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) + { + //LOG_ERROR("malformed pid string: " + tokens[1]); + return false; + } + + if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) + { + //LOG_ERROR("malformed mi string: " + tokens[1]); + return false; + } + + ids = tokenize(tokens[2], '&'); + if(ids.size() < 2) + { + //LOG_ERROR("malformed id string: " + tokens[2]); + return false; + } + unique_id = ids[1]; + return true; +} + +bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id) +{ + auto name = device_id; + std::transform(begin(name), end(name), begin(name), ::tolower); + auto tokens = tokenize(name, '\\'); + if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device + + auto ids = tokenize(tokens[1], '&'); + if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) + { + //LOG_ERROR("malformed vid string: " + tokens[1]); + return false; + } + + if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) + { + //LOG_ERROR("malformed pid string: " + tokens[1]); + return false; + } + + if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) + { + //LOG_ERROR("malformed mi string: " + tokens[1]); + return false; + } + + ids = tokenize(tokens[2], '&'); + if (ids.size() < 2) + { + //LOG_ERROR("malformed id string: " + tokens[2]); + return false; + } + unique_id = ids[1]; + return true; +} + +struct context +{ + context() + { + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET); + } + ~context() + { + MFShutdown(); + CoUninitialize(); + } +}; + +class reader_callback : public IMFSourceReaderCallback +{ + std::weak_ptr owner; // The device holds a reference to us, so use weak_ptr to prevent a cycle + ULONG ref_count; + volatile bool streaming = false; +public: + reader_callback(std::weak_ptr owner) : owner(owner), ref_count() {} + + bool is_streaming() const { return streaming; } + void on_start() { streaming = true; } + +#pragma warning( push ) +#pragma warning( disable: 4838 ) + // Implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override + { + static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}}; + return QISearch(this, table, riid, ppvObject); + } +#pragma warning( pop ) + + ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); } + ULONG STDMETHODCALLTYPE Release() override + { + ULONG count = InterlockedDecrement(&ref_count); + if(count == 0) delete this; + return count; + } + + // Implement IMFSourceReaderCallback + HRESULT STDMETHODCALLTYPE OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) override; + HRESULT STDMETHODCALLTYPE OnFlush(DWORD dwStreamIndex) override { streaming = false; return S_OK; } + HRESULT STDMETHODCALLTYPE OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent) override { return S_OK; } +}; + +struct device { + const std::shared_ptr parent; + int vid, pid; + const std::string unique_id; + std::string name; + + com_ptr reader_callback; + com_ptr mf_activate; + com_ptr mf_media_source; + com_ptr am_camera_control; + com_ptr am_video_proc_amp; + std::map> ks_controls; + com_ptr mf_source_reader; + video_channel_callback callback = nullptr; + + device(std::shared_ptr parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), name(name) + { + } + + ~device() { stop_streaming(); } + + + IKsControl * get_ks_control(const uvc::xu & xu) { + auto it = ks_controls.find(xu.node); + if(it != end(ks_controls)) return it->second; + + get_media_source(); + + // Attempt to retrieve IKsControl + com_ptr ks_topology_info = NULL; + check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info)); + + GUID node_type; + check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); + std::cout << "node_type" << node_type.Data1 << "," << node_type.Data2 << "," < unknown; + check("CreateNodeInstance", ks_topology_info->CreateNodeInstance(xu.node, IID_IUnknown, (LPVOID *)&unknown)); + + com_ptr ks_control; + check("QueryInterface", unknown->QueryInterface(__uuidof(IKsControl), (void **)&ks_control)); + VLOG(2) << "Obtained KS control node" << xu.node; + return ks_controls[xu.node] = ks_control; + } + + void start_streaming() + { + if(mf_source_reader) + { + reader_callback->on_start(); + check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL)); + } + } + + void stop_streaming() + { + + if(mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM); + while(true) + { + bool is_streaming = reader_callback->is_streaming(); + if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10)); + else break; + } + + mf_source_reader = nullptr; + am_camera_control = nullptr; + am_video_proc_amp = nullptr; + ks_controls.clear(); + if(mf_media_source) + { + mf_media_source = nullptr; + check("IMFActivate::ShutdownObject", mf_activate->ShutdownObject()); + } + callback = {}; + } + + com_ptr get_media_source() + { + if(!mf_media_source) + { + check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source)); + if (mf_media_source) + { + check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control)); + if (SUCCEEDED(mf_media_source->QueryInterface(__uuidof(IAMVideoProcAmp), (void **)&am_video_proc_amp))); + } + else throw_error() << "Invalid media source"; + } + return mf_media_source; + } + +}; + +HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) +{ + if(auto owner_ptr = owner.lock()) + { + if(sample) + { + std::cout << "sample is not null" << std::endl; + com_ptr buffer = NULL; + if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) + { + std::cout << "SUCCEEDED(sample->GetBufferByIndex(0, &buffer))" << std::endl; + BYTE * byte_buffer; DWORD max_length, current_length; + if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length))) + { + auto continuation = [buffer, this]() + { + buffer->Unlock(); + }; + + owner_ptr->callback(byte_buffer); + std::cout << "owner_ptr->callback(byte_buffer);" << std::endl; + } + } + } + + if (auto owner_ptr_new = owner.lock()) + { + auto hr = owner_ptr_new->mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL); + switch (hr) + { + case S_OK: break; + case MF_E_INVALIDREQUEST: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST"); break; + case MF_E_INVALIDSTREAMNUMBER: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER"); break; + case MF_E_NOTACCEPTING: LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING"); break; + case E_INVALIDARG: LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG"); break; + case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); break; + default: LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr); break; + } + if (hr != S_OK) streaming = false; + } + } + return S_OK; +} + +std::shared_ptr create_context() { + return std::make_shared(); +} + +std::vector> query_devices( + std::shared_ptr context) { + + IMFAttributes *pAttributes = NULL; + check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); + check("IMFAttributes::SetGUID",pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); + + IMFActivate **ppDevices; + UINT32 numDevices; + check("MFEnumDeviceSources",MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices)); + + std::vector> devices; + for (UINT32 i = 0; i < numDevices; ++i) { + com_ptr pDevice; + *&pDevice = ppDevices[i]; + + WCHAR *wchar_dev_name = NULL; + WCHAR *wchar_name = NULL; + UINT32 length; + + pDevice->GetAllocatedString( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_dev_name, + &length); + auto dev_name = win_to_utf(wchar_dev_name); + CoTaskMemFree(wchar_dev_name); + + pDevice->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &wchar_name, &length); + auto name = win_to_utf(wchar_name); // Device description name + CoTaskMemFree(wchar_name); + + int vid, pid, mi; std::string unique_id; + + if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue; + + std::shared_ptr dev; + for(auto & d : devices) + { + if(d->vid == vid && d->pid == pid && d->unique_id == unique_id) + dev = d; + } + if(!dev) + { + try { + dev = std::make_shared(context, vid, pid, unique_id, name); + devices.push_back(dev); + } catch (const std::exception &e) { + VLOG(2) << "Not a USB video device: " << e.what(); + } + + } + + dev->reader_callback = new reader_callback(dev); + dev->mf_activate = pDevice; + dev->vid = vid; + dev->pid = pid; + + } + + CoTaskMemFree(ppDevices); + return devices; +} + +int get_vendor_id(const device &device) { + return device.vid; +} + +int get_product_id(const device &device) { + return device.pid; +} + +std::string get_name(const device &device) { + return device.name; +} + +std::string get_video_name(const device &device) { + return device.name; +} + +static long get_cid(Option option) { + switch (option) { + case Option::GAIN: + return VideoProcAmp_Gain; + case Option::BRIGHTNESS: + return VideoProcAmp_Brightness; + case Option::CONTRAST: + return VideoProcAmp_Contrast; + default: + LOG(FATAL) << "No VideoProcAmp cid for " << option; + } +} + +bool pu_control_range( + const device &device, Option option, int32_t *min, int32_t *max, + 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)); + 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) { + long data, flags=0; + 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) { + long data = *value; + check("IAMVideoProcAmp::Set", const_cast(device).am_video_proc_amp->Set(property, data, VideoProcAmp_Flags_Auto)); +} + +bool pu_control_query( + const device &device, Option option, pu_query query, int32_t *value) { + CHECK_NOTNULL(value); + const_cast(device).get_media_source(); + switch (query) { + case PU_QUERY_SET: + set_pu_control(device, get_cid(option), value); + return true; + case PU_QUERY_GET: + get_pu_control(device, get_cid(option), value); + return true; + default: + LOG(ERROR) << "pu_control_query request code is unaccepted"; + return false; + } +} + +void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data) +{ + CHECK_NOTNULL(data); + int offset = 0; + auto ks_control = const_cast(device).get_ks_control(xu); + + /* get step, min and max values*/ + KSP_NODE node; + memset(&node, 0, sizeof(KSP_NODE)); + node.Property.Set = reinterpret_cast(xu.id); + node.Property.Id = selector; + node.NodeId = xu.node; + + switch (query) { + 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: + offset = 0; + node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; + break; + default: + LOG(ERROR) << "xu request code is unaccepted"; + break; + } + + KSPROPERTY_DESCRIPTION description; + unsigned long bytes_received = 0; + std::cout << "query" << std::endl; + check("IKsControl::KsProperty", ks_control->KsProperty( + (PKSPROPERTY)&node, + sizeof(node), + &description, + sizeof(KSPROPERTY_DESCRIPTION), + &bytes_received)); + + unsigned long size = description.DescriptionSize; + std::vector buffer((long)size); + + check("IKsControl::KsProperty", ks_control->KsProperty( + (PKSPROPERTY)&node, + sizeof(node), + buffer.data(), + size, + &bytes_received)); + + if (bytes_received != size) { throw std::runtime_error("wrong data"); } + + BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); + * data = (uint8_t)*(pRangeValues + offset); + +} + +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); + + 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.NodeId = xu.node; + unsigned long bytes_received = 0; + std::cout << "selector: " << selector << std::endl; + switch (query) { + case XU_QUERY_SET: + std::cout << "XU_QUERY_SET" << std::endl; + node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + break; + case XU_QUERY_GET: + std::cout << "XU_QUERY_GET" << std::endl; + node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + break; + case XU_QUERY_MIN: + case XU_QUERY_MAX: + case XU_QUERY_DEF: + get_extension_control_range(device, xu, selector, query, data); + return true; + default: + LOG(ERROR) << "xu range query request code is unaccepted"; + return false; + } + std::cout << "set & get" << std::endl; + check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast(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) +{ + if(!device.mf_source_reader) + { + com_ptr pAttributes; + check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); + check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast(device.reader_callback))); + check("MFCreateSourceReaderFromMediaSource", MFCreateSourceReaderFromMediaSource(device.get_media_source(), pAttributes, &device.mf_source_reader)); + } + + if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc); + + for (DWORD j = 0; ; j++) + { + com_ptr media_type; + HRESULT hr = device.mf_source_reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, j, &media_type); + if (hr == MF_E_NO_MORE_TYPES) break; + check("IMFSourceReader::GetNativeMediaType", hr); + + UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; GUID subtype; + check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height)); + if(uvc_width != width || uvc_height != height) continue; + + check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype)); + if(subtype.Data1 != fourcc) continue; + + check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom)); + if(uvc_fps_denom == 0) continue; + + check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type)); + + device.callback = callback; + return; + } + throw_error() << "no matching media type for pixel format " << std::hex << fourcc; +} + +void start_streaming(device & device, int num_transfer_bufs) { device.start_streaming(); } +void stop_streaming(device & device) { device.stop_streaming(); } + +} // namespace uvc + +MYNTEYE_END_NAMESPACE diff --git a/src/uvc/uvc.h b/src/uvc/uvc.h index d0f6466..c64ed21 100644 --- a/src/uvc/uvc.h +++ b/src/uvc/uvc.h @@ -23,9 +23,13 @@ typedef enum pu_query { PU_QUERY_LAST } pu_query; +struct guid { uint32_t data1; uint16_t data2, data3; uint8_t data4[8]; }; + // Extension Unit struct MYNTEYE_API xu { uint8_t unit; + int node; + guid id; }; typedef enum xu_query { From ff33770ca4bdee28f3853bd6579f18c47965e05c Mon Sep 17 00:00:00 2001 From: kalman Date: Sat, 5 May 2018 20:52:36 +0800 Subject: [PATCH 02/19] add some log --- src/uvc/uvc-wmf.cc | 565 +++++++++++++++++++++++---------------------- 1 file changed, 286 insertions(+), 279 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index ccb7dda..2953fba 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -49,9 +49,10 @@ MYNTEYE_BEGIN_NAMESPACE -namespace uvc { +namespace uvc +{ -const std::map fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */ +const std::map fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */ #define LOG_ERROR(severity, str) \ do { \ @@ -82,35 +83,48 @@ struct throw_error { template class com_ptr { T * p; - void ref(T * new_p) - { + void ref(T * new_p) { if(p == new_p) return; unref(); p = new_p; if(p) p->AddRef(); } - void unref() - { - if(p) - { + void unref() { + if(p) { p->Release(); p = nullptr; } } public: com_ptr() : p() {} - com_ptr(T * p) : com_ptr() { ref(p); } + com_ptr(T * p) : com_ptr() { + ref(p); + } com_ptr(const com_ptr & r) : com_ptr(r.p) {} - ~com_ptr() { unref(); } + ~com_ptr() { + unref(); + } - operator T * () const { return p; } - T & operator * () const { return *p; } - T * operator -> () const { return p; } + operator T * () const { + return p; + } + T & operator * () const { + return *p; + } + T * operator -> () const { + return p; + } - T ** operator & () { unref(); return &p; } - com_ptr & operator = (const com_ptr & r) { ref(r.p); return *this; } - }; + T ** operator & () { + unref(); + return &p; + } + com_ptr & operator = (const com_ptr & r) { + ref(r.p); + return *this; + } +}; static std::string win_to_utf(const WCHAR * s) { @@ -120,120 +134,105 @@ static std::string win_to_utf(const WCHAR * s) len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL); if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); return buffer; -} +} -static void check(const char *call, HRESULT hr) { +static void check(const char *call, HRESULT hr) +{ if (FAILED(hr)) { - std::cout << call << "(...) returned 0x" << std::hex << (uint32_t)hr << std::endl; throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; } - std::cout << call << " SUCCESSED " << std::endl; } std::vector tokenize(std::string string, char separator) { - std::vector tokens; - std::string::size_type i1 = 0; - while(true) - { - auto i2 = string.find(separator, i1); - if(i2 == std::string::npos) - { - tokens.push_back(string.substr(i1)); - return tokens; - } - tokens.push_back(string.substr(i1, i2-i1)); - i1 = i2+1; + std::vector tokens; + std::string::size_type i1 = 0; + while(true) { + auto i2 = string.find(separator, i1); + if(i2 == std::string::npos) { + tokens.push_back(string.substr(i1)); + return tokens; } + tokens.push_back(string.substr(i1, i2-i1)); + i1 = i2+1; + } } bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path) { - auto name = path; - std::transform(begin(name), end(name), begin(name), ::tolower); - auto tokens = tokenize(name, '#'); - if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device - if(tokens.size() < 3) - { - //LOG_ERROR("malformed usb device path: " + name); - return false; - } + auto name = path; + std::transform(begin(name), end(name), begin(name), ::tolower); + auto tokens = tokenize(name, '#'); + if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device + if(tokens.size() < 3) { + LOG_ERROR(WARNING,"malformed usb device path: " << name); + return false; + } - auto ids = tokenize(tokens[1], '&'); - if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) - { - //LOG_ERROR("malformed vid string: " + tokens[1]); - return false; - } + auto ids = tokenize(tokens[1], '&'); + if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) { + LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]); + return false; + } - if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) - { - //LOG_ERROR("malformed pid string: " + tokens[1]); - return false; - } + if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) { + LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]); + return false; + } - if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) - { - //LOG_ERROR("malformed mi string: " + tokens[1]); - return false; - } + if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) { + LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]); + return false; + } - ids = tokenize(tokens[2], '&'); - if(ids.size() < 2) - { - //LOG_ERROR("malformed id string: " + tokens[2]); - return false; - } - unique_id = ids[1]; - return true; + ids = tokenize(tokens[2], '&'); + if(ids.size() < 2) { + LOG_ERROR(WARNING,"malformed id string: " << tokens[2]); + return false; + } + unique_id = ids[1]; + return true; } bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id) { - auto name = device_id; - std::transform(begin(name), end(name), begin(name), ::tolower); - auto tokens = tokenize(name, '\\'); - if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device + auto name = device_id; + std::transform(begin(name), end(name), begin(name), ::tolower); + auto tokens = tokenize(name, '\\'); + if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device - auto ids = tokenize(tokens[1], '&'); - if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) - { - //LOG_ERROR("malformed vid string: " + tokens[1]); - return false; - } + auto ids = tokenize(tokens[1], '&'); + if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) { + LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]); + return false; + } - if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) - { - //LOG_ERROR("malformed pid string: " + tokens[1]); - return false; - } + if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) { + LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]); + return false; + } - if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) - { - //LOG_ERROR("malformed mi string: " + tokens[1]); - return false; - } + if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) { + LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]); + return false; + } - ids = tokenize(tokens[2], '&'); - if (ids.size() < 2) - { - //LOG_ERROR("malformed id string: " + tokens[2]); - return false; - } - unique_id = ids[1]; - return true; + ids = tokenize(tokens[2], '&'); + if (ids.size() < 2) { + LOG_ERROR(WARNING,"malformed id string: " + tokens[2]); + return false; + } + unique_id = ids[1]; + return true; } -struct context -{ - context() - { +struct context { + context() { CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); std::this_thread::sleep_for(std::chrono::milliseconds(100)); MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET); } - ~context() - { + ~context() { MFShutdown(); CoUninitialize(); } @@ -247,22 +246,24 @@ class reader_callback : public IMFSourceReaderCallback public: reader_callback(std::weak_ptr owner) : owner(owner), ref_count() {} - bool is_streaming() const { return streaming; } - void on_start() { streaming = true; } + bool is_streaming() const { + return streaming; + } + void on_start() { + streaming = true; + } #pragma warning( push ) #pragma warning( disable: 4838 ) - // Implement IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override - { + // Implement IUnknown + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override { static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}}; return QISearch(this, table, riid, ppvObject); } #pragma warning( pop ) ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); } - ULONG STDMETHODCALLTYPE Release() override - { + ULONG STDMETHODCALLTYPE Release() override { ULONG count = InterlockedDecrement(&ref_count); if(count == 0) delete this; return count; @@ -289,11 +290,12 @@ struct device { com_ptr mf_source_reader; video_channel_callback callback = nullptr; - device(std::shared_ptr parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), name(name) - { - } + device(std::shared_ptr parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), unique_id(move(unique_id)), name(name) + {} - ~device() { stop_streaming(); } + ~device() { + stop_streaming(); + } IKsControl * get_ks_control(const uvc::xu & xu) { @@ -308,7 +310,6 @@ struct device { GUID node_type; check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); - std::cout << "node_type" << node_type.Data1 << "," << node_type.Data2 << "," <on_start(); - check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL)); + check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL)); } } - void stop_streaming() - { + void stop_streaming() { if(mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM); - while(true) - { - bool is_streaming = reader_callback->is_streaming(); + while(true) { + bool is_streaming = reader_callback->is_streaming(); if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10)); else break; } @@ -345,82 +342,80 @@ struct device { am_camera_control = nullptr; am_video_proc_amp = nullptr; ks_controls.clear(); - if(mf_media_source) - { + if(mf_media_source) { mf_media_source = nullptr; check("IMFActivate::ShutdownObject", mf_activate->ShutdownObject()); } callback = {}; } - com_ptr get_media_source() - { - if(!mf_media_source) - { + com_ptr get_media_source() { + if(!mf_media_source) { check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source)); - if (mf_media_source) - { + if (mf_media_source) { check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control)); if (SUCCEEDED(mf_media_source->QueryInterface(__uuidof(IAMVideoProcAmp), (void **)&am_video_proc_amp))); - } - else throw_error() << "Invalid media source"; + } else throw_error() << "Invalid media source"; } return mf_media_source; - } + } }; -HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) +HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) { - if(auto owner_ptr = owner.lock()) - { - if(sample) - { - std::cout << "sample is not null" << std::endl; + if(auto owner_ptr = owner.lock()) { + if(sample) { com_ptr buffer = NULL; - if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) - { - std::cout << "SUCCEEDED(sample->GetBufferByIndex(0, &buffer))" << std::endl; - BYTE * byte_buffer; DWORD max_length, current_length; - if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length))) - { - auto continuation = [buffer, this]() - { + if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) { + BYTE * byte_buffer; + DWORD max_length, current_length; + if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length))) { + auto continuation = [buffer, this]() { buffer->Unlock(); }; - owner_ptr->callback(byte_buffer); - std::cout << "owner_ptr->callback(byte_buffer);" << std::endl; } } } - if (auto owner_ptr_new = owner.lock()) - { + if (auto owner_ptr_new = owner.lock()) { auto hr = owner_ptr_new->mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL); - switch (hr) - { - case S_OK: break; - case MF_E_INVALIDREQUEST: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST"); break; - case MF_E_INVALIDSTREAMNUMBER: LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER"); break; - case MF_E_NOTACCEPTING: LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING"); break; - case E_INVALIDARG: LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG"); break; - case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); break; - default: LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr); break; + switch (hr) { + case S_OK: + break; + case MF_E_INVALIDREQUEST: + LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST"); + break; + case MF_E_INVALIDSTREAMNUMBER: + LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER"); + break; + case MF_E_NOTACCEPTING: + LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING"); + break; + case E_INVALIDARG: + LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG"); + break; + case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: + LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); + break; + default: + LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr); + break; } if (hr != S_OK) streaming = false; } } - return S_OK; + return S_OK; } -std::shared_ptr create_context() { +std::shared_ptr create_context() +{ return std::make_shared(); } -std::vector> query_devices( - std::shared_ptr context) { - +std::vector> query_devices(std::shared_ptr context) +{ IMFAttributes *pAttributes = NULL; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("IMFAttributes::SetGUID",pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); @@ -429,7 +424,7 @@ std::vector> query_devices( UINT32 numDevices; check("MFEnumDeviceSources",MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices)); - std::vector> devices; + std::vector> devices; for (UINT32 i = 0; i < numDevices; ++i) { com_ptr pDevice; *&pDevice = ppDevices[i]; @@ -439,8 +434,8 @@ std::vector> query_devices( UINT32 length; pDevice->GetAllocatedString( - MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_dev_name, - &length); + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_dev_name, + &length); auto dev_name = win_to_utf(wchar_dev_name); CoTaskMemFree(wchar_dev_name); @@ -448,18 +443,17 @@ std::vector> query_devices( auto name = win_to_utf(wchar_name); // Device description name CoTaskMemFree(wchar_name); - int vid, pid, mi; std::string unique_id; - + int vid, pid, mi; + std::string unique_id; + if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue; - + std::shared_ptr dev; - for(auto & d : devices) - { +for(auto & d : devices) { if(d->vid == vid && d->pid == pid && d->unique_id == unique_id) dev = d; } - if(!dev) - { + if(!dev) { try { dev = std::make_shared(context, vid, pid, unique_id, name); devices.push_back(dev); @@ -470,33 +464,38 @@ std::vector> query_devices( } dev->reader_callback = new reader_callback(dev); - dev->mf_activate = pDevice; + dev->mf_activate = pDevice; dev->vid = vid; dev->pid = pid; - + } CoTaskMemFree(ppDevices); return devices; } -int get_vendor_id(const device &device) { +int get_vendor_id(const device &device) +{ return device.vid; } -int get_product_id(const device &device) { +int get_product_id(const device &device) +{ return device.pid; } -std::string get_name(const device &device) { +std::string get_name(const device &device) +{ return device.name; } -std::string get_video_name(const device &device) { +std::string get_video_name(const device &device) +{ return device.name; } -static long get_cid(Option option) { +static long get_cid(Option option) +{ switch (option) { case Option::GAIN: return VideoProcAmp_Gain; @@ -510,8 +509,9 @@ static long get_cid(Option option) { } bool pu_control_range( - const device &device, Option option, int32_t *min, int32_t *max, - int32_t *def) { + const device &device, Option option, int32_t *min, int32_t *max, + 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)); @@ -521,19 +521,22 @@ bool pu_control_range( return true; } -void get_pu_control(const device &device, long property, int32_t *value) { +void get_pu_control(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)); *value = data; } -void set_pu_control(const device &device, long property, int32_t *value) { +void set_pu_control(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)); } 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) +{ CHECK_NOTNULL(value); const_cast(device).get_media_source(); switch (query) { @@ -551,108 +554,106 @@ bool pu_control_query( void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data) { - CHECK_NOTNULL(data); - int offset = 0; - auto ks_control = const_cast(device).get_ks_control(xu); + CHECK_NOTNULL(data); + int offset = 0; + auto ks_control = const_cast(device).get_ks_control(xu); - /* get step, min and max values*/ - KSP_NODE node; - memset(&node, 0, sizeof(KSP_NODE)); - node.Property.Set = reinterpret_cast(xu.id); - node.Property.Id = selector; - node.NodeId = xu.node; + /* get step, min and max values*/ + KSP_NODE node; + memset(&node, 0, sizeof(KSP_NODE)); + node.Property.Set = reinterpret_cast(xu.id); + node.Property.Id = selector; + node.NodeId = xu.node; - switch (query) { - 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: - offset = 0; - node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; - break; - default: - LOG(ERROR) << "xu request code is unaccepted"; - break; - } + switch (query) { + 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: + offset = 0; + node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; + break; + default: + LOG(ERROR) << "xu request code is unaccepted"; + break; + } - KSPROPERTY_DESCRIPTION description; - unsigned long bytes_received = 0; - std::cout << "query" << std::endl; - check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, - sizeof(node), - &description, - sizeof(KSPROPERTY_DESCRIPTION), - &bytes_received)); + KSPROPERTY_DESCRIPTION description; + unsigned long bytes_received = 0; + check("IKsControl::KsProperty", ks_control->KsProperty( + (PKSPROPERTY)&node, + sizeof(node), + &description, + sizeof(KSPROPERTY_DESCRIPTION), + &bytes_received)); - unsigned long size = description.DescriptionSize; - std::vector buffer((long)size); + unsigned long size = description.DescriptionSize; + std::vector buffer((long)size); - check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, - sizeof(node), - buffer.data(), - size, - &bytes_received)); + check("IKsControl::KsProperty", ks_control->KsProperty( + (PKSPROPERTY)&node, + sizeof(node), + buffer.data(), + size, + &bytes_received)); - if (bytes_received != size) { throw std::runtime_error("wrong data"); } + if (bytes_received != size) { + throw std::runtime_error("wrong data"); + } - BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); - * data = (uint8_t)*(pRangeValues + offset); + BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); + * data = (uint8_t)*(pRangeValues + offset); } 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); + 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(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.NodeId = xu.node; - unsigned long bytes_received = 0; - std::cout << "selector: " << selector << std::endl; - switch (query) { - case XU_QUERY_SET: - std::cout << "XU_QUERY_SET" << std::endl; - node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; - break; - case XU_QUERY_GET: - std::cout << "XU_QUERY_GET" << std::endl; - node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; - break; - case XU_QUERY_MIN: - case XU_QUERY_MAX: - case XU_QUERY_DEF: - get_extension_control_range(device, xu, selector, query, data); - return true; - default: - LOG(ERROR) << "xu range query request code is unaccepted"; - return false; - } - std::cout << "set & get" << std::endl; - check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast(data), size, &bytes_received)); - if (bytes_received != size) { throw_error() << "wrong 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.NodeId = xu.node; + unsigned long bytes_received = 0; + switch (query) { + case XU_QUERY_SET: + node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + break; + case XU_QUERY_GET: + node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + break; + case XU_QUERY_MIN: + case XU_QUERY_MAX: + case XU_QUERY_DEF: + get_extension_control_range(device, xu, selector, query, data); + return true; + default: + return false; + } + check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast(data), size, &bytes_received)); + if (bytes_received != size) { + throw_error() << "wrong data"; + } - *data = (int)*(data+offset); + *data = (int)*(data+offset); - return true; + return true; } void set_device_mode(device & device, int width, int height, int fourcc, int fps, video_channel_callback callback) -{ - if(!device.mf_source_reader) - { +{ + if(!device.mf_source_reader) { com_ptr pAttributes; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast(device.reader_callback))); @@ -661,33 +662,39 @@ void set_device_mode(device & device, int width, int height, int fourcc, int fps if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc); - for (DWORD j = 0; ; j++) - { + for (DWORD j = 0; ; j++) { com_ptr media_type; HRESULT hr = device.mf_source_reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, j, &media_type); if (hr == MF_E_NO_MORE_TYPES) break; check("IMFSourceReader::GetNativeMediaType", hr); - UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; GUID subtype; + UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; + GUID subtype; check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height)); if(uvc_width != width || uvc_height != height) continue; - check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype)); + check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype)); if(subtype.Data1 != fourcc) continue; check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom)); if(uvc_fps_denom == 0) continue; check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type)); - + device.callback = callback; return; } throw_error() << "no matching media type for pixel format " << std::hex << fourcc; } -void start_streaming(device & device, int num_transfer_bufs) { device.start_streaming(); } -void stop_streaming(device & device) { device.stop_streaming(); } +void start_streaming(device & device, int num_transfer_bufs) +{ + device.start_streaming(); +} +void stop_streaming(device & device) +{ + device.stop_streaming(); +} } // namespace uvc From 113d2e595115606d0ba0812c7c102db68ffd1f19 Mon Sep 17 00:00:00 2001 From: kalman Date: Sat, 5 May 2018 21:10:49 +0800 Subject: [PATCH 03/19] add two space --- src/uvc/uvc-wmf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 2953fba..e622709 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -449,7 +449,7 @@ std::vector> query_devices(std::shared_ptr cont if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue; std::shared_ptr dev; -for(auto & d : devices) { + for(auto & d : devices) { if(d->vid == vid && d->pid == pid && d->unique_id == unique_id) dev = d; } From b1b9b60626211fb36aac525109f07d30aa10627d Mon Sep 17 00:00:00 2001 From: kalman Date: Mon, 7 May 2018 15:03:52 +0800 Subject: [PATCH 04/19] add uvc extension unit guid --- src/internal/channels.cc | 4 +++- src/uvc/uvc-wmf.cc | 20 +++++++++++++------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/src/internal/channels.cc b/src/internal/channels.cc index 51e8f74..2bdecd0 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -15,6 +15,8 @@ MYNTEYE_BEGIN_NAMESPACE namespace { +const uvc::xu mynteye_xu = {3, 1, {0x18682d34, 0xdd2c, 0x4073, {0xad, 0x23, 0x72, 0x14, 0x73, 0x9a, 0x07, 0x4c}}}; + int XuCamCtrlId(Option option) { switch (option) { case Option::EXPOSURE_MODE: @@ -838,7 +840,7 @@ bool Channels::PuControlQuery( bool Channels::XuControlQuery( channel_t channel, uvc::xu_query query, uint16_t size, uint8_t *data) const { - return XuControlQuery({3}, channel >> 8, query, size, data); + return XuControlQuery(mynteye_xu, channel >> 8, query, size, data); } bool Channels::XuControlQuery( diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index e622709..8061ae7 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -139,7 +139,7 @@ static std::string win_to_utf(const WCHAR * s) static void check(const char *call, HRESULT hr) { if (FAILED(hr)) { - throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; + throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; } } @@ -278,7 +278,7 @@ public: struct device { const std::shared_ptr parent; int vid, pid; - const std::string unique_id; + std::string unique_id; std::string name; com_ptr reader_callback; @@ -551,14 +551,14 @@ bool pu_control_query( return false; } } - +/* void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data) { CHECK_NOTNULL(data); int offset = 0; auto ks_control = const_cast(device).get_ks_control(xu); - /* get step, min and max values*/ + // get step, min and max values KSP_NODE node; memset(&node, 0, sizeof(KSP_NODE)); node.Property.Set = reinterpret_cast(xu.id); @@ -610,7 +610,7 @@ void get_extension_control_range(const device &device, const xu &xu, uint8_t sel * data = (uint8_t)*(pRangeValues + offset); } - +*/ bool xu_control_query( const device &device, const xu &xu, uint8_t selector, xu_query query, uint16_t size, uint8_t *data) @@ -634,10 +634,16 @@ bool xu_control_query( node.Property.Flags = KSPROPERTY_TYPE_SET | 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: - get_extension_control_range(device, xu, selector, query, data); - return true; + node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; + break; default: return false; } From 8ca90f347887be5feeda9564cb1757a7651b632d Mon Sep 17 00:00:00 2001 From: kalman Date: Mon, 7 May 2018 16:43:47 +0800 Subject: [PATCH 05/19] add KSNODETYPE_DEV_SPECIFIC_LOCAL --- src/uvc/uvc-wmf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 8061ae7..69f51f6 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -310,8 +310,8 @@ struct device { GUID node_type; check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); - //const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x6BDD1FC6, 0X810F, 0x11D0, {0xBE, 0xC7 ,0x08, 0x00, 0x2B, 0xE2, 0x09, 0x2F}}; - //if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; + const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0xDFF229E5, 0xF70F, 0x11D0, {0xB9, 0x17 ,0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; + if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; com_ptr unknown; check("CreateNodeInstance", ks_topology_info->CreateNodeInstance(xu.node, IID_IUnknown, (LPVOID *)&unknown)); From b8f20c570c2c047143eeb93c50f08105032b2c24 Mon Sep 17 00:00:00 2001 From: kalman Date: Mon, 7 May 2018 20:33:10 +0800 Subject: [PATCH 06/19] change the node and confirm the KSNODETYPE_DEV --- src/internal/channels.cc | 2 +- src/uvc/uvc-wmf.cc | 33 ++++++++++++++++++++++++++++----- 2 files changed, 29 insertions(+), 6 deletions(-) diff --git a/src/internal/channels.cc b/src/internal/channels.cc index 2bdecd0..fd43702 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -15,7 +15,7 @@ MYNTEYE_BEGIN_NAMESPACE namespace { -const uvc::xu mynteye_xu = {3, 1, {0x18682d34, 0xdd2c, 0x4073, {0xad, 0x23, 0x72, 0x14, 0x73, 0x9a, 0x07, 0x4c}}}; +const uvc::xu mynteye_xu = {3, 2, {0x18682d34, 0xdd2c, 0x4073, {0xad, 0x23, 0x72, 0x14, 0x73, 0x9a, 0x07, 0x4c}}}; int XuCamCtrlId(Option option) { switch (option) { diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 69f51f6..c9f9cc5 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -141,6 +141,7 @@ static void check(const char *call, HRESULT hr) if (FAILED(hr)) { throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; } + LOG(INFO) << call << " SUCCESSED"; } std::vector tokenize(std::string string, char separator) @@ -158,6 +159,18 @@ std::vector tokenize(std::string string, char separator) } } +static void print_guid(const char *call, GUID guid) { + std::cout << call << ":"; + std::cout << " Data1: " << std::hex << guid.Data1 << ","; + std::cout << " Data2: " << std::hex << guid.Data2 << ","; + std::cout << " Data3: " << std::hex << guid.Data3 << ","; + std::cout << " Data4: [ "; + for(int j = 0; j < 8; j++) { + std::cout << std::hex << (int)guid.Data4[j] << " "; + } + std::cout << "]" << std::endl; +} + bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path) { auto name = path; @@ -299,18 +312,28 @@ struct device { IKsControl * get_ks_control(const uvc::xu & xu) { + auto it = ks_controls.find(xu.node); if(it != end(ks_controls)) return it->second; - + get_media_source(); - + // Attempt to retrieve IKsControl com_ptr ks_topology_info = NULL; - check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info)); + check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info)); GUID node_type; + /* + DWORD numberOfNodes; + 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)); + std::cout << "node" << i << " "; + print_guid("node_type", node_type); + } + */ check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); - const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0xDFF229E5, 0xF70F, 0x11D0, {0xB9, 0x17 ,0x00, 0xA0, 0xC9, 0x22, 0x31, 0x96}}; + const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x941C7AC0L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}}; if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; com_ptr unknown; @@ -318,7 +341,7 @@ struct device { com_ptr ks_control; check("QueryInterface", unknown->QueryInterface(__uuidof(IKsControl), (void **)&ks_control)); - VLOG(2) << "Obtained KS control node" << xu.node; + LOG(INFO) << "Obtained KS control node : " << xu.node; return ks_controls[xu.node] = ks_control; } From 9988c4906014b66e32b9b447a71febf333971d55 Mon Sep 17 00:00:00 2001 From: kalman Date: Mon, 7 May 2018 21:53:59 +0800 Subject: [PATCH 07/19] corrected a mistake about get --- src/uvc/uvc-wmf.cc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index c9f9cc5..2d2e669 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -654,7 +654,7 @@ bool xu_control_query( node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; break; case XU_QUERY_GET: - node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY; + node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY; break; case XU_QUERY_MIN: offset = 1; @@ -670,7 +670,7 @@ bool xu_control_query( default: return false; } - check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), reinterpret_cast(data), size, &bytes_received)); + check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(KSP_NODE), data, size, &bytes_received)); if (bytes_received != size) { throw_error() << "wrong data"; } From ca0ae22aea2fc52d133043e12e128416267cfef8 Mon Sep 17 00:00:00 2001 From: kalman Date: Mon, 7 May 2018 21:58:01 +0800 Subject: [PATCH 08/19] change a parameter of ksproperty --- src/uvc/uvc-wmf.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 2d2e669..2c0ea1e 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -670,7 +670,7 @@ bool xu_control_query( default: return false; } - check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(KSP_NODE), data, size, &bytes_received)); + check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), data, size, &bytes_received)); if (bytes_received != size) { throw_error() << "wrong data"; } From 58fdc4c01bd3617b02260f5fb5eab9c90821c270 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Tue, 15 May 2018 17:32:04 +0800 Subject: [PATCH 09/19] Fix capture video stream in uvc-wmf --- samples/uvc/camera.cc | 44 ++++++++++----- src/device/device.cc | 3 +- src/uvc/uvc-wmf.cc | 125 +++++++++++++++++++----------------------- src/uvc/uvc.h | 9 ++- 4 files changed, 95 insertions(+), 86 deletions(-) diff --git a/samples/uvc/camera.cc b/samples/uvc/camera.cc index e0b1554..3bbefd9 100644 --- a/samples/uvc/camera.cc +++ b/samples/uvc/camera.cc @@ -14,8 +14,17 @@ struct frame { const void *data = nullptr; + std::function continuation = nullptr; + frame() { + // VLOG(2) << __func__; + } ~frame() { + // VLOG(2) << __func__; data = nullptr; + if (continuation) { + continuation(); + continuation = nullptr; + } } }; @@ -28,7 +37,11 @@ int main(int argc, char *argv[]) { auto context = uvc::create_context(); auto devices = uvc::query_devices(context); - LOG_IF(FATAL, devices.size() <= 0) << "No devices :("; + if (devices.size() <= 0) { + LOG(ERROR) << "No devices :("; + return 1; + } + for (auto &&device : devices) { auto vid = uvc::get_vendor_id(*device); // auto pid = uvc::get_product_id(*device); @@ -41,7 +54,10 @@ int main(int argc, char *argv[]) { // std::string dashes(80, '-'); size_t n = mynteye_devices.size(); - LOG_IF(FATAL, n <= 0) << "No MYNT EYE devices :("; + if (n <= 0) { + LOG(ERROR) << "No MYNT EYE devices :("; + return 1; + } LOG(INFO) << "MYNT EYE devices: "; for (size_t i = 0; i < n; i++) { @@ -74,18 +90,21 @@ int main(int argc, char *argv[]) { std::mutex mtx; std::condition_variable cv; - std::vector frames; - const auto frame_ready = [&frames]() { return !frames.empty(); }; - const auto frame_empty = [&frames]() { return frames.empty(); }; + std::shared_ptr frame = nullptr; + const auto frame_ready = [&frame]() { return frame != nullptr; }; + const auto frame_empty = [&frame]() { return frame == nullptr; }; uvc::set_device_mode( *device, 752, 480, static_cast(Format::YUYV), 25, - [&mtx, &cv, &frames, &frame_ready](const void *data) { + [&mtx, &cv, &frame, &frame_ready]( + const void *data, std::function continuation) { // reinterpret_cast(data); std::unique_lock lock(mtx); - frame frame; - frame.data = data; // not copy - frames.push_back(frame); + if (frame == nullptr) { + frame = std::make_shared(); + } + frame->data = data; // not copy here + frame->continuation = continuation; if (frame_ready()) cv.notify_one(); }); @@ -106,13 +125,12 @@ int main(int argc, char *argv[]) { throw std::runtime_error("Timeout waiting for frame."); } - auto frame = frames.back(); // only last one is valid - - cv::Mat img(480, 752, CV_8UC2, const_cast(frame.data)); + // only lastest frame is valid + cv::Mat img(480, 752, CV_8UC2, const_cast(frame->data)); cv::cvtColor(img, img, cv::COLOR_YUV2BGR_YUY2); cv::imshow("frame", img); - frames.clear(); + frame = nullptr; char key = static_cast(cv::waitKey(1)); if (key == 27 || key == 'q' || key == 'Q') { // ESC/Q diff --git a/src/device/device.cc b/src/device/device.cc index 4ac51e2..9f3b988 100644 --- a/src/device/device.cc +++ b/src/device/device.cc @@ -376,7 +376,7 @@ void Device::StartVideoStreaming() { uvc::set_device_mode( *device_, stream_request.width, stream_request.height, static_cast(stream_request.format), stream_request.fps, - [this](const void *data) { + [this](const void *data, std::function continuation) { // drop the first stereo stream data static std::uint8_t drop_count = 1; if (drop_count > 0) { @@ -385,6 +385,7 @@ void Device::StartVideoStreaming() { } std::lock_guard _(mtx_streams_); streams_->PushStream(Capabilities::STEREO, data); + continuation(); if (HasStreamCallback(Stream::LEFT)) { auto &&stream_datas = streams_->stream_datas(Stream::LEFT); if (stream_datas.size() > 0) { diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 2c0ea1e..afaf412 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -49,15 +49,12 @@ MYNTEYE_BEGIN_NAMESPACE -namespace uvc -{ +namespace uvc { -const std::map fourcc_map = { { 0x56595559, 0x32595559 } ,{ 0x59555956, 0x59555932 }}; /* 'VYUY' => '2YUY','YUYV' => 'YUY2'. */ - -#define LOG_ERROR(severity, str) \ - do { \ - LOG(severity) << str << " error " << errno << ", " << strerror(errno); \ - } while (0) +const std::map fourcc_map = { + { 0x56595559, 0x32595559 }, // 'VYUY' => '2YUY' + { 0x59555956, 0x59555932 } // 'YUYV' => 'YUY2' +}; struct throw_error { throw_error() = default; @@ -68,7 +65,6 @@ struct throw_error { ~throw_error() noexcept(false) { throw std::runtime_error(ss.str()); - // throw device_error(ss.str()); } template @@ -80,8 +76,16 @@ struct throw_error { std::ostringstream ss; }; -template class com_ptr -{ +static void check(const char *call, HRESULT hr) { + if (FAILED(hr)) { + throw_error() << call << "(...) returned 0x" << std::hex + << static_cast(hr); + } else { + LOG(INFO) << call << " SUCCESSED"; + } +} + +template class com_ptr { T * p; void ref(T * new_p) { if(p == new_p) return; @@ -136,14 +140,6 @@ static std::string win_to_utf(const WCHAR * s) return buffer; } -static void check(const char *call, HRESULT hr) -{ - if (FAILED(hr)) { - throw_error() << call << "(...) returned 0x" << std::hex << (uint32_t)hr; - } - LOG(INFO) << call << " SUCCESSED"; -} - std::vector tokenize(std::string string, char separator) { std::vector tokens; @@ -178,29 +174,29 @@ bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, con auto tokens = tokenize(name, '#'); if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device if(tokens.size() < 3) { - LOG_ERROR(WARNING,"malformed usb device path: " << name); + LOG(ERROR) << "malformed usb device path: " << name; return false; } auto ids = tokenize(tokens[1], '&'); if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) { - LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]); + LOG(ERROR) << "malformed vid string: " << tokens[1]; return false; } if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) { - LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]); + LOG(ERROR) << "malformed pid string: " << tokens[1]; return false; } if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) { - LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]); + LOG(ERROR) << "malformed mi string: " << tokens[1]; return false; } ids = tokenize(tokens[2], '&'); if(ids.size() < 2) { - LOG_ERROR(WARNING,"malformed id string: " << tokens[2]); + LOG(ERROR) << "malformed id string: " << tokens[2]; return false; } unique_id = ids[1]; @@ -216,23 +212,23 @@ bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & auto ids = tokenize(tokens[1], '&'); if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) { - LOG_ERROR(WARNING,"malformed vid string: " << tokens[1]); + LOG(ERROR) << "malformed vid string: " << tokens[1]; return false; } if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid)) { - LOG_ERROR(WARNING,"malformed pid string: " << tokens[1]); + LOG(ERROR) << "malformed pid string: " << tokens[1]; return false; } if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi)) { - LOG_ERROR(WARNING,"malformed mi string: " << tokens[1]); + LOG(ERROR) << "malformed mi string: " << tokens[1]; return false; } ids = tokenize(tokens[2], '&'); if (ids.size() < 2) { - LOG_ERROR(WARNING,"malformed id string: " + tokens[2]); + LOG(ERROR) << "malformed id string: " + tokens[2]; return false; } unique_id = ids[1]; @@ -278,7 +274,7 @@ public: ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); } ULONG STDMETHODCALLTYPE Release() override { ULONG count = InterlockedDecrement(&ref_count); - if(count == 0) delete this; + if (count == 0) delete this; return count; } @@ -303,8 +299,9 @@ struct device { com_ptr mf_source_reader; video_channel_callback callback = nullptr; - device(std::shared_ptr parent, int vid, int pid, std::string unique_id, std::string name) : parent(move(parent)), vid(vid), pid(pid), unique_id(move(unique_id)), name(name) - {} + device(std::shared_ptr parent, int vid, int pid, std::string unique_id, std::string name) + : parent(move(parent)), vid(vid), pid(pid), unique_id(move(unique_id)), name(name) { + } ~device() { stop_streaming(); @@ -312,15 +309,14 @@ struct device { IKsControl * get_ks_control(const uvc::xu & xu) { - auto it = ks_controls.find(xu.node); if(it != end(ks_controls)) return it->second; - + get_media_source(); - + // Attempt to retrieve IKsControl com_ptr ks_topology_info = NULL; - check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info)); + check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info)); GUID node_type; /* @@ -328,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)); - std::cout << "node" << i << " "; + std::cout << "node" << i << " "; print_guid("node_type", node_type); } */ @@ -346,18 +342,18 @@ struct device { } void start_streaming() { - if(mf_source_reader) { + if (mf_source_reader) { reader_callback->on_start(); check("IMFSourceReader::ReadSample", mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL)); } } void stop_streaming() { + if (mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM); - if(mf_source_reader) mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM); - while(true) { + while (true) { bool is_streaming = reader_callback->is_streaming(); - if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10)); + if (is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10)); else break; } @@ -365,7 +361,7 @@ struct device { am_camera_control = nullptr; am_video_proc_amp = nullptr; ks_controls.clear(); - if(mf_media_source) { + if (mf_media_source) { mf_media_source = nullptr; check("IMFActivate::ShutdownObject", mf_activate->ShutdownObject()); } @@ -397,7 +393,7 @@ HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWO auto continuation = [buffer, this]() { buffer->Unlock(); }; - owner_ptr->callback(byte_buffer); + owner_ptr->callback(byte_buffer, continuation); } } } @@ -405,26 +401,13 @@ HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWO if (auto owner_ptr_new = owner.lock()) { auto hr = owner_ptr_new->mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL); switch (hr) { - case S_OK: - break; - case MF_E_INVALIDREQUEST: - LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDREQUEST"); - break; - case MF_E_INVALIDSTREAMNUMBER: - LOG_ERROR(WARNING,"ReadSample returned MF_E_INVALIDSTREAMNUMBER"); - break; - case MF_E_NOTACCEPTING: - LOG_ERROR(WARNING,"ReadSample returned MF_E_NOTACCEPTING"); - break; - case E_INVALIDARG: - LOG_ERROR(WARNING,"ReadSample returned E_INVALIDARG"); - break; - case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: - LOG_ERROR(WARNING,"ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); - break; - default: - LOG_ERROR(WARNING,"ReadSample returned HRESULT " << std::hex << (uint32_t)hr); - break; + case S_OK: break; + case MF_E_INVALIDREQUEST: LOG(ERROR) << "ReadSample returned MF_E_INVALIDREQUEST"; break; + case MF_E_INVALIDSTREAMNUMBER: LOG(ERROR) << "ReadSample returned MF_E_INVALIDSTREAMNUMBER"; break; + case MF_E_NOTACCEPTING: LOG(ERROR) << "ReadSample returned MF_E_NOTACCEPTING"; break; + case E_INVALIDARG: LOG(ERROR) << "ReadSample returned E_INVALIDARG"; break; + case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG(ERROR) << "ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"; break; + default: LOG(ERROR) << "ReadSample returned HRESULT " << std::hex << (uint32_t)hr; break; } if (hr != S_OK) streaming = false; } @@ -441,11 +424,12 @@ std::vector> query_devices(std::shared_ptr cont { IMFAttributes *pAttributes = NULL; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); - check("IMFAttributes::SetGUID",pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE,MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); + check("IMFAttributes::SetGUID", pAttributes->SetGUID( + MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)); IMFActivate **ppDevices; UINT32 numDevices; - check("MFEnumDeviceSources",MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices)); + check("MFEnumDeviceSources", MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices)); std::vector> devices; for (UINT32 i = 0; i < numDevices; ++i) { @@ -490,7 +474,6 @@ std::vector> query_devices(std::shared_ptr cont dev->mf_activate = pDevice; dev->vid = vid; dev->pid = pid; - } CoTaskMemFree(ppDevices); @@ -682,14 +665,14 @@ bool xu_control_query( void set_device_mode(device & device, int width, int height, int fourcc, int fps, video_channel_callback callback) { - if(!device.mf_source_reader) { + if (!device.mf_source_reader) { com_ptr pAttributes; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast(device.reader_callback))); check("MFCreateSourceReaderFromMediaSource", MFCreateSourceReaderFromMediaSource(device.get_media_source(), pAttributes, &device.mf_source_reader)); } - if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc); + if (fourcc_map.count(fourcc)) fourcc = fourcc_map.at(fourcc); for (DWORD j = 0; ; j++) { com_ptr media_type; @@ -700,13 +683,15 @@ void set_device_mode(device & device, int width, int height, int fourcc, int fps UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; GUID subtype; check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height)); - if(uvc_width != width || uvc_height != height) continue; + if (uvc_width != width || uvc_height != height) continue; check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype)); - if(subtype.Data1 != fourcc) continue; + if (subtype.Data1 != fourcc) continue; check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom)); - if(uvc_fps_denom == 0) continue; + if (uvc_fps_denom == 0) continue; + //int uvc_fps = uvc_fps_num / uvc_fps_denom; + //LOG(INFO) << "uvc_fps: " << uvc_fps; check("IMFSourceReader::SetCurrentMediaType", device.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type)); diff --git a/src/uvc/uvc.h b/src/uvc/uvc.h index c64ed21..94439fd 100644 --- a/src/uvc/uvc.h +++ b/src/uvc/uvc.h @@ -23,7 +23,11 @@ typedef enum pu_query { PU_QUERY_LAST } pu_query; -struct guid { uint32_t data1; uint16_t data2, data3; uint8_t data4[8]; }; +struct MYNTEYE_API guid { + uint32_t data1; + uint16_t data2, data3; + uint8_t data4[8]; +}; // Extension Unit struct MYNTEYE_API xu { @@ -73,7 +77,8 @@ MYNTEYE_API bool xu_control_query( uint16_t size, uint8_t *data); // Control streaming -typedef std::function video_channel_callback; +typedef std::function continuation)> video_channel_callback; MYNTEYE_API void set_device_mode( device &device, int width, int height, int fourcc, int fps, // NOLINT From 49771d5b8e7b8f6d530e38bf385076f138bbcc21 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Fri, 18 May 2018 11:12:19 +0800 Subject: [PATCH 10/19] Format uvc-wmf.cc --- src/uvc/uvc-wmf.cc | 258 ++++++++++++++++----------------------------- 1 file changed, 90 insertions(+), 168 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index afaf412..9dde416 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -1,7 +1,5 @@ #include "uvc/uvc.h" // NOLINT -#include - #include #include @@ -9,8 +7,6 @@ #include #include -#include "uvc.h" - #include // For QISearch, etc. #include // For MFStartup, etc. #include // For MF_DEVSOURCE_*, etc. @@ -47,6 +43,11 @@ #include +#include + +// #define VLOG_INFO VLOG(2) +#define VLOG_INFO LOG(INFO) + MYNTEYE_BEGIN_NAMESPACE namespace uvc { @@ -81,121 +82,120 @@ static void check(const char *call, HRESULT hr) { throw_error() << call << "(...) returned 0x" << std::hex << static_cast(hr); } else { - LOG(INFO) << call << " SUCCESSED"; + VLOG_INFO << call << " SUCCESSED"; } } template class com_ptr { - T * p; - void ref(T * new_p) { - if(p == new_p) return; + T *p; + void ref(T *new_p) { + if (p == new_p) return; unref(); p = new_p; - if(p) p->AddRef(); + if (p) p->AddRef(); } void unref() { - if(p) { + if (p) { p->Release(); p = nullptr; } } public: com_ptr() : p() {} - com_ptr(T * p) : com_ptr() { + com_ptr(T *p) : com_ptr() { ref(p); } - com_ptr(const com_ptr & r) : com_ptr(r.p) {} + com_ptr(const com_ptr &r) : com_ptr(r.p) {} ~com_ptr() { unref(); } - operator T * () const { + operator T *() const { return p; } - T & operator * () const { + T &operator*() const { return *p; } - T * operator -> () const { + T *operator->() const { return p; } - T ** operator & () { + T **operator&() { unref(); return &p; } - com_ptr & operator = (const com_ptr & r) { + com_ptr &operator=(const com_ptr &r) { ref(r.p); return *this; } }; -static std::string win_to_utf(const WCHAR * s) -{ +static std::string win_to_utf(const WCHAR *s) { int len = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, NULL, NULL); - if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); - std::string buffer(len-1, ' '); + if (len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); + std::string buffer(len - 1, ' '); len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL); - if(len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); + if (len == 0) throw_error() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError(); return buffer; } -std::vector tokenize(std::string string, char separator) -{ +std::vector tokenize(std::string string, char separator) { std::vector tokens; std::string::size_type i1 = 0; - while(true) { + while (true) { auto i2 = string.find(separator, i1); - if(i2 == std::string::npos) { + if (i2 == std::string::npos) { tokens.push_back(string.substr(i1)); return tokens; } tokens.push_back(string.substr(i1, i2-i1)); - i1 = i2+1; + i1 = i2 + 1; } } static void print_guid(const char *call, GUID guid) { - std::cout << call << ":"; - std::cout << " Data1: " << std::hex << guid.Data1 << ","; - std::cout << " Data2: " << std::hex << guid.Data2 << ","; - std::cout << " Data3: " << std::hex << guid.Data3 << ","; - std::cout << " Data4: [ "; - for(int j = 0; j < 8; j++) { - std::cout << std::hex << (int)guid.Data4[j] << " "; + 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: [ "; + for (int j = 0; j < 8; j++) { + ss << std::hex << (int)guid.Data4[j] << " "; } - std::cout << "]" << std::endl; + ss << "]"; + 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; std::transform(begin(name), end(name), begin(name), ::tolower); auto tokens = tokenize(name, '#'); - if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device - if(tokens.size() < 3) { - LOG(ERROR) << "malformed usb device path: " << name; + if (tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device + if (tokens.size() < 3) { + LOG(ERROR) << "malformed usb device path: " << name; return false; } auto ids = tokenize(tokens[1], '&'); - if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) { + if (ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid)) { LOG(ERROR) << "malformed vid string: " << tokens[1]; return false; } - if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) { + if (ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid)) { LOG(ERROR) << "malformed pid string: " << tokens[1]; return false; } - if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) { + if (ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi)) { LOG(ERROR) << "malformed mi string: " << tokens[1]; return false; } ids = tokenize(tokens[2], '&'); - if(ids.size() < 2) { + if (ids.size() < 2) { LOG(ERROR) << "malformed id string: " << tokens[2]; return false; } @@ -203,12 +203,11 @@ bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, con return true; } -bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id) -{ +bool parse_usb_path_from_device_id(int &vid, int &pid, int &mi, std::string &unique_id, const std::string &device_id) { auto name = device_id; std::transform(begin(name), end(name), begin(name), ::tolower); auto tokens = tokenize(name, '\\'); - if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device + if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device auto ids = tokenize(tokens[1], '&'); if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid)) { @@ -247,8 +246,7 @@ struct context { } }; -class reader_callback : public IMFSourceReaderCallback -{ +class reader_callback : public IMFSourceReaderCallback { std::weak_ptr owner; // The device holds a reference to us, so use weak_ptr to prevent a cycle ULONG ref_count; volatile bool streaming = false; @@ -265,7 +263,7 @@ public: #pragma warning( push ) #pragma warning( disable: 4838 ) // Implement IUnknown - HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override { + HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void **ppvObject) override { static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}}; return QISearch(this, table, riid, ppvObject); } @@ -279,7 +277,7 @@ public: } // Implement IMFSourceReaderCallback - HRESULT STDMETHODCALLTYPE OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) override; + HRESULT STDMETHODCALLTYPE OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *sample) override; HRESULT STDMETHODCALLTYPE OnFlush(DWORD dwStreamIndex) override { streaming = false; return S_OK; } HRESULT STDMETHODCALLTYPE OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent) override { return S_OK; } }; @@ -308,9 +306,9 @@ struct device { } - IKsControl * get_ks_control(const uvc::xu & xu) { + IKsControl *get_ks_control(const uvc::xu &xu) { auto it = ks_controls.find(xu.node); - if(it != end(ks_controls)) return it->second; + if (it != end(ks_controls)) return it->second; get_media_source(); @@ -321,23 +319,22 @@ struct device { GUID node_type; /* DWORD numberOfNodes; - check("get_NumNodes",ks_topology_info->get_NumNodes(&numberOfNodes)); - for(int i = 0; i < numberOfNodes; i++) { + 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)); - std::cout << "node" << i << " "; print_guid("node_type", node_type); } */ check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type)); const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x941C7AC0L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}}; - if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; + if (node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw_error() << "Invalid extension unit node ID: " << xu.node; com_ptr unknown; check("CreateNodeInstance", ks_topology_info->CreateNodeInstance(xu.node, IID_IUnknown, (LPVOID *)&unknown)); com_ptr ks_control; check("QueryInterface", unknown->QueryInterface(__uuidof(IKsControl), (void **)&ks_control)); - LOG(INFO) << "Obtained KS control node : " << xu.node; + VLOG_INFO << "Obtained KS control node : " << xu.node; return ks_controls[xu.node] = ks_control; } @@ -369,7 +366,7 @@ struct device { } com_ptr get_media_source() { - if(!mf_media_source) { + if (!mf_media_source) { check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source)); if (mf_media_source) { check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control)); @@ -381,15 +378,14 @@ struct device { }; -HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) -{ - if(auto owner_ptr = owner.lock()) { - if(sample) { +HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *sample) { + if (auto owner_ptr = owner.lock()) { + if (sample) { com_ptr buffer = NULL; - if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) { - BYTE * byte_buffer; + if (SUCCEEDED(sample->GetBufferByIndex(0, &buffer))) { + BYTE *byte_buffer; DWORD max_length, current_length; - if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length))) { + if (SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length))) { auto continuation = [buffer, this]() { buffer->Unlock(); }; @@ -415,13 +411,11 @@ HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWO return S_OK; } -std::shared_ptr create_context() -{ +std::shared_ptr create_context() { return std::make_shared(); } -std::vector> query_devices(std::shared_ptr context) -{ +std::vector> query_devices(std::shared_ptr context) { IMFAttributes *pAttributes = NULL; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); check("IMFAttributes::SetGUID", pAttributes->SetGUID( @@ -456,18 +450,17 @@ std::vector> query_devices(std::shared_ptr cont if (!parse_usb_path(vid, pid, mi, unique_id, dev_name)) continue; std::shared_ptr dev; - for(auto & d : devices) { - if(d->vid == vid && d->pid == pid && d->unique_id == unique_id) + for (auto & d : devices) { + if (d->vid == vid && d->pid == pid && d->unique_id == unique_id) dev = d; } - if(!dev) { + if (!dev) { try { dev = std::make_shared(context, vid, pid, unique_id, name); devices.push_back(dev); } catch (const std::exception &e) { - VLOG(2) << "Not a USB video device: " << e.what(); + VLOG_INFO << "Not a USB video device: " << e.what(); } - } dev->reader_callback = new reader_callback(dev); @@ -480,28 +473,23 @@ std::vector> query_devices(std::shared_ptr cont return devices; } -int get_vendor_id(const device &device) -{ +int get_vendor_id(const device &device) { return device.vid; } -int get_product_id(const device &device) -{ +int get_product_id(const device &device) { return device.pid; } -std::string get_name(const device &device) -{ +std::string get_name(const device &device) { return device.name; } -std::string get_video_name(const device &device) -{ +std::string get_video_name(const device &device) { return device.name; } -static long get_cid(Option option) -{ +static long get_cid(Option option) { switch (option) { case Option::GAIN: return VideoProcAmp_Gain; @@ -515,34 +503,30 @@ static long get_cid(Option option) } bool pu_control_range( - const device &device, Option option, int32_t *min, int32_t *max, - int32_t *def) -{ + const device &device, Option option, int32_t *min, int32_t *max, + int32_t *def) { const_cast(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(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); + 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) -{ - long data, flags=0; +void get_pu_control(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)); *value = data; } -void set_pu_control(const device &device, long property, int32_t *value) -{ +void set_pu_control(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)); } 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) { CHECK_NOTNULL(value); const_cast(device).get_media_source(); switch (query) { @@ -557,70 +541,10 @@ bool pu_control_query( return false; } } -/* -void get_extension_control_range(const device &device, const xu &xu, uint8_t selector, xu_query query, uint8_t *data) -{ - CHECK_NOTNULL(data); - int offset = 0; - auto ks_control = const_cast(device).get_ks_control(xu); - // get step, min and max values - KSP_NODE node; - memset(&node, 0, sizeof(KSP_NODE)); - node.Property.Set = reinterpret_cast(xu.id); - node.Property.Id = selector; - node.NodeId = xu.node; - - switch (query) { - 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: - offset = 0; - node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY; - break; - default: - LOG(ERROR) << "xu request code is unaccepted"; - break; - } - - KSPROPERTY_DESCRIPTION description; - unsigned long bytes_received = 0; - check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, - sizeof(node), - &description, - sizeof(KSPROPERTY_DESCRIPTION), - &bytes_received)); - - unsigned long size = description.DescriptionSize; - std::vector buffer((long)size); - - check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, - sizeof(node), - buffer.data(), - size, - &bytes_received)); - - if (bytes_received != size) { - throw std::runtime_error("wrong data"); - } - - BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); - * data = (uint8_t)*(pRangeValues + offset); - -} -*/ bool xu_control_query( - const device &device, const xu &xu, uint8_t selector, xu_query query, - uint16_t size, uint8_t *data) -{ + 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); @@ -658,13 +582,12 @@ bool xu_control_query( throw_error() << "wrong data"; } - *data = (int)*(data+offset); + *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) { if (!device.mf_source_reader) { com_ptr pAttributes; check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1)); @@ -701,12 +624,11 @@ void set_device_mode(device & device, int width, int height, int fourcc, int fps throw_error() << "no matching media type for pixel format " << std::hex << fourcc; } -void start_streaming(device & device, int num_transfer_bufs) -{ +void start_streaming(device &device, int num_transfer_bufs) { device.start_streaming(); } -void stop_streaming(device & device) -{ + +void stop_streaming(device &device) { device.stop_streaming(); } From 0b7375698d2e2f8bb3028858d0a256aa6d6cb92a Mon Sep 17 00:00:00 2001 From: kalman Date: Fri, 18 May 2018 18:36:52 +0800 Subject: [PATCH 11/19] change xu guid --- src/internal/channels.cc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/internal/channels.cc b/src/internal/channels.cc index fd43702..ab925c2 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -15,7 +15,7 @@ MYNTEYE_BEGIN_NAMESPACE namespace { -const uvc::xu mynteye_xu = {3, 2, {0x18682d34, 0xdd2c, 0x4073, {0xad, 0x23, 0x72, 0x14, 0x73, 0x9a, 0x07, 0x4c}}}; +const uvc::xu mynteye_xu = {3, 2, {0x947a6d9f, 0x8a2f, 0x418d, {0x85, 0x9e, 0x6c, 0x9a, 0xa0, 0x38, 0x10, 0x14}}}; int XuCamCtrlId(Option option) { switch (option) { From f17eff7e011a20dec01d8d6000030199654ac78e Mon Sep 17 00:00:00 2001 From: John Zhao Date: Thu, 24 May 2018 16:00:22 +0800 Subject: [PATCH 12/19] Improve detect vs version in makefile --- CommonDefs.mk | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/CommonDefs.mk b/CommonDefs.mk index dae46bb..934a81a 100644 --- a/CommonDefs.mk +++ b/CommonDefs.mk @@ -159,23 +159,32 @@ ifeq ($(HOST_OS),Win) ifeq ($(HOST_NAME),MinGW) CMAKE += -G "MinGW Makefiles" else ifeq ($(HOST_ARCH),x64) - VS_VERSION := $(shell echo "$(shell which cl)" | sed "s/.*Visual\sStudio\s\([0-9]\+\).*/\1/g") - ifeq (15,$(VS_VERSION)) + ifeq ($(VS_CODE),) + WHICH_CL := $(shell which cl) + ifeq ($(WHICH_CL),) + $(error "Visual Studio version is unknown. Could set VS_CODE to specify it, e.g. make [TARGET] VS_CODE=2017") + endif + # C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\... + # C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\... + VS_CODE := $(shell echo "$(WHICH_CL)" | grep -Po "(?<=Visual Studio[ /])[0-9]+") + endif + # $(call mkinfo,"VS_CODE: $(VS_CODE)") + ifeq ($(filter $(VS_CODE),15 2017),$(VS_CODE)) CMAKE += -G "Visual Studio 15 2017 Win64" - else ifeq (14,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),14 2015),$(VS_CODE)) CMAKE += -G "Visual Studio 14 2015 Win64" - else ifeq (12,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),12 2013),$(VS_CODE)) CMAKE += -G "Visual Studio 12 2013 Win64" - else ifeq (11,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),11 2012),$(VS_CODE)) CMAKE += -G "Visual Studio 11 2012 Win64" - else ifeq (10,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),10 2010),$(VS_CODE)) CMAKE += -G "Visual Studio 10 2010 Win64" - else ifeq (9,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),9 2008),$(VS_CODE)) CMAKE += -G "Visual Studio 9 2008 Win64" - else ifeq (8,$(VS_VERSION)) + else ifeq ($(filter $(VS_CODE),8 2005),$(VS_CODE)) CMAKE += -G "Visual Studio 8 2005 Win64" else - $(call mkinfo,"Connot specify Visual Studio Win64") + $(error "Visual Studio version is not proper, VS_CODE: $(VS_CODE)") endif endif From 3673324079c706e098dd0dc43a77a2b63898fcd7 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Fri, 25 May 2018 12:32:58 +0800 Subject: [PATCH 13/19] 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); From aed39f094234a35a76825f06777964b9d8c85c84 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Tue, 29 May 2018 12:21:30 +0800 Subject: [PATCH 14/19] Change channel value --- src/internal/channels.cc | 4 ++-- src/internal/channels.h | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/internal/channels.cc b/src/internal/channels.cc index de8f255..b8841db 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -839,7 +839,7 @@ bool Channels::PuControlQuery( 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); + return XuControlRange(mynteye_xu, channel, min, max, def); } bool Channels::XuControlRange( @@ -852,7 +852,7 @@ bool Channels::XuControlRange( bool Channels::XuControlQuery( channel_t channel, uvc::xu_query query, uint16_t size, uint8_t *data) const { - return XuControlQuery(mynteye_xu, channel >> 8, query, size, data); + return XuControlQuery(mynteye_xu, channel, query, size, data); } bool Channels::XuControlQuery( diff --git a/src/internal/channels.h b/src/internal/channels.h index 9feaf32..d4e2d78 100644 --- a/src/internal/channels.h +++ b/src/internal/channels.h @@ -24,11 +24,11 @@ struct xu; class MYNTEYE_API Channels { public: typedef enum Channel { - CHANNEL_CAM_CTRL = 0x0100, - CHANNEL_HALF_DUPLEX = 0x0200, - CHANNEL_IMU_WRITE = 0x0300, - CHANNEL_IMU_READ = 0x0400, - CHANNEL_FILE = 0x0500, + CHANNEL_CAM_CTRL = 1, + CHANNEL_HALF_DUPLEX = 2, + CHANNEL_IMU_WRITE = 3, + CHANNEL_IMU_READ = 4, + CHANNEL_FILE = 5, CHANNEL_LAST } channel_t; From 5daf4162e46100ad396da593e7e522a3e61591ca Mon Sep 17 00:00:00 2001 From: John Zhao Date: Tue, 29 May 2018 12:23:11 +0800 Subject: [PATCH 15/19] Add log info in uvc-wmf.cc --- src/uvc/uvc-wmf.cc | 38 ++++++++++++++++++++++++++++++++------ 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index a5f0c84..c1988f5 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -82,7 +82,7 @@ static void check(const char *call, HRESULT hr) { throw_error() << call << "(...) returned 0x" << std::hex << static_cast(hr); } else { - VLOG_INFO << call << " SUCCESSED"; + // VLOG_INFO << call << " SUCCESSED"; } } @@ -507,6 +507,7 @@ static long get_cid(Option option) { bool pu_control_range( const device &device, Option option, int32_t *min, int32_t *max, int32_t *def) { + VLOG_INFO << __func__ << " " << option; const_cast(device).get_media_source(); long minVal = 0, maxVal = 0, steppingDelta = 0, defVal = 0, capsFlag = 0; check("IAMVideoProcAmp::GetRange", @@ -515,6 +516,8 @@ bool pu_control_range( if (min) *min = static_cast(minVal); if (max) *max = static_cast(maxVal); if (def) *def = static_cast(defVal); + VLOG_INFO << __func__ << " " << option << + ": min=" << *min << ", max=" << *max << ", def=" << *def; return true; } @@ -539,10 +542,14 @@ bool pu_control_query( const_cast(device).get_media_source(); switch (query) { case PU_QUERY_SET: + VLOG_INFO << "pu_control_set " << option << ": " << *value; pu_control_set(device, get_cid(option), value); + VLOG_INFO << "pu_control_set " << option << " done"; return true; case PU_QUERY_GET: + VLOG_INFO << "pu_control_get " << option; pu_control_get(device, get_cid(option), value); + VLOG_INFO << "pu_control_get " << option << ": " << *value; return true; default: LOG(ERROR) << "pu_control_query request code is unaccepted"; @@ -587,6 +594,7 @@ static std::vector xu_control_desc(const device &device, const xu &xu, ULO bool xu_control_range( const device &device, const xu &xu, uint8_t selector, int32_t *min, int32_t *max, int32_t *def) { + VLOG_INFO << __func__ << " " << static_cast(selector); // get step, min and max values { auto &&buffer = xu_control_desc(device, xu, selector, @@ -609,10 +617,22 @@ bool xu_control_range( *def = static_cast(*values); } + VLOG_INFO << __func__ << " " << static_cast(selector) + << ": min=" << *min << ", max=" << *max << ", def=" << *def; return true; } -static void xu_control_get(const device &device, const xu &xu, uint8_t selector, int len, void *data) { +static std::string to_string(uint16_t size, uint8_t *data) { + std::ostringstream ss; + for (uint8_t *beg = data, *end = data + size; beg != end; beg++) { + ss << "0x" << std::hex << static_cast(*beg) << ","; + } + return ss.str(); +} + +static void xu_control_get(const device &device, const xu &xu, uint8_t selector, + uint16_t size, uint8_t *data) { + VLOG_INFO << __func__ << " " << static_cast(selector); auto &&ks_control = const_cast(device).get_ks_control(xu); KSP_NODE node; @@ -624,13 +644,18 @@ static void xu_control_get(const device &device, const xu &xu, uint8_t selector, ULONG bytes_received = 0; check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, sizeof(node), data, len, &bytes_received)); + (PKSPROPERTY)&node, sizeof(node), data, size, &bytes_received)); - if (bytes_received != len) + if (bytes_received != size) throw_error() << "xu_control_get did not return enough data"; + VLOG_INFO << __func__ << " " << static_cast(selector) + << ": size=" << size << ", data=[" << to_string(size, data) << "]"; } -static void xu_control_set(const device &device, const xu &xu, uint8_t selector, int len, void *data) { +static void xu_control_set(const device &device, const xu &xu, uint8_t selector, + uint16_t size, uint8_t *data) { + VLOG_INFO << __func__ << " " << static_cast(selector) + << ": size=" << size << ", data=[" << to_string(size, data) << "]"; auto &&ks_control = const_cast(device).get_ks_control(xu); KSP_NODE node; @@ -642,7 +667,8 @@ static void xu_control_set(const device &device, const xu &xu, uint8_t selector, ULONG bytes_received = 0; check("IKsControl::KsProperty", ks_control->KsProperty( - (PKSPROPERTY)&node, sizeof(node), data, len, &bytes_received)); + (PKSPROPERTY)&node, sizeof(node), data, size, &bytes_received)); + VLOG_INFO << __func__ << " " << static_cast(selector) << " done"; } bool xu_control_query( From 87470f29a93329d73214b7bc37fbc235daff0841 Mon Sep 17 00:00:00 2001 From: John Zhao Date: Wed, 30 May 2018 11:12:28 +0800 Subject: [PATCH 16/19] Update xu_control_range in uvc-wmf.cc --- .gitignore | 4 +++- src/uvc/uvc-wmf.cc | 47 ++++++++++++++++++++++++++++------------------ 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/.gitignore b/.gitignore index 447ddb5..0e4ebcb 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,7 @@ .DS_Store -/.vscode/ + +.vs/ +.vscode/ _build/ _install/ diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index c1988f5..d350a73 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -45,8 +45,8 @@ #include -// #define VLOG_INFO VLOG(2) -#define VLOG_INFO LOG(INFO) +#define VLOG_INFO VLOG(2) +// #define VLOG_INFO LOG(INFO) MYNTEYE_BEGIN_NAMESPACE @@ -557,6 +557,14 @@ bool pu_control_query( } } +static std::string to_string(uint16_t size, uint8_t *data) { + std::ostringstream ss; + for (uint8_t *beg = data, *end = data + size; beg != end; beg++) { + ss << "0x" << std::hex << static_cast(*beg) << ","; + } + return ss.str(); +} + 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); @@ -588,6 +596,8 @@ static std::vector xu_control_desc(const device &device, const xu &xu, ULO if (bytes_received != size) { throw_error() << "wrong data"; } + // VLOG_INFO << "buffer size=" << size << ", data=[" + // << to_string(size, buffer.data()) << "]"; return buffer; } @@ -595,41 +605,42 @@ bool xu_control_range( const device &device, const xu &xu, uint8_t selector, int32_t *min, int32_t *max, int32_t *def) { VLOG_INFO << __func__ << " " << static_cast(selector); + size_t prop_header_size = sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION); // 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); + BYTE *values = buffer.data() + prop_header_size; - // *step = static_cast(*values); - values++; - *min = static_cast(*values); - values++; - *max = static_cast(*values); + // size_t size = buffer.size() - prop_header_size; + // VLOG_INFO << "values size: " << size << ", data=[" + // << to_string(size, values) << "]"; + + *min = (values[1] << 8) | (values[2]); + values += 3; + *max = (values[1] << 8) | (values[2]); + // values += 3; + // *step = (values[1] << 8) | (values[2]); } // 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); + BYTE *values = buffer.data() + prop_header_size; - *def = static_cast(*values); + // size_t size = buffer.size() - prop_header_size; + // VLOG_INFO << "values size: " << size << ", data=[" + // << to_string(size, values) << "]"; + + *def = (values[1] << 8) | (values[2]); } VLOG_INFO << __func__ << " " << static_cast(selector) << ": min=" << *min << ", max=" << *max << ", def=" << *def; return true; } -static std::string to_string(uint16_t size, uint8_t *data) { - std::ostringstream ss; - for (uint8_t *beg = data, *end = data + size; beg != end; beg++) { - ss << "0x" << std::hex << static_cast(*beg) << ","; - } - return ss.str(); -} - static void xu_control_get(const device &device, const xu &xu, uint8_t selector, uint16_t size, uint8_t *data) { VLOG_INFO << __func__ << " " << static_cast(selector); From 5be47846e7c9f4e574167e444701b2fb102df0b3 Mon Sep 17 00:00:00 2001 From: kalman Date: Thu, 31 May 2018 15:09:00 +0800 Subject: [PATCH 17/19] change the way to get xu control's range --- src/internal/channels.cc | 16 +++++----------- src/internal/channels.h | 4 ++-- src/uvc/uvc-libuvc.cc | 2 +- src/uvc/uvc-v4l2.cc | 11 +++++++++-- src/uvc/uvc-wmf.cc | 24 ++++++++++++++++++++++++ src/uvc/uvc.h | 4 ++-- 6 files changed, 43 insertions(+), 18 deletions(-) diff --git a/src/internal/channels.cc b/src/internal/channels.cc index b8841db..3fcd3e8 100644 --- a/src/internal/channels.cc +++ b/src/internal/channels.cc @@ -838,15 +838,15 @@ bool Channels::PuControlQuery( } bool Channels::XuControlRange( - channel_t channel, int32_t *min, int32_t *max, int32_t *def) const { - return XuControlRange(mynteye_xu, channel, min, max, def); + channel_t channel, uint8_t id, int32_t *min, int32_t *max, int32_t *def) const { + return XuControlRange(mynteye_xu, channel, id, min, max, def); } bool Channels::XuControlRange( - const uvc::xu &xu, uint8_t selector, int32_t *min, int32_t *max, + const uvc::xu &xu, uint8_t selector, uint8_t id, int32_t *min, int32_t *max, int32_t *def) const { CHECK_NOTNULL(device_); - return uvc::xu_control_range(*device_, xu, selector, min, max, def); + return uvc::xu_control_range(*device_, xu, selector, id, min, max, def); } bool Channels::XuControlQuery( @@ -983,14 +983,8 @@ Channels::control_info_t Channels::PuControlInfo(Option option) const { Channels::control_info_t Channels::XuControlInfo(Option option) const { int id = XuCamCtrlId(option); - std::uint8_t data[3] = {static_cast((id | 0x80) & 0xFF), 0, 0}; - if (!XuCamCtrlQuery(uvc::XU_QUERY_SET, 3, data)) { - LOG(WARNING) << "Get XuControlInfo of " << option << " failed"; - return {0, 0, 0}; - } - int32_t min = 0, max = 0, def = 0; - if (!XuControlRange(CHANNEL_CAM_CTRL, &min, &max, &def)) { + if (!XuControlRange(CHANNEL_CAM_CTRL, static_cast(id), &min, &max, &def)) { LOG(WARNING) << "Get XuControlInfo of " << option << " failed"; } return {min, max, def}; diff --git a/src/internal/channels.h b/src/internal/channels.h index d4e2d78..c80c620 100644 --- a/src/internal/channels.h +++ b/src/internal/channels.h @@ -98,9 +98,9 @@ class MYNTEYE_API Channels { 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; + channel_t channel, uint8_t id, 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, + const uvc::xu &xu, uint8_t selector, uint8_t id, int32_t *min, int32_t *max, int32_t *def) const; bool XuControlQuery( diff --git a/src/uvc/uvc-libuvc.cc b/src/uvc/uvc-libuvc.cc index e3e2c34..242c098 100644 --- a/src/uvc/uvc-libuvc.cc +++ b/src/uvc/uvc-libuvc.cc @@ -132,7 +132,7 @@ bool pu_control_query( } bool xu_control_range( - const device &device, const xu &xu, uint8_t selector, int32_t *min, + const device &device, const xu &xu, uint8_t selector, uint8_t id, int32_t *min, int32_t *max, int32_t *def) { // TODO(JohnZhao) UNUSED(device) diff --git a/src/uvc/uvc-v4l2.cc b/src/uvc/uvc-v4l2.cc index 91b2540..5f47eb6 100755 --- a/src/uvc/uvc-v4l2.cc +++ b/src/uvc/uvc-v4l2.cc @@ -492,10 +492,17 @@ bool pu_control_query( } bool xu_control_range( - const device &device, const xu &xu, uint8_t selector, int32_t *min, - int32_t *max, int32_t *def) { + const device &device, const xu &xu, uint8_t selector, uint8_t id, + int32_t *min, int32_t *max, int32_t *def) { bool ret = true; std::uint8_t data[3]{}; + std::uint8_t query_id[3]{(id | 0x80), 0, 0}; + + if(!xu_control_query(device, xu, selcetor, XU_QUERY_SET, 3, query_id)) { + LOG(WARNING) << "xu_control_range query failed"; + ret = false; + } + if (xu_control_query(device, xu, selcetor, XU_QUERY_MIN, 3, data)) { *min = (data[1] << 8) | (data[2]); } else { diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index d350a73..29aaf6d 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -565,6 +565,7 @@ static std::string to_string(uint16_t size, uint8_t *data) { return ss.str(); } +/* 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); @@ -640,6 +641,7 @@ bool xu_control_range( << ": min=" << *min << ", max=" << *max << ", def=" << *def; return true; } +*/ static void xu_control_get(const device &device, const xu &xu, uint8_t selector, uint16_t size, uint8_t *data) { @@ -682,6 +684,28 @@ static void xu_control_set(const device &device, const xu &xu, uint8_t selector, VLOG_INFO << __func__ << " " << static_cast(selector) << " done"; } +static int32_t xu_control_range_basic(const device &device, const xu &xu, uint8_t selector, uint8_t id) { + int32_t value = 0; + std::uint8_t data[3]{}; + std::uint8_t query_id[3]{id, 0, 0}; + + xu_control_set(device,xu,selector,3,query_id); + xu_control_get(device,xu,selector,3,data); + value = (data[1] << 8) | (data[2]); + + return value; +} + +bool xu_control_range( + const device &device, const xu &xu, uint8_t selector, uint8_t id, + int32_t *min, int32_t *max, int32_t *def) { + VLOG_INFO << __func__ << " " << static_cast(selector); + *min = xu_control_range_basic(device,xu,selector,id|0x90); + *max = xu_control_range_basic(device,xu,selector,id|0xa0); + *def = xu_control_range_basic(device,xu,selector,id|0xc0); + return true; +} + 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.h b/src/uvc/uvc.h index 2f9a970..2d35f42 100644 --- a/src/uvc/uvc.h +++ b/src/uvc/uvc.h @@ -73,8 +73,8 @@ MYNTEYE_API bool pu_control_query( // Access XU (Extension Unit) controls MYNTEYE_API bool xu_control_range( - const device &device, const xu &xu, uint8_t selector, int32_t *min, - int32_t *max, int32_t *def); + const device &device, const xu &xu, uint8_t selector, uint8_t id, + 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); From 8bf0d982ea6ccb7bad54844e38df8602e1d7871f Mon Sep 17 00:00:00 2001 From: KalmanSLightech Date: Thu, 31 May 2018 15:48:58 +0800 Subject: [PATCH 18/19] spelling mistake --- src/uvc/uvc-v4l2.cc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/uvc/uvc-v4l2.cc b/src/uvc/uvc-v4l2.cc index 5f47eb6..11616ad 100755 --- a/src/uvc/uvc-v4l2.cc +++ b/src/uvc/uvc-v4l2.cc @@ -498,24 +498,24 @@ bool xu_control_range( std::uint8_t data[3]{}; std::uint8_t query_id[3]{(id | 0x80), 0, 0}; - if(!xu_control_query(device, xu, selcetor, XU_QUERY_SET, 3, query_id)) { + if(!xu_control_query(device, xu, selector, XU_QUERY_SET, 3, query_id)) { LOG(WARNING) << "xu_control_range query failed"; ret = false; } - if (xu_control_query(device, xu, selcetor, XU_QUERY_MIN, 3, data)) { + if (xu_control_query(device, xu, selector, 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)) { + if (xu_control_query(device, xu, selector, 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)) { + if (xu_control_query(device, xu, selector, XU_QUERY_DEF, 3, data)) { *def = (data[1] << 8) | (data[2]); } else { LOG(WARNING) << "xu_control_range query def failed"; From 84103d91bb4cb04e859ccf8da8382b4e9bd79514 Mon Sep 17 00:00:00 2001 From: KalmanSLightech Date: Thu, 31 May 2018 16:10:55 +0800 Subject: [PATCH 19/19] change the callback's parameter in uvc-v4l2.cc --- src/uvc/uvc-v4l2.cc | 10 +++++----- src/uvc/uvc-wmf.cc | 6 +++--- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/uvc/uvc-v4l2.cc b/src/uvc/uvc-v4l2.cc index 11616ad..1f960a9 100755 --- a/src/uvc/uvc-v4l2.cc +++ b/src/uvc/uvc-v4l2.cc @@ -368,11 +368,11 @@ struct device { } if (callback) { - callback(buffers[buf.index].start); + callback(buffers[buf.index].start, + [buf, this]() mutable { + if(xioctl(fd, VIDIOC_QBUF, &buf) < 0) throw_error("VIDIOC_QBUF"); + }); } - - if (xioctl(fd, VIDIOC_QBUF, &buf) < 0) - LOG_ERROR(FATAL, "VIDIOC_QBUF"); } } @@ -496,7 +496,7 @@ bool xu_control_range( int32_t *min, int32_t *max, int32_t *def) { bool ret = true; std::uint8_t data[3]{}; - std::uint8_t query_id[3]{(id | 0x80), 0, 0}; + std::uint8_t query_id[3]{static_cast(id | 0x80), 0, 0}; if(!xu_control_query(device, xu, selector, XU_QUERY_SET, 3, query_id)) { LOG(WARNING) << "xu_control_range query failed"; diff --git a/src/uvc/uvc-wmf.cc b/src/uvc/uvc-wmf.cc index 29aaf6d..b7f0b48 100644 --- a/src/uvc/uvc-wmf.cc +++ b/src/uvc/uvc-wmf.cc @@ -700,9 +700,9 @@ bool xu_control_range( const device &device, const xu &xu, uint8_t selector, uint8_t id, int32_t *min, int32_t *max, int32_t *def) { VLOG_INFO << __func__ << " " << static_cast(selector); - *min = xu_control_range_basic(device,xu,selector,id|0x90); - *max = xu_control_range_basic(device,xu,selector,id|0xa0); - *def = xu_control_range_basic(device,xu,selector,id|0xc0); + *min = xu_control_range_basic(device,xu,selector,static_cast(id|0x90)); + *max = xu_control_range_basic(device,xu,selector,static_cast(id|0xa0)); + *def = xu_control_range_basic(device,xu,selector,static_cast(id|0xc0)); return true; }