7 #ifdef RS_USE_WMF_BACKEND 9 #if (_MSC_FULL_VER < 180031101) 10 #error At least Visual Studio 2013 Update 4 is required to compile this backend 22 #include <mfreadwrite.h> 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") 32 #pragma comment(lib, "setupapi.lib") 33 #pragma comment(lib, "winusb.lib") 42 #pragma comment(lib, "cfgmgr32.lib") 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);
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 } };
68 const std::map<uint32_t, uint32_t> fourcc_map = { { 0x59382020, 0x47524559 },
69 { 0x494e5649, 0x59313020 },
70 { 0x494e565a, 0x5a313620 },
71 { 0x52573130, 0x70524141 } };
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());
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());
83 static void check(
const char * call, HRESULT hr)
85 if(FAILED(hr))
throw std::runtime_error(to_string() << call <<
"(...) returned 0x" << std::hex << (uint32_t)hr);
88 template<
class T>
class com_ptr
94 if(p == new_p)
return;
110 com_ptr(T * p) : com_ptr() {
ref(p); }
111 com_ptr(
const com_ptr &
r) : com_ptr(r.p) {}
112 ~com_ptr() { unref(); }
114 operator T * ()
const {
return p; }
116 T * operator -> ()
const {
return p; }
118 T ** operator & () { unref();
return &
p; }
119 com_ptr & operator = (
const com_ptr &
r) {
ref(r.p);
return *
this; }
122 std::vector<std::string> tokenize(
std::string string,
char separator)
124 std::vector<std::string> tokens;
125 std::string::size_type i1 = 0;
128 auto i2 =
string.find(separator, i1);
129 if(i2 == std::string::npos)
131 tokens.push_back(
string.substr(i1));
134 tokens.push_back(
string.substr(i1, i2-i1));
143 auto tokens = tokenize(
name,
'#');
144 if(tokens.size() < 1 || tokens[0] != R
"(\\?\usb)") return false;
145 if(tokens.size() < 3)
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))
154 LOG_ERROR(
"malformed vid string: " << tokens[1]);
158 if(
ids[1].
size() != 8 ||
ids[1].substr(0,4) !=
"pid_" || !(std::istringstream(
ids[1].substr(4,4)) >> std::hex >> pid))
160 LOG_ERROR(
"malformed pid string: " << tokens[1]);
164 if(
ids[2].
size() != 5 ||
ids[2].substr(0,3) !=
"mi_" || !(std::istringstream(
ids[2].substr(3,2)) >> mi))
166 LOG_ERROR(
"malformed mi string: " << tokens[1]);
170 ids = tokenize(tokens[2],
'&');
173 LOG_ERROR(
"malformed id string: " << tokens[2]);
180 bool parse_usb_path_from_device_id(
int & vid,
int & pid,
int & mi,
std::string & unique_id,
const std::string & device_id)
182 auto name = device_id;
184 auto tokens = tokenize(
name,
'\\');
185 if (tokens.size() < 1 || tokens[0] != R
"(usb)") return false;
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))
190 LOG_ERROR(
"malformed vid string: " << tokens[1]);
194 if (
ids[1].
size() != 8 ||
ids[1].substr(0, 4) !=
"pid_" || !(std::istringstream(
ids[1].substr(4, 4)) >> std::hex >> pid))
196 LOG_ERROR(
"malformed pid string: " << tokens[1]);
200 if (
ids[2].
size() != 5 ||
ids[2].substr(0, 3) !=
"mi_" || !(std::istringstream(
ids[2].substr(3, 2)) >> mi))
202 LOG_ERROR(
"malformed mi string: " << tokens[1]);
206 ids = tokenize(tokens[2],
'&');
209 LOG_ERROR(
"malformed id string: " << tokens[2]);
221 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
222 std::this_thread::sleep_for(std::chrono::milliseconds(100));
223 MFStartup(MF_VERSION, MFSTARTUP_NOSOCKET);
232 class reader_callback :
public IMFSourceReaderCallback
234 std::weak_ptr<device> owner;
237 volatile bool streaming =
false;
239 reader_callback(std::weak_ptr<device> owner,
int subdevice_index) : owner(owner), subdevice_index(subdevice_index), ref_count() {}
241 bool is_streaming()
const {
return streaming; }
242 void on_start() { streaming =
true; }
244 #pragma warning( push ) 245 #pragma warning( disable: 4838 ) 247 HRESULT STDMETHODCALLTYPE QueryInterface(REFIID riid,
void ** ppvObject)
override 249 static const QITAB
table[] = {QITABENT(reader_callback, IUnknown), QITABENT(reader_callback, IMFSourceReaderCallback), {0}};
250 return QISearch(
this, table, riid, ppvObject);
252 #pragma warning( pop ) 254 ULONG STDMETHODCALLTYPE AddRef()
override {
return InterlockedIncrement(&ref_count); }
255 ULONG STDMETHODCALLTYPE Release()
override 257 ULONG
count = InterlockedDecrement(&ref_count);
258 if(count == 0)
delete this;
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; }
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;
283 this->channel_data_callback = callback;
286 com_ptr<IMFMediaSource> get_media_source()
290 check(
"IMFActivate::ActivateObject", mf_activate->ActivateObject(__uuidof(IMFMediaSource), (
void **)&mf_media_source));
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");
296 else throw std::runtime_error(to_string() <<
"Invalid media source");
298 return mf_media_source;
302 static bool wait_for_async_operation(WINUSB_INTERFACE_HANDLE interfaceHandle, OVERLAPPED &hOvl, ULONG &lengthTransferred, USHORT
timeout)
304 if (GetOverlappedResult(interfaceHandle, &hOvl, &lengthTransferred, FALSE))
307 auto lastResult = GetLastError();
308 if (lastResult == ERROR_IO_PENDING || lastResult == ERROR_IO_INCOMPLETE)
310 WaitForSingleObject(hOvl.hEvent, timeout);
311 auto res = GetOverlappedResult(interfaceHandle, &hOvl, &lengthTransferred, FALSE);
319 lengthTransferred = 0;
320 WinUsb_ResetPipe(interfaceHandle, 0x84);
330 safe_handle(
HANDLE handle) :_handle(handle)
337 if (_handle !=
nullptr)
339 CloseHandle(_handle);
346 if (_handle ==
nullptr)
return false;
351 bool Wait(DWORD timeout)
const 353 if (_handle ==
nullptr)
return false;
355 return WaitForSingleObject(_handle, timeout) == WAIT_OBJECT_0;
359 HANDLE GetHandle()
const {
return _handle; }
361 safe_handle() =
delete;
364 safe_handle(
const safe_handle&) =
delete;
365 safe_handle& operator=(
const safe_handle&) =
delete;
370 static void poll_interrupts(
HANDLE *handle,
const std::vector<subdevice *> &
subdevices,uint16_t timeout)
372 static const unsigned short interrupt_buf_size = 0x400;
373 uint8_t
buffer[interrupt_buf_size];
376 safe_handle sh(CreateEvent(
nullptr,
false,
false,
nullptr));
377 hOvl.hEvent = sh.GetHandle();
379 int res = WinUsb_ReadPipe(*handle, 0x84, buffer, interrupt_buf_size, &num_bytes, &hOvl);
382 auto lastError = GetLastError();
383 if (lastError == ERROR_IO_PENDING)
385 auto sts = wait_for_async_operation(*handle, hOvl, num_bytes, timeout);
386 lastError = GetLastError();
387 if (lastError == ERROR_OPERATION_ABORTED)
389 perror(
"receiving interrupt_ep bytes failed");
390 fprintf(stderr,
"Error receiving message.\n");
397 WinUsb_ResetPipe(*handle, 0x84);
398 perror(
"receiving interrupt_ep bytes failed");
399 fprintf(stderr,
"Error receiving message.\n");
407 for(
auto & sub : subdevices)
408 if (sub->channel_data_callback)
409 sub->channel_data_callback(buffer, (
unsigned long)num_bytes);
414 perror(
"receiving interrupt_ep bytes failed");
415 fprintf(stderr,
"Error receiving message.\n");
419 IKsControl * get_ks_control(
const uvc::extension_unit & xu)
421 auto it = ks_controls.find(xu.node);
422 if(it !=
end(ks_controls))
return it->second;
427 com_ptr<IKsTopologyInfo> ks_topology_info = NULL;
428 check(
"QueryInterface", mf_media_source->QueryInterface(__uuidof(IKsTopologyInfo), (
void **)&ks_topology_info));
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);
436 check(
"CreateNodeInstance", ks_topology_info->CreateNodeInstance(xu.node, IID_IUnknown, (
LPVOID *)&unknown));
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;
447 const std::shared_ptr<context> parent;
453 HANDLE usb_file_handle = INVALID_HANDLE_VALUE;
454 WINUSB_INTERFACE_HANDLE usb_interface_handle = INVALID_HANDLE_VALUE;
456 std::vector<int> claimed_interfaces;
458 int aux_vid, aux_pid;
460 std::thread data_channel_thread;
461 volatile bool data_stop;
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)
469 IKsControl * get_ks_control(
const uvc::extension_unit & xu)
471 return subdevices[xu.subdevice].get_ks_control(xu);
476 std::vector<subdevice *> data_channel_subs;
477 for (
auto & sub : subdevices)
479 if (sub.channel_data_callback)
481 data_channel_subs.push_back(&sub);
485 if (claimed_interfaces.size())
487 data_channel_thread = std::thread([
this, data_channel_subs]()
492 subdevice::poll_interrupts(&usb_interface_handle, data_channel_subs, 100);
500 if (data_channel_thread.joinable())
503 data_channel_thread.join();
510 for(
auto & sub : subdevices)
512 if(sub.mf_source_reader)
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));
522 for(
auto & sub : subdevices)
524 if(sub.mf_source_reader) sub.mf_source_reader->Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM);
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));
535 for(
auto & sub : subdevices)
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)
543 sub.mf_media_source =
nullptr;
544 check(
"IMFActivate::ShutdownObject", sub.mf_activate->ShutdownObject());
550 com_ptr<IMFMediaSource> get_media_source(
int subdevice_index)
552 return subdevices[subdevice_index].get_media_source();
555 void open_win_usb(
int vid,
int pid,
std::string unique_id,
const guid & interface_guid,
int interface_number)
try 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);
562 for(
int member_index = 0; ; ++member_index)
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)
568 if(GetLastError() == ERROR_NO_MORE_ITEMS)
break;
573 unsigned long detail_data_size = 0;
574 SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData,
nullptr, 0, &detail_data_size,
nullptr);
575 if(GetLastError() != ERROR_INSUFFICIENT_BUFFER)
577 LOG_ERROR(
"SetupDiGetDeviceInterfaceDetail failed");
580 auto alloc = std::malloc(detail_data_size);
581 if(!alloc)
throw std::bad_alloc();
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))
588 LOG_ERROR(
"SetupDiGetDeviceInterfaceDetail failed");
591 if (detail_data->DevicePath ==
nullptr)
continue;
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;
597 HANDLE* file_handle =
nullptr;
598 WINUSB_INTERFACE_HANDLE* usb_handle =
nullptr;
600 file_handle = &usb_file_handle;
601 usb_handle = &usb_interface_handle;
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");
606 if (!WinUsb_Initialize(*file_handle, usb_handle))
608 LOG_ERROR(
"Last Error: " << GetLastError());
609 throw std::runtime_error(
"could not initialize winusb");
615 throw std::runtime_error(
"Unable to open device via WinUSB");
625 if (usb_interface_handle != INVALID_HANDLE_VALUE)
627 WinUsb_Free(usb_interface_handle);
628 usb_interface_handle = INVALID_HANDLE_VALUE;
631 if(usb_file_handle != INVALID_HANDLE_VALUE)
633 CloseHandle(usb_file_handle);
634 usb_file_handle = INVALID_HANDLE_VALUE;
638 bool usb_synchronous_read(uint8_t endpoint,
void * buffer,
int bufferLength,
int * actual_length, DWORD TimeOut)
640 if (usb_interface_handle == INVALID_HANDLE_VALUE)
throw std::runtime_error(
"winusb has not been initialized");
646 ULONG lengthTransferred;
648 bRetVal = WinUsb_ReadPipe(usb_interface_handle, endpoint, (PUCHAR)buffer, bufferLength, &lengthTransferred, NULL);
654 auto lastResult = GetLastError();
655 WinUsb_ResetPipe(usb_interface_handle, endpoint);
659 *actual_length = lengthTransferred;
663 bool usb_synchronous_write(uint8_t endpoint,
void * buffer,
int bufferLength, DWORD TimeOut)
665 if (usb_interface_handle == INVALID_HANDLE_VALUE)
throw std::runtime_error(
"winusb has not been initialized");
670 auto bRetVal = WinUsb_WritePipe(usb_interface_handle, endpoint, (PUCHAR)buffer, bufferLength, &lengthWritten, NULL);
675 auto lastError = GetLastError();
676 WinUsb_ResetPipe(usb_interface_handle, endpoint);
677 LOG_ERROR(
"WinUsb_ReadPipe failure... lastError: " << lastError);
685 HRESULT reader_callback::OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample * sample)
687 if(
auto owner_ptr = owner.lock())
691 com_ptr<IMFMediaBuffer> buffer = NULL;
692 if(SUCCEEDED(sample->GetBufferByIndex(0, &buffer)))
694 BYTE * byte_buffer; DWORD max_length, current_length;
695 if(SUCCEEDED(buffer->Lock(&byte_buffer, &max_length, ¤t_length)))
697 auto continuation = [
buffer,
this]()
702 owner_ptr->subdevices[subdevice_index].callback(byte_buffer, continuation);
707 if (
auto owner_ptr_new = owner.lock())
709 auto hr = owner_ptr_new->subdevices[subdevice_index].mf_source_reader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, NULL, NULL, NULL, NULL);
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;
720 if (hr != S_OK) streaming =
false;
730 int get_vendor_id(
const device & device) {
return device.vid; }
733 void get_control(
const device & device,
const extension_unit & xu, uint8_t ctrl,
void *
data,
int len)
735 auto ks_control =
const_cast<uvc::device &
>(device).get_ks_control(xu);
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;
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");
749 void set_control(device & device,
const extension_unit & xu, uint8_t ctrl,
void *data,
int len)
751 auto ks_control = device.get_ks_control(xu);
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;
760 ULONG bytes_received = 0;
761 check(
"IKsControl::KsProperty", ks_control->KsProperty((PKSPROPERTY)&node,
sizeof(KSP_NODE), data, len, &bytes_received));
764 void claim_interface(device & device,
const guid & interface_guid,
int interface_number)
766 device.open_win_usb(device.vid, device.pid, device.unique_id, interface_guid, interface_number);
767 device.claimed_interfaces.push_back(interface_number);
770 void claim_aux_interface(device & device,
const guid & interface_guid,
int interface_number)
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);
776 void bulk_transfer(device & device, uint8_t endpoint,
void * data,
int length,
int *actual_length,
unsigned int timeout)
778 if(USB_ENDPOINT_DIRECTION_OUT(endpoint))
780 device.usb_synchronous_write(endpoint, data, length, timeout);
783 if(USB_ENDPOINT_DIRECTION_IN(endpoint))
785 device.usb_synchronous_read(endpoint, data, length, actual_length, timeout);
791 auto & sub = device.subdevices[subdevice_index];
793 if(!sub.mf_source_reader)
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));
801 for (DWORD j = 0; ; j++)
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);
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;
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;
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;
821 check(
"IMFSourceReader::SetCurrentMediaType", sub.mf_source_reader->SetCurrentMediaType((DWORD)MF_SOURCE_READER_FIRST_VIDEO_STREAM, NULL, media_type));
822 sub.callback = callback;
825 throw std::runtime_error(to_string() <<
"no matching media type for pixel format " << std::hex << fourcc);
830 device.subdevices[subdevice_index].set_data_channel_cfg(callback);
833 void start_streaming(device & device,
int num_transfer_bufs) { device.start_streaming(); }
838 device.start_data_acquisition();
843 device.stop_data_acquisition();
847 static const pu_control pu_controls[] = {
863 auto & sub = device.subdevices[subdevice];
864 sub.get_media_source();
867 check(
"IAMCameraControl::Set", sub.am_camera_control->Set(CameraControl_Exposure, static_cast<int>(value), CameraControl_Flags_Manual));
872 if(value) check(
"IAMCameraControl::Set", sub.am_camera_control->Set(CameraControl_Exposure, 0, CameraControl_Flags_Auto));
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));
881 for(
auto & pu : pu_controls)
883 if(option == pu.option)
887 if(value) check(
"IAMVideoProcAmp::Set", sub.am_video_proc_amp->Set(pu.property, 0, VideoProcAmp_Flags_Auto));
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));
895 else check(
"IAMVideoProcAmp::Set", sub.am_video_proc_amp->Set(pu.property, value, VideoProcAmp_Flags_Manual));
899 throw std::runtime_error(
"unsupported control");
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;
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;
925 for(
auto & pu : pu_controls)
927 if(option == pu.option)
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);
937 throw std::runtime_error(
"unsupported control");
942 auto ks_control =
const_cast<uvc::device &
>(device).get_ks_control(xu);
946 memset(&node, 0,
sizeof(KSP_NODE));
947 node.Property.Set =
reinterpret_cast<const GUID &
>(xu.id);
949 node.Property.Flags = KSPROPERTY_TYPE_BASICSUPPORT | KSPROPERTY_TYPE_TOPOLOGY;
950 node.NodeId = xu.node;
952 KSPROPERTY_DESCRIPTION description;
953 unsigned long bytes_received = 0;
954 check(
"IKsControl::KsProperty", ks_control->KsProperty(
958 sizeof(KSPROPERTY_DESCRIPTION),
961 unsigned long size = description.DescriptionSize;
962 std::vector<BYTE>
buffer((
long)size);
964 check(
"IKsControl::KsProperty", ks_control->KsProperty(
971 if (bytes_received != size) {
throw std::runtime_error(
"wrong data"); }
973 BYTE * pRangeValues = buffer.data() +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_DESCRIPTION);
975 *step = (
int)*pRangeValues;
977 *min = (
int)*pRangeValues;
979 *max = (
int)*pRangeValues;
983 memset(&node, 0,
sizeof(KSP_NODE));
984 node.Property.Set =
reinterpret_cast<const GUID &
>(xu.id);
986 node.Property.Flags = KSPROPERTY_TYPE_DEFAULTVALUES | KSPROPERTY_TYPE_TOPOLOGY;
987 node.NodeId = xu.node;
990 check(
"IKsControl::KsProperty", ks_control->KsProperty(
994 sizeof(KSPROPERTY_DESCRIPTION),
997 size = description.DescriptionSize;
1001 check(
"IKsControl::KsProperty", ks_control->KsProperty(
1008 if (bytes_received != size) {
throw std::runtime_error(
"wrong data"); }
1010 pRangeValues = buffer.data() +
sizeof(KSPROPERTY_MEMBERSHEADER) +
sizeof(KSPROPERTY_DESCRIPTION);
1012 *def = (
int)*pRangeValues;
1017 auto & sub = device.subdevices[subdevice];
1019 const_cast<uvc::subdevice &
>(sub).get_media_source();
1020 long value=0,
flags=0;
1024 check(
"IAMCameraControl::Get", sub.am_camera_control->Get(CameraControl_Exposure, &value, &
flags));
1029 check(
"IAMCameraControl::Get", sub.am_camera_control->Get(CameraControl_Exposure, &value, &
flags));
1030 return flags == CameraControl_Flags_Auto;
1032 for(
auto & pu : pu_controls)
1034 if(option == pu.option)
1036 check(
"IAMVideoProcAmp::Get", sub.am_video_proc_amp->Get(pu.property, &value, &
flags));
1037 if(pu.enable_auto)
return flags == VideoProcAmp_Flags_Auto;
1041 throw std::runtime_error(
"unsupported control");
1050 return std::make_shared<context>();
1055 for(
auto&
dev : device.subdevices)
1057 if(
dev.vid == vid &&
dev.pid == pid)
1064 std::vector<std::shared_ptr<device>>
query_devices(std::shared_ptr<context> context)
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));
1070 IMFActivate ** ppDevices;
1072 check(
"MFEnumDeviceSources", MFEnumDeviceSources(pAttributes, &ppDevices, &numDevices));
1074 std::vector<std::shared_ptr<device>> devices;
1077 com_ptr<IMFActivate> pDevice;
1078 *&pDevice = ppDevices[i];
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);
1086 if(!parse_usb_path(vid, pid, mi, unique_id,
name))
continue;
1088 std::shared_ptr<device>
dev;
1089 for(
auto & d : devices)
1091 if(d->vid == vid && d->pid == pid && d->unique_id == unique_id)
1098 dev = std::make_shared<device>(context, vid, pid, unique_id);
1099 devices.push_back(dev);
1102 size_t subdevice_index = mi/2;
1103 if(subdevice_index >= dev->subdevices.size()) dev->subdevices.resize(subdevice_index+1);
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;
1111 for(
auto& devA : devices)
1115 for(
auto& devB : devices)
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;
1124 devB->aux_unique_id = devA->unique_id;
1125 devices.erase(std::remove(devices.begin(), devices.end(), devA), devices.end());
1133 CoTaskMemFree(ppDevices);
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))
1144 return std::wstring(L
"");
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);
1153 pName->ConnectionIndex =
index;
1154 if (DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_NAME, pName.get(), name.ActualLength, pName.get(), name.ActualLength,
nullptr,
nullptr))
1156 return std::wstring(pName->NodeName);
1159 return std::wstring(L
"");
1162 bool handleNode(
const std::wstring & targetKey,
HANDLE h, ULONG index)
1164 USB_NODE_CONNECTION_DRIVERKEY_NAME key;
1165 key.ConnectionIndex =
index;
1167 if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_DRIVERKEY_NAME, &key,
sizeof(key), &key,
sizeof(key),
nullptr,
nullptr))
1172 if (key.ActualLength <
sizeof(key))
return false;
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);
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))
1182 if (targetKey == pKey->DriverKeyName) {
1191 std::string handleHub(
const std::wstring & targetKey,
const std::wstring & path)
1193 if (path == L
"")
return "";
1194 std::wstring fullPath = L
"\\\\.\\" +
path;
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);
1200 USB_NODE_INFORMATION
info;
1201 if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_INFORMATION, &info,
sizeof(info), &info,
sizeof(info),
nullptr,
nullptr))
1205 for (ULONG i = 1; i <= info.u.HubInformation.HubDescriptor.bNumberOfPorts; ++i)
1208 char buf[
sizeof(USB_NODE_CONNECTION_INFORMATION_EX)] = { 0 };
1209 PUSB_NODE_CONNECTION_INFORMATION_EX pConInfo = (PUSB_NODE_CONNECTION_INFORMATION_EX)
buf;
1212 pConInfo->ConnectionIndex = i;
1213 if (!DeviceIoControl(h, IOCTL_USB_GET_NODE_CONNECTION_INFORMATION_EX, pConInfo,
sizeof(
buf), pConInfo,
sizeof(
buf),
nullptr,
nullptr))
1219 if (pConInfo->ConnectionStatus != DeviceConnected)
1226 if (pConInfo->DeviceIsHub) ret = handleHub(targetKey, getPath(h, i));
1229 if (handleNode(targetKey, h, i))
1231 ret = win_to_utf(fullPath.c_str()) +
" " + std::to_string(i);
1234 if (ret !=
"")
return ret;
1242 SP_DEVINFO_DATA devInfo = {
sizeof(SP_DEVINFO_DATA) };
1243 static_assert(
sizeof(guid) ==
sizeof(GUID),
"struct packing error");
1246 HDEVINFO device_info = SetupDiGetClassDevsEx((
const GUID *)&GUID_DEVINTERFACE_IMAGE,
1253 if (device_info == INVALID_HANDLE_VALUE)
throw std::runtime_error(
"SetupDiGetClassDevs");
1254 auto di = std::shared_ptr<void>(device_info, SetupDiDestroyDeviceInfoList);
1257 for (
int member_index = 0; ; ++member_index)
1259 SP_DEVICE_INTERFACE_DATA interfaceData = {
sizeof(SP_DEVICE_INTERFACE_DATA) };
1260 unsigned long buf_size = 0;
1262 if (SetupDiEnumDeviceInfo(device_info, member_index, &devInfo) == FALSE)
1264 if (GetLastError() == ERROR_NO_MORE_ITEMS)
break;
1269 if (CM_Get_Device_ID_Size(&buf_size, devInfo.DevInst, 0) != CR_SUCCESS)
1271 LOG_ERROR(
"CM_Get_Device_ID_Size failed");
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) {
1283 if (pInstID ==
nullptr)
continue;
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_unique_id != device.unique_id)
continue;
1292 if (CM_Get_Parent(&instance, devInfo.DevInst, 0) != CR_SUCCESS)
1299 if (CM_Get_Device_ID_Size(&buf_size, instance, 0) != CR_SUCCESS)
1301 LOG_ERROR(
"CM_Get_Device_ID_Size failed");
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) {
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");
1318 auto di_gc = std::shared_ptr<void>(device_info, SetupDiDestroyDeviceInfoList);
1320 interfaceData = {
sizeof(SP_DEVICE_INTERFACE_DATA) };
1321 if (SetupDiEnumDeviceInterfaces(device_info,
nullptr, &GUID_DEVINTERFACE_USB_DEVICE, 0, &interfaceData) == FALSE)
1323 LOG_ERROR(
"SetupDiEnumDeviceInterfaces failed");
1329 SetupDiGetDeviceInterfaceDetail(device_info, &interfaceData,
nullptr, 0, &buf_size,
nullptr);
1330 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1332 LOG_ERROR(
"SetupDiGetDeviceInterfaceDetail failed");
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))
1342 LOG_ERROR(
"SetupDiGetDeviceInterfaceDetail failed");
1348 SetupDiGetDeviceRegistryProperty(device_info, &parent_data, SPDRP_DRIVER,
nullptr,
nullptr, 0, &buf_size);
1349 if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
1351 LOG_ERROR(
"SetupDiGetDeviceRegistryProperty failed in an unexpected manner");
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))
1359 LOG_ERROR(
"SetupDiGetDeviceRegistryProperty failed");
1364 std::wstring targetKey(reinterpret_cast<const wchar_t*>(driver_key.get()));
1367 std::wstringstream
buf;
1368 for (
int i = 0;; i++)
1370 buf <<
"\\\\.\\HCD" << i;
1371 std::wstring hcd = buf.str();
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)
1383 USB_ROOT_HUB_NAME
name;
1386 if (!DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME,
nullptr, 0, &name,
sizeof(name),
nullptr,
nullptr)) {
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);
1397 if (!DeviceIoControl(h, IOCTL_USB_GET_ROOT_HUB_NAME,
nullptr, 0, pName.get(), name.ActualLength,
nullptr,
nullptr)) {
1403 std::string ret = handleHub(targetKey, std::wstring(pName->RootHubName));
1404 if (ret !=
"")
return ret;
1408 throw std::exception(
"could not find camera in windows device tree");
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
GLenum GLenum GLsizei void * table
float3 operator*(const float3 &a, float b)
bool is_device_connected(device &device, int vid, int pid)
GLsizei const GLchar *const * path
const uint16_t VID_INTEL_CAMERA
typedef HANDLE(WINAPI *PFNWGLCREATEBUFFERREGIONARBPROC)(HDC hDC
GLsizei const GLchar *const * string
GLenum GLuint GLenum GLsizei const GLchar * buf
rs_option
Defines general configuration controls.
GLbitfield GLuint64 timeout
std::string get_usb_port_id(const device &device)
GLfloat GLfloat GLfloat GLfloat h
const uint16_t ZR300_FISHEYE_PID
std::function< void(const unsigned char *data, const int size)> data_channel_callback
void set_subdevice_data_channel_handler(device &device, int subdevice_index, data_channel_callback callback)
void start_streaming(device &device, int num_transfer_bufs)
GLuint GLuint GLsizei count
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)
typedef int(WINAPI *PFNWGLRELEASEPBUFFERDCARBPROC)(HPBUFFERARB hPbuffer
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const void * data
void stop_streaming(device &device)
typedef BOOL(WINAPI *PFNWGLSAVEBUFFERREGIONARBPROC)(HANDLE hRegion
GLsizei const GLfloat * value
const uint16_t ZR300_CX3_PID
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)
GLint GLint GLsizei width
GLuint const GLchar * name
void set_control(device &device, const extension_unit &xu, uint8_t ctrl, void *data, int len)
std::vector< std::shared_ptr< device > > query_devices(std::shared_ptr< context > context)
GLuint GLsizei GLsizei * length
void set_pu_control(device &device, int subdevice, rs_option option, int value)
typedef LPVOID(WINAPI *PFNWGLCREATEIMAGEBUFFERI3DPROC)(HDC hDC
GLuint GLenum GLenum transform
void get_control(const device &device, const extension_unit &xu, uint8_t ctrl, void *data, int len)
void stop_data_acquisition(device &device)
GLdouble GLdouble GLdouble r
std::function< void(const void *frame, std::function< void()> continuation)> video_channel_callback
int get_vendor_id(const device &device)