mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-29 00:51:53 +08:00
522 lines
18 KiB
Rust
522 lines
18 KiB
Rust
use cc::Build;
|
|
use std::{
|
|
env,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
fn main() {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let externals_dir = manifest_dir.join("externals");
|
|
let cpp_dir = manifest_dir.join("cpp");
|
|
println!("cargo:rerun-if-changed=src");
|
|
println!("cargo:rerun-if-changed=deps");
|
|
println!("cargo:rerun-if-changed={}", externals_dir.display());
|
|
println!("cargo:rerun-if-changed={}", cpp_dir.display());
|
|
let mut builder = Build::new();
|
|
|
|
build_common(&mut builder);
|
|
ffmpeg::build_ffmpeg(&mut builder);
|
|
#[cfg(all(windows, feature = "vram"))]
|
|
sdk::build_sdk(&mut builder);
|
|
builder.static_crt(true).compile("hwcodec");
|
|
}
|
|
|
|
fn build_common(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
let common_dir = manifest_dir.join("cpp").join("common");
|
|
bindgen::builder()
|
|
.header(common_dir.join("common.h").to_string_lossy().to_string())
|
|
.header(common_dir.join("callback.h").to_string_lossy().to_string())
|
|
.rustified_enum("*")
|
|
.parse_callbacks(Box::new(CommonCallbacks))
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("common_ffi.rs"))
|
|
.unwrap();
|
|
|
|
// system
|
|
#[cfg(windows)]
|
|
{
|
|
["d3d11", "dxgi"].map(|lib| println!("cargo:rustc-link-lib={}", lib));
|
|
}
|
|
|
|
builder.include(&common_dir);
|
|
|
|
// platform
|
|
let _platform_path = common_dir.join("platform");
|
|
#[cfg(windows)]
|
|
{
|
|
let win_path = _platform_path.join("win");
|
|
builder.include(&win_path);
|
|
builder.file(win_path.join("win.cpp"));
|
|
}
|
|
#[cfg(target_os = "linux")]
|
|
{
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let externals_dir = manifest_dir.join("externals");
|
|
// ffnvcodec
|
|
let ffnvcodec_path = externals_dir
|
|
.join("nv-codec-headers_n12.1.14.0")
|
|
.join("include")
|
|
.join("ffnvcodec");
|
|
builder.include(ffnvcodec_path);
|
|
|
|
let linux_path = _platform_path.join("linux");
|
|
builder.include(&linux_path);
|
|
builder.file(linux_path.join("linux.cpp"));
|
|
}
|
|
if target_os == "macos" {
|
|
let macos_path = _platform_path.join("mac");
|
|
builder.include(&macos_path);
|
|
builder.file(macos_path.join("mac.mm"));
|
|
}
|
|
|
|
// tool
|
|
builder.files(["log.cpp", "util.cpp"].map(|f| common_dir.join(f)));
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
struct CommonCallbacks;
|
|
impl bindgen::callbacks::ParseCallbacks for CommonCallbacks {
|
|
fn add_derives(&self, name: &str) -> Vec<String> {
|
|
let names = vec!["DataFormat", "SurfaceFormat", "API"];
|
|
if names.contains(&name) {
|
|
vec!["Serialize", "Deserialize"]
|
|
.drain(..)
|
|
.map(|s| s.to_string())
|
|
.collect()
|
|
} else {
|
|
vec![]
|
|
}
|
|
}
|
|
}
|
|
|
|
mod ffmpeg {
|
|
#[allow(unused_imports)]
|
|
use core::panic;
|
|
|
|
use super::*;
|
|
|
|
pub fn build_ffmpeg(builder: &mut Build) {
|
|
ffmpeg_ffi();
|
|
|
|
// Try VCPKG first, fallback to system FFmpeg via pkg-config
|
|
if let Ok(vcpkg_root) = std::env::var("VCPKG_ROOT") {
|
|
link_vcpkg(builder, vcpkg_root.into());
|
|
} else {
|
|
// Use system FFmpeg via pkg-config
|
|
link_system_ffmpeg(builder);
|
|
}
|
|
|
|
link_os();
|
|
build_ffmpeg_ram(builder);
|
|
#[cfg(feature = "vram")]
|
|
build_ffmpeg_vram(builder);
|
|
build_mux(builder);
|
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
if target_os == "macos" || target_os == "ios" {
|
|
builder.flag("-std=c++11");
|
|
}
|
|
}
|
|
|
|
/// Link system FFmpeg using pkg-config (for Linux development)
|
|
fn link_system_ffmpeg(builder: &mut Build) {
|
|
use std::process::Command;
|
|
|
|
let libs = ["libavcodec", "libavutil", "libavformat", "libswscale"];
|
|
|
|
for lib in &libs {
|
|
// Get cflags
|
|
if let Ok(output) = Command::new("pkg-config")
|
|
.args(["--cflags", lib])
|
|
.output()
|
|
{
|
|
if output.status.success() {
|
|
let cflags = String::from_utf8_lossy(&output.stdout);
|
|
for flag in cflags.split_whitespace() {
|
|
if flag.starts_with("-I") {
|
|
builder.include(&flag[2..]);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Get libs - always use dynamic linking on Linux
|
|
if let Ok(output) = Command::new("pkg-config")
|
|
.args(["--libs", lib])
|
|
.output()
|
|
{
|
|
if output.status.success() {
|
|
let libs_str = String::from_utf8_lossy(&output.stdout);
|
|
for flag in libs_str.split_whitespace() {
|
|
if flag.starts_with("-L") {
|
|
println!("cargo:rustc-link-search=native={}", &flag[2..]);
|
|
} else if flag.starts_with("-l") {
|
|
println!("cargo:rustc-link-lib={}", &flag[2..]);
|
|
}
|
|
}
|
|
} else {
|
|
panic!("pkg-config failed for {}. Install FFmpeg development libraries: sudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev", lib);
|
|
}
|
|
} else {
|
|
panic!("pkg-config not found. Install pkg-config and FFmpeg development libraries.");
|
|
}
|
|
}
|
|
|
|
println!("cargo:info=Using system FFmpeg via pkg-config (dynamic linking)");
|
|
}
|
|
|
|
fn link_vcpkg(builder: &mut Build, mut path: PathBuf) -> PathBuf {
|
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
let mut target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
|
if target_arch == "x86_64" {
|
|
target_arch = "x64".to_owned();
|
|
} else if target_arch == "x86" {
|
|
target_arch = "x86".to_owned();
|
|
} else if target_arch == "loongarch64" {
|
|
target_arch = "loongarch64".to_owned();
|
|
} else if target_arch == "aarch64" {
|
|
target_arch = "arm64".to_owned();
|
|
} else {
|
|
target_arch = "arm".to_owned();
|
|
}
|
|
let mut target = if target_os == "macos" {
|
|
if target_arch == "x64" {
|
|
"x64-osx".to_owned()
|
|
} else if target_arch == "arm64" {
|
|
"arm64-osx".to_owned()
|
|
} else {
|
|
format!("{}-{}", target_arch, target_os)
|
|
}
|
|
} else if target_os == "windows" {
|
|
"x64-windows-static".to_owned()
|
|
} else {
|
|
format!("{}-{}", target_arch, target_os)
|
|
};
|
|
if target_arch == "x86" {
|
|
target = target.replace("x64", "x86");
|
|
}
|
|
println!("cargo:info={}", target);
|
|
path.push("installed");
|
|
path.push(target);
|
|
|
|
println!(
|
|
"{}",
|
|
format!(
|
|
"cargo:rustc-link-search=native={}",
|
|
path.join("lib").to_str().unwrap()
|
|
)
|
|
);
|
|
{
|
|
let mut static_libs = vec!["avcodec", "avutil", "avformat"];
|
|
if target_os == "windows" {
|
|
static_libs.push("libmfx");
|
|
}
|
|
static_libs
|
|
.iter()
|
|
.map(|lib| println!("cargo:rustc-link-lib=static={}", lib))
|
|
.count();
|
|
}
|
|
|
|
let include = path.join("include");
|
|
println!("{}", format!("cargo:include={}", include.to_str().unwrap()));
|
|
builder.include(&include);
|
|
include
|
|
}
|
|
|
|
fn link_os() {
|
|
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
|
|
let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap();
|
|
|
|
let dyn_libs: Vec<&str> = if target_os == "windows" {
|
|
["User32", "bcrypt", "ole32", "advapi32"].to_vec()
|
|
} else if target_os == "linux" {
|
|
// Note: VA-API libraries (va, va-drm, va-x11) must remain dynamic
|
|
// as they load drivers at runtime. Same for libmfx.
|
|
// All dependencies use dynamic linking on Linux.
|
|
let mut v = vec!["drm", "X11", "stdc++"];
|
|
|
|
if target_arch == "x86_64" {
|
|
v.push("z");
|
|
}
|
|
v
|
|
} else if target_os == "macos" || target_os == "ios" {
|
|
["c++", "m"].to_vec()
|
|
} else if target_os == "android" {
|
|
// https://github.com/FFmpeg/FFmpeg/commit/98b5e80fd6980e641199e9ce3bc27100e2df17a4
|
|
// link to mediandk directly since n7.1
|
|
["z", "m", "android", "atomic", "mediandk"].to_vec()
|
|
} else {
|
|
panic!("unsupported os");
|
|
};
|
|
|
|
for lib in dyn_libs.iter() {
|
|
println!("cargo:rustc-link-lib={}", lib);
|
|
}
|
|
|
|
if target_os == "macos" || target_os == "ios" {
|
|
println!("cargo:rustc-link-lib=framework=CoreFoundation");
|
|
println!("cargo:rustc-link-lib=framework=CoreVideo");
|
|
println!("cargo:rustc-link-lib=framework=CoreMedia");
|
|
println!("cargo:rustc-link-lib=framework=VideoToolbox");
|
|
println!("cargo:rustc-link-lib=framework=AVFoundation");
|
|
}
|
|
}
|
|
|
|
fn ffmpeg_ffi() {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let ffmpeg_ram_dir = manifest_dir.join("cpp").join("common");
|
|
let ffi_header = ffmpeg_ram_dir
|
|
.join("ffmpeg_ffi.h")
|
|
.to_string_lossy()
|
|
.to_string();
|
|
bindgen::builder()
|
|
.header(ffi_header)
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("ffmpeg_ffi.rs"))
|
|
.unwrap();
|
|
}
|
|
|
|
fn build_ffmpeg_ram(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let ffmpeg_ram_dir = manifest_dir.join("cpp").join("ffmpeg_ram");
|
|
let ffi_header = ffmpeg_ram_dir
|
|
.join("ffmpeg_ram_ffi.h")
|
|
.to_string_lossy()
|
|
.to_string();
|
|
bindgen::builder()
|
|
.header(ffi_header)
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("ffmpeg_ram_ffi.rs"))
|
|
.unwrap();
|
|
|
|
builder.files(
|
|
["ffmpeg_ram_encode.cpp", "ffmpeg_ram_decode.cpp"].map(|f| ffmpeg_ram_dir.join(f)),
|
|
);
|
|
}
|
|
|
|
#[cfg(feature = "vram")]
|
|
fn build_ffmpeg_vram(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let ffmpeg_ram_dir = manifest_dir.join("cpp").join("ffmpeg_vram");
|
|
let ffi_header = ffmpeg_ram_dir
|
|
.join("ffmpeg_vram_ffi.h")
|
|
.to_string_lossy()
|
|
.to_string();
|
|
bindgen::builder()
|
|
.header(ffi_header)
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("ffmpeg_vram_ffi.rs"))
|
|
.unwrap();
|
|
|
|
builder.files(
|
|
["ffmpeg_vram_decode.cpp", "ffmpeg_vram_encode.cpp"].map(|f| ffmpeg_ram_dir.join(f)),
|
|
);
|
|
}
|
|
|
|
fn build_mux(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let mux_dir = manifest_dir.join("cpp").join("mux");
|
|
let mux_header = mux_dir.join("mux_ffi.h").to_string_lossy().to_string();
|
|
bindgen::builder()
|
|
.header(mux_header)
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("mux_ffi.rs"))
|
|
.unwrap();
|
|
|
|
builder.files(["mux.cpp"].map(|f| mux_dir.join(f)));
|
|
}
|
|
}
|
|
|
|
#[cfg(all(windows, feature = "vram"))]
|
|
mod sdk {
|
|
use super::*;
|
|
|
|
pub(crate) fn build_sdk(builder: &mut Build) {
|
|
build_amf(builder);
|
|
build_nv(builder);
|
|
build_mfx(builder);
|
|
}
|
|
|
|
fn build_nv(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let externals_dir = manifest_dir.join("externals");
|
|
let common_dir = manifest_dir.join("common");
|
|
let nv_dir = manifest_dir.join("cpp").join("nv");
|
|
println!("cargo:rerun-if-changed=src");
|
|
println!("cargo:rerun-if-changed={}", common_dir.display());
|
|
println!("cargo:rerun-if-changed={}", externals_dir.display());
|
|
bindgen::builder()
|
|
.header(&nv_dir.join("nv_ffi.h").to_string_lossy().to_string())
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("nv_ffi.rs"))
|
|
.unwrap();
|
|
|
|
// system
|
|
#[cfg(target_os = "windows")]
|
|
[
|
|
"kernel32", "user32", "gdi32", "winspool", "shell32", "ole32", "oleaut32", "uuid",
|
|
"comdlg32", "advapi32", "d3d11", "dxgi",
|
|
]
|
|
.map(|lib| println!("cargo:rustc-link-lib={}", lib));
|
|
#[cfg(target_os = "linux")]
|
|
println!("cargo:rustc-link-lib=stdc++");
|
|
|
|
// ffnvcodec
|
|
let ffnvcodec_path = externals_dir
|
|
.join("nv-codec-headers_n12.1.14.0")
|
|
.join("include")
|
|
.join("ffnvcodec");
|
|
builder.include(ffnvcodec_path);
|
|
|
|
// video codc sdk
|
|
let sdk_path = externals_dir.join("Video_Codec_SDK_12.1.14");
|
|
builder.includes([
|
|
sdk_path.clone(),
|
|
sdk_path.join("Interface"),
|
|
sdk_path.join("Samples").join("Utils"),
|
|
sdk_path.join("Samples").join("NvCodec"),
|
|
sdk_path.join("Samples").join("NvCodec").join("NVEncoder"),
|
|
sdk_path.join("Samples").join("NvCodec").join("NVDecoder"),
|
|
]);
|
|
|
|
for file in vec!["NvEncoder.cpp", "NvEncoderD3D11.cpp"] {
|
|
builder.file(
|
|
sdk_path
|
|
.join("Samples")
|
|
.join("NvCodec")
|
|
.join("NvEncoder")
|
|
.join(file),
|
|
);
|
|
}
|
|
for file in vec!["NvDecoder.cpp"] {
|
|
builder.file(
|
|
sdk_path
|
|
.join("Samples")
|
|
.join("NvCodec")
|
|
.join("NvDecoder")
|
|
.join(file),
|
|
);
|
|
}
|
|
|
|
// crate
|
|
builder.files(["nv_encode.cpp", "nv_decode.cpp"].map(|f| nv_dir.join(f)));
|
|
}
|
|
|
|
fn build_amf(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let externals_dir = manifest_dir.join("externals");
|
|
let amf_dir = manifest_dir.join("cpp").join("amf");
|
|
println!("cargo:rerun-if-changed=src");
|
|
println!("cargo:rerun-if-changed={}", externals_dir.display());
|
|
bindgen::builder()
|
|
.header(amf_dir.join("amf_ffi.h").to_string_lossy().to_string())
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("amf_ffi.rs"))
|
|
.unwrap();
|
|
|
|
// system
|
|
#[cfg(windows)]
|
|
println!("cargo:rustc-link-lib=ole32");
|
|
#[cfg(target_os = "linux")]
|
|
println!("cargo:rustc-link-lib=stdc++");
|
|
|
|
// amf
|
|
let amf_path = externals_dir.join("AMF_v1.4.35");
|
|
builder.include(format!("{}/amf/public/common", amf_path.display()));
|
|
builder.include(amf_path.join("amf"));
|
|
|
|
for f in vec![
|
|
"AMFFactory.cpp",
|
|
"AMFSTL.cpp",
|
|
"Thread.cpp",
|
|
#[cfg(windows)]
|
|
"Windows/ThreadWindows.cpp",
|
|
#[cfg(target_os = "linux")]
|
|
"Linux/ThreadLinux.cpp",
|
|
"TraceAdapter.cpp",
|
|
] {
|
|
builder.file(format!("{}/amf/public/common/{}", amf_path.display(), f));
|
|
}
|
|
|
|
// crate
|
|
builder.files(["amf_encode.cpp", "amf_decode.cpp"].map(|f| amf_dir.join(f)));
|
|
}
|
|
|
|
fn build_mfx(builder: &mut Build) {
|
|
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
|
|
let externals_dir = manifest_dir.join("externals");
|
|
let mfx_dir = manifest_dir.join("cpp").join("mfx");
|
|
println!("cargo:rerun-if-changed=src");
|
|
println!("cargo:rerun-if-changed={}", externals_dir.display());
|
|
bindgen::builder()
|
|
.header(&mfx_dir.join("mfx_ffi.h").to_string_lossy().to_string())
|
|
.rustified_enum("*")
|
|
.generate()
|
|
.unwrap()
|
|
.write_to_file(Path::new(&env::var_os("OUT_DIR").unwrap()).join("mfx_ffi.rs"))
|
|
.unwrap();
|
|
|
|
// MediaSDK
|
|
let sdk_path = externals_dir.join("MediaSDK_22.5.4");
|
|
|
|
// mfx_dispatch
|
|
let mfx_path = sdk_path.join("api").join("mfx_dispatch");
|
|
// include headers and reuse static lib
|
|
builder.include(mfx_path.join("windows").join("include"));
|
|
|
|
let sample_path = sdk_path.join("samples").join("sample_common");
|
|
builder
|
|
.includes([
|
|
sdk_path.join("api").join("include"),
|
|
sample_path.join("include"),
|
|
])
|
|
.files(
|
|
[
|
|
"sample_utils.cpp",
|
|
"base_allocator.cpp",
|
|
"d3d11_allocator.cpp",
|
|
"avc_bitstream.cpp",
|
|
"avc_spl.cpp",
|
|
"avc_nal_spl.cpp",
|
|
]
|
|
.map(|f| sample_path.join("src").join(f)),
|
|
)
|
|
.files(
|
|
[
|
|
"time.cpp",
|
|
"atomic.cpp",
|
|
"shared_object.cpp",
|
|
"thread_windows.cpp",
|
|
]
|
|
.map(|f| sample_path.join("src").join("vm").join(f)),
|
|
);
|
|
|
|
// link
|
|
[
|
|
"kernel32", "user32", "gdi32", "winspool", "shell32", "ole32", "oleaut32", "uuid",
|
|
"comdlg32", "advapi32", "d3d11", "dxgi",
|
|
]
|
|
.map(|lib| println!("cargo:rustc-link-lib={}", lib));
|
|
|
|
builder
|
|
.files(["mfx_encode.cpp", "mfx_decode.cpp"].map(|f| mfx_dir.join(f)))
|
|
.define("NOMINMAX", None)
|
|
.define("MFX_DEPRECATED_OFF", None)
|
|
.define("MFX_D3D11_SUPPORT", None);
|
|
}
|
|
}
|