Lists all available camera devices connected to the system # Returns A vector of `DeviceInfo` structs containing device name, ID, and backend information. Returns an empty vector if no devices are found.
()
| 98 | /// A vector of `DeviceInfo` structs containing device name, ID, and backend information. |
| 99 | /// Returns an empty vector if no devices are found. |
| 100 | pub fn list_devices() -> Result<Vec<DeviceInfo>> { |
| 101 | initialize_mf()?; |
| 102 | |
| 103 | unsafe { |
| 104 | // Create media foundation attributes for device enumeration |
| 105 | let mut attributes = MaybeUninit::<Option<IMFAttributes>>::uninit(); |
| 106 | MFCreateAttributes(attributes.as_mut_ptr(), 1).map_err(hresult_to_camera_error)?; |
| 107 | let attributes = attributes |
| 108 | .assume_init() |
| 109 | .ok_or_else(|| CameraError::Io(std::io::Error::other("Failed to create attributes")))?; |
| 110 | |
| 111 | // Set the source type to video capture devices |
| 112 | attributes |
| 113 | .SetGUID( |
| 114 | &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, |
| 115 | &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID, |
| 116 | ) |
| 117 | .map_err(hresult_to_camera_error)?; |
| 118 | |
| 119 | // Enumerate all video capture devices |
| 120 | let mut pp_devices = MaybeUninit::<*mut Option<IMFActivate>>::uninit(); |
| 121 | let mut count = MaybeUninit::<u32>::uninit(); |
| 122 | |
| 123 | MFEnumDeviceSources(&attributes, pp_devices.as_mut_ptr(), count.as_mut_ptr()) |
| 124 | .map_err(hresult_to_camera_error)?; |
| 125 | |
| 126 | let pp_devices = pp_devices.assume_init(); |
| 127 | let count = count.assume_init(); |
| 128 | |
| 129 | if count == 0 || pp_devices.is_null() { |
| 130 | return Ok(Vec::new()); |
| 131 | } |
| 132 | |
| 133 | // Convert raw pointer to slice for safe iteration |
| 134 | let slice = std::slice::from_raw_parts_mut(pp_devices, count as usize); |
| 135 | let mut result = Vec::with_capacity(count as usize); |
| 136 | |
| 137 | // Extract device information from each IMFActivate object |
| 138 | for activate_opt in slice { |
| 139 | if let Some(device) = activate_opt.take() { |
| 140 | let name = get_attribute_string(&device, MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME); |
| 141 | |
| 142 | // Skip devices with empty names early to avoid unnecessary ID retrieval |
| 143 | if !name.is_empty() { |
| 144 | let id = get_attribute_string( |
| 145 | &device, |
| 146 | MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, |
| 147 | ); |
| 148 | |
| 149 | result.push(DeviceInfo { |
| 150 | name, |
| 151 | id, |
| 152 | backend: "MSMF".to_string(), |
| 153 | bus_info: None, |
| 154 | }); |
| 155 | } |
| 156 | } |
| 157 | } |
no test coverage detected