mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-01-28 08:31:52 +08:00
- 新增 RustDesk 模块,支持与 RustDesk 客户端连接 - 实现会合服务器协议和 P2P 连接 - 支持 NaCl 加密和密钥交换 - 添加视频帧和 HID 事件适配器 - 添加 Protobuf 协议定义 (message.proto, rendezvous.proto) - 新增完整项目文档 - 各功能模块文档 (video, hid, msd, otg, webrtc 等) - hwcodec 和 RustDesk 协议技术报告 - 系统架构和技术栈文档 - 更新 Web 前端 RustDesk 配置界面和 API
13 KiB
13 KiB
hwcodec 构建系统与集成指南
1. 项目结构
libs/hwcodec/
├── Cargo.toml # 包配置
├── Cargo.lock # 依赖锁定
├── build.rs # 构建脚本
├── src/ # Rust 源码
│ ├── lib.rs # 库入口
│ ├── common.rs # 公共定义
│ ├── ffmpeg.rs # FFmpeg 集成
│ ├── mux.rs # 混流器
│ ├── android.rs # Android 支持
│ ├── ffmpeg_ram/ # RAM 编解码
│ │ ├── mod.rs
│ │ ├── encode.rs
│ │ └── decode.rs
│ ├── vram/ # GPU 编解码 (Windows)
│ │ ├── mod.rs
│ │ ├── encode.rs
│ │ ├── decode.rs
│ │ └── ...
│ └── res/ # 测试资源
│ ├── 720p.h264
│ └── 720p.h265
├── cpp/ # C++ 源码
│ ├── common/ # 公共代码
│ ├── ffmpeg_ram/ # FFmpeg RAM 实现
│ ├── ffmpeg_vram/ # FFmpeg VRAM 实现
│ ├── nv/ # NVIDIA 实现
│ ├── amf/ # AMD 实现
│ ├── mfx/ # Intel 实现
│ ├── mux/ # 混流实现
│ └── yuv/ # YUV 处理
├── externals/ # 外部 SDK (Git 子模块)
│ ├── nv-codec-headers_n12.1.14.0/
│ ├── Video_Codec_SDK_12.1.14/
│ ├── AMF_v1.4.35/
│ └── MediaSDK_22.5.4/
├── dev/ # 开发工具
│ ├── capture/ # 捕获工具
│ ├── render/ # 渲染工具
│ └── tool/ # 通用工具
└── examples/ # 示例程序
2. Cargo 配置
2.1 Cargo.toml
[package]
name = "hwcodec"
version = "0.7.1"
edition = "2021"
[features]
default = []
vram = [] # GPU VRAM 直接编解码 (仅 Windows)
[dependencies]
log = "0.4" # 日志
serde_derive = "1.0" # 序列化派生宏
serde = "1.0" # 序列化
serde_json = "1.0" # JSON 序列化
[build-dependencies]
cc = "1.0" # C++ 编译
bindgen = "0.59" # FFI 绑定生成
[dev-dependencies]
env_logger = "0.10" # 日志输出
rand = "0.8" # 随机数
2.2 Feature 说明
| Feature | 说明 | 平台 |
|---|---|---|
default |
基础功能 | 全平台 |
vram |
GPU VRAM 直接编解码 | 仅 Windows |
2.3 使用方式
# 基础使用
[dependencies]
hwcodec = { path = "libs/hwcodec" }
# 启用 VRAM 功能 (Windows)
[dependencies]
hwcodec = { path = "libs/hwcodec", features = ["vram"] }
3. 构建脚本详解 (build.rs)
3.1 主入口
fn main() {
let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
let mut builder = Build::new();
// 1. 构建公共模块
build_common(&mut builder);
// 2. 构建 FFmpeg 相关模块
ffmpeg::build_ffmpeg(&mut builder);
// 3. 构建 SDK 模块 (Windows + vram feature)
#[cfg(all(windows, feature = "vram"))]
sdk::build_sdk(&mut builder);
// 4. 编译生成静态库
builder.static_crt(true).compile("hwcodec");
}
3.2 公共模块构建
fn build_common(builder: &mut Build) {
let common_dir = manifest_dir.join("cpp").join("common");
// 生成 FFI 绑定
bindgen::builder()
.header(common_dir.join("common.h"))
.header(common_dir.join("callback.h"))
.rustified_enum("*")
.generate()
.write_to_file(OUT_DIR.join("common_ffi.rs"));
// 平台相关代码
#[cfg(windows)]
builder.file(common_dir.join("platform/win/win.cpp"));
#[cfg(target_os = "linux")]
builder.file(common_dir.join("platform/linux/linux.cpp"));
#[cfg(target_os = "macos")]
builder.file(common_dir.join("platform/mac/mac.mm"));
// 工具代码
builder.files([
common_dir.join("log.cpp"),
common_dir.join("util.cpp"),
]);
}
3.3 FFmpeg 模块构建
mod ffmpeg {
pub fn build_ffmpeg(builder: &mut Build) {
// 生成 FFmpeg FFI 绑定
ffmpeg_ffi();
// 链接 FFmpeg 库
if let Ok(vcpkg_root) = std::env::var("VCPKG_ROOT") {
link_vcpkg(builder, vcpkg_root.into());
} else {
link_system_ffmpeg(builder); // pkg-config
}
// 链接系统库
link_os();
// 构建子模块
build_ffmpeg_ram(builder);
#[cfg(feature = "vram")]
build_ffmpeg_vram(builder);
build_mux(builder);
}
}
3.4 FFmpeg 链接方式
VCPKG (跨平台静态链接)
fn link_vcpkg(builder: &mut Build, path: PathBuf) -> PathBuf {
// 目标平台识别
let target = match (target_os, target_arch) {
("windows", "x86_64") => "x64-windows-static",
("macos", "x86_64") => "x64-osx",
("macos", "aarch64") => "arm64-osx",
("linux", arch) => format!("{}-linux", arch),
_ => panic!("unsupported platform"),
};
let lib_path = path.join("installed").join(target).join("lib");
// 链接 FFmpeg 静态库
println!("cargo:rustc-link-search=native={}", lib_path);
["avcodec", "avutil", "avformat"].iter()
.for_each(|lib| println!("cargo:rustc-link-lib=static={}", lib));
}
pkg-config (Linux 动态链接)
fn link_system_ffmpeg(builder: &mut Build) {
let libs = ["libavcodec", "libavutil", "libavformat", "libswscale"];
for lib in &libs {
// 获取编译标志
let cflags = Command::new("pkg-config")
.args(["--cflags", lib])
.output()?;
// 获取链接标志
let libs = Command::new("pkg-config")
.args(["--libs", lib])
.output()?;
// 解析并应用
for flag in libs.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..]);
}
}
}
}
3.5 系统库链接
fn link_os() {
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap();
let libs: Vec<&str> = match target_os.as_str() {
"windows" => vec!["User32", "bcrypt", "ole32", "advapi32"],
"linux" => vec!["drm", "X11", "stdc++", "z"],
"macos" | "ios" => vec!["c++", "m"],
"android" => vec!["z", "m", "android", "atomic", "mediandk"],
_ => panic!("unsupported os"),
};
for lib in libs {
println!("cargo:rustc-link-lib={}", lib);
}
// macOS 框架
if target_os == "macos" || target_os == "ios" {
for framework in ["CoreFoundation", "CoreVideo", "CoreMedia",
"VideoToolbox", "AVFoundation"] {
println!("cargo:rustc-link-lib=framework={}", framework);
}
}
}
3.6 SDK 模块构建 (Windows)
#[cfg(all(windows, feature = "vram"))]
mod sdk {
pub fn build_sdk(builder: &mut Build) {
build_amf(builder); // AMD AMF
build_nv(builder); // NVIDIA
build_mfx(builder); // Intel MFX
}
fn build_nv(builder: &mut Build) {
let sdk_path = externals_dir.join("Video_Codec_SDK_12.1.14");
// 包含 SDK 头文件
builder.includes([
sdk_path.join("Interface"),
sdk_path.join("Samples/Utils"),
sdk_path.join("Samples/NvCodec"),
]);
// 编译 SDK 源文件
builder.file(sdk_path.join("Samples/NvCodec/NvEncoder/NvEncoder.cpp"));
builder.file(sdk_path.join("Samples/NvCodec/NvEncoder/NvEncoderD3D11.cpp"));
builder.file(sdk_path.join("Samples/NvCodec/NvDecoder/NvDecoder.cpp"));
// 编译封装代码
builder.files([
nv_dir.join("nv_encode.cpp"),
nv_dir.join("nv_decode.cpp"),
]);
}
}
4. FFI 绑定生成
4.1 bindgen 配置
bindgen::builder()
.header("path/to/header.h")
.rustified_enum("*") // 生成 Rust 枚举
.parse_callbacks(Box::new(Callbacks)) // 自定义回调
.generate()
.write_to_file(OUT_DIR.join("ffi.rs"));
4.2 自定义派生
#[derive(Debug)]
struct CommonCallbacks;
impl bindgen::callbacks::ParseCallbacks for CommonCallbacks {
fn add_derives(&self, name: &str) -> Vec<String> {
// 为特定类型添加序列化支持
match name {
"DataFormat" | "SurfaceFormat" | "API" => {
vec!["Serialize".to_string(), "Deserialize".to_string()]
}
_ => vec![],
}
}
}
4.3 生成的文件
| 文件 | 来源 | 内容 |
|---|---|---|
common_ffi.rs |
common.h, callback.h |
枚举、常量、回调类型 |
ffmpeg_ffi.rs |
ffmpeg_ffi.h |
FFmpeg 日志级别、函数 |
ffmpeg_ram_ffi.rs |
ffmpeg_ram_ffi.h |
编解码器函数 |
mux_ffi.rs |
mux_ffi.h |
混流器函数 |
5. 外部依赖管理
5.1 Git 子模块
# 初始化子模块
git submodule update --init --recursive
# 更新子模块
git submodule update --remote externals
5.2 子模块配置 (.gitmodules)
[submodule "externals"]
path = libs/hwcodec/externals
url = https://github.com/rustdesk-org/externals.git
5.3 依赖版本
| 依赖 | 版本 | 用途 |
|---|---|---|
| nv-codec-headers | n12.1.14.0 | NVIDIA FFmpeg 编码头 |
| Video_Codec_SDK | 12.1.14 | NVIDIA 编解码 SDK |
| AMF | v1.4.35 | AMD Advanced Media Framework |
| MediaSDK | 22.5.4 | Intel Media SDK |
6. 平台构建指南
6.1 Linux 构建
# 安装 FFmpeg 开发库
sudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
# 安装其他依赖
sudo apt install libdrm-dev libx11-dev pkg-config
# 构建
cargo build --release -p hwcodec
6.2 Windows 构建 (VCPKG)
# 安装 VCPKG
git clone https://github.com/microsoft/vcpkg
cd vcpkg
./bootstrap-vcpkg.bat
# 安装 FFmpeg
./vcpkg install ffmpeg:x64-windows-static
# 设置环境变量
$env:VCPKG_ROOT = "C:\path\to\vcpkg"
# 构建
cargo build --release -p hwcodec --features vram
6.3 macOS 构建
# 安装 FFmpeg (Homebrew)
brew install ffmpeg pkg-config
# 或使用 VCPKG
export VCPKG_ROOT=/path/to/vcpkg
vcpkg install ffmpeg:arm64-osx # Apple Silicon
vcpkg install ffmpeg:x64-osx # Intel
# 构建
cargo build --release -p hwcodec
6.4 交叉编译
# 安装 cross
cargo install cross --git https://github.com/cross-rs/cross
# ARM64 Linux
cross build --release -p hwcodec --target aarch64-unknown-linux-gnu
# ARMv7 Linux
cross build --release -p hwcodec --target armv7-unknown-linux-gnueabihf
7. 集成到 One-KVM
7.1 依赖配置
# Cargo.toml
[dependencies]
hwcodec = { path = "libs/hwcodec" }
7.2 使用示例
use hwcodec::ffmpeg_ram::encode::{Encoder, EncodeContext};
use hwcodec::ffmpeg_ram::decode::{Decoder, DecodeContext};
use hwcodec::ffmpeg::AVPixelFormat;
// 检测可用编码器
let encoders = Encoder::available_encoders(ctx, None);
// 创建编码器
let encoder = Encoder::new(EncodeContext {
name: "h264_vaapi".to_string(),
width: 1920,
height: 1080,
pixfmt: AVPixelFormat::AV_PIX_FMT_NV12,
fps: 30,
gop: 30,
kbs: 4000,
// ...
})?;
// 编码
let frames = encoder.encode(&yuv_data, pts_ms)?;
7.3 日志集成
// hwcodec 使用 log crate,与 One-KVM 日志系统兼容
use log::{debug, info, warn, error};
// C++ 层日志通过回调传递
#[no_mangle]
pub extern "C" fn hwcodec_log(level: i32, message: *const c_char) {
match level {
0 => error!("{}", message),
1 => warn!("{}", message),
2 => info!("{}", message),
3 => debug!("{}", message),
4 => trace!("{}", message),
_ => {}
}
}
8. 故障排除
8.1 编译错误
FFmpeg 未找到:
error: pkg-config failed for libavcodec
解决: 安装 FFmpeg 开发库
sudo apt install libavcodec-dev libavformat-dev libavutil-dev libswscale-dev
bindgen 错误:
error: failed to run custom build command for `hwcodec`
解决: 安装 clang
sudo apt install clang libclang-dev
8.2 链接错误
符号未定义:
undefined reference to `av_log_set_level'
解决: 检查 FFmpeg 库链接顺序,确保 pkg-config 正确配置
动态库未找到:
error while loading shared libraries: libavcodec.so.59
解决:
sudo ldconfig
# 或设置 LD_LIBRARY_PATH
export LD_LIBRARY_PATH=/usr/local/lib:$LD_LIBRARY_PATH
8.3 运行时错误
硬件编码器不可用:
Encoder h264_vaapi test failed
检查:
- 驱动是否正确安装:
vainfo - 权限是否足够:
ls -la /dev/dri/ - 用户是否在 video 组:
groups
解码失败:
avcodec_receive_frame failed, ret = -11
解决: 这通常表示需要更多输入数据 (EAGAIN),是正常行为