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
18 KiB
18 KiB
hwcodec 技术架构报告
1. 项目概述
hwcodec 是一个基于 FFmpeg 的硬件视频编解码库,来源于 RustDesk 项目并针对 One-KVM 进行了定制优化。该库提供跨平台的 GPU 加速视频编解码能力,支持多个 GPU 厂商和多种编码标准。
1.1 项目位置
libs/hwcodec/
├── src/ # Rust 源代码
├── cpp/ # C++ 源代码
├── externals/ # 外部依赖 (SDK)
├── dev/ # 开发工具
└── examples/ # 示例程序
1.2 核心特性
- 多编解码格式支持: H.264, H.265 (HEVC), VP8, VP9, AV1, MJPEG
- 硬件加速: NVENC/NVDEC, AMF, Intel QSV/MFX, VAAPI, RKMPP, V4L2 M2M, VideoToolbox
- 跨平台: Windows, Linux, macOS, Android, iOS
- 低延迟优化: 专为实时流媒体场景设计
- Rust/C++ 混合架构: Rust 提供安全的上层 API,C++ 实现底层编解码逻辑
2. 架构设计
2.1 整体架构图
┌─────────────────────────────────────────────────────────────┐
│ Rust API Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ ffmpeg_ram │ │ vram │ │ mux │ │
│ │ module │ │ module │ │ module │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
├─────────┼────────────────┼───────────────────┼──────────────┤
│ │ │ │ │
│ │ FFI Bindings (bindgen) │ │
│ ▼ ▼ ▼ │
├─────────────────────────────────────────────────────────────┤
│ C++ Core Layer │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ ffmpeg_ram │ │ ffmpeg_vram │ │ mux.cpp │ │
│ │ encode/ │ │ encode/ │ │ │ │
│ │ decode │ │ decode │ │ │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
├─────────┼────────────────┼───────────────────┼──────────────┤
│ │ │ │ │
│ └────────────────┴───────────────────┘ │
│ │ │
│ ▼ │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ FFmpeg Libraries │ │
│ │ libavcodec │ libavutil │ libavformat │ libswscale │ │
│ └──────────────────────────────────────────────────────┘ │
│ │ │
├──────────────────────────┼──────────────────────────────────┤
│ Hardware Acceleration Backends │
│ ┌────────┐ ┌─────┐ ┌─────┐ ┌───────┐ ┌───────┐ ┌───────┐ │
│ │ NVENC │ │ AMF │ │ MFX │ │ VAAPI │ │ RKMPP │ │V4L2M2M│ │
│ └────────┘ └─────┘ └─────┘ └───────┘ └───────┘ └───────┘ │
└─────────────────────────────────────────────────────────────┘
2.2 模块职责
| 模块 | 职责 | 关键文件 |
|---|---|---|
ffmpeg_ram |
基于 RAM 的软件/硬件编解码 | src/ffmpeg_ram/ |
vram |
GPU 显存直接编解码 (Windows) | src/vram/ |
mux |
视频混流 (MP4/MKV) | src/mux.rs |
common |
公共定义和 GPU 检测 | src/common.rs |
ffmpeg |
FFmpeg 日志和初始化 | src/ffmpeg.rs |
3. 模块详细分析
3.1 库入口 (lib.rs)
// libs/hwcodec/src/lib.rs
pub mod common;
pub mod ffmpeg;
pub mod ffmpeg_ram;
pub mod mux;
#[cfg(all(windows, feature = "vram"))]
pub mod vram;
#[cfg(target_os = "android")]
pub mod android;
功能:
- 导出所有子模块
- 提供 C 日志回调函数
hwcodec_log - 条件编译:
vram模块仅在 Windows + vram feature 启用时编译
3.2 公共模块 (common.rs)
核心类型:
pub enum Driver {
NV, // NVIDIA
AMF, // AMD
MFX, // Intel
FFMPEG, // 软件编码
}
GPU 检测函数:
| 平台 | 检测函数 | 检测方式 |
|---|---|---|
| Linux | linux_support_nv() |
加载 CUDA/NVENC 动态库 |
| Linux | linux_support_amd() |
检查 libamfrt64.so.1 |
| Linux | linux_support_intel() |
检查 libvpl.so/libmfx.so |
| Linux | linux_support_rkmpp() |
检查 /dev/mpp_service |
| Linux | linux_support_v4l2m2m() |
检查 /dev/video* 设备 |
| macOS | get_video_toolbox_codec_support() |
调用 VideoToolbox API |
| Windows | 通过 VRAM 模块检测 | 查询 D3D11 设备 |
3.3 FFmpeg RAM 编码模块
3.3.1 Rust 层 (src/ffmpeg_ram/)
CodecInfo 结构体:
pub struct CodecInfo {
pub name: String, // 编码器名称如 "h264_nvenc"
pub mc_name: Option<String>, // MediaCodec 名称 (Android)
pub format: DataFormat, // H264/H265/VP8/VP9/AV1/MJPEG
pub priority: i32, // 优先级 (Best=0, Good=1, Normal=2, Soft=3, Bad=4)
pub hwdevice: AVHWDeviceType, // 硬件设备类型
}
EncodeContext 结构体:
pub struct EncodeContext {
pub name: String, // 编码器名称
pub width: i32, // 视频宽度
pub height: i32, // 视频高度
pub pixfmt: AVPixelFormat, // 像素格式 (NV12/YUV420P)
pub align: i32, // 内存对齐
pub fps: i32, // 帧率
pub gop: i32, // GOP 大小
pub rc: RateControl, // 码率控制模式
pub quality: Quality, // 质量级别
pub kbs: i32, // 目标码率 (kbps)
pub q: i32, // 量化参数
pub thread_count: i32, // 线程数
}
Encoder 类:
pub struct Encoder {
codec: *mut c_void, // C++ 编码器指针
frames: *mut Vec<EncodeFrame>, // 编码输出帧
pub ctx: EncodeContext,
pub linesize: Vec<i32>, // 行大小
pub offset: Vec<i32>, // 平面偏移
pub length: i32, // 总数据长度
}
核心方法:
| 方法 | 功能 |
|---|---|
Encoder::new() |
创建编码器实例 |
Encoder::encode() |
编码一帧 YUV 数据 |
Encoder::set_bitrate() |
动态调整码率 |
Encoder::request_keyframe() |
请求下一帧为关键帧 |
Encoder::available_encoders() |
检测系统可用编码器 |
3.3.2 C++ 层 (cpp/ffmpeg_ram/)
FFmpegRamEncoder 类 (ffmpeg_ram_encode.cpp:97-420):
class FFmpegRamEncoder {
AVCodecContext *c_ = NULL; // FFmpeg 编码上下文
AVFrame *frame_ = NULL; // 输入帧
AVPacket *pkt_ = NULL; // 编码输出包
AVBufferRef *hw_device_ctx_; // 硬件设备上下文
AVFrame *hw_frame_ = NULL; // 硬件帧
bool force_keyframe_ = false; // 强制关键帧标志
// 主要方法
bool init(int *linesize, int *offset, int *length);
int encode(const uint8_t *data, int length, const void *obj, uint64_t ms);
int do_encode(AVFrame *frame, const void *obj, int64_t ms);
int set_hwframe_ctx(); // 设置硬件帧上下文
};
编码流程:
输入 YUV 数据
│
▼
fill_frame() - 填充 AVFrame 数据指针
│
├──▶ (软件编码) 直接使用 frame_
│
└──▶ (硬件编码) av_hwframe_transfer_data() 传输到 GPU
│
▼
使用 hw_frame_
│
▼
avcodec_send_frame() - 发送帧到编码器
│
▼
avcodec_receive_packet() - 获取编码数据
│
▼
callback() - 回调输出
3.4 FFmpeg RAM 解码模块
Decoder 类:
pub struct Decoder {
codec: *mut c_void,
frames: *mut Vec<DecodeFrame>,
pub ctx: DecodeContext,
}
pub struct DecodeFrame {
pub pixfmt: AVPixelFormat,
pub width: i32,
pub height: i32,
pub data: Vec<Vec<u8>>, // Y, U, V 平面数据
pub linesize: Vec<i32>,
pub key: bool,
}
C++ 实现 (ffmpeg_ram_decode.cpp):
class FFmpegRamDecoder {
AVCodecContext *c_ = NULL;
AVBufferRef *hw_device_ctx_ = NULL;
AVFrame *sw_frame_ = NULL; // 软件帧 (用于硬件→软件转换)
AVFrame *frame_ = NULL; // 解码输出帧
AVPacket *pkt_ = NULL;
bool hwaccel_ = true;
int do_decode(const void *obj);
};
解码流程:
输入编码数据
│
▼
avcodec_send_packet() - 发送数据到解码器
│
▼
avcodec_receive_frame() - 获取解码帧
│
├──▶ (软件解码) 直接使用 frame_
│
└──▶ (硬件解码) av_hwframe_transfer_data()
│
▼
sw_frame_ (GPU → CPU)
│
▼
callback() - 回调输出
4. 硬件加速支持
4.1 支持的硬件加速后端
| 后端 | 厂商 | 平台 | 编码器名称 |
|---|---|---|---|
| NVENC | NVIDIA | Windows/Linux | h264_nvenc, hevc_nvenc |
| AMF | AMD | Windows/Linux | h264_amf, hevc_amf |
| QSV | Intel | Windows | h264_qsv, hevc_qsv |
| VAAPI | 通用 | Linux | h264_vaapi, hevc_vaapi, vp8_vaapi, vp9_vaapi |
| RKMPP | Rockchip | Linux | h264_rkmpp, hevc_rkmpp |
| V4L2 M2M | ARM SoC | Linux | h264_v4l2m2m, hevc_v4l2m2m |
| VideoToolbox | Apple | macOS/iOS | hevc_videotoolbox |
| MediaCodec | Android | h264_mediacodec, hevc_mediacodec |
4.2 硬件检测逻辑 (Linux)
// libs/hwcodec/cpp/common/platform/linux/linux.cpp
// NVIDIA 检测 - 加载 CUDA 和 NVENC 动态库
int linux_support_nv() {
CudaFunctions *cuda_dl = NULL;
NvencFunctions *nvenc_dl = NULL;
CuvidFunctions *cvdl = NULL;
load_driver(&cuda_dl, &nvenc_dl, &cvdl);
// 成功加载则返回 0
}
// AMD 检测 - 检查 AMF 运行时库
int linux_support_amd() {
void *handle = dlopen("libamfrt64.so.1", RTLD_LAZY);
// 成功加载则返回 0
}
// Intel 检测 - 检查 VPL/MFX 库
int linux_support_intel() {
const char *libs[] = {"libvpl.so", "libmfx.so", ...};
// 任一成功加载则返回 0
}
// Rockchip MPP 检测 - 检查设备节点
int linux_support_rkmpp() {
if (access("/dev/mpp_service", F_OK) == 0) return 0;
if (access("/dev/rga", F_OK) == 0) return 0;
return -1;
}
// V4L2 M2M 检测 - 检查视频设备
int linux_support_v4l2m2m() {
const char *devices[] = {"/dev/video10", "/dev/video11", ...};
// 任一设备可打开则返回 0
}
4.3 编码器优先级系统
pub enum Priority {
Best = 0, // 最高优先级 (硬件加速)
Good = 1, // 良好 (VAAPI, 部分硬件)
Normal = 2, // 普通
Soft = 3, // 软件编码
Bad = 4, // 最低优先级
}
优先级分配:
| 编码器 | 优先级 |
|---|---|
| h264_nvenc, hevc_nvenc | Best (0) |
| h264_amf, hevc_amf | Best (0) |
| h264_qsv, hevc_qsv | Best (0) |
| h264_rkmpp, hevc_rkmpp | Best (0) |
| h264_vaapi, hevc_vaapi | Good (1) |
| h264_v4l2m2m, hevc_v4l2m2m | Good (1) |
| h264 (x264), hevc (x265) | Soft (3) |
4.4 低延迟优化配置
// libs/hwcodec/cpp/common/util.cpp
bool set_lantency_free(void *priv_data, const std::string &name) {
// NVENC: 禁用延迟缓冲
if (name.find("nvenc") != std::string::npos) {
av_opt_set(priv_data, "delay", "0", 0);
}
// AMF: 设置查询超时
if (name.find("amf") != std::string::npos) {
av_opt_set(priv_data, "query_timeout", "1000", 0);
}
// QSV/VAAPI: 设置异步深度为 1
if (name.find("qsv") != std::string::npos ||
name.find("vaapi") != std::string::npos) {
av_opt_set(priv_data, "async_depth", "1", 0);
}
// VideoToolbox: 实时模式
if (name.find("videotoolbox") != std::string::npos) {
av_opt_set_int(priv_data, "realtime", 1, 0);
av_opt_set_int(priv_data, "prio_speed", 1, 0);
}
// libvpx: 实时模式
if (name.find("libvpx") != std::string::npos) {
av_opt_set(priv_data, "deadline", "realtime", 0);
av_opt_set_int(priv_data, "cpu-used", 6, 0);
av_opt_set_int(priv_data, "lag-in-frames", 0, 0);
}
return true;
}
5. 混流模块 (Mux)
5.1 功能概述
混流模块提供将编码后的视频流写入容器格式 (MP4/MKV) 的功能。
5.2 Rust API
// libs/hwcodec/src/mux.rs
pub struct MuxContext {
pub filename: String, // 输出文件名
pub width: usize, // 视频宽度
pub height: usize, // 视频高度
pub is265: bool, // 是否为 H.265
pub framerate: usize, // 帧率
}
pub struct Muxer {
inner: *mut c_void, // C++ Muxer 指针
pub ctx: MuxContext,
start: Instant, // 开始时间
}
impl Muxer {
pub fn new(ctx: MuxContext) -> Result<Self, ()>;
pub fn write_video(&mut self, data: &[u8], key: bool) -> Result<(), i32>;
pub fn write_tail(&mut self) -> Result<(), i32>;
}
5.3 C++ 实现
// libs/hwcodec/cpp/mux/mux.cpp
class Muxer {
OutputStream video_st; // 视频流
AVFormatContext *oc = NULL; // 格式上下文
int framerate;
int64_t start_ms; // 起始时间戳
int64_t last_pts; // 上一帧 PTS
int got_first; // 是否收到第一帧
bool init(const char *filename, int width, int height,
int is265, int framerate);
int write_video_frame(const uint8_t *data, int len,
int64_t pts_ms, int key);
};
写入流程:
write_video_frame()
│
├── 检查是否为关键帧 (第一帧必须是关键帧)
│
├── 计算 PTS (相对于 start_ms)
│
├── 填充 AVPacket
│
├── av_packet_rescale_ts() (ms → stream timebase)
│
└── av_write_frame() → 写入文件
6. 构建系统
6.1 Cargo.toml 配置
[package]
name = "hwcodec"
version = "0.7.1"
[features]
default = []
vram = [] # GPU VRAM 直接编解码 (Windows only)
[dependencies]
log = "0.4"
serde_derive = "1.0"
serde = "1.0"
serde_json = "1.0"
[build-dependencies]
cc = "1.0" # C++ 编译
bindgen = "0.59" # FFI 绑定生成
6.2 构建流程 (build.rs)
build.rs
│
├── build_common()
│ ├── 生成 common_ffi.rs (bindgen)
│ ├── 编译平台相关 C++ 代码
│ └── 链接系统库 (d3d11, dxgi, stdc++)
│
├── ffmpeg::build_ffmpeg()
│ ├── 生成 ffmpeg_ffi.rs
│ ├── 链接 FFmpeg 库 (VCPKG 或 pkg-config)
│ ├── build_ffmpeg_ram()
│ │ └── 编译 ffmpeg_ram_encode.cpp, ffmpeg_ram_decode.cpp
│ ├── build_ffmpeg_vram() [vram feature]
│ │ └── 编译 ffmpeg_vram_encode.cpp, ffmpeg_vram_decode.cpp
│ └── build_mux()
│ └── 编译 mux.cpp
│
└── sdk::build_sdk() [Windows + vram feature]
├── build_nv() - NVIDIA SDK
├── build_amf() - AMD AMF
└── build_mfx() - Intel MFX
6.3 FFmpeg 链接方式
| 方式 | 平台 | 条件 |
|---|---|---|
| VCPKG 静态链接 | 跨平台 | 设置 VCPKG_ROOT 环境变量 |
| pkg-config 动态链接 | Linux | 默认方式 |
7. 外部依赖
7.1 SDK 版本
| SDK | 版本 | 用途 |
|---|---|---|
| nv-codec-headers | n12.1.14.0 | NVIDIA 编码头文件 |
| Video_Codec_SDK | 12.1.14 | NVIDIA 编解码 SDK |
| AMF | v1.4.35 | AMD Advanced Media Framework |
| MediaSDK | 22.5.4 | Intel Media SDK |
7.2 FFmpeg 依赖库
libavcodec - 编解码核心
libavutil - 工具函数
libavformat - 容器格式
libswscale - 图像缩放转换
8. 总结
hwcodec 库通过 Rust/C++ 混合架构,在保证内存安全的同时实现了高性能的视频编解码。其核心设计特点包括:
- 统一的编解码器 API: 无论使用硬件还是软件编解码,上层 API 保持一致
- 自动硬件检测: 运行时自动检测并选择最优的硬件加速后端
- 优先级系统: 基于质量和性能为不同编码器分配优先级
- 低延迟优化: 针对实时流媒体场景进行了专门优化
- 跨平台支持: 覆盖主流操作系统和 GPU 厂商