feat(ffvk): bindgen shim for FFmpeg's Vulkan hwcontext (pf-ffvk)
ffmpeg-sys-next binds a curated header list that omits every hwcontext_*.h, so AVVulkanDeviceContext/AVVulkanFramesContext/AVVkFrame — the surface that lets FFmpeg's Vulkan Video decoder run on the presenter's own VkDevice and hand the decoded VkImages back — had no Rust bindings at all. pf-ffvk generates them at build time from the SYSTEM headers, which is the only ABI-safe option: the struct layout depends on FF_API_* deprecation gates resolved in libavutil/version.h (confirmed: FFmpeg 8.1 still carries the FIXED_QUEUES fields). Ships ash<->vulkan.h handle conversions; opaque AVHW*/AVFrame types keep ffmpeg-sys-next the owner of the core surface (pointer casts across). Needs vulkan-headers (Arch) / libvulkan-dev (CI, added); PF_FFVK_VULKAN_INCLUDE overrides for cross builds. Verified: bindgen layout tests pass, av_vk_frame_alloc links and zero-initializes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,75 @@
|
||||
//! Generate bindings for `libavutil/hwcontext_vulkan.h` against the SYSTEM headers.
|
||||
//!
|
||||
//! ffmpeg-sys-next binds a curated header list that omits every hwcontext_*.h; the
|
||||
//! Vulkan hwcontext structs (`AVVulkanDeviceContext`, `AVVkFrame`) are what let us run
|
||||
//! FFmpeg's Vulkan Video decoder on the presenter's own VkDevice and read the decoded
|
||||
//! VkImages back. Their layout depends on compile-time FF_API_* deprecation gates in
|
||||
//! libavutil/version.h, so bindgen over the installed header is the only ABI-safe
|
||||
//! source of truth — hand transcription would silently skew on the next FFmpeg bump.
|
||||
//!
|
||||
//! Non-Linux targets get an empty file: the workspace builds on macOS (clients/apple is
|
||||
//! the client there), and this shim is Linux-client plumbing only.
|
||||
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=wrapper.h");
|
||||
let out = PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs");
|
||||
|
||||
if env::var("CARGO_CFG_TARGET_OS").as_deref() != Ok("linux") {
|
||||
std::fs::write(&out, "// pf-ffvk: Linux-only, empty on this target\n").unwrap();
|
||||
return;
|
||||
}
|
||||
|
||||
// Include paths from pkg-config (libavutil for the hwcontext header; the Vulkan
|
||||
// headers usually live in /usr/include, but honor a registered vulkan.pc too).
|
||||
// PF_FFVK_VULKAN_INCLUDE prepends an explicit Vulkan-Headers include dir — for
|
||||
// cross builds and boxes without the system package.
|
||||
println!("cargo:rerun-if-env-changed=PF_FFVK_VULKAN_INCLUDE");
|
||||
let mut includes: Vec<PathBuf> = Vec::new();
|
||||
if let Ok(dir) = env::var("PF_FFVK_VULKAN_INCLUDE") {
|
||||
includes.push(PathBuf::from(dir));
|
||||
}
|
||||
let avutil = pkg_config::Config::new()
|
||||
.cargo_metadata(false)
|
||||
.probe("libavutil")
|
||||
.expect("pkg-config: libavutil not found — install the FFmpeg dev package");
|
||||
includes.extend(avutil.include_paths);
|
||||
if let Ok(vk) = pkg_config::Config::new()
|
||||
.cargo_metadata(false)
|
||||
.probe("vulkan")
|
||||
{
|
||||
includes.extend(vk.include_paths);
|
||||
}
|
||||
|
||||
let mut builder = bindgen::Builder::default()
|
||||
.header("wrapper.h")
|
||||
// The whole point of this crate: the Vulkan hwcontext surface…
|
||||
.allowlist_type("AVVulkan.*")
|
||||
.allowlist_type("AVVkFrame.*")
|
||||
.allowlist_function("av_vk_frame_alloc")
|
||||
.allowlist_function("av_vkfmt_from_pixfmt")
|
||||
// …plus nothing else of FFmpeg: the core types these structs reference only
|
||||
// ever appear behind pointers here, so keep them opaque instead of duplicating
|
||||
// ffmpeg-sys-next's definitions (callers cast pointers between the crates).
|
||||
.opaque_type("AVHWDeviceContext")
|
||||
.opaque_type("AVHWFramesContext")
|
||||
.opaque_type("AVBufferRef")
|
||||
.opaque_type("AVFrame")
|
||||
.derive_debug(false)
|
||||
.layout_tests(true);
|
||||
for dir in &includes {
|
||||
builder = builder.clang_arg(format!("-I{}", dir.display()));
|
||||
}
|
||||
let bindings = builder.generate().expect(
|
||||
"bindgen over libavutil/hwcontext_vulkan.h failed — is `vulkan-headers` installed? \
|
||||
(the header includes <vulkan/vulkan.h>)",
|
||||
);
|
||||
bindings.write_to_file(&out).unwrap();
|
||||
|
||||
// The av_vk_* symbols live in libavutil, which ffmpeg-sys-next already links into
|
||||
// every consumer of this crate; no extra link flags needed. Emitting the lib anyway
|
||||
// keeps `cargo test -p pf-ffvk` linking standalone.
|
||||
println!("cargo:rustc-link-lib=avutil");
|
||||
}
|
||||
Reference in New Issue
Block a user