Skip to content

MFTEnumEx memory management confusion #1685

@CarePackage17

Description

@CarePackage17

I'm having trouble with the MFTEnumEx function. It's documentation says that I'm supposed to call Release on each of the returned IMFActivate pointers, which as far as I could tell is a Drop impl on ::windows::core::IUnknown (there are no methods to call explicitly like in C++).
I was a bit confused getting this to compile at all, in particular the maybe_activate line; there's some stuff going on with references that I don't fully understand, but just dereferencing the pointer without borowing resulted in a move which didn't compile because Option<IMFActivate> does not implement Copy.

As you can see I'm calling drop on whatever I get out of the array, though I suspect this is incorrect. If I place a breakpoint on IUnknown's Drop function, it is not hit. So I guess I'm freeing the reference (a no-op) instead of the IMFActivate object that I'm supposed to free.

Can anyone explain how to use this function correctly?

use windows::Win32::{Media::MediaFoundation::{
    IMFActivate, MFShutdown, MFStartup, MFTEnumEx, MFSTARTUP_NOSOCKET, MFT_CATEGORY_VIDEO_ENCODER,
    MFT_ENUM_FLAG_HARDWARE, MF_API_VERSION, MF_SDK_VERSION,
}, System::Com::CoTaskMemFree};

fn main() -> windows::core::Result<()> {
    let mf_version = (MF_SDK_VERSION << 16) | MF_API_VERSION;
    unsafe {
        let res = MFStartup(mf_version, MFSTARTUP_NOSOCKET);

        if res.is_ok() {
            println!("Media Foundation initialized!");

            let mut tmp: Option<IMFActivate> = None;
            let mut activate_ptrs = &mut tmp as *mut Option<IMFActivate>;
            let mut activate_ptr_count = 0u32;

            let res = MFTEnumEx(
                MFT_CATEGORY_VIDEO_ENCODER,
                MFT_ENUM_FLAG_HARDWARE.0.try_into().unwrap(),
                std::ptr::null(),
                std::ptr::null(),
                &mut activate_ptrs,
                &mut activate_ptr_count,
            );
            if res.is_ok() {
                println!("MFTEnumEx succeeded, {} MFTs returned!", activate_ptr_count);

                //call release on every IMFActivate pointer
                for i in 0..activate_ptr_count {
                    let maybe_activate = &mut *activate_ptrs.add(i as usize);
                    if let Some(activate) = maybe_activate {
                        drop(activate);
                    }
                }

                CoTaskMemFree(activate_ptrs as *const std::ffi::c_void);
                println!("Freed activate_ptrs");
            }

            let res = MFShutdown();
            assert_eq!(res.is_ok(), true);
        } else {
            println!("{:?}", res.err());
        }
    }

    Ok(())
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    questionFurther information is requested

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions