32#include <unordered_map>
36#ifndef DUVC_ABI_VERSION
37#define DUVC_ABI_VERSION ((1 << 16) | (0 << 8) | 0)
40#ifndef DUVC_ABI_VERSION_STRING
41#define DUVC_ABI_VERSION_STRING "1.0.0"
44#ifdef DeviceCapabilities
45#undef DeviceCapabilities
52std::atomic<bool> g_initialized{
false};
55std::mutex g_library_mutex;
58thread_local std::string g_last_error_details;
62void *g_log_callback_user_data =
nullptr;
63std::mutex g_log_mutex;
67void *g_device_change_user_data =
nullptr;
68std::mutex g_device_change_mutex;
71std::vector<std::unique_ptr<duvc::Device>> g_device_storage;
72std::mutex g_device_storage_mutex;
75std::unordered_map<duvc_connection_t *, std::unique_ptr<duvc::Camera>>
77std::mutex g_connection_mutex;
80std::vector<std::unique_ptr<duvc::DeviceCapabilities>> g_capabilities_storage;
81std::mutex g_capabilities_mutex;
91duvc_result_t copy_string_to_buffer(
const std::string &cpp_str,
char *buffer,
92 size_t buffer_size,
size_t *required_size) {
93 size_t needed = cpp_str.length() + 1;
95 *required_size = needed;
97 if (!buffer || buffer_size < needed) {
101 std::memcpy(buffer, cpp_str.c_str(), needed);
108duvc_result_t copy_wstring_to_buffer(
const std::wstring &wide_str,
char *buffer,
110 size_t *required_size) {
113 return copy_string_to_buffer(utf8_str, buffer, buffer_size, required_size);
114 }
catch (
const std::exception &e) {
115 g_last_error_details = std::string(
"String conversion failed: ") + e.what();
155 if (result.
is_ok()) {
156 g_last_error_details.clear();
160 const auto &error = result.
error();
161 g_last_error_details = error.description();
162 return convert_error_code(error.code());
169 const std::string &message) {
170 std::lock_guard<std::mutex> lock(g_log_mutex);
171 if (g_log_callback) {
175 g_log_callback(c_level, message.c_str(), g_log_callback_user_data);
204 cpp_setting.
mode = convert_cam_mode_from_c(setting.
mode);
212 c_setting.
mode = convert_cam_mode_to_c(setting.
mode);
242 uint32_t compiled_major = (compiled_version >> 16) & 0xFF;
243 uint32_t runtime_major = (runtime_version >> 16) & 0xFF;
246 if (compiled_major != runtime_major) {
251 uint32_t compiled_minor = (compiled_version >> 8) & 0xFF;
252 uint32_t runtime_minor = (runtime_version >> 8) & 0xFF;
254 return (runtime_minor >= compiled_minor) ? 1 : 0;
262 std::lock_guard<std::mutex> lock(g_library_mutex);
264 if (g_initialized.load()) {
270 g_last_error_details.clear();
276 g_device_storage.clear();
277 g_connections.clear();
278 g_capabilities_storage.clear();
280 g_initialized.store(
true);
284 }
catch (
const std::exception &e) {
285 g_last_error_details = std::string(
"Initialization failed: ") + e.what();
288 g_last_error_details =
"Initialization failed: unknown error";
294 std::lock_guard<std::mutex> lock(g_library_mutex);
295 if (!g_initialized.load()) {
305 std::lock_guard<std::mutex> conn_lock(g_connection_mutex);
306 g_connections.clear();
311 std::lock_guard<std::mutex> dev_lock(g_device_storage_mutex);
312 g_device_storage.clear();
317 std::lock_guard<std::mutex> caps_lock(g_capabilities_mutex);
318 g_capabilities_storage.clear();
323 std::lock_guard<std::mutex> log_lock(g_log_mutex);
324 g_log_callback =
nullptr;
325 g_log_callback_user_data =
nullptr;
328 g_initialized.store(
false);
346 return "Not Implemented";
348 return "Invalid Argument";
350 return "Device Not Found";
352 return "Device Busy";
354 return "Property Not Supported";
356 return "Invalid Value";
358 return "Permission Denied";
360 return "System Error";
362 return "Connection Failed";
366 return "Buffer Too Small";
368 return "Unknown Error";
408 if (!g_initialized.load()) {
409 g_last_error_details =
"Library not initialized";
414 std::lock_guard<std::mutex> lock(g_log_mutex);
415 g_log_callback = callback;
416 g_log_callback_user_data = user_data;
425 }
catch (
const std::exception &e) {
426 g_last_error_details =
427 std::string(
"Failed to set log callback: ") + e.what();
433 if (!g_initialized.load()) {
434 g_last_error_details =
"Library not initialized";
443 }
catch (
const std::exception &e) {
444 g_last_error_details = std::string(
"Failed to set log level: ") + e.what();
452 if (!g_initialized.load()) {
453 g_last_error_details =
"Library not initialized";
461 }
catch (
const std::exception &e) {
462 g_last_error_details = std::string(
"Failed to get log level: ") + e.what();
470 if (!g_initialized.load()) {
480 }
catch (
const std::exception &) {
511 if (!devices || !count)
513 if (!g_initialized.load()) {
514 g_last_error_details =
"Library not initialized";
519 std::lock_guard<std::mutex> lock(g_device_storage_mutex);
522 g_device_storage.clear();
530 if (!c_devices && !device_list.empty()) {
531 g_last_error_details =
"Failed to allocate memory for device list";
536 for (
size_t i = 0; i < device_list.size(); ++i) {
538 std::make_unique<duvc::Device>(std::move(device_list[i]));
539 c_devices[i] =
reinterpret_cast<duvc_device_t *
>(stored_device.get());
540 g_device_storage.push_back(std::move(stored_device));
543 *devices = c_devices;
544 *count = device_list.size();
547 }
catch (
const std::exception &e) {
548 g_last_error_details = std::string(
"Failed to list devices: ") + e.what();
551 g_last_error_details =
"Unknown error while listing devices";
558 if (!device_path_utf8 || !device)
560 if (!g_initialized.load()) {
561 g_last_error_details =
"Library not initialized";
573 std::lock_guard<std::mutex> lock(g_device_storage_mutex);
574 auto stored_device = std::make_unique<duvc::Device>(std::move(found_device));
575 *device =
reinterpret_cast<duvc_device_t *
>(stored_device.get());
576 g_device_storage.push_back(std::move(stored_device));
580 }
catch (
const std::exception &e) {
581 g_last_error_details =
582 std::string(
"Failed to find device by path: ") + e.what();
585 g_last_error_details =
"Unknown error while finding device by path";
602 if (!device || !connected)
604 if (!g_initialized.load()) {
605 g_last_error_details =
"Library not initialized";
613 *connected = is_connected ? 1 : 0;
616 }
catch (
const std::exception &e) {
617 g_last_error_details =
618 std::string(
"Failed to check device connection: ") + e.what();
621 g_last_error_details =
"Unknown error while checking device connection";
627 size_t buffer_size,
size_t *required) {
630 if (!g_initialized.load()) {
631 g_last_error_details =
"Library not initialized";
638 return copy_wstring_to_buffer(cpp_device->
name, buffer, buffer_size,
640 }
catch (
const std::exception &e) {
641 g_last_error_details =
642 std::string(
"Failed to get device name: ") + e.what();
648 size_t buffer_size,
size_t *required) {
651 if (!g_initialized.load()) {
652 g_last_error_details =
"Library not initialized";
659 return copy_wstring_to_buffer(cpp_device->
path, buffer, buffer_size,
661 }
catch (
const std::exception &e) {
662 g_last_error_details =
663 std::string(
"Failed to get device path: ") + e.what();
669 size_t buffer_size,
size_t *required) {
672 if (!g_initialized.load()) {
673 g_last_error_details =
"Library not initialized";
681 const std::wstring &id_str =
682 cpp_device->
path.empty() ? cpp_device->
name : cpp_device->
path;
683 return copy_wstring_to_buffer(id_str, buffer, buffer_size, required);
684 }
catch (
const std::exception &e) {
685 g_last_error_details = std::string(
"Failed to get device ID: ") + e.what();
691 if (!device || !valid)
693 if (!g_initialized.load()) {
694 g_last_error_details =
"Library not initialized";
701 *valid = cpp_device->
is_valid() ? 1 : 0;
703 }
catch (
const std::exception &e) {
704 g_last_error_details =
705 std::string(
"Failed to check device validity: ") + e.what();
717 if (!g_initialized.load()) {
718 g_last_error_details =
"Library not initialized";
723 std::lock_guard<std::mutex> lock(g_device_change_mutex);
725 g_device_change_callback = callback;
726 g_device_change_user_data = user_data;
730 [=](
bool added,
const std::wstring &device_path) {
731 std::lock_guard<std::mutex> cb_lock(g_device_change_mutex);
732 if (g_device_change_callback) {
735 g_device_change_callback(added ? 1 : 0, utf8_path.c_str(),
736 g_device_change_user_data);
745 }
catch (
const std::exception &e) {
746 g_last_error_details =
747 std::string(
"Failed to register device change callback: ") + e.what();
753 if (!g_initialized.load()) {
758 std::lock_guard<std::mutex> lock(g_device_change_mutex);
763 g_device_change_callback =
nullptr;
764 g_device_change_user_data =
nullptr;
777 if (!conn || device_index < 0)
779 if (!g_initialized.load()) {
780 g_last_error_details =
"Library not initialized";
786 if (!cam_result.is_ok()) {
787 return handle_cpp_result(cam_result);
790 std::lock_guard<std::mutex> conn_lock(g_connection_mutex);
792 std::make_unique<duvc::Camera>(std::move(cam_result).value());
795 g_connections[handle] = std::move(camera_ptr);
799 }
catch (
const std::exception &e) {
800 g_last_error_details =
801 std::string(
"Failed to open camera by index: ") + e.what();
808 if (!device || !conn)
810 if (!g_initialized.load()) {
811 g_last_error_details =
"Library not initialized";
819 if (!cam_result.is_ok()) {
820 return handle_cpp_result(cam_result);
823 std::lock_guard<std::mutex> lock(g_connection_mutex);
825 std::make_unique<duvc::Camera>(std::move(cam_result).value());
828 g_connections[handle] = std::move(camera_ptr);
832 }
catch (
const std::exception &e) {
833 g_last_error_details = std::string(
"Failed to open camera: ") + e.what();
839 if (!conn || !g_initialized.load()) {
844 std::lock_guard<std::mutex> lock(g_connection_mutex);
845 auto it = g_connections.find(conn);
846 if (it != g_connections.end()) {
847 g_connections.erase(it);
855 if (!conn || !g_initialized.load()) {
860 std::lock_guard<std::mutex> lock(g_connection_mutex);
862 if (it == g_connections.end()) {
865 return it->second->is_valid() ? 1 : 0;
878 if (!conn || !setting)
880 if (!g_initialized.load()) {
881 g_last_error_details =
"Library not initialized";
886 std::lock_guard<std::mutex> lock(g_connection_mutex);
887 auto it = g_connections.find(conn);
888 if (it == g_connections.end()) {
889 g_last_error_details =
"Invalid connection handle";
893 auto result = it->second->get(convert_cam_prop(prop));
894 if (!result.is_ok()) {
895 return handle_cpp_result(result);
898 *setting = convert_prop_setting_to_c(result.value());
900 }
catch (
const std::exception &e) {
901 g_last_error_details =
902 std::string(
"Failed to get camera property: ") + e.what();
910 if (!conn || !setting)
912 if (!g_initialized.load()) {
913 g_last_error_details =
"Library not initialized";
918 std::lock_guard<std::mutex> lock(g_connection_mutex);
919 auto it = g_connections.find(conn);
920 if (it == g_connections.end()) {
921 g_last_error_details =
"Invalid connection handle";
926 auto result = it->second->set(convert_cam_prop(prop), cpp_setting);
927 return handle_cpp_result(result);
928 }
catch (
const std::exception &e) {
929 g_last_error_details =
930 std::string(
"Failed to set camera property: ") + e.what();
940 if (!g_initialized.load()) {
941 g_last_error_details =
"Library not initialized";
946 std::lock_guard<std::mutex> lock(g_connection_mutex);
947 auto it = g_connections.find(conn);
948 if (it == g_connections.end()) {
949 g_last_error_details =
"Invalid connection handle";
953 auto result = it->second->get_range(convert_cam_prop(prop));
954 if (!result.is_ok()) {
955 return handle_cpp_result(result);
958 *range = convert_prop_range_to_c(result.value());
960 }
catch (
const std::exception &e) {
961 g_last_error_details =
962 std::string(
"Failed to get camera property range: ") + e.what();
970 if (!conn || !setting)
972 if (!g_initialized.load()) {
973 g_last_error_details =
"Library not initialized";
978 std::lock_guard<std::mutex> lock(g_connection_mutex);
979 auto it = g_connections.find(conn);
980 if (it == g_connections.end()) {
981 g_last_error_details =
"Invalid connection handle";
985 auto result = it->second->get(convert_vid_prop(prop));
986 if (!result.is_ok()) {
987 return handle_cpp_result(result);
990 *setting = convert_prop_setting_to_c(result.value());
992 }
catch (
const std::exception &e) {
993 g_last_error_details =
994 std::string(
"Failed to get video property: ") + e.what();
1002 if (!conn || !setting)
1004 if (!g_initialized.load()) {
1005 g_last_error_details =
"Library not initialized";
1010 std::lock_guard<std::mutex> lock(g_connection_mutex);
1011 auto it = g_connections.find(conn);
1012 if (it == g_connections.end()) {
1013 g_last_error_details =
"Invalid connection handle";
1018 auto result = it->second->set(convert_vid_prop(prop), cpp_setting);
1019 return handle_cpp_result(result);
1020 }
catch (
const std::exception &e) {
1021 g_last_error_details =
1022 std::string(
"Failed to set video property: ") + e.what();
1030 if (!conn || !range)
1032 if (!g_initialized.load()) {
1033 g_last_error_details =
"Library not initialized";
1038 std::lock_guard<std::mutex> lock(g_connection_mutex);
1039 auto it = g_connections.find(conn);
1040 if (it == g_connections.end()) {
1041 g_last_error_details =
"Invalid connection handle";
1045 auto result = it->second->get_range(convert_vid_prop(prop));
1046 if (!result.is_ok()) {
1047 return handle_cpp_result(result);
1050 *range = convert_prop_range_to_c(result.value());
1052 }
catch (
const std::exception &e) {
1053 g_last_error_details =
1054 std::string(
"Failed to get video property range: ") + e.what();
1067 if (!conn || !props || !settings || count == 0)
1069 if (!g_initialized.load()) {
1070 g_last_error_details =
"Library not initialized";
1075 std::lock_guard<std::mutex> lock(g_connection_mutex);
1076 auto it = g_connections.find(conn);
1077 if (it == g_connections.end()) {
1078 g_last_error_details =
"Invalid connection handle";
1083 for (
size_t i = 0; i < count; ++i) {
1084 auto result = camera->
get(convert_cam_prop(props[i]));
1085 if (!result.is_ok()) {
1086 g_last_error_details =
1087 "Failed to get camera property at index " + std::to_string(i);
1088 return handle_cpp_result(result);
1090 settings[i] = convert_prop_setting_to_c(result.value());
1094 }
catch (
const std::exception &e) {
1095 g_last_error_details =
1096 std::string(
"Failed to get multiple camera properties: ") + e.what();
1104 if (!conn || !props || !settings || count == 0)
1106 if (!g_initialized.load()) {
1107 g_last_error_details =
"Library not initialized";
1112 std::lock_guard<std::mutex> lock(g_connection_mutex);
1113 auto it = g_connections.find(conn);
1114 if (it == g_connections.end()) {
1115 g_last_error_details =
"Invalid connection handle";
1120 for (
size_t i = 0; i < count; ++i) {
1122 auto result = camera->
set(convert_cam_prop(props[i]), cpp_setting);
1123 if (!result.is_ok()) {
1124 g_last_error_details =
1125 "Failed to set camera property at index " + std::to_string(i);
1126 return handle_cpp_result(result);
1131 }
catch (
const std::exception &e) {
1132 g_last_error_details =
1133 std::string(
"Failed to set multiple camera properties: ") + e.what();
1142 if (!conn || !props || !settings || count == 0)
1144 if (!g_initialized.load()) {
1145 g_last_error_details =
"Library not initialized";
1150 std::lock_guard<std::mutex> lock(g_connection_mutex);
1151 auto it = g_connections.find(conn);
1152 if (it == g_connections.end()) {
1153 g_last_error_details =
"Invalid connection handle";
1158 for (
size_t i = 0; i < count; ++i) {
1159 auto result = camera->
get(convert_vid_prop(props[i]));
1160 if (!result.is_ok()) {
1161 g_last_error_details =
1162 "Failed to get video property at index " + std::to_string(i);
1163 return handle_cpp_result(result);
1165 settings[i] = convert_prop_setting_to_c(result.value());
1169 }
catch (
const std::exception &e) {
1170 g_last_error_details =
1171 std::string(
"Failed to get multiple video properties: ") + e.what();
1179 if (!conn || !props || !settings || count == 0)
1181 if (!g_initialized.load()) {
1182 g_last_error_details =
"Library not initialized";
1187 std::lock_guard<std::mutex> lock(g_connection_mutex);
1188 auto it = g_connections.find(conn);
1189 if (it == g_connections.end()) {
1190 g_last_error_details =
"Invalid connection handle";
1195 for (
size_t i = 0; i < count; ++i) {
1197 auto result = camera->
set(convert_vid_prop(props[i]), cpp_setting);
1198 if (!result.is_ok()) {
1199 g_last_error_details =
1200 "Failed to set video property at index " + std::to_string(i);
1201 return handle_cpp_result(result);
1206 }
catch (
const std::exception &e) {
1207 g_last_error_details =
1208 std::string(
"Failed to set multiple video properties: ") + e.what();
1220 if (!device || !setting)
1222 if (!g_initialized.load()) {
1223 g_last_error_details =
"Library not initialized";
1231 if (!cam_result.is_ok()) {
1232 return handle_cpp_result(cam_result);
1235 auto camera = std::move(cam_result).value();
1236 auto result = camera.get(convert_cam_prop(prop));
1237 if (!result.is_ok()) {
1238 return handle_cpp_result(result);
1241 *setting = convert_prop_setting_to_c(result.value());
1243 }
catch (
const std::exception &e) {
1244 g_last_error_details =
1245 std::string(
"Failed to quick get camera property: ") + e.what();
1254 if (!device || !setting)
1256 if (!g_initialized.load()) {
1257 g_last_error_details =
"Library not initialized";
1265 if (!cam_result.is_ok()) {
1266 return handle_cpp_result(cam_result);
1269 auto camera = std::move(cam_result).value();
1271 auto result = camera.set(convert_cam_prop(prop), cpp_setting);
1272 return handle_cpp_result(result);
1273 }
catch (
const std::exception &e) {
1274 g_last_error_details =
1275 std::string(
"Failed to quick set camera property: ") + e.what();
1283 if (!device || !range)
1285 if (!g_initialized.load()) {
1286 g_last_error_details =
"Library not initialized";
1294 if (!cam_result.is_ok()) {
1295 return handle_cpp_result(cam_result);
1298 auto camera = std::move(cam_result).value();
1299 auto result = camera.get_range(convert_cam_prop(prop));
1300 if (!result.is_ok()) {
1301 return handle_cpp_result(result);
1304 *range = convert_prop_range_to_c(result.value());
1306 }
catch (
const std::exception &e) {
1307 g_last_error_details =
1308 std::string(
"Failed to quick get camera property range: ") + e.what();
1316 if (!device || !setting)
1318 if (!g_initialized.load()) {
1319 g_last_error_details =
"Library not initialized";
1327 if (!cam_result.is_ok()) {
1328 return handle_cpp_result(cam_result);
1331 auto camera = std::move(cam_result).value();
1332 auto result = camera.get(convert_vid_prop(prop));
1333 if (!result.is_ok()) {
1334 return handle_cpp_result(result);
1337 *setting = convert_prop_setting_to_c(result.value());
1339 }
catch (
const std::exception &e) {
1340 g_last_error_details =
1341 std::string(
"Failed to quick get video property: ") + e.what();
1349 if (!device || !setting)
1351 if (!g_initialized.load()) {
1352 g_last_error_details =
"Library not initialized";
1360 if (!cam_result.is_ok()) {
1361 return handle_cpp_result(cam_result);
1364 auto camera = std::move(cam_result).value();
1366 auto result = camera.set(convert_vid_prop(prop), cpp_setting);
1367 return handle_cpp_result(result);
1368 }
catch (
const std::exception &e) {
1369 g_last_error_details =
1370 std::string(
"Failed to quick set video property: ") + e.what();
1378 if (!device || !range)
1380 if (!g_initialized.load()) {
1381 g_last_error_details =
"Library not initialized";
1389 if (!cam_result.is_ok()) {
1390 return handle_cpp_result(cam_result);
1393 auto camera = std::move(cam_result).value();
1394 auto result = camera.get_range(convert_vid_prop(prop));
1395 if (!result.is_ok()) {
1396 return handle_cpp_result(result);
1399 *range = convert_prop_range_to_c(result.value());
1401 }
catch (
const std::exception &e) {
1402 g_last_error_details =
1403 std::string(
"Failed to quick get video property range: ") + e.what();
1414 if (!device || !caps)
1416 if (!g_initialized.load()) {
1417 g_last_error_details =
"Library not initialized";
1425 if (!result.is_ok()) {
1426 return handle_cpp_result(result);
1429 std::lock_guard lock(g_capabilities_mutex);
1431 std::make_unique<duvc::DeviceCapabilities>(std::move(result.value()));
1434 g_capabilities_storage.push_back(std::move(stored_caps));
1438 }
catch (
const std::exception &e) {
1439 g_last_error_details =
1440 std::string(
"Failed to get device capabilities: ") + e.what();
1448 if (device_index < 0 || !caps)
1450 if (!g_initialized.load()) {
1451 g_last_error_details =
"Library not initialized";
1457 if (!result.is_ok()) {
1458 return handle_cpp_result(result);
1461 std::lock_guard lock(g_capabilities_mutex);
1463 std::make_unique<duvc::DeviceCapabilities>(std::move(result.value()));
1466 g_capabilities_storage.push_back(std::move(stored_caps));
1470 }
catch (
const std::exception &e) {
1471 g_last_error_details =
1472 std::string(
"Failed to get device capabilities by index: ") + e.what();
1478 if (!caps || !g_initialized.load()) {
1483 std::lock_guard lock(g_capabilities_mutex);
1484 auto it = std::find_if(
1485 g_capabilities_storage.begin(), g_capabilities_storage.end(),
1486 [caps](
const std::unique_ptr<duvc::DeviceCapabilities> &ptr) {
1487 return reinterpret_cast<duvc_device_capabilities_t *>(ptr.get()) ==
1491 if (it != g_capabilities_storage.end()) {
1492 g_capabilities_storage.erase(it);
1503 if (!g_initialized.load()) {
1504 g_last_error_details =
"Library not initialized";
1509 std::lock_guard lock(g_capabilities_mutex);
1512 auto result = cpp_caps->
refresh();
1513 return handle_cpp_result(result);
1514 }
catch (
const std::exception &e) {
1515 g_last_error_details =
1516 std::string(
"Failed to refresh device capabilities: ") + e.what();
1531 if (!g_initialized.load()) {
1532 g_last_error_details =
"Library not initialized";
1539 const auto &capability =
1542 if (!capability.supported) {
1543 g_last_error_details =
"Camera property not supported";
1548 *range = convert_prop_range_to_c(capability.range);
1552 *current = convert_prop_setting_to_c(capability.current);
1556 }
catch (
const std::exception &e) {
1557 g_last_error_details =
1558 std::string(
"Failed to get camera capability: ") + e.what();
1569 if (!g_initialized.load()) {
1570 g_last_error_details =
"Library not initialized";
1577 const auto &capability =
1580 if (!capability.supported) {
1581 g_last_error_details =
"Video property not supported";
1586 *range = convert_prop_range_to_c(capability.range);
1590 *current = convert_prop_setting_to_c(capability.current);
1594 }
catch (
const std::exception &e) {
1595 g_last_error_details =
1596 std::string(
"Failed to get video capability: ") + e.what();
1604 if (!caps || !supported)
1606 if (!g_initialized.load()) {
1607 g_last_error_details =
"Library not initialized";
1617 }
catch (
const std::exception &e) {
1618 g_last_error_details =
1619 std::string(
"Failed to check camera property support: ") + e.what();
1627 if (!caps || !supported)
1629 if (!g_initialized.load()) {
1630 g_last_error_details =
"Library not initialized";
1640 }
catch (
const std::exception &e) {
1641 g_last_error_details =
1642 std::string(
"Failed to check video property support: ") + e.what();
1650 size_t *actual_count) {
1651 if (!caps || !actual_count)
1653 if (!g_initialized.load()) {
1654 g_last_error_details =
"Library not initialized";
1663 *actual_count = supported_props.size();
1665 if (!props || max_count < supported_props.size()) {
1669 for (
size_t i = 0; i < supported_props.size(); ++i) {
1675 }
catch (
const std::exception &e) {
1676 g_last_error_details =
1677 std::string(
"Failed to get supported camera properties: ") + e.what();
1685 size_t *actual_count) {
1686 if (!caps || !actual_count)
1688 if (!g_initialized.load()) {
1689 g_last_error_details =
"Library not initialized";
1698 *actual_count = supported_props.size();
1700 if (!props || max_count < supported_props.size()) {
1704 for (
size_t i = 0; i < supported_props.size(); ++i) {
1710 }
catch (
const std::exception &e) {
1711 g_last_error_details =
1712 std::string(
"Failed to get supported video properties: ") + e.what();
1720 if (!caps || !accessible)
1722 if (!g_initialized.load()) {
1723 g_last_error_details =
"Library not initialized";
1732 }
catch (
const std::exception &e) {
1733 g_last_error_details =
1734 std::string(
"Failed to check device accessibility: ") + e.what();
1744 int32_t value,
int *valid) {
1745 if (!range || !valid) {
1751 if (value < range->min || value > range->
max) {
1757 if (range->
step > 0) {
1758 int32_t offset = value - range->
min;
1759 if (offset % range->
step != 0) {
1767 }
catch (
const std::exception &e) {
1768 g_last_error_details =
1769 std::string(
"Failed to validate property range: ") + e.what();
1775 int32_t value, int32_t *clamped_value) {
1776 if (!range || !clamped_value) {
1781 int32_t clamped = value;
1784 if (clamped < range->min) {
1785 clamped = range->
min;
1786 }
else if (clamped > range->
max) {
1787 clamped = range->
max;
1791 if (range->
step > 0) {
1792 int32_t offset = clamped - range->
min;
1793 int32_t remainder = offset % range->
step;
1794 if (remainder != 0) {
1796 if (remainder < range->step / 2) {
1797 clamped -= remainder;
1799 clamped += (range->
step - remainder);
1803 if (clamped > range->
max) {
1804 clamped = range->
max - (range->
max - range->
min) % range->
step;
1809 *clamped_value = clamped;
1811 }
catch (
const std::exception &e) {
1812 g_last_error_details =
1813 std::string(
"Failed to clamp property value: ") + e.what();
1819 int *supports_auto) {
1820 if (!range || !supports_auto) {
1828 }
catch (
const std::exception &e) {
1829 g_last_error_details =
1830 std::string(
"Failed to check auto mode support: ") + e.what();
1840 size_t *required_size) {
1841 return copy_string_to_buffer(g_last_error_details, buffer, buffer_size,
duvc_result_t duvc_get_multiple_video_properties(duvc_connection_t *conn, const duvc_vid_prop_t *props, duvc_prop_setting_t *settings, size_t count)
Get multiple video properties.
duvc_result_t duvc_get_supported_video_properties(const duvc_device_capabilities_t *caps, duvc_vid_prop_t *props, size_t max_count, size_t *actual_count)
Get list of supported video properties.
const char * duvc_cam_prop_to_string(duvc_cam_prop_t prop)
Convert camera property to string.
duvc_result_t duvc_set_camera_property(duvc_connection_t *conn, duvc_cam_prop_t prop, const duvc_prop_setting_t *setting)
Set camera property value.
duvc_result_t duvc_get_camera_property_range(duvc_connection_t *conn, duvc_cam_prop_t prop, duvc_prop_range_t *range)
Get camera property range.
duvc_result_t duvc_get_video_property_range(duvc_connection_t *conn, duvc_vid_prop_t prop, duvc_prop_range_t *range)
Get video property range.
duvc_result_t duvc_get_device_capabilities(const duvc_device_t *device, duvc_device_capabilities_t **caps)
Get device capabilities snapshot.
duvc_result_t duvc_supports_camera_property(const duvc_device_capabilities_t *caps, duvc_cam_prop_t prop, int *supported)
Check if camera property is supported.
duvc_result_t duvc_set_multiple_camera_properties(duvc_connection_t *conn, const duvc_cam_prop_t *props, const duvc_prop_setting_t *settings, size_t count)
Set multiple camera properties.
duvc_result_t duvc_refresh_device_capabilities(duvc_device_capabilities_t *caps)
Refresh capabilities snapshot.
duvc_result_t duvc_is_device_connected(const duvc_device_t *device, int *connected)
Check if device is connected.
void duvc_close_camera(duvc_connection_t *conn)
Close camera connection.
duvc_result_t duvc_initialize(void)
Initialize library.
void duvc_free_device_list(duvc_device_t **devices, size_t count)
Free device list.
duvc_result_t duvc_set_log_level(duvc_log_level_t level)
Set minimum log level.
duvc_result_t duvc_supports_video_property(const duvc_device_capabilities_t *caps, duvc_vid_prop_t prop, int *supported)
Check if video property is supported.
duvc_result_t duvc_device_is_valid(const duvc_device_t *device, int *valid)
Check if device is valid.
duvc_result_t duvc_quick_get_camera_property(const duvc_device_t *device, duvc_cam_prop_t prop, duvc_prop_setting_t *setting)
Quick get camera property (creates temporary connection)
duvc_result_t duvc_get_camera_property(duvc_connection_t *conn, duvc_cam_prop_t prop, duvc_prop_setting_t *setting)
Get camera property value.
duvc_result_t duvc_list_devices(duvc_device_t ***devices, size_t *count)
List all connected devices.
void duvc_unregister_device_change_callback(void)
Unregister device change callback.
const char * duvc_get_version_string(void)
Get library version string.
duvc_result_t duvc_get_device_name(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device name.
duvc_result_t duvc_log_error(const char *message)
Log error message.
duvc_result_t duvc_quick_get_camera_property_range(const duvc_device_t *device, duvc_cam_prop_t prop, duvc_prop_range_t *range)
Quick get camera property range.
duvc_result_t duvc_set_multiple_video_properties(duvc_connection_t *conn, const duvc_vid_prop_t *props, const duvc_prop_setting_t *settings, size_t count)
Set multiple video properties.
duvc_result_t duvc_get_device_capabilities_by_index(int device_index, duvc_device_capabilities_t **caps)
Get device capabilities by index.
duvc_result_t duvc_log_message(duvc_log_level_t level, const char *message)
Log message at specific level.
duvc_result_t duvc_get_device_id(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device ID.
const char * duvc_cam_mode_to_string(duvc_cam_mode_t mode)
Convert camera mode to string.
duvc_result_t duvc_log_info(const char *message)
Log info message.
duvc_result_t duvc_open_camera(const duvc_device_t *device, duvc_connection_t **conn)
Open camera by device handle.
duvc_result_t duvc_capabilities_is_device_accessible(const duvc_device_capabilities_t *caps, int *accessible)
Check if device is accessible.
duvc_result_t duvc_set_log_callback(duvc_log_callback callback, void *user_data)
Set log callback.
duvc_result_t duvc_get_supported_camera_properties(const duvc_device_capabilities_t *caps, duvc_cam_prop_t *props, size_t max_count, size_t *actual_count)
Get list of supported camera properties.
duvc_result_t duvc_find_device_by_path(const char *device_path_utf8, duvc_device_t **device)
Find device by unique Windows device path.
void duvc_free_device_capabilities(duvc_device_capabilities_t *caps)
Free device capabilities.
duvc_result_t duvc_prop_range_clamp(const duvc_prop_range_t *range, int32_t value, int32_t *clamped_value)
Clamp value to valid range.
duvc_result_t duvc_log_debug(const char *message)
Log debug message.
#define DUVC_ABI_VERSION_STRING
duvc_result_t duvc_quick_get_video_property_range(const duvc_device_t *device, duvc_vid_prop_t prop, duvc_prop_range_t *range)
Quick get video property range.
duvc_result_t duvc_set_video_property(duvc_connection_t *conn, duvc_vid_prop_t prop, const duvc_prop_setting_t *setting)
Set video property value.
int duvc_camera_is_valid(const duvc_connection_t *conn)
Check if camera connection is valid.
duvc_result_t duvc_get_multiple_camera_properties(duvc_connection_t *conn, const duvc_cam_prop_t *props, duvc_prop_setting_t *settings, size_t count)
Get multiple camera properties.
duvc_result_t duvc_quick_set_camera_property(const duvc_device_t *device, duvc_cam_prop_t prop, const duvc_prop_setting_t *setting)
Quick set camera property (creates temporary connection)
uint32_t duvc_get_version(void)
Get library version.
void duvc_shutdown(void)
Shutdown library.
duvc_result_t duvc_prop_capability_supports_auto(const duvc_prop_range_t *range, int *supports_auto)
Check if property supports auto mode.
duvc_result_t duvc_quick_get_video_property(const duvc_device_t *device, duvc_vid_prop_t prop, duvc_prop_setting_t *setting)
Quick get video property.
duvc_result_t duvc_log_warning(const char *message)
Log warning message.
duvc_result_t duvc_get_video_capability(const duvc_device_capabilities_t *caps, duvc_vid_prop_t prop, duvc_prop_range_t *range, duvc_prop_setting_t *current)
Get video property capability.
duvc_result_t duvc_quick_set_video_property(const duvc_device_t *device, duvc_vid_prop_t prop, const duvc_prop_setting_t *setting)
Quick set video property.
void duvc_clear_last_error(void)
Clear last error information.
int duvc_check_abi_compatibility(uint32_t compiled_version)
Check ABI compatibility.
const char * duvc_vid_prop_to_string(duvc_vid_prop_t prop)
Convert video property to string.
duvc_result_t duvc_prop_range_is_valid(const duvc_prop_range_t *range, int32_t value, int *valid)
Check if value is valid for range.
duvc_result_t duvc_log_critical(const char *message)
Log critical message.
duvc_result_t duvc_get_last_error_details(char *buffer, size_t buffer_size, size_t *required_size)
Get last error details.
duvc_result_t duvc_get_device_path(const duvc_device_t *device, char *buffer, size_t buffer_size, size_t *required)
Get device path.
const char * duvc_error_code_to_string(duvc_result_t code)
Convert error code to string.
duvc_result_t duvc_get_log_level(duvc_log_level_t *level)
Get current log level.
duvc_result_t duvc_open_camera_by_index(int device_index, duvc_connection_t **conn)
Open camera by device index.
duvc_result_t duvc_get_video_property(duvc_connection_t *conn, duvc_vid_prop_t prop, duvc_prop_setting_t *setting)
Get video property value.
duvc_result_t duvc_register_device_change_callback(duvc_device_change_callback callback, void *user_data)
Register device change callback.
duvc_result_t duvc_get_camera_capability(const duvc_device_capabilities_t *caps, duvc_cam_prop_t prop, duvc_prop_range_t *range, duvc_prop_setting_t *current)
Get camera property capability.
int duvc_is_initialized(void)
Check if library is initialized.
const char * duvc_log_level_to_string(duvc_log_level_t level)
Convert log level to string.
Complete C ABI for duvc-ctl with comprehensive API coverage.
duvc_result_t
Result codes for duvc operations.
@ DUVC_ERROR_TIMEOUT
Operation timed out.
@ DUVC_ERROR_CONNECTION_FAILED
Failed to establish device connection.
@ DUVC_ERROR_INVALID_ARGUMENT
Invalid function argument provided.
@ DUVC_ERROR_INVALID_VALUE
Property value out of valid range.
@ DUVC_ERROR_NOT_IMPLEMENTED
Feature not implemented on this platform.
@ DUVC_ERROR_DEVICE_BUSY
Device is busy or in use by another process.
@ DUVC_ERROR_PERMISSION_DENIED
Insufficient permissions to access device.
@ DUVC_ERROR_DEVICE_NOT_FOUND
Device not found or disconnected.
@ DUVC_ERROR_BUFFER_TOO_SMALL
Provided buffer is too small for data.
@ DUVC_ERROR_SYSTEM_ERROR
System/platform error occurred.
@ DUVC_ERROR_PROPERTY_NOT_SUPPORTED
Property not supported by device.
@ DUVC_SUCCESS
Operation completed successfully.
duvc_vid_prop_t
Video processing properties.
duvc_cam_prop_t
Camera control properties.
void(* duvc_log_callback)(duvc_log_level_t level, const char *message, void *user_data)
Log message callback.
#define DUVC_LOG_ERROR(msg)
struct duvc_connection_t duvc_connection_t
Opaque camera connection handle.
duvc_cam_mode_t
Camera control modes.
@ DUVC_CAM_MODE_AUTO
Automatic control by camera.
#define DUVC_LOG_WARNING(msg)
struct duvc_device_capabilities_t duvc_device_capabilities_t
Opaque device capabilities handle.
struct duvc_device_t duvc_device_t
Opaque device handle.
#define DUVC_LOG_INFO(msg)
duvc_log_level_t
Log levels.
#define DUVC_LOG_CRITICAL(msg)
void(* duvc_device_change_callback)(int added, const char *device_path, void *user_data)
Device hotplug callback.
#define DUVC_LOG_DEBUG(msg)
RAII camera handle for simplified device management.
Device capability detection and snapshots using Camera API.
RAII camera handle for simplified device management.
Result< void > set(CamProp prop, const PropSetting &setting)
Set camera property value.
Result< PropSetting > get(CamProp prop)
Get camera property value.
Complete device capability snapshot.
const PropertyCapability & get_video_capability(VidProp prop) const
Get video property capability.
std::vector< CamProp > supported_camera_properties() const
Get list of supported camera properties.
bool supports_video_property(VidProp prop) const
Check if video property is supported.
Result< void > refresh()
Refresh capability snapshot.
bool supports_camera_property(CamProp prop) const
Check if camera property is supported.
std::vector< VidProp > supported_video_properties() const
Get list of supported video properties.
const PropertyCapability & get_camera_capability(CamProp prop) const
Get camera property capability.
bool is_device_accessible() const
Check if device is connected and accessible.
Result type that can contain either a value or an error.
bool is_ok() const
Check if result contains a value (success)
const Error & error() const
Get the error (assumes error)
Windows-specific device connection pooling.
Device enumeration and management functions.
HRESULT decoder and diagnostics utilities.
Structured logging interface for duvc-ctl.
void log_info(const std::string &message)
Log info message.
VidProp
Video processing properties (IAMVideoProcAmp interface)
ErrorCode
Error codes for duvc operations.
@ InvalidValue
Property value out of range.
@ InvalidArgument
Invalid function argument.
@ DeviceBusy
Device is busy or in use.
@ PermissionDenied
Insufficient permissions.
@ Success
Operation succeeded.
@ PropertyNotSupported
Property not supported by device.
@ NotImplemented
Feature not implemented on this platform.
@ SystemError
System/platform error.
@ DeviceNotFound
Device not found or disconnected.
Result< DeviceCapabilities > get_device_capabilities(const Device &device)
Create device capability snapshot.
std::vector< Device > list_devices()
Enumerate all available video input devices.
void unregister_device_change_callback()
Unregister device change callback.
CamMode
Property control mode.
@ Info
Informational messages.
const wchar_t * to_wstring(CamProp)
Convert camera property enum to wide string.
void set_log_callback(LogCallback callback)
Set global log callback.
const char * to_string(CamProp)
Convert camera property enum to string.
std::string to_utf8(const std::wstring &wstr)
Converts a wide string (UTF-16 on Windows) to a UTF-8 string.
CamProp
Camera control properties (IAMCameraControl interface)
void log_message(LogLevel level, const std::string &message)
Log a message.
bool is_device_connected(const Device &dev)
Check if a device is currently connected and accessible.
void register_device_change_callback(DeviceChangeCallback callback)
Register callback for device hotplug events.
Result< Camera > open_camera(int device_index)
Create camera from device index.
void set_log_level(LogLevel level)
Set minimum log level.
Device find_device_by_path(const std::wstring &device_path)
Find device by unique Windows device path.
LogLevel get_log_level()
Get current minimum log level.
Result/Error type system for duvc-ctl.
String conversion utilities for enums and types.
Represents a camera device.
std::wstring path
Unique device path/identifier.
std::wstring name
Human-readable device name.
bool is_valid() const
Check if device has valid identifying information.
Property range and default information.
int default_val
Default value.
int min
Minimum supported value.
int step
Step size between valid values.
int max
Maximum supported value.
CamMode default_mode
Default control mode.
Property setting with value and control mode.
CamMode mode
Control mode (auto/manual)
Property range information.
int32_t max
Maximum supported value.
duvc_cam_mode_t default_mode
Default control mode.
int32_t step
Step size between valid values.
int32_t min
Minimum supported value.
int32_t default_val
Default value.
Property setting with value and mode.
duvc_cam_mode_t mode
Control mode (auto/manual)
int32_t value
Property value.
Core data types and enumerations for duvc-ctl.