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