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