duvc-ctl 2.0.0
USB Video Class Camera Control Library
Loading...
Searching...
No Matches
core.cpp
Go to the documentation of this file.
1#include "duvc-ctl/core.h"
2#include "duvc-ctl/defs.h"
3
4#ifdef _WIN32
5
6#ifndef NOMINMAX
7#define NOMINMAX
8#endif
9
10#include <windows.h>
11#include <dshow.h>
12#include <iostream>
13#include <vector>
14#include <string>
15#include <sstream>
16#include <stdexcept>
17#include <comdef.h>
18#include <strmif.h>
19#include <control.h>
20#include <uuids.h>
21#include <dbt.h>
22#include <ks.h>
23#include <ksproxy.h>
24#include <unordered_map>
25#include <memory>
26#include <mutex>
27
28// Fallback IAMCameraControl (rarely needed but safe)
29#ifndef __AMCAMERACONTROL__
30#define CameraControl_Pan 0L
31#define CameraControl_Tilt 1L
32#define CameraControl_Roll 2L
33#define CameraControl_Zoom 3L
34#define CameraControl_Exposure 4L
35#define CameraControl_Iris 5L
36#define CameraControl_Focus 6L
37#define CameraControl_ScanMode 7L
38#define CameraControl_Privacy 8L
39#define CameraControl_PanRelative 9L
40#define CameraControl_TiltRelative 10L
41#define CameraControl_RollRelative 11L
42#define CameraControl_ZoomRelative 12L
43#define CameraControl_ExposureRelative 13L
44#define CameraControl_IrisRelative 14L
45#define CameraControl_FocusRelative 15L
46#define CameraControl_PanTilt 16L
47#define CameraControl_PanTiltRelative 17L
48#define CameraControl_FocusSimple 18L
49#define CameraControl_DigitalZoom 19L
50#define CameraControl_DigitalZoomRelative 20L
51#define CameraControl_BacklightCompensation 21L
52#define CameraControl_Lamp 22L
53#define CameraControl_Flags_Auto 0x0001
54#define CameraControl_Flags_Manual 0x0002
55#endif
56
57// Fallback IAMVideoProcAmp
58#ifndef __AMVIDEOPROCAMP__
59#define VideoProcAmp_Brightness 0
60#define VideoProcAmp_Contrast 1
61#define VideoProcAmp_Hue 2
62#define VideoProcAmp_Saturation 3
63#define VideoProcAmp_Sharpness 4
64#define VideoProcAmp_Gamma 5
65#define VideoProcAmp_ColorEnable 6
66#define VideoProcAmp_WhiteBalance 7
67#define VideoProcAmp_BacklightCompensation 8
68#define VideoProcAmp_Gain 9
69#define VideoProcAmp_Flags_Auto 0x0001
70#define VideoProcAmp_Flags_Manual 0x0002
71#endif
72
73#ifdef _MSC_VER
74#pragma comment(lib, "ole32.lib")
75#pragma comment(lib, "oleaut32.lib")
76#pragma comment(lib, "strmiids.lib")
77#endif
78
79namespace duvc {
80
81template<typename T>
82class com_ptr {
83public:
86 ~com_ptr() { reset(); }
87
88 com_ptr(const com_ptr&) = delete;
89 com_ptr& operator=(const com_ptr&) = delete;
90
91 com_ptr(com_ptr&& o) noexcept : p_(o.p_) { o.p_ = nullptr; }
92 com_ptr& operator=(com_ptr&& o) noexcept {
93 if (this != &o) { reset(); p_ = o.p_; o.p_ = nullptr; }
94 return *this;
95 }
96
97 T* get() const noexcept { return p_; }
98 T** put() noexcept { reset(); return &p_; }
99 T* operator->() const noexcept { return p_; }
100 explicit operator bool() const noexcept { return p_ != nullptr; }
101 void reset() noexcept { if (p_) { p_->Release(); p_ = nullptr; } }
102
103private:
104 T* p_ = nullptr;
105};
106
107[[maybe_unused]] static std::string wide_to_utf8(const wchar_t* ws) {
108 if (!ws) return {};
109 int sz = WideCharToMultiByte(CP_UTF8, 0, ws, -1, nullptr, 0, nullptr, nullptr);
110 std::string out(sz > 0 ? sz - 1 : 0, '\0');
111 if (sz > 0) WideCharToMultiByte(CP_UTF8, 0, ws, -1, out.data(), sz, nullptr, nullptr);
112 return out;
113}
114
115static void throw_hr(HRESULT hr, const char* where) {
117 std::ostringstream oss;
118 oss << where << " failed (hr=0x" << std::hex << hr << ")";
119 if (err.ErrorMessage()) {
120 #ifdef UNICODE
121 oss << " - " << wide_to_utf8(err.ErrorMessage());
122 #else
123 oss << " - " << err.ErrorMessage();
124 #endif
125 }
126 throw std::runtime_error(oss.str());
127}
128
130public:
133 if (FAILED(hr_) && hr_ != RPC_E_CHANGED_MODE) {
134 throw_hr(hr_, "CoInitializeEx");
135 }
136 }
137
139 if (SUCCEEDED(hr_)) CoUninitialize();
140 }
141
142private:
143 HRESULT hr_{ S_OK };
144};
145
146// Device monitoring globals
150
151// Connection pool globals
152static std::mutex g_cache_mutex;
153static std::unordered_map<std::wstring, std::unique_ptr<DeviceConnection>> g_connection_cache;
154
155// Window procedure for device notifications
170
171
172
176 IID_ICreateDevEnum, reinterpret_cast<void**>(dev.put()));
177 if (FAILED(hr)) throw_hr(hr, "CoCreateInstance(SystemDeviceEnum)");
178 return dev;
179}
180
183 HRESULT hr = dev->CreateClassEnumerator(CLSID_VideoInputDeviceCategory, e.put(), 0);
184 if (hr == S_FALSE) return {}; // none
185 if (FAILED(hr)) throw_hr(hr, "CreateClassEnumerator(VideoInputDeviceCategory)");
186 return e;
187}
188
189static std::wstring read_prop_bstr(IPropertyBag* bag, const wchar_t* key) {
191 std::wstring res;
192 if (SUCCEEDED(bag->Read(key, &v, nullptr)) && v.vt == VT_BSTR && v.bstrVal) {
193 res.assign(v.bstrVal, SysStringLen(v.bstrVal));
194 }
195 VariantClear(&v);
196 return res;
197}
198
199static std::wstring read_friendly_name(IMoniker* mon) {
201 HRESULT hr = mon->BindToStorage(nullptr, nullptr, IID_IPropertyBag, reinterpret_cast<void**>(bag.put()));
202 if (FAILED(hr)) return L"";
203 auto name = read_prop_bstr(bag.get(), L"FriendlyName");
204 return name.empty() ? L"" : name;
205}
206
207static std::wstring read_device_path(IMoniker* mon) {
209 if (SUCCEEDED(mon->BindToStorage(nullptr, nullptr, IID_IPropertyBag, reinterpret_cast<void**>(bag.put())))) {
210 auto dp = read_prop_bstr(bag.get(), L"DevicePath");
211 if (!dp.empty()) return dp;
212 }
213
214 LPOLESTR disp = nullptr;
215 std::wstring res;
216 if (SUCCEEDED(mon->GetDisplayName(nullptr, nullptr, &disp)) && disp) {
217 res.assign(disp);
219 }
220 return res;
221}
222
225 HRESULT hr = mon->BindToObject(nullptr, nullptr, IID_IBaseFilter, reinterpret_cast<void**>(f.put()));
226 if (FAILED(hr)) throw_hr(hr, "BindToObject(IBaseFilter)");
227 return f;
228}
229
232 if (FAILED(f->QueryInterface(IID_IAMCameraControl, reinterpret_cast<void**>(cam.put())))) return {};
233 return cam;
234}
235
238 if (FAILED(f->QueryInterface(IID_IAMVideoProcAmp, reinterpret_cast<void**>(vp.put())))) return {};
239 return vp;
240}
241
244 if (FAILED(f->QueryInterface(IID_IKsPropertySet, reinterpret_cast<void**>(props.put())))) {
245 return {};
246 }
247 return props;
248}
249
250static bool is_same_device(const Device& d, const std::wstring& name, const std::wstring& path) {
251 if (!d.path.empty() && !path.empty()) {
252 if (_wcsicmp(d.path.c_str(), path.c_str()) == 0) return true;
253 }
254 if (!d.name.empty() && !name.empty()) {
255 if (_wcsicmp(d.name.c_str(), name.c_str()) == 0) return true;
256 }
257 return false;
258}
259
261 auto de = create_dev_enum();
262 auto en = enum_video_devices(de.get());
263 if (!en) throw std::runtime_error("No video devices available");
264
265 ULONG fetched = 0;
267 while (en->Next(1, mon.put(), &fetched) == S_OK && fetched) {
268 auto fname = read_friendly_name(mon.get());
269 auto dpath = read_device_path(mon.get());
270 if (is_same_device(dev, fname, dpath)) {
271 return bind_to_filter(mon.get());
272 }
273 mon.reset();
274 }
275 throw std::runtime_error("Device not found");
276}
277
278// Mapping helpers
280 switch (p) {
281 case CamProp::Pan: return CameraControl_Pan;
304 default: return -1;
305 }
306}
307
323
331
339
340// DeviceConnection implementation
342public:
345 if (FAILED(hr_) && hr_ != RPC_E_CHANGED_MODE) {
346 throw_hr(hr_, "CoInitializeEx");
347 }
348 }
349
351 if (SUCCEEDED(hr_)) CoUninitialize();
352 }
353
354private:
355 HRESULT hr_{ S_OK };
356};
357
359 com_(std::make_unique<com_apartment>()),
360 filter_(nullptr),
361 cam_ctrl_(nullptr),
362 vid_proc_(nullptr) {
363 try {
365 if (filter) {
366 auto cam_ctrl = get_cam_ctrl(filter.get());
367 auto vid_proc = get_vproc(filter.get());
368
369 // Store as raw pointers but keep references
370 filter_ = new com_ptr<IBaseFilter>(std::move(filter));
371 cam_ctrl_ = new com_ptr<IAMCameraControl>(std::move(cam_ctrl));
372 vid_proc_ = new com_ptr<IAMVideoProcAmp>(std::move(vid_proc));
373 }
374 } catch (...) {
375 filter_ = nullptr;
376 }
377}
378
380 delete static_cast<com_ptr<IBaseFilter>*>(filter_);
381 delete static_cast<com_ptr<IAMCameraControl>*>(cam_ctrl_);
382 delete static_cast<com_ptr<IAMVideoProcAmp>*>(vid_proc_);
383}
384
386 auto* cam_ctrl = static_cast<com_ptr<IAMCameraControl>*>(cam_ctrl_);
387 if (!cam_ctrl || !*cam_ctrl) return false;
388
389 long pid = camprop_to_dshow(prop);
390 if (pid < 0) return false;
391
392 long value = 0, flags = 0;
393 HRESULT hr = (*cam_ctrl)->Get(pid, &value, &flags);
394 if (FAILED(hr)) return false;
395
396 val.value = static_cast<int>(value);
397 val.mode = from_flag(flags, true);
398 return true;
399}
400
402 auto* cam_ctrl = static_cast<com_ptr<IAMCameraControl>*>(cam_ctrl_);
403 if (!cam_ctrl || !*cam_ctrl) return false;
404
405 long pid = camprop_to_dshow(prop);
406 if (pid < 0) return false;
407
408 long flags = to_flag(val.mode, true);
409 HRESULT hr = (*cam_ctrl)->Set(pid, static_cast<long>(val.value), flags);
410 return SUCCEEDED(hr);
411}
412
414 auto* vid_proc = static_cast<com_ptr<IAMVideoProcAmp>*>(vid_proc_);
415 if (!vid_proc || !*vid_proc) return false;
416
417 long pid = vidprop_to_dshow(prop);
418 if (pid < 0) return false;
419
420 long value = 0, flags = 0;
421 HRESULT hr = (*vid_proc)->Get(pid, &value, &flags);
422 if (FAILED(hr)) return false;
423
424 val.value = static_cast<int>(value);
425 val.mode = from_flag(flags, false);
426 return true;
427}
428
430 auto* vid_proc = static_cast<com_ptr<IAMVideoProcAmp>*>(vid_proc_);
431 if (!vid_proc || !*vid_proc) return false;
432
433 long pid = vidprop_to_dshow(prop);
434 if (pid < 0) return false;
435
436 long flags = to_flag(val.mode, false);
437 HRESULT hr = (*vid_proc)->Set(pid, static_cast<long>(val.value), flags);
438 return SUCCEEDED(hr);
439}
440
442 auto* cam_ctrl = static_cast<com_ptr<IAMCameraControl>*>(cam_ctrl_);
443 if (!cam_ctrl || !*cam_ctrl) return false;
444
445 long pid = camprop_to_dshow(prop);
446 if (pid < 0) return false;
447
448 long min = 0, max = 0, step = 0, def = 0, flags = 0;
449 HRESULT hr = (*cam_ctrl)->GetRange(pid, &min, &max, &step, &def, &flags);
450 if (FAILED(hr)) return false;
451
452 range.min = static_cast<int>(min);
453 range.max = static_cast<int>(max);
454 range.step = static_cast<int>(step);
455 range.default_val = static_cast<int>(def);
456 range.default_mode = from_flag(flags, true);
457 return true;
458}
459
461 auto* vid_proc = static_cast<com_ptr<IAMVideoProcAmp>*>(vid_proc_);
462 if (!vid_proc || !*vid_proc) return false;
463
464 long pid = vidprop_to_dshow(prop);
465 if (pid < 0) return false;
466
467 long min = 0, max = 0, step = 0, def = 0, flags = 0;
468 HRESULT hr = (*vid_proc)->GetRange(pid, &min, &max, &step, &def, &flags);
469 if (FAILED(hr)) return false;
470
471 range.min = static_cast<int>(min);
472 range.max = static_cast<int>(max);
473 range.step = static_cast<int>(step);
474 range.default_val = static_cast<int>(def);
475 range.default_mode = from_flag(flags, false);
476 return true;
477}
478
479// Connection pool management
481 std::lock_guard<std::mutex> lock(g_cache_mutex);
482
483 std::wstring key = dev.path.empty() ? dev.name : dev.path;
484 auto it = g_connection_cache.find(key);
485
486 if (it != g_connection_cache.end() && it->second->is_valid()) {
487 return it->second.get();
488 }
489
490 // Create new connection
491 auto conn = std::make_unique<DeviceConnection>(dev);
492 if (!conn->is_valid()) return nullptr;
493
495 g_connection_cache[key] = std::move(conn);
496 return result;
497}
498
500 std::lock_guard<std::mutex> lock(g_cache_mutex);
501 std::wstring key = dev.path.empty() ? dev.name : dev.path;
502 g_connection_cache.erase(key);
503}
504
506 std::lock_guard<std::mutex> lock(g_cache_mutex);
507 g_connection_cache.clear();
508}
509
510// Device monitoring implementation
512 if (g_notification_window) return; // Already registered
513
515
516 // Create invisible window for notifications
517 WNDCLASSW wc = {}; // Use WNDCLASSW for Unicode
518 wc.lpfnWndProc = device_wndproc;
519 wc.hInstance = GetModuleHandle(nullptr);
520 wc.lpszClassName = L"DuvcDeviceNotification";
521 RegisterClassW(&wc); // Use RegisterClassW
522
523 g_notification_window = CreateWindowW(L"DuvcDeviceNotification", L"", 0, 0, 0, 0, 0, // Use CreateWindowW
524 HWND_MESSAGE, nullptr, GetModuleHandle(nullptr), nullptr);
525
526 // Register for device interface notifications
528 filter.dbcc_size = sizeof(filter);
529 filter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
530 filter.dbcc_classguid = CLSID_VideoInputDeviceCategory;
531
534}
535
536
548
550 try {
551 // First try: Check if device still exists in enumeration
553 auto de = create_dev_enum();
554 auto en = enum_video_devices(de.get());
555 if (!en) return false;
556
557 ULONG fetched = 0;
559 while (en->Next(1, mon.put(), &fetched) == S_OK && fetched) {
560 auto fname = read_friendly_name(mon.get());
561 auto dpath = read_device_path(mon.get());
562 if (is_same_device(dev, fname, dpath)) {
563 // Found in enumeration - now try lightweight access test
564 try {
565 // Try to create a cached connection (uses existing connection if available)
567 return conn != nullptr && conn->is_valid();
568 } catch (...) {
569 // If cached connection fails, device exists but might be busy
570 // Since it's enumerated, consider it "connected" but potentially busy
571 return true;
572 }
573 }
574 mon.reset();
575 }
576 return false; // Not found in enumeration
577 } catch (...) {
578 return false;
579 }
580}
581
582
583// Vendor property implementation
584bool get_vendor_property(const Device& dev, const GUID& property_set, ULONG property_id,
585 std::vector<uint8_t>& data) {
588 auto props = get_property_set(filter.get());
589 if (!props) return false;
590
592 HRESULT hr = props->Get(property_set, property_id, nullptr, 0,
593 nullptr, 0, &bytes_returned);
594 if (FAILED(hr) || bytes_returned == 0) return false;
595
596 data.resize(bytes_returned);
597 hr = props->Get(property_set, property_id, nullptr, 0,
598 data.data(), bytes_returned, &bytes_returned);
599 return SUCCEEDED(hr);
600}
601
602bool set_vendor_property(const Device& dev, const GUID& property_set, ULONG property_id,
603 const std::vector<uint8_t>& data) {
606 auto props = get_property_set(filter.get());
607 if (!props) return false;
608
609 HRESULT hr = props->Set(property_set, property_id, nullptr, 0,
610 const_cast<uint8_t*>(data.data()), data.size());
611 return SUCCEEDED(hr);
612}
613
614bool query_vendor_property_support(const Device& dev, const GUID& property_set, ULONG property_id) {
617 auto props = get_property_set(filter.get());
618 if (!props) return false;
619
621 HRESULT hr = props->QuerySupported(property_set, property_id, &type_support);
623}
624
625// Public API: enumeration
626std::vector<Device> list_devices() {
628 std::vector<Device> out;
629
630 auto de = create_dev_enum();
631 auto en = enum_video_devices(de.get());
632 if (!en) return out;
633
634 ULONG fetched = 0;
636 while (en->Next(1, mon.put(), &fetched) == S_OK && fetched) {
637 Device d;
638 d.name = read_friendly_name(mon.get());
639 d.path = read_device_path(mon.get());
640 out.emplace_back(std::move(d));
641 mon.reset();
642 }
643 return out;
644}
645
646// Updated public API functions to use cached connections
647bool get_range(const Device& dev, CamProp prop, PropRange& range) {
648 auto* conn = get_cached_connection(dev);
649 return conn ? conn->get_range(prop, range) : false;
650}
651
652bool get(const Device& dev, CamProp prop, PropSetting& val) {
653 auto* conn = get_cached_connection(dev);
654 return conn ? conn->get(prop, val) : false;
655}
656
657bool set(const Device& dev, CamProp prop, const PropSetting& val) {
658 auto* conn = get_cached_connection(dev);
659 return conn ? conn->set(prop, val) : false;
660}
661
662bool get_range(const Device& dev, VidProp prop, PropRange& range) {
663 auto* conn = get_cached_connection(dev);
664 return conn ? conn->get_range(prop, range) : false;
665}
666
667bool get(const Device& dev, VidProp prop, PropSetting& val) {
668 auto* conn = get_cached_connection(dev);
669 return conn ? conn->get(prop, val) : false;
670}
671
672bool set(const Device& dev, VidProp prop, const PropSetting& val) {
673 auto* conn = get_cached_connection(dev);
674 return conn ? conn->set(prop, val) : false;
675}
676
677// String helpers
678const char* to_string(CamProp p) {
679 switch (p) {
680 case CamProp::Pan: return "Pan";
681 case CamProp::Tilt: return "Tilt";
682 case CamProp::Roll: return "Roll";
683 case CamProp::Zoom: return "Zoom";
684 case CamProp::Exposure: return "Exposure";
685 case CamProp::Iris: return "Iris";
686 case CamProp::Focus: return "Focus";
687 case CamProp::ScanMode: return "ScanMode";
688 case CamProp::Privacy: return "Privacy";
689 case CamProp::PanRelative: return "PanRelative";
690 case CamProp::TiltRelative: return "TiltRelative";
691 case CamProp::RollRelative: return "RollRelative";
692 case CamProp::ZoomRelative: return "ZoomRelative";
693 case CamProp::ExposureRelative: return "ExposureRelative";
694 case CamProp::IrisRelative: return "IrisRelative";
695 case CamProp::FocusRelative: return "FocusRelative";
696 case CamProp::PanTilt: return "PanTilt";
697 case CamProp::PanTiltRelative: return "PanTiltRelative";
698 case CamProp::FocusSimple: return "FocusSimple";
699 case CamProp::DigitalZoom: return "DigitalZoom";
700 case CamProp::DigitalZoomRelative: return "DigitalZoomRelative";
701 case CamProp::BacklightCompensation: return "BacklightCompensation";
702 case CamProp::Lamp: return "Lamp";
703 default: return "Unknown";
704 }
705}
706
707const wchar_t* to_wstring(CamProp p) {
708 switch (p) {
709 case CamProp::Pan: return L"Pan";
710 case CamProp::Tilt: return L"Tilt";
711 case CamProp::Roll: return L"Roll";
712 case CamProp::Zoom: return L"Zoom";
713 case CamProp::Exposure: return L"Exposure";
714 case CamProp::Iris: return L"Iris";
715 case CamProp::Focus: return L"Focus";
716 case CamProp::ScanMode: return L"ScanMode";
717 case CamProp::Privacy: return L"Privacy";
718 case CamProp::PanRelative: return L"PanRelative";
719 case CamProp::TiltRelative: return L"TiltRelative";
720 case CamProp::RollRelative: return L"RollRelative";
721 case CamProp::ZoomRelative: return L"ZoomRelative";
722 case CamProp::ExposureRelative: return L"ExposureRelative";
723 case CamProp::IrisRelative: return L"IrisRelative";
724 case CamProp::FocusRelative: return L"FocusRelative";
725 case CamProp::PanTilt: return L"PanTilt";
726 case CamProp::PanTiltRelative: return L"PanTiltRelative";
727 case CamProp::FocusSimple: return L"FocusSimple";
728 case CamProp::DigitalZoom: return L"DigitalZoom";
729 case CamProp::DigitalZoomRelative: return L"DigitalZoomRelative";
730 case CamProp::BacklightCompensation: return L"BacklightCompensation";
731 case CamProp::Lamp: return L"Lamp";
732 default: return L"Unknown";
733 }
734}
735
736const char* to_string(VidProp p) {
737 switch (p) {
738 case VidProp::Brightness: return "Brightness";
739 case VidProp::Contrast: return "Contrast";
740 case VidProp::Hue: return "Hue";
741 case VidProp::Saturation: return "Saturation";
742 case VidProp::Sharpness: return "Sharpness";
743 case VidProp::Gamma: return "Gamma";
744 case VidProp::ColorEnable: return "ColorEnable";
745 case VidProp::WhiteBalance: return "WhiteBalance";
746 case VidProp::BacklightCompensation: return "BacklightCompensation";
747 case VidProp::Gain: return "Gain";
748 default: return "Unknown";
749 }
750}
751
752const wchar_t* to_wstring(VidProp p) {
753 switch (p) {
754 case VidProp::Brightness: return L"Brightness";
755 case VidProp::Contrast: return L"Contrast";
756 case VidProp::Hue: return L"Hue";
757 case VidProp::Saturation: return L"Saturation";
758 case VidProp::Sharpness: return L"Sharpness";
759 case VidProp::Gamma: return L"Gamma";
760 case VidProp::ColorEnable: return L"ColorEnable";
761 case VidProp::WhiteBalance: return L"WhiteBalance";
762 case VidProp::BacklightCompensation: return L"BacklightCompensation";
763 case VidProp::Gain: return L"Gain";
764 default: return L"Unknown";
765 }
766}
767
768const char* to_string(CamMode m) {
769 return (m == CamMode::Auto) ? "AUTO" : "MANUAL";
770}
771
772const wchar_t* to_wstring(CamMode m) {
773 return (m == CamMode::Auto) ? L"AUTO" : L"MANUAL";
774}
775
776} // namespace duvc
777
778#else // _WIN32
779
780// Non-Windows stubs to allow inclusion without linking errors
781namespace duvc {
782
783std::vector<Device> list_devices() { return {}; }
784bool get_range(const Device&, CamProp, PropRange&) { return false; }
785bool get(const Device&, CamProp, PropSetting&) { return false; }
786bool set(const Device&, CamProp, const PropSetting&) { return false; }
787bool get_range(const Device&, VidProp, PropRange&) { return false; }
788bool get(const Device&, VidProp, PropSetting&) { return false; }
789bool set(const Device&, VidProp, const PropSetting&) { return false; }
790
791const char* to_string(CamProp) { return "Unknown"; }
792const char* to_string(VidProp) { return "Unknown"; }
793const char* to_string(CamMode) { return "MANUAL"; }
794
795const wchar_t* to_wstring(CamProp) { return L"Unknown"; }
796const wchar_t* to_wstring(VidProp) { return L"Unknown"; }
797const wchar_t* to_wstring(CamMode) { return L"MANUAL"; }
798
799// Stubs for new functionality
802bool is_device_connected(const Device&) { return false; }
803
804bool get_vendor_property(const Device&, const GUID&, ULONG, std::vector<uint8_t>&) { return false; }
805bool set_vendor_property(const Device&, const GUID&, ULONG, const std::vector<uint8_t>&) { return false; }
806bool query_vendor_property_support(const Device&, const GUID&, ULONG) { return false; }
807
808DeviceConnection* get_cached_connection(const Device&) { return nullptr; }
809void release_cached_connection(const Device&) {}
811
812} // namespace duvc
813
814#endif // _WIN32
RAII wrapper for DirectShow device connections.
Definition core.h:55
DeviceConnection(const Device &dev)
Definition core.cpp:358
bool get(CamProp prop, PropSetting &val)
Definition core.cpp:385
bool set(CamProp prop, const PropSetting &val)
Definition core.cpp:401
bool get_range(CamProp prop, PropRange &range)
Definition core.cpp:441
Result type that can contain either a value or an error.
Definition result.h:75
const T & value() const &
Get the value (assumes success)
Definition result.h:114
com_ptr() noexcept=default
T * operator->() const noexcept
Definition core.cpp:99
T ** put() noexcept
Definition core.cpp:98
com_ptr(com_ptr &&o) noexcept
Definition core.cpp:91
T * get() const noexcept
Definition core.cpp:97
com_ptr & operator=(const com_ptr &)=delete
com_ptr(const com_ptr &)=delete
com_ptr & operator=(com_ptr &&o) noexcept
Definition core.cpp:92
void reset() noexcept
Definition core.cpp:101
#define VideoProcAmp_Contrast
Definition core.cpp:60
#define VideoProcAmp_Hue
Definition core.cpp:61
#define CameraControl_PanRelative
Definition core.cpp:39
#define CameraControl_Roll
Definition core.cpp:32
#define VideoProcAmp_ColorEnable
Definition core.cpp:65
#define CameraControl_DigitalZoom
Definition core.cpp:49
#define CameraControl_Tilt
Definition core.cpp:31
#define CameraControl_Zoom
Definition core.cpp:33
#define VideoProcAmp_Sharpness
Definition core.cpp:63
#define CameraControl_Focus
Definition core.cpp:36
#define CameraControl_IrisRelative
Definition core.cpp:44
#define CameraControl_Lamp
Definition core.cpp:52
#define CameraControl_FocusSimple
Definition core.cpp:48
#define CameraControl_TiltRelative
Definition core.cpp:40
#define CameraControl_ExposureRelative
Definition core.cpp:43
#define CameraControl_PanTiltRelative
Definition core.cpp:47
#define VideoProcAmp_WhiteBalance
Definition core.cpp:66
#define CameraControl_ZoomRelative
Definition core.cpp:42
#define VideoProcAmp_Gamma
Definition core.cpp:64
#define CameraControl_ScanMode
Definition core.cpp:37
#define CameraControl_Pan
Definition core.cpp:30
#define CameraControl_Privacy
Definition core.cpp:38
#define CameraControl_Exposure
Definition core.cpp:34
#define CameraControl_Flags_Manual
Definition core.cpp:54
#define CameraControl_DigitalZoomRelative
Definition core.cpp:50
#define CameraControl_Iris
Definition core.cpp:35
#define VideoProcAmp_BacklightCompensation
Definition core.cpp:67
#define CameraControl_PanTilt
Definition core.cpp:46
#define CameraControl_RollRelative
Definition core.cpp:41
#define CameraControl_BacklightCompensation
Definition core.cpp:51
#define CameraControl_Flags_Auto
Definition core.cpp:53
#define CameraControl_FocusRelative
Definition core.cpp:45
#define VideoProcAmp_Flags_Manual
Definition core.cpp:70
#define VideoProcAmp_Brightness
Definition core.cpp:59
#define VideoProcAmp_Flags_Auto
Definition core.cpp:69
#define VideoProcAmp_Saturation
Definition core.cpp:62
#define VideoProcAmp_Gain
Definition core.cpp:68
EXTERN_C const IID IID_IPropertyBag
Definition device.cpp:20
EXTERN_C const CLSID CLSID_SystemDeviceEnum
Definition device.cpp:17
EXTERN_C const CLSID CLSID_VideoInputDeviceCategory
Definition device.cpp:18
EXTERN_C const IID IID_ICreateDevEnum
Definition device.cpp:19
bool get(const Device &, CamProp, PropSetting &)
Get a camera control property value.
Definition duvc.hpp:63
bool set(const Device &, CamProp, const PropSetting &)
Set a camera control property value.
Definition duvc.hpp:81
bool get_range(const Device &, CamProp, PropRange &)
Get the valid range for a camera control property.
Definition duvc.hpp:95
#define KSPROPERTY_SUPPORT_SET
Definition logitech.cpp:18
#define KSPROPERTY_SUPPORT_GET
Definition logitech.cpp:17
Definition core.h:13
std::wstring read_friendly_name(IMoniker *mon)
Read friendly name from device moniker.
Definition core.cpp:199
static std::mutex g_cache_mutex
Definition core.cpp:152
static std::string wide_to_utf8(const wchar_t *ws)
Definition core.cpp:107
static com_ptr< IAMVideoProcAmp > get_vproc(IBaseFilter *f)
Definition core.cpp:236
static std::wstring read_prop_bstr(IPropertyBag *bag, const wchar_t *key)
Definition core.cpp:189
VidProp
Video processing properties (IAMVideoProcAmp interface)
Definition types.h:50
@ Saturation
Color saturation level.
@ Gain
Sensor gain level.
@ WhiteBalance
White balance adjustment.
@ Brightness
Image brightness level.
@ ColorEnable
Color vs. monochrome mode.
@ Sharpness
Image sharpness level.
@ Contrast
Image contrast level.
@ Gamma
Gamma correction value.
@ BacklightCompensation
Backlight compensation level.
@ Hue
Color hue adjustment.
void clear_connection_cache()
Definition core.cpp:505
com_ptr< IBaseFilter > open_device_filter(const Device &dev)
Create DirectShow filter from device.
Definition core.cpp:260
bool is_same_device(const Device &d, const std::wstring &name, const std::wstring &path)
Check if two device identifiers refer to same device.
Definition core.cpp:250
static DeviceChangeCallback g_device_callback
Definition core.cpp:147
com_ptr< IEnumMoniker > enum_video_devices(ICreateDevEnum *dev)
Enumerate video input devices.
Definition core.cpp:181
static void throw_hr(HRESULT hr, const char *where)
Definition core.cpp:115
std::vector< Device > list_devices()
Enumerate all available video input devices.
Definition core.cpp:626
std::wstring read_device_path(IMoniker *mon)
Read device path from moniker.
Definition core.cpp:207
void unregister_device_change_callback()
Unregister device change callback.
Definition core.cpp:537
void release_cached_connection(const Device &dev)
Definition core.cpp:499
CamMode
Property control mode.
Definition types.h:66
@ Auto
Automatic control by camera.
@ Manual
Manual control by application.
static com_ptr< IAMCameraControl > get_cam_ctrl(IBaseFilter *f)
Definition core.cpp:230
bool query_vendor_property_support(const Device &dev, const GUID &property_set, ULONG property_id)
Query whether device supports a vendor-specific property.
Definition core.cpp:614
static LRESULT CALLBACK device_wndproc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
Definition core.cpp:156
static std::unordered_map< std::wstring, std::unique_ptr< DeviceConnection > > g_connection_cache
Definition core.cpp:153
const wchar_t * to_wstring(CamProp)
Convert camera property enum to wide string.
Definition core.cpp:707
static com_ptr< IBaseFilter > bind_to_filter(IMoniker *mon)
Definition core.cpp:223
static com_ptr< IKsPropertySet > get_property_set(IBaseFilter *f)
Definition core.cpp:242
const char * to_string(CamProp)
Convert camera property enum to string.
Definition core.cpp:678
CamProp
Camera control properties (IAMCameraControl interface)
Definition types.h:18
@ ExposureRelative
Relative exposure adjustment.
@ Roll
Camera roll rotation.
@ FocusSimple
Simple focus control.
@ PanRelative
Relative pan movement.
@ RollRelative
Relative roll movement.
@ Zoom
Optical zoom level.
@ Lamp
Camera lamp/flash control.
@ PanTiltRelative
Relative pan/tilt movement.
@ Tilt
Vertical camera rotation.
@ TiltRelative
Relative tilt movement.
@ ScanMode
Scan mode (progressive/interlaced)
@ ZoomRelative
Relative zoom movement.
@ Privacy
Privacy mode on/off.
@ IrisRelative
Relative iris adjustment.
@ Iris
Aperture/iris setting.
@ Exposure
Exposure time.
@ Focus
Focus position.
@ FocusRelative
Relative focus adjustment.
@ PanTilt
Combined pan/tilt control.
@ DigitalZoomRelative
Relative digital zoom.
@ Pan
Horizontal camera rotation.
@ BacklightCompensation
Backlight compensation.
@ DigitalZoom
Digital zoom level.
static HDEVNOTIFY g_device_notify
Definition core.cpp:149
bool get_vendor_property(const Device &dev, const GUID &property_set, ULONG property_id, std::vector< uint8_t > &data)
Get vendor-specific property data from device.
Definition core.cpp:584
static long to_flag(CamMode m, bool is_camera_control)
Definition core.cpp:324
DeviceConnection * get_cached_connection(const Device &dev)
Definition core.cpp:480
bool set_vendor_property(const Device &dev, const GUID &property_set, ULONG property_id, const std::vector< uint8_t > &data)
Set vendor-specific property data on device.
Definition core.cpp:602
bool is_device_connected(const Device &dev)
Check if a device is currently connected and accessible.
Definition core.cpp:549
com_ptr< ICreateDevEnum > create_dev_enum()
Create DirectShow device enumerator.
Definition core.cpp:173
void register_device_change_callback(DeviceChangeCallback callback)
Register callback for device hotplug events.
Definition core.cpp:511
std::function< void(bool device_added, const std::wstring &device_path)> DeviceChangeCallback
Device change callback function type.
Definition core.h:34
static long camprop_to_dshow(CamProp p)
Definition core.cpp:279
static HWND g_notification_window
Definition core.cpp:148
static CamMode from_flag(long flag, bool is_camera_control)
Definition core.cpp:332
static long vidprop_to_dshow(VidProp p)
Definition core.cpp:308
Represents a camera device.
Definition types.h:131
Property range and default information.
Definition types.h:92
int default_val
Default value.
Definition types.h:96
int min
Minimum supported value.
Definition types.h:93
int step
Step size between valid values.
Definition types.h:95
int max
Maximum supported value.
Definition types.h:94
CamMode default_mode
Default control mode.
Definition types.h:97
Property setting with value and control mode.
Definition types.h:74