1use std::{
2 mem::MaybeUninit,
3 num::NonZeroU32,
4 ptr::null_mut,
5 slice::from_raw_parts,
6 sync::{
7 atomic::{AtomicBool, Ordering::SeqCst},
8 Arc, Condvar, Mutex, Weak,
9 },
10 time::Duration,
11};
12
13use media_core::{
14 error::Error,
15 frame::Frame,
16 none_param_error, not_found_error,
17 time::NSEC_PER_MSEC,
18 variant::Variant,
19 video::{ColorRange, CompressionFormat, Origin, PixelFormat, VideoFormat, VideoFrameDescriptor},
20 Result,
21};
22use windows::{
23 core::{implement, AsImpl, Interface, GUID, PWSTR},
24 Win32::{
25 Media::MediaFoundation::{
26 IMF2DBuffer, IMF2DBuffer2, IMFActivate, IMFAttributes, IMFMediaBuffer, IMFMediaEvent, IMFMediaSource, IMFMediaType, IMFSample,
27 IMFSourceReader, IMFSourceReaderCallback, IMFSourceReaderCallback_Impl, MF2DBuffer_LockFlags_Read, MFCreateAttributes,
28 MFCreateSourceReaderFromMediaSource, MFEnumDeviceSources, MFGetStrideForBitmapInfoHeader, MFMediaType_Video, MFNominalRange,
29 MFNominalRange_Normal, MFNominalRange_Wide, MFShutdown, MFStartup, MFVideoFormat_ARGB32, MFVideoFormat_I420, MFVideoFormat_MJPG,
30 MFVideoFormat_NV12, MFVideoFormat_RGB24, MFVideoFormat_UYVY, MFVideoFormat_YUY2, MFVideoFormat_YV12, MFSTARTUP_LITE,
31 MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID,
32 MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, MF_MT_DEFAULT_STRIDE, MF_MT_FRAME_RATE, MF_MT_FRAME_SIZE, MF_MT_MAJOR_TYPE,
33 MF_MT_SUBTYPE, MF_MT_VIDEO_NOMINAL_RANGE, MF_READWRITE_DISABLE_CONVERTERS, MF_SOURCE_READER_ASYNC_CALLBACK,
34 MF_SOURCE_READER_FIRST_VIDEO_STREAM, MF_VERSION,
35 },
36 System::Com::{CoInitializeEx, CoTaskMemFree, CoUninitialize, COINIT_APARTMENTTHREADED, COINIT_DISABLE_OLE1DDE},
37 },
38};
39
40use crate::{camera::CameraFormat, Device, DeviceEvent, DeviceEventHandler, DeviceInformation, DeviceManager, OutputDevice, OutputHandler};
41
42pub struct MediaFoundationDeviceManager {
43 devices: Option<Vec<MediaFoundationDevice>>,
44 handler: Option<DeviceEventHandler>,
45}
46
47impl DeviceManager for MediaFoundationDeviceManager {
48 type DeviceType = MediaFoundationDevice;
49
50 fn init() -> Result<Self>
51 where
52 Self: Sized,
53 {
54 unsafe {
55 CoInitializeEx(None, COINIT_APARTMENTTHREADED | COINIT_DISABLE_OLE1DDE).ok().map_err(|err| Error::InitializationFailed(err.message()))?;
56 MFStartup(MF_VERSION, MFSTARTUP_LITE).map_err(|err| Error::InitializationFailed(err.message()))?;
57 }
58 Ok(Self {
59 devices: None,
60 handler: None,
61 })
62 }
63
64 fn deinit(&mut self) {
65 unsafe {
66 MFShutdown().ok();
67 CoUninitialize();
68 }
69 }
70
71 fn list(&self) -> Vec<&Self::DeviceType> {
72 self.devices.as_ref().map(|devices| devices.iter().collect()).unwrap_or_default()
73 }
74
75 fn index(&self, index: usize) -> Option<&Self::DeviceType> {
76 self.devices.as_ref().and_then(|devices| devices.get(index))
77 }
78
79 fn index_mut(&mut self, index: usize) -> Option<&mut Self::DeviceType> {
80 self.devices.as_mut().and_then(|devices| devices.get_mut(index))
81 }
82
83 fn lookup(&self, id: &str) -> Option<&Self::DeviceType> {
84 self.devices.as_ref().and_then(|devices| devices.iter().find(|device| device.info.id == id))
85 }
86
87 fn lookup_mut(&mut self, id: &str) -> Option<&mut Self::DeviceType> {
88 self.devices.as_mut().and_then(|devices| devices.iter_mut().find(|device| device.info.id == id))
89 }
90
91 fn refresh(&mut self) -> Result<()> {
92 let device_sources = Self::get_device_sources()?;
93 let mut devices = Vec::with_capacity(device_sources.len());
94
95 for (index, activate) in device_sources.iter().enumerate() {
96 let dev_info = DeviceInformation::from_source_activate(activate)?;
97 devices.push(MediaFoundationDevice::new(dev_info, index)?);
98 }
99
100 let count = devices.len();
101 self.devices = Some(devices);
102 if let Some(handler) = &self.handler {
103 handler(&DeviceEvent::Refreshed(count));
104 }
105 Ok(())
106 }
107
108 fn set_change_handler<F>(&mut self, handler: F) -> Result<()>
109 where
110 F: Fn(&DeviceEvent) + Send + Sync + 'static,
111 {
112 self.handler = Some(Box::new(handler));
113 Ok(())
114 }
115}
116
117impl Default for MediaFoundationDeviceManager {
118 fn default() -> Self {
119 Self::new()
120 }
121}
122
123impl MediaFoundationDeviceManager {
124 pub fn new() -> Self {
125 Self {
126 devices: None,
127 handler: None,
128 }
129 }
130
131 fn get_device_sources() -> Result<Vec<IMFActivate>> {
132 let attributes: IMFAttributes = unsafe {
133 let mut attributes: Option<IMFAttributes> = None;
134 MFCreateAttributes(&mut attributes, 1).map_err(|err| Error::CreationFailed(err.message()))?;
135 attributes.ok_or_else(|| none_param_error!(attributes))?
136 };
137
138 unsafe {
139 attributes
140 .SetGUID(&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE, &MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_GUID)
141 .map_err(|err| Error::SetFailed(err.message()))?;
142 }
143
144 let mut source_activate_ptr: MaybeUninit<*mut Option<IMFActivate>> = MaybeUninit::uninit();
145 let mut source_activate_count: u32 = 0;
146 unsafe {
147 MFEnumDeviceSources(&attributes, source_activate_ptr.as_mut_ptr(), &mut source_activate_count)
148 .map_err(|err| Error::Failed(err.message()))?;
149 }
150
151 let mut device_sources = vec![];
152
153 if source_activate_count > 0 {
154 unsafe { from_raw_parts(source_activate_ptr.assume_init(), source_activate_count as usize) }.iter().for_each(|ptr| {
155 if let Some(activate) = ptr {
156 device_sources.push(activate.clone());
157 }
158 });
159 };
160
161 Ok(device_sources)
162 }
163}
164
165impl DeviceInformation {
166 fn from_source_activate(activate: &IMFActivate) -> Result<Self> {
167 let mut symbolic_link_ptr = PWSTR(null_mut());
168 let mut symbolic_link_len = 0;
169 unsafe {
170 activate
171 .GetAllocatedString(&MF_DEVSOURCE_ATTRIBUTE_SOURCE_TYPE_VIDCAP_SYMBOLIC_LINK, &mut symbolic_link_ptr, &mut symbolic_link_len)
172 .map_err(|err| Error::Failed(err.message()))?;
173 }
174 if symbolic_link_ptr.is_null() {
175 return Err(none_param_error!(symbolic_link_ptr));
176 }
177 let id = unsafe {
178 let symbolic_link = symbolic_link_ptr.to_string().map_err(|err| Error::Failed(err.to_string()));
179 CoTaskMemFree(Some(symbolic_link_ptr.as_ptr() as _));
180 symbolic_link?
181 };
182
183 let mut friendly_name_ptr = PWSTR(null_mut());
184 let mut friendly_name_len = 0;
185 unsafe {
186 activate
187 .GetAllocatedString(&MF_DEVSOURCE_ATTRIBUTE_FRIENDLY_NAME, &mut friendly_name_ptr, &mut friendly_name_len)
188 .map_err(|err| Error::Failed(err.message()))?;
189 }
190 if friendly_name_ptr.is_null() {
191 return Err(none_param_error!(friendly_name_ptr));
192 }
193 let name = unsafe {
194 let name = friendly_name_ptr.to_string().map_err(|err| Error::Failed(err.to_string()));
195 CoTaskMemFree(Some(friendly_name_ptr.as_ptr() as _));
196 name?
197 };
198
199 Ok(Self {
200 id,
201 name,
202 })
203 }
204}
205
206struct BufferLockGuard<'a> {
207 buffer: &'a IMFMediaBuffer,
208 buffer_2d: Option<IMF2DBuffer>,
209 data: &'a [u8],
210 stride: i32,
211}
212
213impl<'a> BufferLockGuard<'a> {
214 fn new(buffer: &'a IMFMediaBuffer, height: NonZeroU32) -> windows_core::Result<Self> {
215 let buffer_2d = buffer.cast::<IMF2DBuffer>();
216 let mut buffer_ptr = null_mut::<u8>();
217 let mut buffer_stride = 0;
218 let mut buffer_length = 0;
219
220 let mut result = match &buffer_2d {
221 Ok(buffer_2d_ref) => {
222 let mut scanline_ptr = null_mut::<u8>();
223 let mut result = match buffer.cast::<IMF2DBuffer2>() {
224 Ok(buffer_2d_2) => unsafe {
225 buffer_2d_2.Lock2DSize(MF2DBuffer_LockFlags_Read, &mut scanline_ptr, &mut buffer_stride, &mut buffer_ptr, &mut buffer_length)
226 },
227 Err(err) => Err(err),
228 };
229
230 if result.is_err() {
231 unsafe {
232 result = buffer_2d_ref.Lock2D(&mut scanline_ptr, &mut buffer_stride);
233 if result.is_ok() {
234 if buffer_stride < 0 {
235 buffer_ptr = scanline_ptr.offset((height.get() - 1) as isize * buffer_stride as isize);
236 } else {
237 buffer_ptr = scanline_ptr;
238 }
239
240 match buffer.GetCurrentLength() {
241 Ok(length) => buffer_length = length,
242 Err(err) => {
243 result = Err(err);
244 buffer_2d_ref.Unlock2D().ok();
245 }
246 }
247 }
248 };
249 }
250
251 result
252 }
253 Err(err) => Err(err.clone()),
254 };
255
256 let buffer_2d = if result.is_err() {
257 result = unsafe { buffer.Lock(&mut buffer_ptr, None, Some(&mut buffer_length)) };
258 None
259 } else {
260 buffer_2d.ok()
261 };
262
263 result.map(|_| {
264 let data = unsafe { from_raw_parts(buffer_ptr, buffer_length as usize) };
265 Self {
266 buffer,
267 buffer_2d,
268 data,
269 stride: buffer_stride,
270 }
271 })
272 }
273}
274
275impl Drop for BufferLockGuard<'_> {
276 fn drop(&mut self) {
277 if let Some(buffer_2d) = &self.buffer_2d {
278 unsafe {
279 buffer_2d.Unlock2D().ok();
280 }
281 } else {
282 unsafe {
283 self.buffer.Unlock().ok();
284 }
285 }
286 }
287}
288
289#[implement(IMFSourceReaderCallback)]
290struct SourceReaderCallback {
291 info: DeviceInformation,
292 current_format: Option<CameraFormat>,
293 stride_cache: Option<i32>,
294 handler: OutputHandler,
295 source_reader: Weak<Mutex<IMFSourceReader>>,
296 running: AtomicBool,
297 signal: Option<Arc<(Mutex<bool>, Condvar)>>,
298}
299
300impl SourceReaderCallback {
301 pub fn new(info: DeviceInformation, handler: OutputHandler) -> Self {
302 Self {
303 info,
304 current_format: None,
305 stride_cache: None,
306 handler,
307 source_reader: Weak::new(),
308 running: AtomicBool::new(false),
309 signal: None,
310 }
311 }
312
313 pub fn get_default_stride(&self) -> i32 {
314 self.stride_cache.unwrap_or(0)
315 }
316
317 pub fn set_default_stride(&mut self, stride: i32) {
318 self.stride_cache = Some(stride);
319 }
320
321 pub fn set_source_reader(&mut self, source_reader: &Arc<Mutex<IMFSourceReader>>) {
322 self.source_reader = Arc::downgrade(source_reader);
323 }
324
325 pub fn set_current_format(&mut self, current_format: CameraFormat) {
326 self.current_format = Some(current_format);
327 }
328
329 pub fn set_running(&self, running: bool) {
330 self.running.store(running, SeqCst);
331 }
332
333 pub fn set_signal(&mut self, signal: Option<Arc<(Mutex<bool>, Condvar)>>) {
334 self.signal = signal;
335 }
336}
337
338impl IMFSourceReaderCallback_Impl for SourceReaderCallback_Impl {
339 fn OnReadSample(
340 &self,
341 hrstatus: windows_core::HRESULT,
342 _dwstreamindex: u32,
343 _dwstreamflags: u32,
344 lltimestamp: i64,
345 psample: windows_core::Ref<'_, IMFSample>,
346 ) -> windows_core::Result<()> {
347 if hrstatus.is_err() || !self.running.load(SeqCst) {
348 return Ok(());
349 }
350
351 let current_format = match &self.current_format {
352 Some(format) => format,
353 None => return Ok(()),
354 };
355
356 let width = match NonZeroU32::new(current_format.width) {
357 Some(width) => width,
358 None => return Ok(()),
359 };
360 let height = match NonZeroU32::new(current_format.height) {
361 Some(height) => height,
362 None => return Ok(()),
363 };
364 let pixel_format = match current_format.format {
365 VideoFormat::Pixel(format) => format,
366 _ => return Ok(()),
367 };
368
369 let buffer = psample.as_ref().and_then(|sample| unsafe { sample.ConvertToContiguousBuffer().ok() });
370
371 if let Some(buffer) = buffer {
372 if let Ok(locked_buffer) = BufferLockGuard::new(&buffer, height) {
373 let stride = if locked_buffer.stride == 0 {
374 self.get_default_stride()
375 } else {
376 locked_buffer.stride
377 };
378
379 let (stride, origin) = if stride >= 0 {
380 (stride as u32, Origin::TopDown)
381 } else {
382 (-stride as u32, Origin::BottomUp)
383 };
384
385 let mut desc = VideoFrameDescriptor::new(pixel_format, width, height);
386 desc.color_range = current_format.color_range;
387 desc.origin = origin;
388
389 let video_frame = if stride != 0 {
390 Frame::video_creator().create_from_aligned_buffer_with_descriptor(desc, NonZeroU32::new(stride).unwrap(), locked_buffer.data)
391 } else {
392 Frame::video_creator().create_from_buffer_with_descriptor(desc, locked_buffer.data)
393 };
394
395 if let Ok(mut video_frame) = video_frame {
396 video_frame.source = Some(self.info.id.clone());
397 video_frame.pts = Some(lltimestamp * 100 / NSEC_PER_MSEC as i64); let handler = self.handler.as_ref();
399 handler(video_frame).ok();
400 }
401 }
402 };
403
404 let source_reader = self.source_reader.upgrade();
405 if let Some(source_reader) = source_reader {
406 unsafe {
407 source_reader.lock().unwrap().ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, 0, None, None, None, None).ok();
408 }
409 };
410
411 Ok(())
412 }
413
414 fn OnFlush(&self, _dwstreamindex: u32) -> windows_core::Result<()> {
415 if let Some(signal) = &self.signal {
416 let (lock, condvar) = &**signal;
417 let mut flushed = lock.lock().unwrap();
418 *flushed = true;
419 condvar.notify_one();
420 }
421 Ok(())
422 }
423
424 fn OnEvent(&self, _dwstreamindex: u32, _pevent: windows_core::Ref<'_, IMFMediaEvent>) -> windows_core::Result<()> {
425 Ok(())
426 }
427}
428
429fn from_mf_video_format(subtype: GUID) -> Option<VideoFormat> {
430 #[allow(non_snake_case, non_upper_case_globals)]
431 match subtype {
432 MFVideoFormat_I420 => Some(VideoFormat::Pixel(PixelFormat::I420)),
433 MFVideoFormat_YUY2 => Some(VideoFormat::Pixel(PixelFormat::YUYV)),
434 MFVideoFormat_UYVY => Some(VideoFormat::Pixel(PixelFormat::UYVY)),
435 MFVideoFormat_ARGB32 => Some(VideoFormat::Pixel(PixelFormat::ARGB32)),
436 MFVideoFormat_RGB24 => Some(VideoFormat::Pixel(PixelFormat::RGB24)),
437 MFVideoFormat_MJPG => Some(VideoFormat::Compression(CompressionFormat::MJPEG)),
438 MFVideoFormat_NV12 => Some(VideoFormat::Pixel(PixelFormat::NV12)),
439 MFVideoFormat_YV12 => Some(VideoFormat::Pixel(PixelFormat::YV12)),
440 _ => None,
441 }
442}
443
444fn get_radio(media_type: &IMFMediaType, key: &GUID) -> Result<f32> {
445 let (numerator, denominator) = match unsafe { media_type.GetUINT64(key) } {
446 Ok(value) => {
447 let numerator = (value >> 32) as u32;
448 let denominator = value as u32;
449 (numerator, denominator)
450 }
451 Err(err) => return Err(Error::GetFailed(err.message())),
452 };
453
454 Ok(numerator as f32 / denominator as f32)
455}
456
457fn from_mf_media_type(media_type: &IMFMediaType) -> Option<CameraFormat> {
458 if let Ok(major_type) = unsafe { media_type.GetGUID(&MF_MT_MAJOR_TYPE) } {
459 if major_type != MFMediaType_Video {
460 return None;
461 }
462 } else {
463 return None;
464 }
465
466 let subtype = match unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) } {
467 Ok(subtype) => subtype,
468 Err(_) => return None,
469 };
470
471 let format = from_mf_video_format(subtype)?;
472
473 let color_range = match unsafe { media_type.GetUINT32(&MF_MT_VIDEO_NOMINAL_RANGE) } {
474 #[allow(non_upper_case_globals)]
475 Ok(range) => match MFNominalRange(range as i32) {
476 MFNominalRange_Normal => ColorRange::Full,
477 MFNominalRange_Wide => ColorRange::Video,
478 _ => ColorRange::Unspecified,
479 },
480 Err(_) => ColorRange::Unspecified,
481 };
482
483 let (width, height) = match unsafe { media_type.GetUINT64(&MF_MT_FRAME_SIZE) } {
484 Ok(value) => {
485 let width = (value >> 32) as u32;
486 let height = value as u32;
487 (width, height)
488 }
489 Err(_) => return None,
490 };
491
492 let frame_rate = match get_radio(media_type, &MF_MT_FRAME_RATE) {
493 Ok(frame_rate) => frame_rate,
494 Err(_) => return None,
495 };
496
497 Some(CameraFormat {
498 format,
499 color_range,
500 width,
501 height,
502 frame_rates: vec![frame_rate],
503 })
504}
505
506fn get_formats(source_reader: &IMFSourceReader) -> Result<Vec<CameraFormat>> {
507 let mut video_formats = vec![];
508 let mut index = 0;
509
510 while let Ok(media_type) = unsafe { source_reader.GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, index) } {
511 if let Some(camera_format) = from_mf_media_type(&media_type) {
512 video_formats.push(camera_format);
513 }
514 index += 1;
515 }
516
517 Ok(video_formats)
518}
519
520fn get_current_format(source_reader: &IMFSourceReader) -> Result<CameraFormat> {
521 let media_type = unsafe { source_reader.GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32) };
522 let media_type = media_type.map_err(|err| Error::GetFailed(err.message()))?;
523 let camera_format = from_mf_media_type(&media_type).ok_or_else(|| Error::Unsupported(stringify!(media_type).to_string()))?;
524 Ok(camera_format)
525}
526
527fn get_default_stride_with_width(source_reader: &IMFSourceReader, width: u32) -> Option<i32> {
528 let media_type = unsafe { source_reader.GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32) }.ok()?;
529 let stride = unsafe { media_type.GetUINT32(&MF_MT_DEFAULT_STRIDE) }.ok().map(|s| s as i32);
530
531 if stride.is_some() {
532 return stride;
533 }
534
535 let sub_type = unsafe { media_type.GetGUID(&MF_MT_SUBTYPE) }.ok()?;
536 let stride = unsafe { MFGetStrideForBitmapInfoHeader(sub_type.data1, width).ok() };
537
538 if let Some(stride) = stride {
539 unsafe { media_type.SetUINT32(&MF_MT_DEFAULT_STRIDE, stride as u32) }.ok();
540 }
541
542 stride
543}
544
545fn start_internal(source_reader: &IMFSourceReader, callback: &mut SourceReaderCallback, camera_format: &CameraFormat) {
546 callback.set_current_format(camera_format.clone());
547 if let Some(stride) = get_default_stride_with_width(source_reader, camera_format.width) {
548 callback.set_default_stride(stride);
549 }
550
551 unsafe {
552 source_reader.SetStreamSelection(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, true).ok();
553 source_reader.ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, 0, None, None, None, None).ok();
554 }
555
556 callback.set_running(true);
557}
558
559const TIMEOUT_SECONDS: u64 = 1;
560
561fn stop_internal(source_reader: &IMFSourceReader, callback: &mut SourceReaderCallback) -> Result<()> {
562 callback.set_running(false);
563 let signal = Arc::new((Mutex::new(false), Condvar::new()));
564 callback.set_signal(Some(signal.clone()));
565
566 let wait = unsafe {
567 match source_reader.Flush(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32) {
568 Ok(()) => true,
569 Err(err) => return Err(Error::StopFailed(err.message())),
570 }
571 };
572
573 if wait {
574 let (lock, condvar) = &*signal;
575 let flushed = lock.lock().map_err(|err| Error::StopFailed(err.to_string()))?;
576 if !*flushed {
577 condvar.wait_timeout(flushed, Duration::from_secs(TIMEOUT_SECONDS)).ok();
578 }
579 }
580
581 Ok(())
582}
583
584const SIMILAR_FORMAT_DIFF: f32 = 1.0;
585const DIFFERENT_FORMAT_DIFF: f32 = 2.0;
586
587fn match_supported_format(
588 source_reader: &IMFSourceReader,
589 width: Option<u32>,
590 height: Option<u32>,
591 video_format: Option<VideoFormat>,
592 frame_rate: Option<f32>,
593) -> Option<IMFMediaType> {
594 let mut matched_media_type: Option<IMFMediaType> = None;
595 let mut min_diff = f32::MAX;
596 let mut index = 0;
597
598 while let Ok(media_type) = unsafe { source_reader.GetNativeMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, index) } {
599 if let Some(camera_format) = from_mf_media_type(&media_type) {
600 let resolution_diff = match (width, height) {
601 (Some(width), Some(height)) => {
602 (camera_format.width as f32 - width as f32).abs() + (camera_format.height as f32 - height as f32).abs()
603 }
604 _ => 0.0,
605 };
606
607 let frame_rate_diff = match frame_rate {
608 Some(frame_rate) => (camera_format.frame_rates[0] - frame_rate).abs(),
609 None => 0.0,
610 };
611
612 let format_diff = match video_format {
613 Some(video_format) => {
614 if camera_format.format == video_format {
615 0.0
616 } else if camera_format.format.is_yuv() && video_format.is_yuv() {
617 SIMILAR_FORMAT_DIFF
618 } else {
619 DIFFERENT_FORMAT_DIFF
620 }
621 }
622 None => 0.0,
623 };
624
625 let diff = resolution_diff + frame_rate_diff + format_diff;
626
627 if diff < min_diff {
628 min_diff = diff;
629 matched_media_type = Some(media_type.clone());
630 }
631 }
632 index += 1;
633 }
634
635 matched_media_type
636}
637
638pub struct MediaFoundationDevice {
639 info: DeviceInformation,
640 index: usize,
641 running: bool,
642 formats: Option<Vec<CameraFormat>>,
643 current_format: Option<CameraFormat>,
644 handler: Option<OutputHandler>,
645 source_reader: Option<(Arc<Mutex<IMFSourceReader>>, IMFSourceReaderCallback)>,
646}
647
648impl Device for MediaFoundationDevice {
649 fn name(&self) -> &str {
650 &self.info.name
651 }
652
653 fn id(&self) -> &str {
654 &self.info.id
655 }
656
657 fn start(&mut self) -> Result<()> {
658 let (running, current_format, formats) = {
659 let camera_format = self.current_format.clone();
660 let (source_reader, callback) = self.get_source_reader()?;
661 let source_reader = source_reader.lock().map_err(|err| Error::StartFailed(err.to_string()))?;
662
663 if let Some(camera_format) = camera_format {
664 let media_type = match_supported_format(
665 &source_reader,
666 Some(camera_format.width),
667 Some(camera_format.height),
668 Some(camera_format.format),
669 Some(camera_format.frame_rates[0]),
670 );
671 if let Some(media_type) = media_type {
672 unsafe { source_reader.SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, None, &media_type).ok() };
673 }
674 }
675
676 let current_format = get_current_format(&source_reader)?;
677 let formats = get_formats(&source_reader)?;
678
679 start_internal(&source_reader, callback, ¤t_format);
680
681 (true, current_format, formats)
682 };
683
684 self.running = running;
685 self.current_format = Some(current_format);
686 self.formats = Some(formats);
687
688 Ok(())
689 }
690
691 fn stop(&mut self) -> Result<()> {
692 self.running = false;
693
694 {
695 let (source_reader, callback) = self.get_source_reader()?;
696 let source_reader = source_reader.lock().map_err(|err| Error::StopFailed(err.to_string()))?;
697
698 stop_internal(&source_reader, callback)?;
699 }
700
701 self.source_reader = None;
702
703 Ok(())
704 }
705
706 fn configure(&mut self, options: &Variant) -> Result<()> {
707 let width = options["width"].get_uint32();
708 let height = options["height"].get_uint32();
709 let video_format = options["format"].get_uint32();
710 let frame_rate = options["frame-rate"].get_float();
711
712 let video_format = match video_format {
713 Some(video_format) => VideoFormat::try_from(video_format).ok(),
714 None => None,
715 };
716
717 let camera_format = if self.running {
718 let (source_reader, callback) = self.get_source_reader()?;
719 let source_reader = source_reader.lock().map_err(|err| Error::SetFailed(err.to_string()))?;
720 let media_type = match_supported_format(&source_reader, width, height, video_format, frame_rate);
721
722 if let Some(media_type) = media_type {
723 match from_mf_media_type(&media_type) {
724 Some(camera_format) => {
725 stop_internal(&source_reader, callback).ok();
726 unsafe { source_reader.SetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM.0 as u32, None, &media_type).ok() };
727 callback.set_current_format(camera_format.clone());
728 start_internal(&source_reader, callback, &camera_format);
729 Some(camera_format)
730 }
731 None => return Err(Error::Unsupported("format".to_string())),
732 }
733 } else {
734 return Err(Error::Unsupported("format".to_string()));
735 }
736 } else {
737 Some(CameraFormat {
738 format: video_format.unwrap_or(VideoFormat::Pixel(PixelFormat::NV12)),
739 color_range: ColorRange::default(),
740 width: width.unwrap_or_default(),
741 height: height.unwrap_or_default(),
742 frame_rates: vec![frame_rate.unwrap_or_default()],
743 })
744 };
745
746 self.current_format = camera_format;
747
748 Ok(())
749 }
750
751 fn control(&mut self, _action: &Variant) -> Result<()> {
752 Err(Error::NotImplemented)
753 }
754
755 fn running(&self) -> bool {
756 self.running
757 }
758
759 fn formats(&self) -> Result<Variant> {
760 if !self.running {
761 return Err(Error::NotRunning(self.info.name.clone()));
762 }
763
764 let video_formats = self.formats.as_ref().ok_or_else(|| Error::NotFound("video formats".to_string()))?;
765 let mut formats = Variant::new_array();
766 for video_format in video_formats {
767 let mut format = Variant::new_dict();
768 format["format"] = (Into::<u32>::into(video_format.format)).into();
769 format["width"] = video_format.width.into();
770 format["height"] = video_format.height.into();
771 format["frame-rates"] = video_format.frame_rates.iter().map(|frame_rate| Variant::from(*frame_rate)).collect();
772 formats.array_add(format);
773 }
774
775 Ok(formats)
776 }
777}
778
779impl OutputDevice for MediaFoundationDevice {
780 fn set_output_handler<F>(&mut self, handler: F) -> Result<()>
781 where
782 F: Fn(Frame) -> Result<()> + Send + Sync + 'static,
783 {
784 self.handler = Some(Arc::new(handler));
785 Ok(())
786 }
787}
788
789impl MediaFoundationDevice {
790 fn new(dev_info: DeviceInformation, index: usize) -> Result<Self> {
791 Ok(Self {
792 info: dev_info,
793 index,
794 running: false,
795 current_format: None,
796 formats: None,
797 handler: None,
798 source_reader: None,
799 })
800 }
801
802 fn get_source_reader(&mut self) -> Result<(&Mutex<IMFSourceReader>, &mut SourceReaderCallback)> {
803 if self.source_reader.is_none() {
804 let device_sources = MediaFoundationDeviceManager::get_device_sources()?;
805 let activate = device_sources.get(self.index).ok_or_else(|| not_found_error!(self.index))?;
806 let media_source = unsafe { activate.ActivateObject::<IMFMediaSource>().map_err(|err| Error::OpenFailed(err.message()))? };
807
808 let attributes: IMFAttributes = unsafe {
809 let mut attributes: Option<IMFAttributes> = None;
810 MFCreateAttributes(&mut attributes, 1).map_err(|err| Error::CreationFailed(err.message()))?;
811 attributes.ok_or_else(|| none_param_error!(attributes))?
812 };
813
814 unsafe {
815 attributes.SetUINT32(&MF_READWRITE_DISABLE_CONVERTERS, true as u32).map_err(|err| Error::SetFailed(err.message()))?;
816 }
817
818 let handler = self.handler.as_ref().ok_or_else(|| none_param_error!(output_handler))?;
819 let callback: IMFSourceReaderCallback = SourceReaderCallback::new(self.info.clone(), handler.clone()).into();
820
821 unsafe {
822 attributes.SetUnknown(&MF_SOURCE_READER_ASYNC_CALLBACK, &callback).map_err(|err| Error::SetFailed(err.message()))?;
823 }
824
825 let source_reader =
826 unsafe { MFCreateSourceReaderFromMediaSource(&media_source, &attributes).map_err(|err| Error::CreationFailed(err.message()))? };
827
828 #[allow(clippy::arc_with_non_send_sync)]
829 let source_reader = Arc::new(Mutex::new(source_reader));
830
831 unsafe {
832 callback.as_impl_ptr().as_mut().set_source_reader(&source_reader);
833 }
834
835 self.source_reader = Some((source_reader.clone(), callback));
836 }
837 let (source_reader, reader_callback) = self.source_reader.as_ref().unwrap();
838 let reader_callback = unsafe { reader_callback.as_impl_ptr().as_mut() };
839 Ok((source_reader.as_ref(), reader_callback))
840 }
841}