uvc-wmf.cpp
Go to the documentation of this file.
1 // License: Apache 2.0. See LICENSE file in root directory.
2 // Copyright(c) 2015 Intel Corporation. All Rights Reserved.
3 #include <chrono>
4 #include <iostream>
5 
6 
7 #ifdef RS_USE_WMF_BACKEND
8 
9 #if (_MSC_FULL_VER < 180031101)
10  #error At least Visual Studio 2013 Update 4 is required to compile this backend
11 #endif
12 
13 #include <windows.h>
14 #include <usbioctl.h>
15 #include <sstream>
16 
17 #include "uvc.h"
18 
19 #include <Shlwapi.h> // For QISearch, etc.
20 #include <mfapi.h> // For MFStartup, etc.
21 #include <mfidl.h> // For MF_DEVSOURCE_*, etc.
22 #include <mfreadwrite.h> // MFCreateSourceReaderFromMediaSource
23 #include <mferror.h>
24 #include "hw-monitor.h"
25 
26 #pragma comment(lib, "Shlwapi.lib")
27 #pragma comment(lib, "mf.lib")
28 #pragma comment(lib, "mfplat.lib")
29 #pragma comment(lib, "mfreadwrite.lib")
30 #pragma comment(lib, "mfuuid.lib")
31 
32 #pragma comment(lib, "setupapi.lib")
33 #pragma comment(lib, "winusb.lib")
34 
35 #include <uuids.h>
36 #include <vidcap.h>
37 #include <ksmedia.h>
38 #include <ksproxy.h>
39 
40 #include <Cfgmgr32.h>
41 
42 #pragma comment(lib, "cfgmgr32.lib")
43 
44 #include <SetupAPI.h>
45 #include <WinUsb.h>
46 
47 #include <functional>
48 #include <thread>
49 #include <chrono>
50 #include <algorithm>
51 #include <regex>
52 #include <map>
53 
54 #include <strsafe.h>
55 
56 DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, \
57  0xC0, 0x4F, 0xB9, 0x51, 0xED);
58 DEFINE_GUID(GUID_DEVINTERFACE_IMAGE, 0x6bdd1fc6L, 0x810f, 0x11d0, 0xbe, 0xc7, 0x08, 0x00, \
59  0x2b, 0xe2, 0x09, 0x2f);
60 
61 namespace rsimpl
62 {
63  namespace uvc
64  {
65  const auto FISHEYE_HWMONITOR_INTERFACE = 2;
66  const uvc::guid FISHEYE_WIN_USB_DEVICE_GUID = { 0xC0B55A29, 0xD7B6, 0x436E, { 0xA6, 0xEF, 0x2E, 0x76, 0xED, 0x0A, 0xBC, 0xA5 } };
67  // Translation of user-provided fourcc code into device-advertized:
68  const std::map<uint32_t, uint32_t> fourcc_map = { { 0x59382020, 0x47524559 }, /* 'Y8 ' as 'GREY' */
69  { 0x494e5649, 0x59313020 }, /* 'INVI' as 'Y10' */
70  { 0x494e565a, 0x5a313620 }, /* 'INVZ' as 'Z16' */
71  { 0x52573130, 0x70524141 } }; /* 'pRAA' as 'RW10' */
72 
73  static std::string win_to_utf(const WCHAR * s)
74  {
75  int len = WideCharToMultiByte(CP_UTF8, 0, s, -1, nullptr, 0, NULL, NULL);
76  if(len == 0) throw std::runtime_error(to_string() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError());
77  std::string buffer(len-1, ' ');
78  len = WideCharToMultiByte(CP_UTF8, 0, s, -1, &buffer[0], (int)buffer.size()+1, NULL, NULL);
79  if(len == 0) throw std::runtime_error(to_string() << "WideCharToMultiByte(...) returned 0 and GetLastError() is " << GetLastError());
80  return buffer;
81  }
82 
83  static void check(const char * call, HRESULT hr)
84  {
85  if(FAILED(hr)) throw std::runtime_error(to_string() << call << "(...) returned 0x" << std::hex << (uint32_t)hr);
86  }
87 
88  template<class T> class com_ptr
89  {
90  T * p;
91 
92  void ref(T * new_p)
93  {
94  if(p == new_p) return;
95  unref();
96  p = new_p;
97  if(p) p->AddRef();
98  }
99 
100  void unref()
101  {
102  if(p)
103  {
104  p->Release();
105  p = nullptr;
106  }
107  }
108  public:
109  com_ptr() : p() {}
110  com_ptr(T * p) : com_ptr() { ref(p); }
111  com_ptr(const com_ptr & r) : com_ptr(r.p) {}
112  ~com_ptr() { unref(); }
113 
114  operator T * () const { return p; }
115  T & operator * () const { return *p; }
116  T * operator -> () const { return p; }
117 
118  T ** operator & () { unref(); return &p; }
119  com_ptr & operator = (const com_ptr & r) { ref(r.p); return *this; }
120  };
121 
122  std::vector<std::string> tokenize(std::string string, char separator)
123  {
124  std::vector<std::string> tokens;
125  std::string::size_type i1 = 0;
126  while(true)
127  {
128  auto i2 = string.find(separator, i1);
129  if(i2 == std::string::npos)
130  {
131  tokens.push_back(string.substr(i1));
132  return tokens;
133  }
134  tokens.push_back(string.substr(i1, i2-i1));
135  i1 = i2+1;
136  }
137  }
138 
139  bool parse_usb_path(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & path)
140  {
141  auto name = path;
142  std::transform(begin(name), end(name), begin(name), ::tolower);
143  auto tokens = tokenize(name, '#');
144  if(tokens.size() < 1 || tokens[0] != R"(\\?\usb)") return false; // Not a USB device
145  if(tokens.size() < 3)
146  {
147  LOG_ERROR("malformed usb device path: " << name);
148  return false;
149  }
150 
151  auto ids = tokenize(tokens[1], '&');
152  if(ids[0].size() != 8 || ids[0].substr(0,4) != "vid_" || !(std::istringstream(ids[0].substr(4,4)) >> std::hex >> vid))
153  {
154  LOG_ERROR("malformed vid string: " << tokens[1]);
155  return false;
156  }
157 
158  if(ids[1].size() != 8 || ids[1].substr(0,4) != "pid_" || !(std::istringstream(ids[1].substr(4,4)) >> std::hex >> pid))
159  {
160  LOG_ERROR("malformed pid string: " << tokens[1]);
161  return false;
162  }
163 
164  if(ids[2].size() != 5 || ids[2].substr(0,3) != "mi_" || !(std::istringstream(ids[2].substr(3,2)) >> mi))
165  {
166  LOG_ERROR("malformed mi string: " << tokens[1]);
167  return false;
168  }
169 
170  ids = tokenize(tokens[2], '&');
171  if(ids.size() < 2)
172  {
173  LOG_ERROR("malformed id string: " << tokens[2]);
174  return false;
175  }
176  unique_id = ids[1];
177  return true;
178  }
179 
180  bool parse_usb_path_from_device_id(int & vid, int & pid, int & mi, std::string & unique_id, const std::string & device_id)
181  {
182  auto name = device_id;
183  std::transform(begin(name), end(name), begin(name), ::tolower);
184  auto tokens = tokenize(name, '\\');
185  if (tokens.size() < 1 || tokens[0] != R"(usb)") return false; // Not a USB device
186 
187  auto ids = tokenize(tokens[1], '&');
188  if (ids[0].size() != 8 || ids[0].substr(0, 4) != "vid_" || !(std::istringstream(ids[0].substr(4, 4)) >> std::hex >> vid))
189  {
190  LOG_ERROR("malformed vid string: " << tokens[1]);
191  return false;
192  }
193 
194  if (ids[1].size() != 8 || ids[1].substr(0, 4) != "pid_" || !(std::istringstream(ids[1].substr(4, 4)) >> std::hex >> pid))
195  {
196  LOG_ERROR("malformed pid string: " << tokens[1]);
197  return false;
198  }
199 
200  if (ids[2].size() != 5 || ids[2].substr(0, 3) != "mi_" || !(std::istringstream(ids[2].substr(3, 2)) >> mi))
201  {
202  LOG_ERROR("malformed mi string: " << tokens[1]);
203  return false;
204  }
205 
206  ids = tokenize(tokens[2], '&');
207  if (ids.size() < 2)
208  {
209  LOG_ERROR("malformed id string: " << tokens[2]);
210  return false;
211  }
212  unique_id = ids[1];
213  return true;
214  }
215 
216 
217  struct context
218  {
219  context()
220  {
221  CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
222  std::this_thread::sleep_for(std::chrono::milliseconds(100));
223  MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
224  }
225  ~context()
226  {
227  MFShutdown();
228  CoUninitialize();
229  }
230  };
231 
232  class reader_callback : public IMFSourceReaderCallback
233  {
234  std::weak_ptr<device> owner; // The device holds a reference to us, so use weak_ptr to prevent a cycle
235  int subdevice_index;
236  ULONG ref_count;
237  volatile bool streaming = false;
238  public:
239  reader_callback(std::weak_ptr<device> owner, int subdevice_index) : owner(owner), subdevice_index(subdevice_index), ref_count() {}
240 
241  bool is_streaming() const { return streaming; }
242  void on_start() { streaming = true; }
243 
244 #pragma warning( push )
245 #pragma warning( disable: 4838 )
246  // Implement IUnknown
247  HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid, void ** ppvObject) override
248  {
249  static const QITAB table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}};
250  return QISearch(this, table, riid, ppvObject);
251  }
252 #pragma warning( pop )
253 
254  ULONG STDMETHODCALLTYPE AddRef() override { return InterlockedIncrement(&ref_count); }
255  ULONG STDMETHODCALLTYPE Release() override
256  {
257  ULONG count = InterlockedDecrement(&ref_count);
258  if(count == 0) delete this;
259  return count;
260  }
261 
262  // Implement IMFSourceReaderCallback
263  HRESULT STDMETHODCALLTYPE OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample) override;
264  HRESULT STDMETHODCALLTYPE OnFlush(DWORD dwStreamIndex) override { streaming = false; return S_OK; }
265  HRESULT STDMETHODCALLTYPE OnEvent(DWORD dwStreamIndex, IMFMediaEvent *pEvent) override { return S_OK; }
266  };
267 
268  struct subdevice
269  {
270  com_ptr<reader_callback> reader_callback;
271  com_ptr<IMFActivate> mf_activate;
272  com_ptr<IMFMediaSource> mf_media_source;
273  com_ptr<IAMCameraControl> am_camera_control;
274  com_ptr<IAMVideoProcAmp> am_video_proc_amp;
275  std::map<int, com_ptr<IKsControl>> ks_controls;
276  com_ptr<IMFSourceReader> mf_source_reader;
277  video_channel_callback callback = nullptr;
278  data_channel_callback channel_data_callback = nullptr;
279  int vid, pid;
280 
281  void set_data_channel_cfg(data_channel_callback callback)
282  {
283  this->channel_data_callback = callback;
284  }
285 
286  com_ptr<IMFMediaSource> get_media_source()
287  {
288  if(!mf_media_source)
289  {
290  check("IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (void **)&mf_media_source));
291  if (mf_media_source)
292  {
293  check("IMFMediaSource::QueryInterface", mf_media_source->QueryInterface(__uuidof(IAMCameraControl), (void **)&am_camera_control));
294  if (SUCCEEDED(mf_media_source->QueryInterface(__uuidof(IAMVideoProcAmp), (void **)&am_video_proc_amp))) LOG_DEBUG("obtained IAMVideoProcAmp");
295  }
296  else throw std::runtime_error(to_string() << "Invalid media source");
297  }
298  return mf_media_source;
299 
300  }
301 
302  static bool wait_for_async_operation(WINUSB_INTERFACE_HANDLE interfaceHandle, OVERLAPPED &hOvl, ULONG &lengthTransferred, USHORT timeout)
303  {
304  if (GetOverlappedResult(interfaceHandle, &hOvl, &lengthTransferred, FALSE))
305  return true;
306 
307  auto lastResult = GetLastError();
308  if (lastResult == ERROR_IO_PENDING || lastResult == ERROR_IO_INCOMPLETE)
309  {
310  WaitForSingleObject(hOvl.hEvent, timeout);
311  auto res = GetOverlappedResult(interfaceHandle, &hOvl, &lengthTransferred, FALSE);
312  if (res != 1)
313  {
314  return false;
315  }
316  }
317  else
318  {
319  lengthTransferred = 0;
320  WinUsb_ResetPipe(interfaceHandle, 0x84);
321  return false;
322  }
323 
324  return true;
325  }
326 
327  class safe_handle
328  {
329  public:
330  safe_handle(HANDLE handle) :_handle(handle)
331  {
332 
333  }
334 
335  ~safe_handle()
336  {
337  if (_handle != nullptr)
338  {
339  CloseHandle(_handle);
340  _handle = nullptr;
341  }
342  }
343 
344  bool Set()
345  {
346  if (_handle == nullptr) return false;
347  SetEvent(_handle);
348  return true;
349  }
350 
351  bool Wait(DWORD timeout) const
352  {
353  if (_handle == nullptr) return false;
354 
355  return WaitForSingleObject(_handle, timeout) == WAIT_OBJECT_0; // Return true only if object was signaled
356  }
357 
358 
359  HANDLE GetHandle() const { return _handle; }
360  private:
361  safe_handle() = delete;
362 
363  // Disallow copy:
364  safe_handle(const safe_handle&) = delete;
365  safe_handle& operator=(const safe_handle&) = delete;
366 
367  HANDLE _handle;
368  };
369 
370  static void poll_interrupts(HANDLE *handle, const std::vector<subdevice *> & subdevices,uint16_t timeout)
371  {
372  static const unsigned short interrupt_buf_size = 0x400;
373  uint8_t buffer[interrupt_buf_size]; /* 64 byte transfer buffer - dedicated channel*/
374  ULONG num_bytes = 0; /* Actual bytes transferred. */
375  OVERLAPPED hOvl;
376  safe_handle sh(CreateEvent(nullptr, false, false, nullptr));
377  hOvl.hEvent = sh.GetHandle();
378  // TODO - replace hard-coded values : 0x82 and 1000
379  int res = WinUsb_ReadPipe(*handle, 0x84, buffer, interrupt_buf_size, &num_bytes, &hOvl);
380  if (0 == res)
381  {
382  auto lastError = GetLastError();
383  if (lastError == ERROR_IO_PENDING)
384  {
385  auto sts = wait_for_async_operation(*handle, hOvl, num_bytes, timeout);
386  lastError = GetLastError();
387  if (lastError == ERROR_OPERATION_ABORTED)
388  {
389  perror("receiving interrupt_ep bytes failed");
390  fprintf(stderr, "Error receiving message.\n");
391  }
392  if (!sts)
393  return;
394  }
395  else
396  {
397  WinUsb_ResetPipe(*handle, 0x84);
398  perror("receiving interrupt_ep bytes failed");
399  fprintf(stderr, "Error receiving message.\n");
400  return;
401  }
402 
403  if (num_bytes == 0)
404  return;
405 
406  // Propagate the data to device layer
407  for(auto & sub : subdevices)
408  if (sub->channel_data_callback)
409  sub->channel_data_callback(buffer, (unsigned long)num_bytes);
410  }
411  else
412  {
413  // todo exception
414  perror("receiving interrupt_ep bytes failed");
415  fprintf(stderr, "Error receiving message.\n");
416  }
417  }
418 
419  IKsControl * get_ks_control(const uvc::extension_unit & xu)
420  {
421  auto it = ks_controls.find(xu.node);
422  if(it != end(ks_controls)) return it->second;
423 
424  get_media_source();
425 
426  // Attempt to retrieve IKsControl
427  com_ptr<IKsTopologyInfo> ks_topology_info = NULL;
428  check("QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (void **)&ks_topology_info));
429 
430  GUID node_type;
431  check("get_NodeType", ks_topology_info->get_NodeType(xu.node, &node_type));
432  const GUID KSNODETYPE_DEV_SPECIFIC_LOCAL{0x941C7AC0L, 0xC559, 0x11D0, {0x8A, 0x2B, 0x00, 0xA0, 0xC9, 0x25, 0x5A, 0xC1}};
433  if(node_type != KSNODETYPE_DEV_SPECIFIC_LOCAL) throw std::runtime_error(to_string() << "Invalid extension unit node ID: " << xu.node);
434 
435  com_ptr<IUnknown> unknown;
436  check("CreateNodeInstance", ks_topology_info->CreateNodeInstance(xu.node, IID_IUnknown, (LPVOID *)&unknown));
437 
438  com_ptr<IKsControl> ks_control;
439  check("QueryInterface", unknown->QueryInterface(__uuidof(IKsControl), (void **)&ks_control));
440  LOG_INFO("Obtained KS control node " << xu.node);
441  return ks_controls[xu.node] = ks_control;
442  }
443  };
444 
445  struct device
446  {
447  const std::shared_ptr<context> parent;
448  const int vid, pid;
449  const std::string unique_id;
450 
451  std::vector<subdevice> subdevices;
452 
453  HANDLE usb_file_handle = INVALID_HANDLE_VALUE;
454  WINUSB_INTERFACE_HANDLE usb_interface_handle = INVALID_HANDLE_VALUE;
455 
456  std::vector<int> claimed_interfaces;
457 
458  int aux_vid, aux_pid;
459  std::string aux_unique_id;
460  std::thread data_channel_thread;
461  volatile bool data_stop;
462 
463  device(std::shared_ptr<context> parent, int vid, int pid, std::string unique_id) : parent(move(parent)), vid(vid), pid(pid), unique_id(move(unique_id)), aux_pid(0), aux_vid(0), data_stop(false)
464  {
465  }
466 
467  ~device() { stop_streaming(); stop_data_acquisition(); close_win_usb(); }
468 
469  IKsControl * get_ks_control(const uvc::extension_unit & xu)
470  {
471  return subdevices[xu.subdevice].get_ks_control(xu);
472  }
473 
475  {
476  std::vector<subdevice *> data_channel_subs;
477  for (auto & sub : subdevices)
478  {
479  if (sub.channel_data_callback)
480  {
481  data_channel_subs.push_back(&sub);
482  }
483  }
484 
485  if (claimed_interfaces.size())
486  {
487  data_channel_thread = std::thread([this, data_channel_subs]()
488  {
489  // Polling
490  while (!data_stop)
491  {
492  subdevice::poll_interrupts(&usb_interface_handle, data_channel_subs, 100);
493  }
494  });
495  }
496  }
497 
498  void stop_data_acquisition()
499  {
500  if (data_channel_thread.joinable())
501  {
502  data_stop = true;
503  data_channel_thread.join();
504  data_stop = false;
505  }
506  }
507 
508  void start_streaming()
509  {
510  for(auto & sub : subdevices)
511  {
512  if(sub.mf_source_reader)
513  {
514  sub.reader_callback->on_start();
515  check("IMFSourceReader::ReadSample", sub.mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL));
516  }
517  }
518  }
519 
520  void stop_streaming()
521  {
522  for(auto & sub : subdevices)
523  {
524  if(sub.mf_source_reader) sub.mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
525  }
526  while(true)
527  {
528  bool is_streaming = false;
529  for(auto & sub : subdevices) is_streaming |= sub.reader_callback->is_streaming();
530  if(is_streaming) std::this_thread::sleep_for(std::chrono::milliseconds(10));
531  else break;
532  }
533 
534  // Free up our source readers, our KS control nodes, and our media sources, but retain our original IMFActivate objects for later reuse
535  for(auto & sub : subdevices)
536  {
537  sub.mf_source_reader = nullptr;
538  sub.am_camera_control = nullptr;
539  sub.am_video_proc_amp = nullptr;
540  sub.ks_controls.clear();
541  if(sub.mf_media_source)
542  {
543  sub.mf_media_source = nullptr;
544  check("IMFActivate::ShutdownObject", sub.mf_activate->ShutdownObject());
545  }
546  sub.callback = {};
547  }
548  }
549 
550  com_ptr<IMFMediaSource> get_media_source(int subdevice_index)
551  {
552  return subdevices[subdevice_index].get_media_source();
553  }
554 
555  void open_win_usb(int vid, int pid, std::string unique_id, const guid & interface_guid, int interface_number) try
556  {
557  static_assert(sizeof(guid) == sizeof(GUID), "struct packing error");
558  HDEVINFO device_info = SetupDiGetClassDevs((const GUID *)&interface_guid, nullptr, nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE);
559  if (device_info == INVALID_HANDLE_VALUE) throw std::runtime_error("SetupDiGetClassDevs");
560  auto di = std::shared_ptr<void>(device_info, SetupDiDestroyDeviceInfoList);
561 
562  for(int member_index = 0; ; ++member_index)
563  {
564  // Enumerate all the device interfaces in the device information set.
565  SP_DEVICE_INTERFACE_DATA interfaceData = {sizeof(SP_DEVICE_INTERFACE_DATA)};
566  if(SetupDiEnumDeviceInterfaces(device_info, nullptr, (const GUID *)&interface_guid, member_index, &interfaceData) == FALSE)
567  {
568  if(GetLastError() == ERROR_NO_MORE_ITEMS) break;
569  continue;
570  }
571 
572  // Allocate space for a detail data struct
573  unsigned long detail_data_size = 0;
574  SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData, nullptr, 0, &detail_data_size, nullptr);
575  if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
576  {
577  LOG_ERROR("SetupDiGetDeviceInterfaceDetail failed");
578  continue;
579  }
580  auto alloc = std::malloc(detail_data_size);
581  if(!alloc) throw std::bad_alloc();
582 
583  // Retrieve the detail data struct
584  auto detail_data = std::shared_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA>(reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(alloc), std::free);
585  detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
586  if (!SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData, detail_data.get(), detail_data_size, nullptr, nullptr))
587  {
588  LOG_ERROR("SetupDiGetDeviceInterfaceDetail failed");
589  continue;
590  }
591  if (detail_data->DevicePath == nullptr) continue;
592  // Check if this is our device
593  int usb_vid, usb_pid, usb_mi; std::string usb_unique_id;
594  if(!parse_usb_path(usb_vid, usb_pid, usb_mi, usb_unique_id, win_to_utf(detail_data->DevicePath))) continue;
595  if(usb_vid != vid || usb_pid != pid || usb_mi != interface_number || usb_unique_id != unique_id) continue;
596 
597  HANDLE* file_handle = nullptr;
598  WINUSB_INTERFACE_HANDLE* usb_handle = nullptr;
599 
600  file_handle = &usb_file_handle;
601  usb_handle = &usb_interface_handle;
602 
603  *file_handle = CreateFile(detail_data->DevicePath, GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ, nullptr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, nullptr);
604  if (*file_handle == INVALID_HANDLE_VALUE) throw std::runtime_error("CreateFile(...) failed");
605 
606  if (!WinUsb_Initialize(*file_handle, usb_handle))
607  {
608  LOG_ERROR("Last Error: " << GetLastError());
609  throw std::runtime_error("could not initialize winusb");
610  }
611 
612  // We successfully set up a WinUsb interface handle to our device
613  return;
614  }
615  throw std::runtime_error("Unable to open device via WinUSB");
616  }
617  catch(...)
618  {
619  close_win_usb();
620  throw;
621  }
622 
623  void close_win_usb()
624  {
625  if (usb_interface_handle != INVALID_HANDLE_VALUE)
626  {
627  WinUsb_Free(usb_interface_handle);
628  usb_interface_handle = INVALID_HANDLE_VALUE;
629  }
630 
631  if(usb_file_handle != INVALID_HANDLE_VALUE)
632  {
633  CloseHandle(usb_file_handle);
634  usb_file_handle = INVALID_HANDLE_VALUE;
635  }
636  }
637 
638  bool usb_synchronous_read(uint8_t endpoint, void * buffer, int bufferLength, int * actual_length, DWORD TimeOut)
639  {
640  if (usb_interface_handle == INVALID_HANDLE_VALUE) throw std::runtime_error("winusb has not been initialized");
641 
642  auto result = false;
643 
644  BOOL bRetVal = true;
645 
646  ULONG lengthTransferred;
647 
648  bRetVal = WinUsb_ReadPipe(usb_interface_handle, endpoint, (PUCHAR)buffer, bufferLength, &lengthTransferred, NULL);
649 
650  if (bRetVal)
651  result = true;
652  else
653  {
654  auto lastResult = GetLastError();
655  WinUsb_ResetPipe(usb_interface_handle, endpoint);
656  result = false;
657  }
658 
659  *actual_length = lengthTransferred;
660  return result;
661  }
662 
663  bool usb_synchronous_write(uint8_t endpoint, void * buffer, int bufferLength, DWORD TimeOut)
664  {
665  if (usb_interface_handle == INVALID_HANDLE_VALUE) throw std::runtime_error("winusb has not been initialized");
666 
667  auto result = false;
668 
669  ULONG lengthWritten;
670  auto bRetVal = WinUsb_WritePipe(usb_interface_handle, endpoint, (PUCHAR)buffer, bufferLength, &lengthWritten, NULL);
671  if (bRetVal)
672  result = true;
673  else
674  {
675  auto lastError = GetLastError();
676  WinUsb_ResetPipe(usb_interface_handle, endpoint);
677  LOG_ERROR("WinUsb_ReadPipe failure... lastError: " << lastError);
678  result = false;
679  }
680 
681  return result;
682  }
683  };
684 
685  HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample)
686  {
687  if(auto owner_ptr = owner.lock())
688  {
689  if(sample)
690  {
691  com_ptr<IMFMediaBuffer> buffer = NULL;
692  if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer)))
693  {
694  BYTE * byte_buffer; DWORD max_length, current_length;
695  if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, &current_length)))
696  {
697  auto continuation = [buffer, this]()
698  {
699  buffer->Unlock();
700  };
701 
702  owner_ptr->subdevices[subdevice_index].callback(byte_buffer, continuation);
703  }
704  }
705  }
706 
707  if (auto owner_ptr_new = owner.lock())
708  {
709  auto hr = owner_ptr_new->subdevices[subdevice_index].mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL);
710  switch (hr)
711  {
712  case S_OK: break;
713  case MF_E_INVALIDREQUEST: LOG_ERROR("ReadSample returned MF_E_INVALIDREQUEST"); break;
714  case MF_E_INVALIDSTREAMNUMBER: LOG_ERROR("ReadSample returned MF_E_INVALIDSTREAMNUMBER"); break;
715  case MF_E_NOTACCEPTING: LOG_ERROR("ReadSample returned MF_E_NOTACCEPTING"); break;
716  case E_INVALIDARG: LOG_ERROR("ReadSample returned E_INVALIDARG"); break;
717  case MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED: LOG_ERROR("ReadSample returned MF_E_VIDEO_RECORDING_DEVICE_INVALIDATED"); break;
718  default: LOG_ERROR("ReadSample returned HRESULT " << std::hex << (uint32_t)hr); break;
719  }
720  if (hr != S_OK) streaming = false;
721  }
722  }
723  return S_OK;
724  }
725 
727  // device //
729 
730  int get_vendor_id(const device & device) { return device.vid; }
731  int get_product_id(const device & device) { return device.pid; }
732 
733  void get_control(const device & device, const extension_unit & xu, uint8_t ctrl, void *data, int len)
734  {
735  auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
736 
737  KSP_NODE node;
738  memset(&node, 0, sizeof(KSP_NODE));
739  node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
740  node.Property.Id = ctrl;
741  node.Property.Flags = KSPROPERTY_TYPE_GET | KSPROPERTY_TYPE_TOPOLOGY;
742  node.NodeId = xu.node;
743 
744  ULONG bytes_received = 0;
745  check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(node), data, len, &bytes_received));
746  if(bytes_received != len) throw std::runtime_error("XU read did not return enough data");
747  }
748 
749  void set_control(device & device, const extension_unit & xu, uint8_t ctrl, void *data, int len)
750  {
751  auto ks_control = device.get_ks_control(xu);
752 
753  KSP_NODE node;
754  memset(&node, 0, sizeof(KSP_NODE));
755  node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
756  node.Property.Id = ctrl;
757  node.Property.Flags = KSPROPERTY_TYPE_SET | KSPROPERTY_TYPE_TOPOLOGY;
758  node.NodeId = xu.node;
759 
760  ULONG bytes_received = 0;
761  check("IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node, sizeof(KSP_NODE), data, len, &bytes_received));
762  }
763 
764  void claim_interface(device & device, const guid & interface_guid, int interface_number)
765  {
766  device.open_win_usb(device.vid, device.pid, device.unique_id, interface_guid, interface_number);
767  device.claimed_interfaces.push_back(interface_number);
768  }
769 
770  void claim_aux_interface(device & device, const guid & interface_guid, int interface_number)
771  {
772  device.open_win_usb(device.aux_vid, device.aux_pid, device.aux_unique_id, interface_guid, interface_number);
773  device.claimed_interfaces.push_back(interface_number);
774  }
775 
776  void bulk_transfer(device & device, uint8_t endpoint, void * data, int length, int *actual_length, unsigned int timeout)
777  {
778  if(USB_ENDPOINT_DIRECTION_OUT(endpoint))
779  {
780  device.usb_synchronous_write(endpoint, data, length, timeout);
781  }
782 
783  if(USB_ENDPOINT_DIRECTION_IN(endpoint))
784  {
785  device.usb_synchronous_read(endpoint, data, length, actual_length, timeout);
786  }
787  }
788 
789  void set_subdevice_mode(device & device, int subdevice_index, int width, int height, uint32_t fourcc, int fps, video_channel_callback callback)
790  {
791  auto & sub = device.subdevices[subdevice_index];
792 
793  if(!sub.mf_source_reader)
794  {
795  com_ptr<IMFAttributes> pAttributes;
796  check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1));
797  check("IMFAttributes::SetUnknown", pAttributes->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, static_cast<IUnknown *>(sub.reader_callback)));
798  check("MFCreateSourceReaderFromMediaSource", MFCreateSourceReaderFromMediaSource(sub.get_media_source(), pAttributes, &sub.mf_source_reader));
799  }
800 
801  for (DWORD j = 0; ; j++)
802  {
803  com_ptr<IMFMediaType> media_type;
804  HRESULT hr = sub.mf_source_reader->GetNativeMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, j, &media_type);
805  if (hr == MF_E_NO_MORE_TYPES) break;
806  check("IMFSourceReader::GetNativeMediaType", hr);
807 
808  UINT32 uvc_width, uvc_height, uvc_fps_num, uvc_fps_denom; GUID subtype;
809  check("MFGetAttributeSize", MFGetAttributeSize(media_type, MF_MT_FRAME_SIZE, &uvc_width, &uvc_height));
810  if(uvc_width != width || uvc_height != height) continue;
811 
812  check("IMFMediaType::GetGUID", media_type->GetGUID(MF_MT_SUBTYPE, &subtype));
813  uint32_t device_fourcc = reinterpret_cast<const big_endian<uint32_t> &>(subtype.Data1);
814  if ((device_fourcc != fourcc) && (!fourcc_map.count(device_fourcc) || (fourcc != fourcc_map.at(device_fourcc)))) continue;
815 
816  check("MFGetAttributeRatio", MFGetAttributeRatio(media_type, MF_MT_FRAME_RATE, &uvc_fps_num, &uvc_fps_denom));
817  if(uvc_fps_denom == 0) continue;
818  int uvc_fps = uvc_fps_num / uvc_fps_denom;
819  if(std::abs(fps - uvc_fps) > 1) continue;
820 
821  check("IMFSourceReader::SetCurrentMediaType", sub.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type));
822  sub.callback = callback;
823  return;
824  }
825  throw std::runtime_error(to_string() << "no matching media type for pixel format " << std::hex << fourcc);
826  }
827 
828  void set_subdevice_data_channel_handler(device & device, int subdevice_index, data_channel_callback callback)
829  {
830  device.subdevices[subdevice_index].set_data_channel_cfg(callback);
831  }
832 
833  void start_streaming(device & device, int num_transfer_bufs) { device.start_streaming(); }
834  void stop_streaming(device & device) { device.stop_streaming(); }
835 
836  void start_data_acquisition(device & device)
837  {
838  device.start_data_acquisition();
839  }
840 
841  void stop_data_acquisition(device & device)
842  {
843  device.stop_data_acquisition();
844  }
845 
846  struct pu_control { rs_option option; long property; bool enable_auto; };
847  static const pu_control pu_controls[] = {
848  {RS_OPTION_COLOR_BACKLIGHT_COMPENSATION, VideoProcAmp_BacklightCompensation},
849  {RS_OPTION_COLOR_BRIGHTNESS, VideoProcAmp_Brightness},
850  {RS_OPTION_COLOR_CONTRAST, VideoProcAmp_Contrast},
851  {RS_OPTION_COLOR_GAIN, VideoProcAmp_Gain},
852  {RS_OPTION_COLOR_GAMMA, VideoProcAmp_Gamma},
853  {RS_OPTION_COLOR_HUE, VideoProcAmp_Hue},
854  {RS_OPTION_COLOR_SATURATION, VideoProcAmp_Saturation},
855  {RS_OPTION_COLOR_SHARPNESS, VideoProcAmp_Sharpness},
856  {RS_OPTION_COLOR_WHITE_BALANCE, VideoProcAmp_WhiteBalance},
857  {RS_OPTION_COLOR_ENABLE_AUTO_WHITE_BALANCE, VideoProcAmp_WhiteBalance, true},
858  {RS_OPTION_FISHEYE_GAIN, VideoProcAmp_Gain}
859  };
860 
861  void set_pu_control(device & device, int subdevice, rs_option option, int value)
862  {
863  auto & sub = device.subdevices[subdevice];
864  sub.get_media_source();
865  if (option == RS_OPTION_COLOR_EXPOSURE)
866  {
867  check("IAMCameraControl::Set", sub.am_camera_control->Set(CameraControl_Exposure, static_cast<int>(value), CameraControl_Flags_Manual));
868  return;
869  }
871  {
872  if(value) check("IAMCameraControl::Set", sub.am_camera_control->Set(CameraControl_Exposure, 0, CameraControl_Flags_Auto));
873  else
874  {
875  long min, max, step, def, caps;
876  check("IAMCameraControl::GetRange", sub.am_camera_control->GetRange(CameraControl_Exposure, &min, &max, &step, &def, &caps));
877  check("IAMCameraControl::Set", sub.am_camera_control->Set(CameraControl_Exposure, def, CameraControl_Flags_Manual));
878  }
879  return;
880  }
881  for(auto & pu : pu_controls)
882  {
883  if(option == pu.option)
884  {
885  if(pu.enable_auto)
886  {
887  if(value) check("IAMVideoProcAmp::Set", sub.am_video_proc_amp->Set(pu.property, 0, VideoProcAmp_Flags_Auto));
888  else
889  {
890  long min, max, step, def, caps;
891  check("IAMVideoProcAmp::GetRange", sub.am_video_proc_amp->GetRange(pu.property, &min, &max, &step, &def, &caps));
892  check("IAMVideoProcAmp::Set", sub.am_video_proc_amp->Set(pu.property, def, VideoProcAmp_Flags_Manual));
893  }
894  }
895  else check("IAMVideoProcAmp::Set", sub.am_video_proc_amp->Set(pu.property, value, VideoProcAmp_Flags_Manual));
896  return;
897  }
898  }
899  throw std::runtime_error("unsupported control");
900  }
901 
902  void get_pu_control_range(const device & device, int subdevice, rs_option option, int * min, int * max, int * step, int * def)
903  {
905  {
906  if(min) *min = 0;
907  if(max) *max = 1;
908  if(step) *step = 1;
909  if(def) *def = 1;
910  return;
911  }
912 
913  auto & sub = device.subdevices[subdevice];
914  const_cast<uvc::subdevice &>(sub).get_media_source();
915  long minVal=0, maxVal=0, steppingDelta=0, defVal=0, capsFlag=0;
916  if (option == RS_OPTION_COLOR_EXPOSURE)
917  {
918  check("IAMCameraControl::Get", sub.am_camera_control->GetRange(CameraControl_Exposure, &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag));
919  if (min) *min = minVal;
920  if (max) *max = maxVal;
921  if (step) *step = steppingDelta;
922  if (def) *def = defVal;
923  return;
924  }
925  for(auto & pu : pu_controls)
926  {
927  if(option == pu.option)
928  {
929  check("IAMVideoProcAmp::GetRange", sub.am_video_proc_amp->GetRange(pu.property, &minVal, &maxVal, &steppingDelta, &defVal, &capsFlag));
930  if(min) *min = static_cast<int>(minVal);
931  if(max) *max = static_cast<int>(maxVal);
932  if(step) *step = static_cast<int>(steppingDelta);
933  if(def) *def = static_cast<int>(defVal);
934  return;
935  }
936  }
937  throw std::runtime_error("unsupported control");
938  }
939 
940  void get_extension_control_range(const device & device, const extension_unit & xu, char control , int * min, int * max, int * step, int * def)
941  {
942  auto ks_control = const_cast<uvc::device &>(device).get_ks_control(xu);
943 
944  /* get step, min and max values*/
945  KSP_NODE node;
946  memset(&node, 0, sizeof(KSP_NODE));
947  node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
948  node.Property.Id = control;
949  node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
950  node.NodeId = xu.node;
951 
952  KSPROPERTY_DESCRIPTION description;
953  unsigned long bytes_received = 0;
954  check("IKsControl::KsProperty", ks_control->KsProperty(
955  (PKSPROPERTY)&node,
956  sizeof(node),
957  &description,
958  sizeof(KSPROPERTY_DESCRIPTION),
959  &bytes_received));
960 
961  unsigned long size = description.DescriptionSize;
962  std::vector<BYTE> buffer((long)size);
963 
964  check("IKsControl::KsProperty", ks_control->KsProperty(
965  (PKSPROPERTY)&node,
966  sizeof(node),
967  buffer.data(),
968  size,
969  &bytes_received));
970 
971  if (bytes_received != size) { throw std::runtime_error("wrong data"); }
972 
973  BYTE * pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
974 
975  *step = (int)*pRangeValues;
976  pRangeValues++;
977  *min = (int)*pRangeValues;
978  pRangeValues++;
979  *max = (int)*pRangeValues;
980 
981 
982  /* get def value*/
983  memset(&node, 0, sizeof(KSP_NODE));
984  node.Property.Set = reinterpret_cast<const GUID &>(xu.id);
985  node.Property.Id = control;
986  node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY;
987  node.NodeId = xu.node;
988 
989  bytes_received = 0;
990  check("IKsControl::KsProperty", ks_control->KsProperty(
991  (PKSPROPERTY)&node,
992  sizeof(node),
993  &description,
994  sizeof(KSPROPERTY_DESCRIPTION),
995  &bytes_received));
996 
997  size = description.DescriptionSize;
998  buffer.clear();
999  buffer.resize(size);
1000 
1001  check("IKsControl::KsProperty", ks_control->KsProperty(
1002  (PKSPROPERTY)&node,
1003  sizeof(node),
1004  buffer.data(),
1005  size,
1006  &bytes_received));
1007 
1008  if (bytes_received != size) { throw std::runtime_error("wrong data"); }
1009 
1010  pRangeValues = buffer.data() + sizeof(KSPROPERTY_MEMBERSHEADER) + sizeof(KSPROPERTY_DESCRIPTION);
1011 
1012  *def = (int)*pRangeValues;
1013  }
1014 
1015  int get_pu_control(const device & device, int subdevice, rs_option option)
1016  {
1017  auto & sub = device.subdevices[subdevice];
1018  // first call to get_media_source is also initializing the am_camera_control pointer, required for this method
1019  const_cast<uvc::subdevice &>(sub).get_media_source(); // initialize am_camera_control
1020  long value=0, flags=0;
1021  if (option == RS_OPTION_COLOR_EXPOSURE)
1022  {
1023  // am_camera_control != null, because get_media_source was called at least once
1024  check("IAMCameraControl::Get", sub.am_camera_control->Get(CameraControl_Exposure, &value, &flags));
1025  return value;
1026  }
1028  {
1029  check("IAMCameraControl::Get", sub.am_camera_control->Get(CameraControl_Exposure, &value, &flags));
1030  return flags == CameraControl_Flags_Auto;
1031  }
1032  for(auto & pu : pu_controls)
1033  {
1034  if(option == pu.option)
1035  {
1036  check("IAMVideoProcAmp::Get", sub.am_video_proc_amp->Get(pu.property, &value, &flags));
1037  if(pu.enable_auto) return flags == VideoProcAmp_Flags_Auto;
1038  else return value;
1039  }
1040  }
1041  throw std::runtime_error("unsupported control");
1042  }
1043 
1045  // context //
1047 
1048  std::shared_ptr<context> create_context()
1049  {
1050  return std::make_shared<context>();
1051  }
1052 
1053  bool is_device_connected(device & device, int vid, int pid)
1054  {
1055  for(auto& dev : device.subdevices)
1056  {
1057  if(dev.vid == vid && dev.pid == pid)
1058  return true;
1059  }
1060 
1061  return false;
1062  }
1063 
1064  std::vector<std::shared_ptr<device>> query_devices(std::shared_ptr<context> context)
1065  {
1066  IMFAttributes * pAttributes = NULL;
1067  check("MFCreateAttributes", MFCreateAttributes(&pAttributes, 1));
1068  check("IMFAttributes::SetGUID", pAttributes->SetGUID(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID));
1069 
1070  IMFActivate ** ppDevices;
1071  UINT32 numDevices;
1072  check("MFEnumDeviceSources", MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices));
1073 
1074  std::vector<std::shared_ptr<device>> devices;
1075  for(UINT32 i=0; i<numDevices; ++i)
1076  {
1077  com_ptr<IMFActivate> pDevice;
1078  *&pDevice = ppDevices[i];
1079 
1080  WCHAR * wchar_name = NULL; UINT32 length;
1081  pDevice->GetAllocatedString(MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &wchar_name, &length);
1082  auto name = win_to_utf(wchar_name);
1083  CoTaskMemFree(wchar_name);
1084 
1085  int vid, pid, mi; std::string unique_id;
1086  if(!parse_usb_path(vid, pid, mi, unique_id, name)) continue;
1087 
1088  std::shared_ptr<device> dev;
1089  for(auto & d : devices)
1090  {
1091  if(d->vid == vid && d->pid == pid && d->unique_id == unique_id)
1092  {
1093  dev = d;
1094  }
1095  }
1096  if(!dev)
1097  {
1098  dev = std::make_shared<device>(context, vid, pid, unique_id);
1099  devices.push_back(dev);
1100  }
1101 
1102  size_t subdevice_index = mi/2;
1103  if(subdevice_index >= dev->subdevices.size()) dev->subdevices.resize(subdevice_index+1);
1104 
1105  dev->subdevices[subdevice_index].reader_callback = new reader_callback(dev, static_cast<int>(subdevice_index));
1106  dev->subdevices[subdevice_index].mf_activate = pDevice;
1107  dev->subdevices[subdevice_index].vid = vid;
1108  dev->subdevices[subdevice_index].pid = pid;
1109  }
1110 
1111  for(auto& devA : devices) // Look for CX3 Fisheye camera
1112  {
1113  if(devA->vid == VID_INTEL_CAMERA && devA->pid == ZR300_FISHEYE_PID)
1114  {
1115  for(auto& devB : devices) // Look for DS ZR300 camera
1116  {
1117  if(devB->vid == VID_INTEL_CAMERA && devB->pid == ZR300_CX3_PID)
1118  {
1119  devB->subdevices.resize(4);
1120  devB->subdevices[3].reader_callback = new reader_callback(devB, static_cast<int>(3));
1121  devB->subdevices[3].mf_activate = devA->subdevices[0].mf_activate;
1122  devB->subdevices[3].vid = devB->aux_vid = VID_INTEL_CAMERA;
1123  devB->subdevices[3].pid = devB->aux_pid = ZR300_FISHEYE_PID;
1124  devB->aux_unique_id = devA->unique_id;
1125  devices.erase(std::remove(devices.begin(), devices.end(), devA), devices.end());
1126  break;
1127  }
1128  }
1129  break;
1130  }
1131  }
1132 
1133  CoTaskMemFree(ppDevices);
1134  return devices;
1135  }
1136 
1137  std::wstring getPath(HANDLE h, ULONG index)
1138  {
1139  // get name length
1140  USB_NODE_CONNECTION_NAME name;
1141  name.ConnectionIndex = index;
1142  if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, &name, sizeof(name), &name, sizeof(name), nullptr, nullptr))
1143  {
1144  return std::wstring(L"");
1145  }
1146 
1147  // alloc space
1148  if (name.ActualLength < sizeof(name)) return std::wstring(L"");
1149  auto alloc = std::malloc(name.ActualLength);
1150  auto pName = std::shared_ptr<USB_NODE_CONNECTION_NAME>(reinterpret_cast<USB_NODE_CONNECTION_NAME *>(alloc), std::free);
1151 
1152  // get name
1153  pName->ConnectionIndex = index;
1154  if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, pName.get(), name.ActualLength, pName.get(), name.ActualLength, nullptr, nullptr))
1155  {
1156  return std::wstring(pName->NodeName);
1157  }
1158 
1159  return std::wstring(L"");
1160  }
1161 
1162  bool handleNode(const std::wstring & targetKey, HANDLE h, ULONG index)
1163  {
1164  USB_NODE_CONNECTION_DRIVERKEY_NAME key;
1165  key.ConnectionIndex = index;
1166 
1167  if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &key, sizeof(key), &key, sizeof(key), nullptr, nullptr))
1168  {
1169  return false;
1170  }
1171 
1172  if (key.ActualLength < sizeof(key)) return false;
1173 
1174  auto alloc = std::malloc(key.ActualLength);
1175  if (!alloc) throw std::bad_alloc();
1176  auto pKey = std::shared_ptr<USB_NODE_CONNECTION_DRIVERKEY_NAME>(reinterpret_cast<USB_NODE_CONNECTION_DRIVERKEY_NAME *>(alloc), std::free);
1177 
1178  pKey->ConnectionIndex = index;
1179  if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, pKey.get(), key.ActualLength, pKey.get(), key.ActualLength, nullptr, nullptr))
1180  {
1181  //std::wcout << pKey->DriverKeyName << std::endl;
1182  if (targetKey == pKey->DriverKeyName) {
1183  return true;
1184  }
1185  else return false;
1186  }
1187 
1188  return false;
1189  }
1190 
1191  std::string handleHub(const std::wstring & targetKey, const std::wstring & path)
1192  {
1193  if (path == L"") return "";
1194  std::wstring fullPath = L"\\\\.\\" + path;
1195 
1196  HANDLE h = CreateFile(fullPath.c_str(), GENERIC_WRITE, FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
1197  if (h == INVALID_HANDLE_VALUE) return "";
1198  auto h_gc = std::shared_ptr<void>(h, CloseHandle);
1199 
1200  USB_NODE_INFORMATION info;
1201  if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_INFORMATION, &info, sizeof(info), &info, sizeof(info), nullptr, nullptr))
1202  return "";
1203 
1204  // for each port on the hub
1205  for (ULONG i = 1; i <= info.u.HubInformation.HubDescriptor.bNumberOfPorts; ++i)
1206  {
1207  // allocate something or other
1208  char buf[sizeof(USB_NODE_CONNECTION_INFORMATION_EX)] = { 0 };
1209  PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)buf;
1210 
1211  // get info about port i
1212  pConInfo->ConnectionIndex = i;
1213  if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, pConInfo, sizeof(buf), pConInfo, sizeof(buf), nullptr, nullptr))
1214  {
1215  continue;
1216  }
1217 
1218  // check if device is connected
1219  if (pConInfo->ConnectionStatus != DeviceConnected)
1220  {
1221  continue; // almost assuredly silently. I think this flag gets set for any port without a device
1222  }
1223 
1224  // if connected, handle correctly, setting the location info if the device is found
1225  std::string ret = "";
1226  if (pConInfo->DeviceIsHub) ret = handleHub(targetKey, getPath(h, i));
1227  else
1228  {
1229  if (handleNode(targetKey, h, i))
1230  {
1231  ret = win_to_utf(fullPath.c_str()) + " " + std::to_string(i);
1232  }
1233  }
1234  if (ret != "") return ret;
1235  }
1236 
1237  return "";
1238  }
1239 
1240  std::string get_usb_port_id(const device & device) // Not implemented for Windows at this point
1241  {
1242  SP_DEVINFO_DATA devInfo = { sizeof(SP_DEVINFO_DATA) };
1243  static_assert(sizeof(guid) == sizeof(GUID), "struct packing error"); // not sure this is needed. maybe because the original function gets the guid object from outside?
1244 
1245  // build a device info represent all imaging devices.
1246  HDEVINFO device_info = SetupDiGetClassDevsEx((const GUID *)&GUID_DEVINTERFACE_IMAGE,
1247  nullptr,
1248  nullptr,
1249  DIGCF_PRESENT,
1250  nullptr,
1251  nullptr,
1252  nullptr);
1253  if (device_info == INVALID_HANDLE_VALUE) throw std::runtime_error("SetupDiGetClassDevs");
1254  auto di = std::shared_ptr<void>(device_info, SetupDiDestroyDeviceInfoList);
1255 
1256  // enumerate all imaging devices.
1257  for (int member_index = 0; ; ++member_index)
1258  {
1259  SP_DEVICE_INTERFACE_DATA interfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
1260  unsigned long buf_size = 0;
1261 
1262  if (SetupDiEnumDeviceInfo(device_info, member_index, &devInfo) == FALSE)
1263  {
1264  if (GetLastError() == ERROR_NO_MORE_ITEMS) break; // stop when none left
1265  continue; // silently ignore other errors
1266  }
1267 
1268  // get the device ID of current device.
1269  if (CM_Get_Device_ID_Size(&buf_size, devInfo.DevInst, 0) != CR_SUCCESS)
1270  {
1271  LOG_ERROR("CM_Get_Device_ID_Size failed");
1272  return "";
1273  }
1274 
1275  auto alloc = std::malloc(buf_size * sizeof(WCHAR) + sizeof(WCHAR));
1276  if (!alloc) throw std::bad_alloc();
1277  auto pInstID = std::shared_ptr<WCHAR>(reinterpret_cast<WCHAR *>(alloc), std::free);
1278  if (CM_Get_Device_ID(devInfo.DevInst, pInstID.get(), buf_size * sizeof(WCHAR) + sizeof(WCHAR), 0) != CR_SUCCESS) {
1279  LOG_ERROR("CM_Get_Device_ID failed");
1280  return "";
1281  }
1282 
1283  if (pInstID == nullptr) continue;
1284 
1285  // Check if this is our device
1286  int usb_vid, usb_pid, usb_mi; std::string usb_unique_id;
1287  if (!parse_usb_path_from_device_id(usb_vid, usb_pid, usb_mi, usb_unique_id, std::string(win_to_utf(pInstID.get())))) continue;
1288  if (usb_vid != device.vid || usb_pid != device.pid || /* usb_mi != device->mi || */ usb_unique_id != device.unique_id) continue;
1289 
1290  // get parent (composite device) instance
1291  DEVINST instance;
1292  if (CM_Get_Parent(&instance, devInfo.DevInst, 0) != CR_SUCCESS)
1293  {
1294  LOG_ERROR("CM_Get_Parent failed");
1295  return "";
1296  }
1297 
1298  // get composite device instance id
1299  if (CM_Get_Device_ID_Size(&buf_size, instance, 0) != CR_SUCCESS)
1300  {
1301  LOG_ERROR("CM_Get_Device_ID_Size failed");
1302  return "";
1303  }
1304  alloc = std::malloc(buf_size*sizeof(WCHAR) + sizeof(WCHAR));
1305  if (!alloc) throw std::bad_alloc();
1306  pInstID = std::shared_ptr<WCHAR>(reinterpret_cast<WCHAR *>(alloc), std::free);
1307  if (CM_Get_Device_ID(instance, pInstID.get(), buf_size * sizeof(WCHAR) + sizeof(WCHAR), 0) != CR_SUCCESS) {
1308  LOG_ERROR("CM_Get_Device_ID failed");
1309  return "";
1310  }
1311 
1312  // upgrade to DEVINFO_DATA for SetupDiGetDeviceRegistryProperty
1313  device_info = SetupDiGetClassDevs(nullptr, pInstID.get(), nullptr, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE | DIGCF_ALLCLASSES);
1314  if (device_info == INVALID_HANDLE_VALUE) {
1315  LOG_ERROR("SetupDiGetClassDevs failed");
1316  return "";
1317  }
1318  auto di_gc = std::shared_ptr<void>(device_info, SetupDiDestroyDeviceInfoList);
1319 
1320  interfaceData = { sizeof(SP_DEVICE_INTERFACE_DATA) };
1321  if (SetupDiEnumDeviceInterfaces(device_info, nullptr, &GUID_DEVINTERFACE_USB_DEVICE, 0, &interfaceData) == FALSE)
1322  {
1323  LOG_ERROR("SetupDiEnumDeviceInterfaces failed");
1324  return "";
1325  }
1326 
1327  // get the SP_DEVICE_INTERFACE_DETAIL_DATA object, and also grab the SP_DEVINFO_DATA object for the device
1328  buf_size = 0;
1329  SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData, nullptr, 0, &buf_size, nullptr);
1330  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1331  {
1332  LOG_ERROR("SetupDiGetDeviceInterfaceDetail failed");
1333  return "";
1334  }
1335  alloc = std::malloc(buf_size);
1336  if (!alloc) throw std::bad_alloc();
1337  auto detail_data = std::shared_ptr<SP_DEVICE_INTERFACE_DETAIL_DATA>(reinterpret_cast<SP_DEVICE_INTERFACE_DETAIL_DATA *>(alloc), std::free);
1338  detail_data->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
1339  SP_DEVINFO_DATA parent_data = { sizeof(SP_DEVINFO_DATA) };
1340  if (!SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData, detail_data.get(), buf_size, nullptr, &parent_data))
1341  {
1342  LOG_ERROR("SetupDiGetDeviceInterfaceDetail failed");
1343  return "";
1344  }
1345 
1346  // get driver key for composite device
1347  buf_size = 0;
1348  SetupDiGetDeviceRegistryProperty(device_info, &parent_data, SPDRP_DRIVER, nullptr, nullptr, 0, &buf_size);
1349  if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1350  {
1351  LOG_ERROR("SetupDiGetDeviceRegistryProperty failed in an unexpected manner");
1352  return "";
1353  }
1354  alloc = std::malloc(buf_size);
1355  if (!alloc) throw std::bad_alloc();
1356  auto driver_key = std::shared_ptr<BYTE>(reinterpret_cast<BYTE*>(alloc), std::free);
1357  if (!SetupDiGetDeviceRegistryProperty(device_info, &parent_data, SPDRP_DRIVER, nullptr, driver_key.get(), buf_size, nullptr))
1358  {
1359  LOG_ERROR("SetupDiGetDeviceRegistryProperty failed");
1360  return "";
1361  }
1362 
1363  // contains composite device key
1364  std::wstring targetKey(reinterpret_cast<const wchar_t*>(driver_key.get()));
1365 
1366  // recursively check all hubs, searching for composite device
1367  std::wstringstream buf;
1368  for (int i = 0;; i++)
1369  {
1370  buf << "\\\\.\\HCD" << i;
1371  std::wstring hcd = buf.str();
1372 
1373  // grab handle
1374  HANDLE h = CreateFile(hcd.c_str(), GENERIC_WRITE | GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, nullptr, OPEN_EXISTING, 0, nullptr);
1375  auto h_gc = std::shared_ptr<void>(h, CloseHandle);
1376  if (h == INVALID_HANDLE_VALUE)
1377  {
1378  LOG_ERROR("CreateFile failed");
1379  break;
1380  }
1381  else
1382  {
1383  USB_ROOT_HUB_NAME name;
1384 
1385  // get required space
1386  if (!DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, &name, sizeof(name), nullptr, nullptr)) {
1387  LOG_ERROR("DeviceIoControl failed");
1388  return ""; // alt: fail silently and hope its on a different root hub
1389  }
1390 
1391  // alloc space
1392  alloc = std::malloc(name.ActualLength);
1393  if (!alloc) throw std::bad_alloc();
1394  auto pName = std::shared_ptr<USB_ROOT_HUB_NAME>(reinterpret_cast<USB_ROOT_HUB_NAME *>(alloc), std::free);
1395 
1396  // get name
1397  if (!DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME, nullptr, 0, pName.get(), name.ActualLength, nullptr, nullptr)) {
1398  LOG_ERROR("DeviceIoControl failed");
1399  return ""; // alt: fail silently and hope its on a different root hub
1400  }
1401 
1402  // return location if device is connected under this root hub
1403  std::string ret = handleHub(targetKey, std::wstring(pName->RootHubName));
1404  if (ret != "") return ret;
1405  }
1406  }
1407  }
1408  throw std::exception("could not find camera in windows device tree");
1409  }
1410  }
1411 }
1412 
1413 #endif
std::shared_ptr< context > create_context()
void get_pu_control_range(const device &device, int subdevice, rs_option option, int *min, int *max, int *step, int *def)
void claim_aux_interface(device &device, const guid &interface_guid, int interface_number)
void set_subdevice_mode(device &device, int subdevice_index, int width, int height, uint32_t fourcc, int fps, video_channel_callback callback)
GLint GLint GLsizei GLsizei height
Definition: glext.h:112
GLenum GLenum GLsizei void * table
Definition: glext.h:2715
float3 operator*(const float3 &a, float b)
Definition: types.h:115
bool is_device_connected(device &device, int vid, int pid)
GLsizei const GLchar *const * path
Definition: glext.h:4034
const uint16_t VID_INTEL_CAMERA
Definition: uvc.h:14
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
GLsizei const GLchar *const * string
Definition: glext.h:683
int numDevices
Definition: wglext.h:802
GLenum GLuint GLenum GLsizei const GLchar * buf
Definition: glext.h:2479
Definition: archive.h:12
rs_option
Defines general configuration controls.
Definition: rs.h:128
GLbitfield GLuint64 timeout
Definition: glext.h:1481
std::string get_usb_port_id(const device &device)
GLbitfield flags
Definition: glext.h:1478
GLfloat GLfloat GLfloat GLfloat h
Definition: glext.h:1944
const uint16_t ZR300_FISHEYE_PID
Definition: uvc.h:16
GLuint * ids
Definition: glext.h:520
GLuint buffer
Definition: glext.h:528
std::function< void(const unsigned char *data, const int size)> data_channel_callback
Definition: uvc.h:57
GLenum GLsizei len
Definition: glext.h:3213
GLenum GLint ref
Definition: glext.h:652
GLuint GLenum option
Definition: glext.h:5581
void set_subdevice_data_channel_handler(device &device, int subdevice_index, data_channel_callback callback)
#define LOG_DEBUG(...)
Definition: types.h:77
void start_streaming(device &device, int num_transfer_bufs)
GLuint index
Definition: glext.h:655
GLuint GLuint GLsizei count
Definition: glext.h:111
void start_data_acquisition(device &device)
void get_extension_control_range(const device &device, const extension_unit &xu, char control, int *min, int *max, int *step, int *def)
GLuint GLuint end
Definition: glext.h:111
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
#define unknown
Definition: types.cpp:15
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * data
Definition: glext.h:223
void stop_streaming(device &device)
typedef BOOL(WINAPI *PFNWGLSAVEBUFFERREGIONARBPROC)(HANDLE hRegion
GLsizei const GLfloat * value
Definition: glext.h:693
const uint16_t ZR300_CX3_PID
Definition: uvc.h:15
#define LOG_INFO(...)
Definition: types.h:78
void claim_interface(device &device, const guid &interface_guid, int interface_number)
int get_pu_control(const device &device, int subdevice, rs_option option)
int get_product_id(const device &device)
void bulk_transfer(device &device, unsigned char endpoint, void *data, int length, int *actual_length, unsigned int timeout)
GLdouble s
Definition: glext.h:231
GLint GLint GLsizei width
Definition: glext.h:112
GLuint const GLchar * name
Definition: glext.h:655
void set_control(device &device, const extension_unit &xu, uint8_t ctrl, void *data, int len)
rs_device * dev
GLsizeiptr size
Definition: glext.h:532
std::vector< std::shared_ptr< device > > query_devices(std::shared_ptr< context > context)
GLuint GLsizei GLsizei * length
Definition: glext.h:664
void set_pu_control(device &device, int subdevice, rs_option option, int value)
typedef LPVOID(WINAPI *PFNWGLCREATEIMAGEBUFFERI3DPROC)(HDC hDC
const HANDLE * pEvent
Definition: wglext.h:580
GLuint res
Definition: glext.h:8310
GLuint GLenum GLenum transform
Definition: glext.h:10445
void get_control(const device &device, const extension_unit &xu, uint8_t ctrl, void *data, int len)
int property
Definition: wglext.h:318
void stop_data_acquisition(device &device)
GLfloat GLfloat p
Definition: glext.h:11539
GLdouble GLdouble GLdouble r
Definition: glext.h:247
GLuint64EXT * result
Definition: glext.h:9881
std::function< void(const void *frame, std::function< void()> continuation)> video_channel_callback
Definition: uvc.h:64
#define LOG_ERROR(...)
Definition: types.h:80
int get_vendor_id(const device &device)


librealsense
Author(s): Sergey Dorodnicov , Mark Horn , Reagan Lopez
autogenerated on Fri Mar 13 2020 03:16:18