amffi

Crates.ioamffi
lib.rsamffi
version0.0.2
created_at2025-11-17 22:38:39.00264+00
updated_at2025-12-19 17:04:17.978505+00
descriptionRust bindings to Advanced Media Framework
homepage
repositoryhttps://github.com/AlsoSylv/amffi
max_upload_size
id1937632
size164,365
Cyberite (AlsoSylv)

documentation

README

If you like my work and want to support what I do, support me on Ko-Fi 💜!

Ko-Fi

Crates.io MSRV Crates.io License GitHub Repo stars

amffi is a wrapper of Advanced Media Framework's C++ API.

This works as a cross platform COM style API, in a similar way to AMDs own examples.

32-bit environments are currently supported through the usage of macros to change the calling convention between x86_64 and x86, and any breakage is considered a bug

#include "public/common/AMFFactory.h"

int main() {
    AMF_RESULT res = AMF_OK;
    res = g_AMFFactory.Init();

    amf::AMFContextPtr context;
    res = g_AMFFactory.GetFactory()->CreateContext(&context);
}
use amf_bindings::amf_init;
use amf_bindings::version::AMF_VERSION;
use amf_bindings::factory::AMFFactory;
use amf_bindings::context::AMFContext;

fn main() {
    let library = amf_init().unwrap();

    let factory: AMFFactory = library.init_factory(AMF_VERSION).unwrap();
    let context: AMFContext = factory.create_context().unwrap();
}

This creates an AMF context, which can then be used like a COM-API

Certain APIs, such as buffer observers, have been wrapped to create a more idiomatic feeling API, such as

fn import_dx_buffer(context: &AMFContext, buffer: &ID3D11Texture2D) {
    let surface: AMFSurface = context.create_surface_from_dx11_native(buffer);
    surface.add_observer(|surface: AMFSurface| {
        println!("Releasing!");
    });
}

This is done by creating trait wrappers for the equivalent C++ interface, such as:

pub trait SurfaceObserver {
    fn on_surface_data_release(&mut self, surface: AMFSurface);
}

And wrapping them in a struct equivalent to how the AMD driver expects them, like so:

#[repr(C)]
pub(crate) struct InternalSurfaceObserver<T: SurfaceObserver> {
    vtbl: &'static AMFSurfaceObserverVtbl,
    this: T,
}

impl<T: SurfaceObserver> InternalSurfaceObserver<T> {
    pub(crate) fn new(observer: T) -> Self {
        Self {
            vtbl: &AMFSurfaceObserverVtbl {
                on_surface_data_release: internal_observer::<T>,
            },
            this: observer,
        }
    }
}

stdcall! {
    fn internal_observer<T: SurfaceObserver>(this: *mut *const AMFSurfaceObserverVtbl, surface: AMFSurface) {
        let this = unsafe { &mut *(this as *mut InternalSurfaceObserver<T>) };
        this.this.on_surface_data_release(surface);
    }
}
class AMF_NO_VTABLE AMFSurfaceObserver
{
public:
    virtual void AMF_STD_CALL OnSurfaceDataRelease(AMFSurface* pSurface) = 0;
};

Not all features are currently implemented, but are planned. Things such as Compute, D3D12 and AV1 are all going to be implemented as time and testing allow.

Commit count: 0

cargo fmt