refactor(pf-encode): move the AMF C-ABI mirror to its own file (WP7.4)
The ~410-line hand-mirrored AMF vtable ABI was already isolated in an inline `mod sys` — the remaining value of the audit's 'best split in the crate' is the FILE boundary: amf.rs drops 3379 → 2965 lines and the pure unsafe-FFI surface (25 unsafe fns, zero policy) is reviewable in isolation, which is the crate's stated review goal. Pure move: `#[path = "amf_sys.rs"] mod sys;` keeps the module name and every `sys::` call site byte-identical; the module was self-contained (only `use std::ffi::c_void`, no super:: references). The banner became the file's module docs; contents de-indented one level — rustfmt-clean on the first check, which is what proves the move byte-exact. Gated on .173: all five clippy combos + the amf-qsv,qsv test leg (38 passed — the live AMF matrix on real VCN silicon among them). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -66,425 +66,11 @@ use windows::Win32::Storage::FileSystem::{
|
|||||||
};
|
};
|
||||||
use windows::Win32::System::LibraryLoader::GetModuleFileNameW;
|
use windows::Win32::System::LibraryLoader::GetModuleFileNameW;
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
// The hand-mirrored AMF C ABI lives in `amf_sys.rs` (WP7.4): pure FFI surface, no policy —
|
||||||
// Mirrored AMF C ABI (written against GPUOpen header release v1.4.36 — amf/public/include; every
|
// isolating the unsafe vtable mirror from the encoder logic is the crate's stated review
|
||||||
// slot below is a base-interface slot whose layout is stable since <= v1.4.34, the loader's
|
// goal, and the `#[path]` keeps the module name (`sys::`) and every call site unchanged.
|
||||||
// accepted ABI floor, so the mirror is valid on every runtime the loader admits).
|
#[path = "amf_sys.rs"]
|
||||||
//
|
mod sys;
|
||||||
// Layout rules this mirror relies on: every AMF interface is a struct whose sole member is a
|
|
||||||
// pointer to a C vtable; derived interfaces PREPEND their base's slots in order (AMFInterface →
|
|
||||||
// AMFPropertyStorage → AMFData → AMFBuffer/AMFSurface), so a derived pointer is usable through a
|
|
||||||
// base vtable mirror. Slots we never call are declared as bare `*const c_void` placeholders —
|
|
||||||
// same size/alignment as the function pointer they stand in for. `AMF_STD_CALL` is `__stdcall`
|
|
||||||
// (Rust `extern "system"`); the two DLL entry points are `__cdecl` (`extern "C"`); on x86_64
|
|
||||||
// both collapse to the one Windows calling convention.
|
|
||||||
// ---------------------------------------------------------------------------------------------
|
|
||||||
mod sys {
|
|
||||||
use std::ffi::c_void;
|
|
||||||
|
|
||||||
/// `AMF_RESULT` (core/Result.h) — a plain C enum, sequential from 0. Only the codes this
|
|
||||||
/// module branches on are named; everything else is reported numerically via [`result_name`].
|
|
||||||
pub type AmfResult = i32;
|
|
||||||
pub const AMF_OK: AmfResult = 0;
|
|
||||||
pub const AMF_EOF: AmfResult = 23;
|
|
||||||
pub const AMF_REPEAT: AmfResult = 24;
|
|
||||||
pub const AMF_INPUT_FULL: AmfResult = 25;
|
|
||||||
pub const AMF_NEED_MORE_INPUT: AmfResult = 44;
|
|
||||||
|
|
||||||
/// Human-readable name for an `AMF_RESULT` (diagnostics only — the numeric value rides along
|
|
||||||
/// so an unnamed code is still identifiable against Result.h).
|
|
||||||
pub fn result_name(r: AmfResult) -> &'static str {
|
|
||||||
match r {
|
|
||||||
0 => "AMF_OK",
|
|
||||||
1 => "AMF_FAIL",
|
|
||||||
2 => "AMF_UNEXPECTED",
|
|
||||||
3 => "AMF_ACCESS_DENIED",
|
|
||||||
4 => "AMF_INVALID_ARG",
|
|
||||||
5 => "AMF_OUT_OF_RANGE",
|
|
||||||
6 => "AMF_OUT_OF_MEMORY",
|
|
||||||
7 => "AMF_INVALID_POINTER",
|
|
||||||
8 => "AMF_NO_INTERFACE",
|
|
||||||
9 => "AMF_NOT_IMPLEMENTED",
|
|
||||||
10 => "AMF_NOT_SUPPORTED",
|
|
||||||
11 => "AMF_NOT_FOUND",
|
|
||||||
12 => "AMF_ALREADY_INITIALIZED",
|
|
||||||
13 => "AMF_NOT_INITIALIZED",
|
|
||||||
14 => "AMF_INVALID_FORMAT",
|
|
||||||
15 => "AMF_WRONG_STATE",
|
|
||||||
17 => "AMF_NO_DEVICE",
|
|
||||||
18 => "AMF_DIRECTX_FAILED",
|
|
||||||
23 => "AMF_EOF",
|
|
||||||
24 => "AMF_REPEAT",
|
|
||||||
25 => "AMF_INPUT_FULL",
|
|
||||||
26 => "AMF_RESOLUTION_CHANGED",
|
|
||||||
28 => "AMF_INVALID_DATA_TYPE",
|
|
||||||
29 => "AMF_INVALID_RESOLUTION",
|
|
||||||
30 => "AMF_CODEC_NOT_SUPPORTED",
|
|
||||||
31 => "AMF_SURFACE_FORMAT_NOT_SUPPORTED",
|
|
||||||
32 => "AMF_SURFACE_MUST_BE_SHARED",
|
|
||||||
36 => "AMF_ENCODER_NOT_PRESENT",
|
|
||||||
44 => "AMF_NEED_MORE_INPUT",
|
|
||||||
_ => "AMF_<unnamed>",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// The AMF header release this FFI mirror was written against: `AMF_FULL_VERSION` for 1.4.36.0
|
|
||||||
/// (core/Version.h `AMF_MAKE_FULL_VERSION`). This is the version claimed to `AMFInit` — but
|
|
||||||
/// capped at the runtime's own reported version (see `load_factory`), so an older-but-accepted
|
|
||||||
/// runtime is asked only for the ABI it actually provides.
|
|
||||||
pub const AMF_HEADER_VERSION: u64 = (1u64 << 48) | (4u64 << 32) | (36u64 << 16);
|
|
||||||
|
|
||||||
/// The oldest AMF runtime the loader accepts (`AMF_FULL_VERSION` 1.4.34.0 — AMD Adrenalin
|
|
||||||
/// 24.6.1). This is an **ABI floor, not a feature floor**: every vtable slot mirrored in this
|
|
||||||
/// module belongs to a base interface (`AMFFactory`/`AMFContext`/`AMFComponent`/`AMFData`/
|
|
||||||
/// `AMFBuffer`) whose layout has been stable — append-only, no mid-vtable insertions — since
|
|
||||||
/// well before 1.4.34, so a 1.4.34 runtime is guaranteed to expose every mirrored slot at its
|
|
||||||
/// mirrored offset. Everything 1.4.35/1.4.36 added that this path can touch (new HQ presets,
|
|
||||||
/// AV1 B-frame / picture management) is a *string-keyed encoder property*, applied through
|
|
||||||
/// [`set_prop`] with `required=false` — a runtime that lacks it rejects the property (logged)
|
|
||||||
/// and the feature degrades, rather than shifting any vtable offset. Below this floor the
|
|
||||||
/// mirror is not guaranteed to match, so the loader declines cleanly (an old-driver decline,
|
|
||||||
/// never UB).
|
|
||||||
pub const AMF_MIN_VERSION: u64 = (1u64 << 48) | (4u64 << 32) | (34u64 << 16);
|
|
||||||
|
|
||||||
/// `AMF_SURFACE_FORMAT` (core/Surface.h).
|
|
||||||
pub const AMF_SURFACE_NV12: i32 = 1;
|
|
||||||
pub const AMF_SURFACE_P010: i32 = 10;
|
|
||||||
|
|
||||||
/// `AMF_DX_VERSION::AMF_DX11_1` (core/Data.h) — the `InitDX11` version argument.
|
|
||||||
pub const AMF_DX11_1: i32 = 111;
|
|
||||||
|
|
||||||
/// `AMF_MEMORY_TYPE::AMF_MEMORY_HOST` (core/Data.h) — the `AllocBuffer` memory type for the
|
|
||||||
/// CPU-filled HDR-metadata buffer.
|
|
||||||
pub const AMF_MEMORY_HOST: i32 = 1;
|
|
||||||
|
|
||||||
/// `AMFHDRMetadata` (components/ColorSpace.h) — the payload of the `*InHDRMetadata` encoder
|
|
||||||
/// property (an `AMFBuffer` holding exactly this struct). Same units as the HEVC ST.2086 SEI
|
|
||||||
/// and [`punktfunk_core::quic::HdrMeta`]: chromaticities in 1/50000, mastering luminance in
|
|
||||||
/// 0.0001 cd/m², CLL/FALL in nits. 28 bytes, no padding.
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfHdrMetadata {
|
|
||||||
pub red_primary: [u16; 2],
|
|
||||||
pub green_primary: [u16; 2],
|
|
||||||
pub blue_primary: [u16; 2],
|
|
||||||
pub white_point: [u16; 2],
|
|
||||||
pub max_mastering_luminance: u32,
|
|
||||||
pub min_mastering_luminance: u32,
|
|
||||||
pub max_content_light_level: u16,
|
|
||||||
pub max_frame_average_light_level: u16,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `AMFGuid` (core/Platform.h) — data41..data48 flattened into an array (identical layout).
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfGuid {
|
|
||||||
pub data1: u32,
|
|
||||||
pub data2: u16,
|
|
||||||
pub data3: u16,
|
|
||||||
pub data4: [u8; 8],
|
|
||||||
}
|
|
||||||
|
|
||||||
/// `IID_AMFBuffer` (core/Buffer.h `AMF_DECLARE_IID`) — for `QueryInterface` on the encoder's
|
|
||||||
/// output `AMFData` to reach `GetNative`/`GetSize`.
|
|
||||||
pub const IID_AMF_BUFFER: AmfGuid = AmfGuid {
|
|
||||||
data1: 0xb04b_7248,
|
|
||||||
data2: 0xb6f0,
|
|
||||||
data3: 0x4321,
|
|
||||||
data4: [0xb6, 0x91, 0xba, 0xa4, 0x74, 0x0f, 0x9f, 0xcb],
|
|
||||||
};
|
|
||||||
|
|
||||||
// `AMF_VARIANT_TYPE` (core/Variant.h) — the tags this module writes/reads.
|
|
||||||
pub const AMF_VARIANT_BOOL: i32 = 1;
|
|
||||||
pub const AMF_VARIANT_INT64: i32 = 2;
|
|
||||||
pub const AMF_VARIANT_RATE: i32 = 7;
|
|
||||||
pub const AMF_VARIANT_INTERFACE: i32 = 12;
|
|
||||||
|
|
||||||
/// `AMFVariantStruct` (core/Variant.h): a 4-byte C-enum tag + a 16-byte union whose largest
|
|
||||||
/// members are pointer/`amf_int64`/`AMFFloatVector4D` (align 8) → 24 bytes total, tag at 0,
|
|
||||||
/// payload at 8. Passed BY VALUE to `SetProperty` (Win64 passes >8-byte aggregates by hidden
|
|
||||||
/// reference on both sides, so declaring it by value matches the C compiler). The payload is
|
|
||||||
/// stored as two fully-initialised `u64`s — little-endian packing puts a bool in byte 0, an
|
|
||||||
/// `amf_int64` in word 0, and an `AMFRate{num,den}` as `num | den << 32`, exactly the union's
|
|
||||||
/// in-memory layout — so no partially-initialised union bytes ever cross the FFI.
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfVariant {
|
|
||||||
pub vtype: i32,
|
|
||||||
pub payload: [u64; 2],
|
|
||||||
}
|
|
||||||
|
|
||||||
impl AmfVariant {
|
|
||||||
pub fn zeroed() -> Self {
|
|
||||||
AmfVariant {
|
|
||||||
vtype: 0, // AMF_VARIANT_EMPTY
|
|
||||||
payload: [0, 0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_i64(v: i64) -> Self {
|
|
||||||
AmfVariant {
|
|
||||||
vtype: AMF_VARIANT_INT64,
|
|
||||||
payload: [v as u64, 0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pub fn from_bool(v: bool) -> Self {
|
|
||||||
AmfVariant {
|
|
||||||
vtype: AMF_VARIANT_BOOL,
|
|
||||||
payload: [v as u64, 0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// `AMFRate { num, den }` — two little-endian `amf_uint32`s in the union's first 8 bytes.
|
|
||||||
pub fn from_rate(num: u32, den: u32) -> Self {
|
|
||||||
AmfVariant {
|
|
||||||
vtype: AMF_VARIANT_RATE,
|
|
||||||
payload: [num as u64 | ((den as u64) << 32), 0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// An `AMFInterface*` payload (`pInterface` in the union's first 8 bytes). The property
|
|
||||||
/// storage AddRefs the interface when it copies the variant in (the C++ template
|
|
||||||
/// `SetProperty(name, AMFVariant(value))` passes a temporary whose destructor releases,
|
|
||||||
/// so `SetProperty` must take its own reference) — the caller keeps sole ownership of the
|
|
||||||
/// reference it already holds.
|
|
||||||
pub fn from_interface(p: *mut c_void) -> Self {
|
|
||||||
AmfVariant {
|
|
||||||
vtype: AMF_VARIANT_INTERFACE,
|
|
||||||
payload: [p as usize as u64, 0],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/// Read back an `amf_int64` payload (only valid when `vtype == AMF_VARIANT_INT64`).
|
|
||||||
pub fn as_i64(&self) -> Option<i64> {
|
|
||||||
(self.vtype == AMF_VARIANT_INT64).then_some(self.payload[0] as i64)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Placeholder for a vtable slot this module never calls — same size/align as the function
|
|
||||||
/// pointer it stands in for, present only to keep the following slots at their C offsets.
|
|
||||||
pub type Slot = *const c_void;
|
|
||||||
|
|
||||||
// -- AMFFactory (core/Factory.h; NOT refcounted — a process singleton) ----------------------
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfFactory {
|
|
||||||
pub vtbl: *const AmfFactoryVtbl,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfFactoryVtbl {
|
|
||||||
pub create_context:
|
|
||||||
unsafe extern "system" fn(*mut AmfFactory, *mut *mut AmfContext) -> AmfResult,
|
|
||||||
pub create_component: unsafe extern "system" fn(
|
|
||||||
*mut AmfFactory,
|
|
||||||
*mut AmfContext,
|
|
||||||
*const u16,
|
|
||||||
*mut *mut AmfComponent,
|
|
||||||
) -> AmfResult,
|
|
||||||
pub set_cache_folder: Slot,
|
|
||||||
pub get_cache_folder: Slot,
|
|
||||||
pub get_debug: Slot,
|
|
||||||
pub get_trace: Slot,
|
|
||||||
pub get_programs: Slot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- AMFContext (core/Context.h) ------------------------------------------------------------
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfContext {
|
|
||||||
pub vtbl: *const AmfContextVtbl,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfContextVtbl {
|
|
||||||
// AMFInterface
|
|
||||||
pub acquire: Slot,
|
|
||||||
pub release: unsafe extern "system" fn(*mut AmfContext) -> i32,
|
|
||||||
pub query_interface: Slot,
|
|
||||||
// AMFPropertyStorage
|
|
||||||
pub set_property: Slot,
|
|
||||||
pub get_property: Slot,
|
|
||||||
pub has_property: Slot,
|
|
||||||
pub get_property_count: Slot,
|
|
||||||
pub get_property_at: Slot,
|
|
||||||
pub clear: Slot,
|
|
||||||
pub add_to: Slot,
|
|
||||||
pub copy_to: Slot,
|
|
||||||
pub add_observer: Slot,
|
|
||||||
pub remove_observer: Slot,
|
|
||||||
// AMFContext
|
|
||||||
pub terminate: unsafe extern "system" fn(*mut AmfContext) -> AmfResult,
|
|
||||||
pub init_dx9: Slot,
|
|
||||||
pub get_dx9_device: Slot,
|
|
||||||
pub lock_dx9: Slot,
|
|
||||||
pub unlock_dx9: Slot,
|
|
||||||
pub init_dx11: unsafe extern "system" fn(*mut AmfContext, *mut c_void, i32) -> AmfResult,
|
|
||||||
pub get_dx11_device: Slot,
|
|
||||||
pub lock_dx11: Slot,
|
|
||||||
pub unlock_dx11: Slot,
|
|
||||||
pub init_opencl: Slot,
|
|
||||||
pub get_opencl_context: Slot,
|
|
||||||
pub get_opencl_command_queue: Slot,
|
|
||||||
pub get_opencl_device_id: Slot,
|
|
||||||
pub get_opencl_compute_factory: Slot,
|
|
||||||
pub init_opencl_ex: Slot,
|
|
||||||
pub lock_opencl: Slot,
|
|
||||||
pub unlock_opencl: Slot,
|
|
||||||
pub init_opengl: Slot,
|
|
||||||
pub get_opengl_context: Slot,
|
|
||||||
pub get_opengl_drawable: Slot,
|
|
||||||
pub lock_opengl: Slot,
|
|
||||||
pub unlock_opengl: Slot,
|
|
||||||
pub init_xv: Slot,
|
|
||||||
pub get_xv_device: Slot,
|
|
||||||
pub lock_xv: Slot,
|
|
||||||
pub unlock_xv: Slot,
|
|
||||||
pub init_gralloc: Slot,
|
|
||||||
pub get_gralloc_device: Slot,
|
|
||||||
pub lock_gralloc: Slot,
|
|
||||||
pub unlock_gralloc: Slot,
|
|
||||||
pub alloc_buffer: unsafe extern "system" fn(
|
|
||||||
*mut AmfContext,
|
|
||||||
i32, // AMF_MEMORY_TYPE
|
|
||||||
usize,
|
|
||||||
*mut *mut AmfBuffer,
|
|
||||||
) -> AmfResult,
|
|
||||||
pub alloc_surface: Slot,
|
|
||||||
pub alloc_audio_buffer: Slot,
|
|
||||||
pub create_buffer_from_host_native: Slot,
|
|
||||||
pub create_surface_from_host_native: Slot,
|
|
||||||
pub create_surface_from_dx9_native: Slot,
|
|
||||||
/// Out-param is `AMFSurface**` in the header; declared as the `AmfData` base here because
|
|
||||||
/// every surface call this module makes (`SetPts`, `SetProperty`, `Release`,
|
|
||||||
/// `SubmitInput`) lives in the `AMFData` vtable prefix, which `AMFSurfaceVtbl` reproduces
|
|
||||||
/// slot-for-slot (single inheritance, same object pointer).
|
|
||||||
pub create_surface_from_dx11_native: unsafe extern "system" fn(
|
|
||||||
*mut AmfContext,
|
|
||||||
*mut c_void,
|
|
||||||
*mut *mut AmfData,
|
|
||||||
*mut c_void,
|
|
||||||
) -> AmfResult,
|
|
||||||
pub create_surface_from_opengl_native: Slot,
|
|
||||||
pub create_surface_from_gralloc_native: Slot,
|
|
||||||
pub create_surface_from_opencl_native: Slot,
|
|
||||||
pub create_buffer_from_opencl_native: Slot,
|
|
||||||
pub get_compute: Slot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- AMFComponent (components/Component.h) --------------------------------------------------
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfComponent {
|
|
||||||
pub vtbl: *const AmfComponentVtbl,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfComponentVtbl {
|
|
||||||
// AMFInterface
|
|
||||||
pub acquire: Slot,
|
|
||||||
pub release: unsafe extern "system" fn(*mut AmfComponent) -> i32,
|
|
||||||
pub query_interface: Slot,
|
|
||||||
// AMFPropertyStorage
|
|
||||||
pub set_property:
|
|
||||||
unsafe extern "system" fn(*mut AmfComponent, *const u16, AmfVariant) -> AmfResult,
|
|
||||||
pub get_property: Slot,
|
|
||||||
pub has_property: Slot,
|
|
||||||
pub get_property_count: Slot,
|
|
||||||
pub get_property_at: Slot,
|
|
||||||
pub clear: Slot,
|
|
||||||
pub add_to: Slot,
|
|
||||||
pub copy_to: Slot,
|
|
||||||
pub add_observer: Slot,
|
|
||||||
pub remove_observer: Slot,
|
|
||||||
// AMFPropertyStorageEx
|
|
||||||
pub get_properties_info_count: Slot,
|
|
||||||
pub get_property_info_at: Slot,
|
|
||||||
pub get_property_info: Slot,
|
|
||||||
pub validate_property: Slot,
|
|
||||||
// AMFComponent
|
|
||||||
pub init: unsafe extern "system" fn(*mut AmfComponent, i32, i32, i32) -> AmfResult,
|
|
||||||
pub reinit: Slot,
|
|
||||||
pub terminate: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
|
||||||
pub drain: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
|
||||||
pub flush: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
|
||||||
pub submit_input: unsafe extern "system" fn(*mut AmfComponent, *mut AmfData) -> AmfResult,
|
|
||||||
pub query_output:
|
|
||||||
unsafe extern "system" fn(*mut AmfComponent, *mut *mut AmfData) -> AmfResult,
|
|
||||||
pub get_context: Slot,
|
|
||||||
pub set_output_data_allocator_cb: Slot,
|
|
||||||
pub get_caps: Slot,
|
|
||||||
pub optimize: Slot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- AMFData (core/Data.h) — also the usable prefix of AMFSurface --------------------------
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfData {
|
|
||||||
pub vtbl: *const AmfDataVtbl,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfDataVtbl {
|
|
||||||
// AMFInterface
|
|
||||||
pub acquire: Slot,
|
|
||||||
pub release: unsafe extern "system" fn(*mut AmfData) -> i32,
|
|
||||||
pub query_interface:
|
|
||||||
unsafe extern "system" fn(*mut AmfData, *const AmfGuid, *mut *mut c_void) -> AmfResult,
|
|
||||||
// AMFPropertyStorage
|
|
||||||
pub set_property:
|
|
||||||
unsafe extern "system" fn(*mut AmfData, *const u16, AmfVariant) -> AmfResult,
|
|
||||||
pub get_property:
|
|
||||||
unsafe extern "system" fn(*mut AmfData, *const u16, *mut AmfVariant) -> AmfResult,
|
|
||||||
pub has_property: Slot,
|
|
||||||
pub get_property_count: Slot,
|
|
||||||
pub get_property_at: Slot,
|
|
||||||
pub clear: Slot,
|
|
||||||
pub add_to: Slot,
|
|
||||||
pub copy_to: Slot,
|
|
||||||
pub add_observer: Slot,
|
|
||||||
pub remove_observer: Slot,
|
|
||||||
// AMFData
|
|
||||||
pub get_memory_type: Slot,
|
|
||||||
pub duplicate: Slot,
|
|
||||||
pub convert: Slot,
|
|
||||||
pub interop: Slot,
|
|
||||||
pub get_data_type: Slot,
|
|
||||||
pub is_reusable: Slot,
|
|
||||||
pub set_pts: unsafe extern "system" fn(*mut AmfData, i64),
|
|
||||||
pub get_pts: Slot,
|
|
||||||
pub set_duration: Slot,
|
|
||||||
pub get_duration: Slot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- AMFBuffer (core/Buffer.h) — the encoder's output object -------------------------------
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfBuffer {
|
|
||||||
pub vtbl: *const AmfBufferVtbl,
|
|
||||||
}
|
|
||||||
#[repr(C)]
|
|
||||||
pub struct AmfBufferVtbl {
|
|
||||||
// AMFInterface + AMFPropertyStorage + AMFData prefix (identical order to AmfDataVtbl).
|
|
||||||
pub acquire: Slot,
|
|
||||||
pub release: unsafe extern "system" fn(*mut AmfBuffer) -> i32,
|
|
||||||
pub query_interface: Slot,
|
|
||||||
pub set_property: Slot,
|
|
||||||
pub get_property: Slot,
|
|
||||||
pub has_property: Slot,
|
|
||||||
pub get_property_count: Slot,
|
|
||||||
pub get_property_at: Slot,
|
|
||||||
pub clear: Slot,
|
|
||||||
pub add_to: Slot,
|
|
||||||
pub copy_to: Slot,
|
|
||||||
pub add_observer: Slot,
|
|
||||||
pub remove_observer: Slot,
|
|
||||||
pub get_memory_type: Slot,
|
|
||||||
pub duplicate: Slot,
|
|
||||||
pub convert: Slot,
|
|
||||||
pub interop: Slot,
|
|
||||||
pub get_data_type: Slot,
|
|
||||||
pub is_reusable: Slot,
|
|
||||||
pub set_pts: Slot,
|
|
||||||
pub get_pts: Slot,
|
|
||||||
pub set_duration: Slot,
|
|
||||||
pub get_duration: Slot,
|
|
||||||
// AMFBuffer
|
|
||||||
pub set_size: Slot,
|
|
||||||
pub get_size: unsafe extern "system" fn(*mut AmfBuffer) -> usize,
|
|
||||||
pub get_native: unsafe extern "system" fn(*mut AmfBuffer) -> *mut c_void,
|
|
||||||
pub add_observer_buffer: Slot,
|
|
||||||
pub remove_observer_buffer: Slot,
|
|
||||||
}
|
|
||||||
|
|
||||||
// -- DLL entry points (core/Factory.h; AMF_CDECL_CALL) --------------------------------------
|
|
||||||
pub type AmfQueryVersionFn = unsafe extern "C" fn(*mut u64) -> AmfResult;
|
|
||||||
pub type AmfInitFn = unsafe extern "C" fn(u64, *mut *mut AmfFactory) -> AmfResult;
|
|
||||||
}
|
|
||||||
|
|
||||||
use sys::{result_name, AmfVariant};
|
use sys::{result_name, AmfVariant};
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,414 @@
|
|||||||
|
//! Mirrored AMF C ABI (written against GPUOpen header release v1.4.36 — amf/public/include; every
|
||||||
|
//! slot below is a base-interface slot whose layout is stable since <= v1.4.34, the loader's
|
||||||
|
//! accepted ABI floor, so the mirror is valid on every runtime the loader admits).
|
||||||
|
//!
|
||||||
|
//! Layout rules this mirror relies on: every AMF interface is a struct whose sole member is a
|
||||||
|
//! pointer to a C vtable; derived interfaces PREPEND their base's slots in order (AMFInterface →
|
||||||
|
//! AMFPropertyStorage → AMFData → AMFBuffer/AMFSurface), so a derived pointer is usable through a
|
||||||
|
//! base vtable mirror. Slots we never call are declared as bare `*const c_void` placeholders —
|
||||||
|
//! same size/alignment as the function pointer they stand in for. `AMF_STD_CALL` is `__stdcall`
|
||||||
|
//! (Rust `extern "system"`); the two DLL entry points are `__cdecl` (`extern "C"`); on x86_64
|
||||||
|
//! both collapse to the one Windows calling convention.
|
||||||
|
|
||||||
|
use std::ffi::c_void;
|
||||||
|
|
||||||
|
/// `AMF_RESULT` (core/Result.h) — a plain C enum, sequential from 0. Only the codes this
|
||||||
|
/// module branches on are named; everything else is reported numerically via [`result_name`].
|
||||||
|
pub type AmfResult = i32;
|
||||||
|
pub const AMF_OK: AmfResult = 0;
|
||||||
|
pub const AMF_EOF: AmfResult = 23;
|
||||||
|
pub const AMF_REPEAT: AmfResult = 24;
|
||||||
|
pub const AMF_INPUT_FULL: AmfResult = 25;
|
||||||
|
pub const AMF_NEED_MORE_INPUT: AmfResult = 44;
|
||||||
|
|
||||||
|
/// Human-readable name for an `AMF_RESULT` (diagnostics only — the numeric value rides along
|
||||||
|
/// so an unnamed code is still identifiable against Result.h).
|
||||||
|
pub fn result_name(r: AmfResult) -> &'static str {
|
||||||
|
match r {
|
||||||
|
0 => "AMF_OK",
|
||||||
|
1 => "AMF_FAIL",
|
||||||
|
2 => "AMF_UNEXPECTED",
|
||||||
|
3 => "AMF_ACCESS_DENIED",
|
||||||
|
4 => "AMF_INVALID_ARG",
|
||||||
|
5 => "AMF_OUT_OF_RANGE",
|
||||||
|
6 => "AMF_OUT_OF_MEMORY",
|
||||||
|
7 => "AMF_INVALID_POINTER",
|
||||||
|
8 => "AMF_NO_INTERFACE",
|
||||||
|
9 => "AMF_NOT_IMPLEMENTED",
|
||||||
|
10 => "AMF_NOT_SUPPORTED",
|
||||||
|
11 => "AMF_NOT_FOUND",
|
||||||
|
12 => "AMF_ALREADY_INITIALIZED",
|
||||||
|
13 => "AMF_NOT_INITIALIZED",
|
||||||
|
14 => "AMF_INVALID_FORMAT",
|
||||||
|
15 => "AMF_WRONG_STATE",
|
||||||
|
17 => "AMF_NO_DEVICE",
|
||||||
|
18 => "AMF_DIRECTX_FAILED",
|
||||||
|
23 => "AMF_EOF",
|
||||||
|
24 => "AMF_REPEAT",
|
||||||
|
25 => "AMF_INPUT_FULL",
|
||||||
|
26 => "AMF_RESOLUTION_CHANGED",
|
||||||
|
28 => "AMF_INVALID_DATA_TYPE",
|
||||||
|
29 => "AMF_INVALID_RESOLUTION",
|
||||||
|
30 => "AMF_CODEC_NOT_SUPPORTED",
|
||||||
|
31 => "AMF_SURFACE_FORMAT_NOT_SUPPORTED",
|
||||||
|
32 => "AMF_SURFACE_MUST_BE_SHARED",
|
||||||
|
36 => "AMF_ENCODER_NOT_PRESENT",
|
||||||
|
44 => "AMF_NEED_MORE_INPUT",
|
||||||
|
_ => "AMF_<unnamed>",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The AMF header release this FFI mirror was written against: `AMF_FULL_VERSION` for 1.4.36.0
|
||||||
|
/// (core/Version.h `AMF_MAKE_FULL_VERSION`). This is the version claimed to `AMFInit` — but
|
||||||
|
/// capped at the runtime's own reported version (see `load_factory`), so an older-but-accepted
|
||||||
|
/// runtime is asked only for the ABI it actually provides.
|
||||||
|
pub const AMF_HEADER_VERSION: u64 = (1u64 << 48) | (4u64 << 32) | (36u64 << 16);
|
||||||
|
|
||||||
|
/// The oldest AMF runtime the loader accepts (`AMF_FULL_VERSION` 1.4.34.0 — AMD Adrenalin
|
||||||
|
/// 24.6.1). This is an **ABI floor, not a feature floor**: every vtable slot mirrored in this
|
||||||
|
/// module belongs to a base interface (`AMFFactory`/`AMFContext`/`AMFComponent`/`AMFData`/
|
||||||
|
/// `AMFBuffer`) whose layout has been stable — append-only, no mid-vtable insertions — since
|
||||||
|
/// well before 1.4.34, so a 1.4.34 runtime is guaranteed to expose every mirrored slot at its
|
||||||
|
/// mirrored offset. Everything 1.4.35/1.4.36 added that this path can touch (new HQ presets,
|
||||||
|
/// AV1 B-frame / picture management) is a *string-keyed encoder property*, applied through
|
||||||
|
/// [`set_prop`] with `required=false` — a runtime that lacks it rejects the property (logged)
|
||||||
|
/// and the feature degrades, rather than shifting any vtable offset. Below this floor the
|
||||||
|
/// mirror is not guaranteed to match, so the loader declines cleanly (an old-driver decline,
|
||||||
|
/// never UB).
|
||||||
|
pub const AMF_MIN_VERSION: u64 = (1u64 << 48) | (4u64 << 32) | (34u64 << 16);
|
||||||
|
|
||||||
|
/// `AMF_SURFACE_FORMAT` (core/Surface.h).
|
||||||
|
pub const AMF_SURFACE_NV12: i32 = 1;
|
||||||
|
pub const AMF_SURFACE_P010: i32 = 10;
|
||||||
|
|
||||||
|
/// `AMF_DX_VERSION::AMF_DX11_1` (core/Data.h) — the `InitDX11` version argument.
|
||||||
|
pub const AMF_DX11_1: i32 = 111;
|
||||||
|
|
||||||
|
/// `AMF_MEMORY_TYPE::AMF_MEMORY_HOST` (core/Data.h) — the `AllocBuffer` memory type for the
|
||||||
|
/// CPU-filled HDR-metadata buffer.
|
||||||
|
pub const AMF_MEMORY_HOST: i32 = 1;
|
||||||
|
|
||||||
|
/// `AMFHDRMetadata` (components/ColorSpace.h) — the payload of the `*InHDRMetadata` encoder
|
||||||
|
/// property (an `AMFBuffer` holding exactly this struct). Same units as the HEVC ST.2086 SEI
|
||||||
|
/// and [`punktfunk_core::quic::HdrMeta`]: chromaticities in 1/50000, mastering luminance in
|
||||||
|
/// 0.0001 cd/m², CLL/FALL in nits. 28 bytes, no padding.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfHdrMetadata {
|
||||||
|
pub red_primary: [u16; 2],
|
||||||
|
pub green_primary: [u16; 2],
|
||||||
|
pub blue_primary: [u16; 2],
|
||||||
|
pub white_point: [u16; 2],
|
||||||
|
pub max_mastering_luminance: u32,
|
||||||
|
pub min_mastering_luminance: u32,
|
||||||
|
pub max_content_light_level: u16,
|
||||||
|
pub max_frame_average_light_level: u16,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `AMFGuid` (core/Platform.h) — data41..data48 flattened into an array (identical layout).
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfGuid {
|
||||||
|
pub data1: u32,
|
||||||
|
pub data2: u16,
|
||||||
|
pub data3: u16,
|
||||||
|
pub data4: [u8; 8],
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `IID_AMFBuffer` (core/Buffer.h `AMF_DECLARE_IID`) — for `QueryInterface` on the encoder's
|
||||||
|
/// output `AMFData` to reach `GetNative`/`GetSize`.
|
||||||
|
pub const IID_AMF_BUFFER: AmfGuid = AmfGuid {
|
||||||
|
data1: 0xb04b_7248,
|
||||||
|
data2: 0xb6f0,
|
||||||
|
data3: 0x4321,
|
||||||
|
data4: [0xb6, 0x91, 0xba, 0xa4, 0x74, 0x0f, 0x9f, 0xcb],
|
||||||
|
};
|
||||||
|
|
||||||
|
// `AMF_VARIANT_TYPE` (core/Variant.h) — the tags this module writes/reads.
|
||||||
|
pub const AMF_VARIANT_BOOL: i32 = 1;
|
||||||
|
pub const AMF_VARIANT_INT64: i32 = 2;
|
||||||
|
pub const AMF_VARIANT_RATE: i32 = 7;
|
||||||
|
pub const AMF_VARIANT_INTERFACE: i32 = 12;
|
||||||
|
|
||||||
|
/// `AMFVariantStruct` (core/Variant.h): a 4-byte C-enum tag + a 16-byte union whose largest
|
||||||
|
/// members are pointer/`amf_int64`/`AMFFloatVector4D` (align 8) → 24 bytes total, tag at 0,
|
||||||
|
/// payload at 8. Passed BY VALUE to `SetProperty` (Win64 passes >8-byte aggregates by hidden
|
||||||
|
/// reference on both sides, so declaring it by value matches the C compiler). The payload is
|
||||||
|
/// stored as two fully-initialised `u64`s — little-endian packing puts a bool in byte 0, an
|
||||||
|
/// `amf_int64` in word 0, and an `AMFRate{num,den}` as `num | den << 32`, exactly the union's
|
||||||
|
/// in-memory layout — so no partially-initialised union bytes ever cross the FFI.
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfVariant {
|
||||||
|
pub vtype: i32,
|
||||||
|
pub payload: [u64; 2],
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AmfVariant {
|
||||||
|
pub fn zeroed() -> Self {
|
||||||
|
AmfVariant {
|
||||||
|
vtype: 0, // AMF_VARIANT_EMPTY
|
||||||
|
payload: [0, 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_i64(v: i64) -> Self {
|
||||||
|
AmfVariant {
|
||||||
|
vtype: AMF_VARIANT_INT64,
|
||||||
|
payload: [v as u64, 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub fn from_bool(v: bool) -> Self {
|
||||||
|
AmfVariant {
|
||||||
|
vtype: AMF_VARIANT_BOOL,
|
||||||
|
payload: [v as u64, 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// `AMFRate { num, den }` — two little-endian `amf_uint32`s in the union's first 8 bytes.
|
||||||
|
pub fn from_rate(num: u32, den: u32) -> Self {
|
||||||
|
AmfVariant {
|
||||||
|
vtype: AMF_VARIANT_RATE,
|
||||||
|
payload: [num as u64 | ((den as u64) << 32), 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// An `AMFInterface*` payload (`pInterface` in the union's first 8 bytes). The property
|
||||||
|
/// storage AddRefs the interface when it copies the variant in (the C++ template
|
||||||
|
/// `SetProperty(name, AMFVariant(value))` passes a temporary whose destructor releases,
|
||||||
|
/// so `SetProperty` must take its own reference) — the caller keeps sole ownership of the
|
||||||
|
/// reference it already holds.
|
||||||
|
pub fn from_interface(p: *mut c_void) -> Self {
|
||||||
|
AmfVariant {
|
||||||
|
vtype: AMF_VARIANT_INTERFACE,
|
||||||
|
payload: [p as usize as u64, 0],
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Read back an `amf_int64` payload (only valid when `vtype == AMF_VARIANT_INT64`).
|
||||||
|
pub fn as_i64(&self) -> Option<i64> {
|
||||||
|
(self.vtype == AMF_VARIANT_INT64).then_some(self.payload[0] as i64)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Placeholder for a vtable slot this module never calls — same size/align as the function
|
||||||
|
/// pointer it stands in for, present only to keep the following slots at their C offsets.
|
||||||
|
pub type Slot = *const c_void;
|
||||||
|
|
||||||
|
// -- AMFFactory (core/Factory.h; NOT refcounted — a process singleton) ----------------------
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfFactory {
|
||||||
|
pub vtbl: *const AmfFactoryVtbl,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfFactoryVtbl {
|
||||||
|
pub create_context:
|
||||||
|
unsafe extern "system" fn(*mut AmfFactory, *mut *mut AmfContext) -> AmfResult,
|
||||||
|
pub create_component: unsafe extern "system" fn(
|
||||||
|
*mut AmfFactory,
|
||||||
|
*mut AmfContext,
|
||||||
|
*const u16,
|
||||||
|
*mut *mut AmfComponent,
|
||||||
|
) -> AmfResult,
|
||||||
|
pub set_cache_folder: Slot,
|
||||||
|
pub get_cache_folder: Slot,
|
||||||
|
pub get_debug: Slot,
|
||||||
|
pub get_trace: Slot,
|
||||||
|
pub get_programs: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- AMFContext (core/Context.h) ------------------------------------------------------------
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfContext {
|
||||||
|
pub vtbl: *const AmfContextVtbl,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfContextVtbl {
|
||||||
|
// AMFInterface
|
||||||
|
pub acquire: Slot,
|
||||||
|
pub release: unsafe extern "system" fn(*mut AmfContext) -> i32,
|
||||||
|
pub query_interface: Slot,
|
||||||
|
// AMFPropertyStorage
|
||||||
|
pub set_property: Slot,
|
||||||
|
pub get_property: Slot,
|
||||||
|
pub has_property: Slot,
|
||||||
|
pub get_property_count: Slot,
|
||||||
|
pub get_property_at: Slot,
|
||||||
|
pub clear: Slot,
|
||||||
|
pub add_to: Slot,
|
||||||
|
pub copy_to: Slot,
|
||||||
|
pub add_observer: Slot,
|
||||||
|
pub remove_observer: Slot,
|
||||||
|
// AMFContext
|
||||||
|
pub terminate: unsafe extern "system" fn(*mut AmfContext) -> AmfResult,
|
||||||
|
pub init_dx9: Slot,
|
||||||
|
pub get_dx9_device: Slot,
|
||||||
|
pub lock_dx9: Slot,
|
||||||
|
pub unlock_dx9: Slot,
|
||||||
|
pub init_dx11: unsafe extern "system" fn(*mut AmfContext, *mut c_void, i32) -> AmfResult,
|
||||||
|
pub get_dx11_device: Slot,
|
||||||
|
pub lock_dx11: Slot,
|
||||||
|
pub unlock_dx11: Slot,
|
||||||
|
pub init_opencl: Slot,
|
||||||
|
pub get_opencl_context: Slot,
|
||||||
|
pub get_opencl_command_queue: Slot,
|
||||||
|
pub get_opencl_device_id: Slot,
|
||||||
|
pub get_opencl_compute_factory: Slot,
|
||||||
|
pub init_opencl_ex: Slot,
|
||||||
|
pub lock_opencl: Slot,
|
||||||
|
pub unlock_opencl: Slot,
|
||||||
|
pub init_opengl: Slot,
|
||||||
|
pub get_opengl_context: Slot,
|
||||||
|
pub get_opengl_drawable: Slot,
|
||||||
|
pub lock_opengl: Slot,
|
||||||
|
pub unlock_opengl: Slot,
|
||||||
|
pub init_xv: Slot,
|
||||||
|
pub get_xv_device: Slot,
|
||||||
|
pub lock_xv: Slot,
|
||||||
|
pub unlock_xv: Slot,
|
||||||
|
pub init_gralloc: Slot,
|
||||||
|
pub get_gralloc_device: Slot,
|
||||||
|
pub lock_gralloc: Slot,
|
||||||
|
pub unlock_gralloc: Slot,
|
||||||
|
pub alloc_buffer: unsafe extern "system" fn(
|
||||||
|
*mut AmfContext,
|
||||||
|
i32, // AMF_MEMORY_TYPE
|
||||||
|
usize,
|
||||||
|
*mut *mut AmfBuffer,
|
||||||
|
) -> AmfResult,
|
||||||
|
pub alloc_surface: Slot,
|
||||||
|
pub alloc_audio_buffer: Slot,
|
||||||
|
pub create_buffer_from_host_native: Slot,
|
||||||
|
pub create_surface_from_host_native: Slot,
|
||||||
|
pub create_surface_from_dx9_native: Slot,
|
||||||
|
/// Out-param is `AMFSurface**` in the header; declared as the `AmfData` base here because
|
||||||
|
/// every surface call this module makes (`SetPts`, `SetProperty`, `Release`,
|
||||||
|
/// `SubmitInput`) lives in the `AMFData` vtable prefix, which `AMFSurfaceVtbl` reproduces
|
||||||
|
/// slot-for-slot (single inheritance, same object pointer).
|
||||||
|
pub create_surface_from_dx11_native: unsafe extern "system" fn(
|
||||||
|
*mut AmfContext,
|
||||||
|
*mut c_void,
|
||||||
|
*mut *mut AmfData,
|
||||||
|
*mut c_void,
|
||||||
|
) -> AmfResult,
|
||||||
|
pub create_surface_from_opengl_native: Slot,
|
||||||
|
pub create_surface_from_gralloc_native: Slot,
|
||||||
|
pub create_surface_from_opencl_native: Slot,
|
||||||
|
pub create_buffer_from_opencl_native: Slot,
|
||||||
|
pub get_compute: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- AMFComponent (components/Component.h) --------------------------------------------------
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfComponent {
|
||||||
|
pub vtbl: *const AmfComponentVtbl,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfComponentVtbl {
|
||||||
|
// AMFInterface
|
||||||
|
pub acquire: Slot,
|
||||||
|
pub release: unsafe extern "system" fn(*mut AmfComponent) -> i32,
|
||||||
|
pub query_interface: Slot,
|
||||||
|
// AMFPropertyStorage
|
||||||
|
pub set_property:
|
||||||
|
unsafe extern "system" fn(*mut AmfComponent, *const u16, AmfVariant) -> AmfResult,
|
||||||
|
pub get_property: Slot,
|
||||||
|
pub has_property: Slot,
|
||||||
|
pub get_property_count: Slot,
|
||||||
|
pub get_property_at: Slot,
|
||||||
|
pub clear: Slot,
|
||||||
|
pub add_to: Slot,
|
||||||
|
pub copy_to: Slot,
|
||||||
|
pub add_observer: Slot,
|
||||||
|
pub remove_observer: Slot,
|
||||||
|
// AMFPropertyStorageEx
|
||||||
|
pub get_properties_info_count: Slot,
|
||||||
|
pub get_property_info_at: Slot,
|
||||||
|
pub get_property_info: Slot,
|
||||||
|
pub validate_property: Slot,
|
||||||
|
// AMFComponent
|
||||||
|
pub init: unsafe extern "system" fn(*mut AmfComponent, i32, i32, i32) -> AmfResult,
|
||||||
|
pub reinit: Slot,
|
||||||
|
pub terminate: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
||||||
|
pub drain: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
||||||
|
pub flush: unsafe extern "system" fn(*mut AmfComponent) -> AmfResult,
|
||||||
|
pub submit_input: unsafe extern "system" fn(*mut AmfComponent, *mut AmfData) -> AmfResult,
|
||||||
|
pub query_output: unsafe extern "system" fn(*mut AmfComponent, *mut *mut AmfData) -> AmfResult,
|
||||||
|
pub get_context: Slot,
|
||||||
|
pub set_output_data_allocator_cb: Slot,
|
||||||
|
pub get_caps: Slot,
|
||||||
|
pub optimize: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- AMFData (core/Data.h) — also the usable prefix of AMFSurface --------------------------
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfData {
|
||||||
|
pub vtbl: *const AmfDataVtbl,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfDataVtbl {
|
||||||
|
// AMFInterface
|
||||||
|
pub acquire: Slot,
|
||||||
|
pub release: unsafe extern "system" fn(*mut AmfData) -> i32,
|
||||||
|
pub query_interface:
|
||||||
|
unsafe extern "system" fn(*mut AmfData, *const AmfGuid, *mut *mut c_void) -> AmfResult,
|
||||||
|
// AMFPropertyStorage
|
||||||
|
pub set_property: unsafe extern "system" fn(*mut AmfData, *const u16, AmfVariant) -> AmfResult,
|
||||||
|
pub get_property:
|
||||||
|
unsafe extern "system" fn(*mut AmfData, *const u16, *mut AmfVariant) -> AmfResult,
|
||||||
|
pub has_property: Slot,
|
||||||
|
pub get_property_count: Slot,
|
||||||
|
pub get_property_at: Slot,
|
||||||
|
pub clear: Slot,
|
||||||
|
pub add_to: Slot,
|
||||||
|
pub copy_to: Slot,
|
||||||
|
pub add_observer: Slot,
|
||||||
|
pub remove_observer: Slot,
|
||||||
|
// AMFData
|
||||||
|
pub get_memory_type: Slot,
|
||||||
|
pub duplicate: Slot,
|
||||||
|
pub convert: Slot,
|
||||||
|
pub interop: Slot,
|
||||||
|
pub get_data_type: Slot,
|
||||||
|
pub is_reusable: Slot,
|
||||||
|
pub set_pts: unsafe extern "system" fn(*mut AmfData, i64),
|
||||||
|
pub get_pts: Slot,
|
||||||
|
pub set_duration: Slot,
|
||||||
|
pub get_duration: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- AMFBuffer (core/Buffer.h) — the encoder's output object -------------------------------
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfBuffer {
|
||||||
|
pub vtbl: *const AmfBufferVtbl,
|
||||||
|
}
|
||||||
|
#[repr(C)]
|
||||||
|
pub struct AmfBufferVtbl {
|
||||||
|
// AMFInterface + AMFPropertyStorage + AMFData prefix (identical order to AmfDataVtbl).
|
||||||
|
pub acquire: Slot,
|
||||||
|
pub release: unsafe extern "system" fn(*mut AmfBuffer) -> i32,
|
||||||
|
pub query_interface: Slot,
|
||||||
|
pub set_property: Slot,
|
||||||
|
pub get_property: Slot,
|
||||||
|
pub has_property: Slot,
|
||||||
|
pub get_property_count: Slot,
|
||||||
|
pub get_property_at: Slot,
|
||||||
|
pub clear: Slot,
|
||||||
|
pub add_to: Slot,
|
||||||
|
pub copy_to: Slot,
|
||||||
|
pub add_observer: Slot,
|
||||||
|
pub remove_observer: Slot,
|
||||||
|
pub get_memory_type: Slot,
|
||||||
|
pub duplicate: Slot,
|
||||||
|
pub convert: Slot,
|
||||||
|
pub interop: Slot,
|
||||||
|
pub get_data_type: Slot,
|
||||||
|
pub is_reusable: Slot,
|
||||||
|
pub set_pts: Slot,
|
||||||
|
pub get_pts: Slot,
|
||||||
|
pub set_duration: Slot,
|
||||||
|
pub get_duration: Slot,
|
||||||
|
// AMFBuffer
|
||||||
|
pub set_size: Slot,
|
||||||
|
pub get_size: unsafe extern "system" fn(*mut AmfBuffer) -> usize,
|
||||||
|
pub get_native: unsafe extern "system" fn(*mut AmfBuffer) -> *mut c_void,
|
||||||
|
pub add_observer_buffer: Slot,
|
||||||
|
pub remove_observer_buffer: Slot,
|
||||||
|
}
|
||||||
|
|
||||||
|
// -- DLL entry points (core/Factory.h; AMF_CDECL_CALL) --------------------------------------
|
||||||
|
pub type AmfQueryVersionFn = unsafe extern "C" fn(*mut u64) -> AmfResult;
|
||||||
|
pub type AmfInitFn = unsafe extern "C" fn(u64, *mut *mut AmfFactory) -> AmfResult;
|
||||||
Reference in New Issue
Block a user