#![expect(
unsafe_code,
reason = "COM apartment and Media Foundation platform initialization"
)]
use std::marker::PhantomData;
use std::sync::{Mutex, PoisonError};
use windows::Win32::Media::MediaFoundation::{MF_VERSION, MFSTARTUP_LITE, MFShutdown, MFStartup};
use windows::Win32::System::Com::{COINIT_MULTITHREADED, CoInitializeEx, CoUninitialize};
pub(crate) struct ComApartment {
owned: bool,
_not_send: PhantomData<*const ()>,
}
impl ComApartment {
pub(crate) fn enter() -> Self {
let hr = unsafe { CoInitializeEx(None, COINIT_MULTITHREADED) };
Self {
owned: hr.is_ok(),
_not_send: PhantomData,
}
}
pub(crate) fn start_media_foundation(&self) -> windows::core::Result<MediaFoundation<'_>> {
let mut live = live_guards();
if *live == 0 {
unsafe { MFStartup(MF_VERSION, MFSTARTUP_LITE) }?;
}
*live += 1;
Ok(MediaFoundation { _com: self })
}
}
impl Drop for ComApartment {
fn drop(&mut self) {
if !self.owned {
return;
}
unsafe { CoUninitialize() };
}
}
pub(crate) struct MediaFoundation<'a> {
_com: &'a ComApartment,
}
impl Drop for MediaFoundation<'_> {
fn drop(&mut self) {
let mut live = live_guards();
*live -= 1;
if *live != 0 {
return;
}
let _ = unsafe { MFShutdown() };
}
}
fn live_guards() -> std::sync::MutexGuard<'static, usize> {
static LIVE: Mutex<usize> = Mutex::new(0);
LIVE.lock().unwrap_or_else(PoisonError::into_inner)
}