use crate::error::FindDevicesError;
use crate::error::FindDevicesError::MediaTypeSupported;
use crate::error::FindDevicesError::OsNotSupported;
use ffmpeg_sys_next::{avdevice_free_list_devices, avdevice_list_input_sources, AVMediaType};
use std::ffi::CStr;
use std::ptr::{null, null_mut};
pub fn find_input_video_device_list() -> crate::error::Result<Vec<String>> {
find_input_device_list(AVMediaType::AVMEDIA_TYPE_VIDEO)
}
pub fn find_input_audio_device_list() -> crate::error::Result<Vec<String>> {
find_input_device_list(AVMediaType::AVMEDIA_TYPE_AUDIO)
}
fn find_input_device_list(media_type: AVMediaType) -> crate::error::Result<Vec<String>> {
unsafe {
crate::core::initialize_ffmpeg();
let mut device_descriptions = Vec::new();
let mut device_list = null_mut();
let device_name = if media_type == AVMediaType::AVMEDIA_TYPE_VIDEO {
if cfg!(target_os = "windows") {
std::ffi::CString::new("dshow").unwrap()
} else if cfg!(target_os = "linux") {
std::ffi::CString::new("v4l2").unwrap()
} else {
return Err(OsNotSupported.into());
}
} else if media_type == AVMediaType::AVMEDIA_TYPE_AUDIO {
if cfg!(target_os = "windows") {
std::ffi::CString::new("dshow").unwrap()
} else if cfg!(target_os = "linux") {
std::ffi::CString::new("alsa").unwrap()
} else {
return Err(OsNotSupported.into());
}
} else {
return Err(MediaTypeSupported(media_type as i32).into());
};
let ret = avdevice_list_input_sources(null(), device_name.as_ptr(), null_mut(), &mut device_list);
if ret >= 0 && !device_list.is_null() {
let nb_devices = (*device_list).nb_devices;
for i in 0..nb_devices {
let device = *(*device_list).devices.offset(i as isize);
let nb_media_types = (*device).nb_media_types;
let media_types = (*device).media_types;
let mut flag = false;
for j in 0..nb_media_types {
let device_media_type = *media_types.offset(j as isize);
if device_media_type == media_type {
flag = true;
break;
}
}
if !flag {
continue;
}
let result = CStr::from_ptr((*device).device_description).to_str();
if let Err(_e) = result {
return Err(FindDevicesError::UTF8Error.into());
}
let device_description = result.unwrap();
device_descriptions.push(device_description.to_string());
}
}
avdevice_free_list_devices(&mut device_list);
Ok(device_descriptions)
}
}