From e7d8c93bff2d61ccf6c1c8a12ca8e3bab818071a Mon Sep 17 00:00:00 2001 From: mofeng Date: Tue, 20 Jan 2026 19:53:15 +0800 Subject: [PATCH 1/4] =?UTF-8?q?docs:=20=E6=96=B0=E6=98=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 305 ++++++++++++++++++++++++++++++++++++++++++-------- build/init.sh | 30 +++-- 2 files changed, 278 insertions(+), 57 deletions(-) diff --git a/README.md b/README.md index 2ff2c63f..54ad79dd 100644 --- a/README.md +++ b/README.md @@ -1,81 +1,294 @@ -# One-KVM +
+ One-KVM Logo +

One-KVM

+

Rust 编写的开放轻量 IP-KVM 解决方案,实现 BIOS 级远程管理

-

- 开放轻量的 IP-KVM 解决方案,实现 BIOS 级远程管理 -

+

简体中文

-

- 功能特性 • - 快速开始 -

+ [![GitHub stars](https://img.shields.io/github/stars/mofeng-git/One-KVM?style=social)](https://github.com/mofeng-git/One-KVM/stargazers) + [![GitHub forks](https://img.shields.io/github/forks/mofeng-git/One-KVM?style=social)](https://github.com/mofeng-git/One-KVM/network/members) + [![GitHub issues](https://img.shields.io/github/issues/mofeng-git/One-KVM)](https://github.com/mofeng-git/One-KVM/issues) + +

+ 📖 技术文档 • + ⚡ 快速开始 • + 📊 功能介绍 • + 🔁 迁移说明 +

+
--- -## 介绍 +## 📋 目录 -One-KVM 是一个用 Rust 编写的开放轻量的 IP-KVM(基于 IP 的键盘、视频、鼠标)解决方案,让你可以通过网络远程控制计算机,包括 BIOS 级别的操作。 +- [项目概述](#项目概述) +- [迁移说明](#迁移说明) +- [功能介绍](#功能介绍) +- [快速开始](#快速开始) +- [贡献与反馈](#贡献与反馈) +- [致谢](#致谢) +- [许可证](#许可证) -**当前软件处于开发早期阶段,各种功能和细节还有待完善,欢迎体验,但请勿应用于生产环境。** +## 📖 项目概述 -## 功能特性 +**One-KVM Rust** 是一个用 Rust 编写的轻量级 IP-KVM 解决方案,可通过网络远程管理服务器和工作站,实现 BIOS 级远程控制。 + +项目目标: + +- **开放**:不绑定特定硬件配置,尽量适配常见 Linux 设备 +- **轻量**:单二进制分发,部署过程更简单 +- **易用**:网页界面完成设备与参数配置,尽量减少手动改配置文件 + +> **注意:** One-KVM Rust 目前仍处于开发早期阶段,功能与细节会快速迭代,欢迎体验与反馈。 + +## 🔁 迁移说明 + +开发重心正在从 **One-KVM Python** 逐步转向 **One-KVM Rust**。 + +- 如果你在使用 **One-KVM Python(基于 PiKVM)**,请查看 [One-KVM Python 文档](https://docs.one-kvm.cn/python/) +- One-KVM Rust 相较于 One-KVM Python:**尚未适配 CSI HDMI 采集卡**、**不支持 VNC 访问**,仍处于开发早期阶段 + +## 📊 功能介绍 ### 核心功能 | 功能 | 说明 | |------|------| -| 视频采集 | HDMI USB 采集卡支持,提供 MJPEG/H264/H265/VP8/VP9 视频流 | -| 键鼠控制 | USB OTG HID 或 CH340 + CH39329 HID,支持绝对/相对鼠标模式 | -| 虚拟U盘 | USB Mass Storage,支持 ISO/IMG 镜像挂载和 Ventoy 虚拟U盘模式 | +| 视频采集 | HDMI USB 采集卡支持,提供 MJPEG / WebRTC(H.264/H.265/VP8/VP9) | +| 键鼠控制 | USB OTG HID 或 CH340 + CH9329 HID,支持绝对/相对鼠标模式 | +| 虚拟媒体 | USB Mass Storage,支持 ISO/IMG 镜像挂载和 Ventoy 虚拟U盘模式 | | ATX 电源控制 | GPIO 控制电源/重启按钮 | | 音频传输 | ALSA 采集 + Opus 编码(HTTP/WebRTC) | ### 硬件编码 支持自动检测和选择硬件加速: -- **VAAPI** - Intel/AMD GPU -- **RKMPP** - Rockchip SoC (**尚未实现**) -- **V4L2 M2M** - 通用硬件编码器 (**尚未实现**) -- **软件编码** - CPU 编码 -### 其他特性 +- **VAAPI**:Intel/AMD GPU +- **RKMPP**:Rockchip SoC +- **V4L2 M2M**:通用硬件编码器(尚未实现) +- **软件编码**:CPU 编码 -- 单二进制部署,依赖更轻量 -- Web UI 配置,无需编辑配置文件,多语言支持 (中文/英文) -- 内置 Web 终端 (ttyd),内网穿透支持 (gostc),P2P 组网支持 (EasyTier) +### 扩展能力 -## 快速开始 +- Web UI 配置,多语言支持(中文/英文) +- 内置 Web 终端(ttyd)内网穿透支持(gostc)、P2P 组网支持(EasyTier)、RustDesk 协议集成(用于跨平台远程访问能力扩展) -### Docker 运行 +## ⚡ 快速开始 + +安装方式:Docker / DEB 软件包 / 飞牛 NAS(FPK)。 + +### 方式一:Docker 安装(推荐) + +前提条件: + +- Linux 主机已安装 Docker +- 插好 USB HDMI 采集卡 +- 启用 USB OTG 或插好 CH340+CH9329 HID 线(用于 HID 模拟) + +启动容器: ```bash -docker run -d --privileged \ - --name one-kvm \ - -v /dev:/dev \ - -v /sys/kernel/config:/sys/kernel/config \ - --net=host \ - silentwind0/one-kvm +docker run --name one-kvm -itd --privileged=true \ + -v /dev:/dev -v /sys/:/sys \ + --net=host \ + silentwind0/one-kvm ``` -访问 http://IP:8080 +访问 Web 界面:`http://<设备IP>:8080`(首次访问会引导创建管理员账户)。默认端口:HTTP `8080`;启用 HTTPS 后为 `8443`。 -### 环境变量 +#### 常用环境变量(Docker) -| 变量 | 说明 | 默认值 | -|------|------|--------| -| `ENABLE_HTTPS` | 启用 HTTPS | `false` | -| `HTTP_PORT` | HTTP 端口 | `8080` | -| `VERBOSE` | 日志级别 (1/2/3) | - | +| 变量名 | 默认值 | 说明 | +|------|------|------| +| `ENABLE_HTTPS` | `false` | 是否启用 HTTPS(`true/false`) | +| `HTTP_PORT` | `8080` | HTTP 端口(`ENABLE_HTTPS=false` 时生效) | +| `HTTPS_PORT` | `8443` | HTTPS 端口(`ENABLE_HTTPS=true` 时生效) | +| `BIND_ADDRESS` | - | 监听地址(如 `0.0.0.0`) | +| `VERBOSE` | `0` | 日志详细程度:`1`(-v)、`2`(-vv)、`3`(-vvv) | +| `DATA_DIR` | `/etc/one-kvm` | 数据目录(等价于 `one-kvm -d `,优先级高于 `ONE_KVM_DATA_DIR`) | +> 说明:`--privileged=true` 和挂载 `/dev`、`/sys` 是硬件访问所需配置,当前版本不可省略。 +> +> 兼容性:同时支持旧变量名 `ONE_KVM_DATA_DIR`。 +> +> HTTPS:未提供证书时会自动生成默认自签名证书。 +> +> Ventoy:若修改 `DATA_DIR`,请确保 Ventoy 资源文件位于 `${DATA_DIR}/ventoy`(`boot.img`、`core.img`、`ventoy.disk.img`)。 -## 致谢 +### 方式二:DEB 软件包安装 -感谢以下项目: +前提条件: -- [PiKVM](https://github.com/pikvm/pikvm) - 原始 Python 版 IP-KVM -- [RustDesk](https://github.com/rustdesk/rustdesk) - hwcodec 硬件编码库 -- [ttyd](https://github.com/tsl0922/ttyd) - Web 终端 -- [EasyTier](https://github.com/EasyTier/EasyTier) - P2P 组网 +- Debian 11+ / Ubuntu 22+ +- 插好 USB HDMI 采集卡、HID 线(OTG 或 CH340+CH9329) -## 许可证 +安装步骤: -待定 +1. 从 GitHub Releases 下载适合架构的 `one-kvm_*.deb`:[Releases](https://github.com/mofeng-git/One-KVM/releases) +2. 安装: + +```bash +sudo apt update +sudo apt install ./one-kvm_*_*.deb +``` + +访问 Web 界面:`http://<设备IP>:8080`。 + +### 方式三:飞牛 NAS(FPK)安装 + +前提条件: + +- 飞牛 NAS 系统(目前仅支持 x86_64 架构) +- 插好 USB HDMI 采集卡、CH340+CH9329 HID 线 + +安装步骤: + +1. 从 GitHub Releases 下载 `*.fpk` 软件包:[Releases](https://github.com/mofeng-git/One-KVM/releases) +2. 在飞牛应用商店选择“手动安装”,导入 `*.fpk` + +访问 Web 界面:`http://<设备IP>:8420`。 + +## 报告问题 + +如果您发现了问题,请: +1. 使用 [GitHub Issues](https://github.com/mofeng-git/One-KVM/issues) 报告 +2. 提供详细的错误信息和复现步骤 +3. 包含您的硬件配置和系统信息 + +## 赞助支持 + +本项目基于多个优秀开源项目进行二次开发,作者投入了大量时间进行测试和维护。如果您觉得这个项目有价值,欢迎通过 **[为爱发电](https://afdian.com/a/silentwind)** 支持项目发展。 + +### 感谢名单 + +
+点击查看感谢名单 + +- 浩龙的电子嵌入式之路 + +- Tsuki + +- H_xiaoming + +- 0蓝蓝0 + +- fairybl + +- Will + +- 浩龙的电子嵌入式之路 + +- 自.知 + +- 观棋不语٩ ི۶ + +- 爱发电用户_a57a4 + +- 爱发电用户_2c769 + +- 霜序 + +- 远方(闲鱼用户名:小远技术店铺) + +- 爱发电用户_399fc + +- 斐斐の + +- 爱发电用户_09451 + +- 超高校级的錆鱼 + +- 爱发电用户_08cff + +- guoke + +- mgt + +- 姜沢掵 + +- ui_beam + +- 爱发电用户_c0dd7 + +- 爱发电用户_dnjK + +- 忍者胖猪 + +- 永遠の願い + +- 爱发电用户_GBrF + +- 爱发电用户_fd65c + +- 爱发电用户_vhNa + +- 爱发电用户_Xu6S + +- moss + +- woshididi + +- 爱发电用户_a0fd1 + +- 爱发电用户_f6bH + +- 码农 + +- 爱发电用户_6639f + +- jeron + +- 爱发电用户_CN7y + +- 爱发电用户_Up6w + +- 爱发电用户_e3202 + +- 一语念白 + +- 云边 + +- 爱发电用户_5a711 + +- 爱发电用户_9a706 + +- T0m9ir1SUKI + +- 爱发电用户_56d52 + +- 爱发电用户_3N6F + +- DUSK + +- 飘零 + +- . + +- 饭太稀 + +- 葱 + +- ...... + +
+ +### 赞助商 + +本项目得到以下赞助商的支持: + +**CDN 加速及安全防护:** +- **[Tencent EdgeOne](https://edgeone.ai/zh?from=github)** - 提供 CDN 加速及安全防护服务 + +![Tencent EdgeOne](https://edgeone.ai/media/34fe3a45-492d-4ea4-ae5d-ea1087ca7b4b.png) + +**文件存储服务:** +- **[Huang1111公益计划](https://pan.huang1111.cn/s/mxkx3T1)** - 提供免登录下载服务 + +**云服务商** + +- **[林枫云](https://www.dkdun.cn)** - 赞助了本项目宁波大带宽服务器 + +![林枫云](https://docs.one-kvm.cn/img/36076FEFF0898A80EBD5756D28F4076C.png) + +林枫云主营国内外地域的精品线路业务服务器、高主频游戏服务器和大带宽服务器。 \ No newline at end of file diff --git a/build/init.sh b/build/init.sh index 6929f8ae..70089554 100644 --- a/build/init.sh +++ b/build/init.sh @@ -4,36 +4,44 @@ set -e -# Start one-kvm with default options -# Additional options can be passed via environment variables -EXTRA_ARGS="-d /etc/one-kvm" +# Start one-kvm with default options. +# Additional options can be passed via environment variables. + +# Data directory (prefer DATA_DIR, keep ONE_KVM_DATA_DIR for backward compatibility) +DATA_DIR="${DATA_DIR:-${ONE_KVM_DATA_DIR:-/etc/one-kvm}}" +ARGS=(-d "$DATA_DIR") # Enable HTTPS if requested if [ "${ENABLE_HTTPS:-false}" = "true" ]; then - EXTRA_ARGS="$EXTRA_ARGS --enable-https" + ARGS+=(--enable-https) fi # Custom bind address if [ -n "$BIND_ADDRESS" ]; then - EXTRA_ARGS="$EXTRA_ARGS -a $BIND_ADDRESS" + ARGS+=(-a "$BIND_ADDRESS") fi # Custom port if [ -n "$HTTP_PORT" ]; then - EXTRA_ARGS="$EXTRA_ARGS -p $HTTP_PORT" + ARGS+=(-p "$HTTP_PORT") +fi + +# Custom HTTPS port +if [ -n "$HTTPS_PORT" ]; then + ARGS+=(--https-port "$HTTPS_PORT") fi # Verbosity level if [ -n "$VERBOSE" ]; then case "$VERBOSE" in - 1) EXTRA_ARGS="$EXTRA_ARGS -v" ;; - 2) EXTRA_ARGS="$EXTRA_ARGS -vv" ;; - 3) EXTRA_ARGS="$EXTRA_ARGS -vvv" ;; + 1) ARGS+=(-v) ;; + 2) ARGS+=(-vv) ;; + 3) ARGS+=(-vvv) ;; esac fi echo "[INFO] Starting one-kvm..." -echo "[INFO] Extra arguments: $EXTRA_ARGS" +echo "[INFO] Arguments: ${ARGS[*]}" # Execute one-kvm -exec /usr/bin/one-kvm $EXTRA_ARGS +exec /usr/bin/one-kvm "${ARGS[@]}" From 89072ad58de91009d0e802490d41a6025a76fb6a Mon Sep 17 00:00:00 2001 From: a15355447898a Date: Fri, 23 Jan 2026 17:11:19 +0800 Subject: [PATCH 2/4] =?UTF-8?q?=E6=94=AF=E6=8C=81v4l2=E7=BC=96=E7=A0=81,ar?= =?UTF-8?q?m=E6=9C=BA=E5=99=A8=E5=8E=9F=E7=94=9F=E6=9E=84=E5=BB=BA,docker?= =?UTF-8?q?=E9=95=9C=E5=83=8F=E6=8D=A2archlinux,=E5=85=81=E8=AE=B8?= =?UTF-8?q?=E5=88=9D=E5=A7=8B=E5=8C=96=E6=97=B6=E7=A6=81=E7=94=A8HID?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/Dockerfile.runtime | 31 ++++++------ build/build-images.sh | 18 ++++++- libs/hwcodec/build.rs | 7 +-- .../cpp/common/platform/linux/linux.cpp | 15 ++++-- libs/hwcodec/cpp/common/util.cpp | 16 +++++-- .../cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp | 4 ++ libs/hwcodec/src/ffmpeg_ram/encode.rs | 47 ++++++++++--------- web/src/views/SettingsView.vue | 1 + web/src/views/SetupView.vue | 18 +++++++ 9 files changed, 107 insertions(+), 50 deletions(-) diff --git a/build/Dockerfile.runtime b/build/Dockerfile.runtime index 44617adf..36a0e7ef 100644 --- a/build/Dockerfile.runtime +++ b/build/Dockerfile.runtime @@ -1,38 +1,37 @@ # One-KVM Runtime Image # This Dockerfile only packages pre-compiled binaries (no compilation) # Used after cross-compiling with `cross build` -# Using Debian 11 for maximum compatibility (GLIBC 2.31) +# Using Arch Linux base to match rolling glibc on build hosts. ARG TARGETPLATFORM=linux/amd64 -FROM debian:11-slim +FROM lsiobase/arch ARG TARGETPLATFORM # Install runtime dependencies in a single layer # All codec libraries (libx264, libx265, libopus) are now statically linked # Only hardware acceleration drivers and core system libraries remain dynamic -RUN apt-get update && \ - apt-get install -y --no-install-recommends \ - # Core runtime (all platforms) - no codec libs needed +RUN pacman -Syu --noconfirm --needed \ ca-certificates \ - libudev1 \ - libasound2 \ - # v4l2 is handled by kernel, minimal userspace needed - libv4l-0 \ + systemd-libs \ + alsa-lib \ + libv4l \ + libyuv \ + ffmpeg \ && \ # Platform-specific hardware acceleration if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ - apt-get install -y --no-install-recommends \ - libva2 libva-drm2 libva-x11-2 libx11-6 libxcb1 libxau6 libxdmcp6 libmfx1; \ + pacman -S --noconfirm --needed \ + libva libx11 libxcb libxau libxdmcp libmfx; \ elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ - apt-get install -y --no-install-recommends \ - libdrm2 libva2; \ + pacman -S --noconfirm --needed \ + libdrm libva; \ elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \ - apt-get install -y --no-install-recommends \ - libdrm2 libva2; \ + pacman -S --noconfirm --needed \ + libdrm libva; \ fi && \ - rm -rf /var/lib/apt/lists/* && \ + pacman -Scc --noconfirm && \ mkdir -p /etc/one-kvm/ventoy # Copy init script diff --git a/build/build-images.sh b/build/build-images.sh index 106a9b6e..a5bf06bb 100755 --- a/build/build-images.sh +++ b/build/build-images.sh @@ -19,8 +19,22 @@ ARCH_MAP=( build_arch() { local rust_target="$1" - echo "=== Building: $rust_target (via cross with custom Dockerfile) ===" - cross build --release --target "$rust_target" + # Build frontend first + if [ ! -d "$PROJECT_DIR/web/dist" ]; then + echo "=== Building Frontend ===" + cd "$PROJECT_DIR/web" && npm install && npm run build + cd "$PROJECT_DIR" + fi + + local host_arch=$(rustc -vV | grep host | cut -d ' ' -f 2) + + if [ "$rust_target" == "$host_arch" ]; then + echo "=== Building: $rust_target (NATIVE build, skipping cross) ===" + cargo build --release --target "$rust_target" + else + echo "=== Building: $rust_target (via cross) ===" + cross build --release --target "$rust_target" + fi } # Main diff --git a/libs/hwcodec/build.rs b/libs/hwcodec/build.rs index 791316eb..bdae4450 100644 --- a/libs/hwcodec/build.rs +++ b/libs/hwcodec/build.rs @@ -361,10 +361,11 @@ mod ffmpeg { // RKMPP decode only exists on ARM builds where FFmpeg is compiled with RKMPP support. // Avoid compiling this file on x86/x64 where `AV_HWDEVICE_TYPE_RKMPP` doesn't exist. + // Also check if RKMPP is available in the current FFmpeg environment to avoid compilation errors on non-Rockchip ARM (e.g. RPi). let target_arch = std::env::var("CARGO_CFG_TARGET_ARCH").unwrap_or_default(); - let enable_rkmpp = matches!(target_arch.as_str(), "aarch64" | "arm") - || std::env::var_os("CARGO_FEATURE_RKMPP").is_some(); - if enable_rkmpp { + let is_arm = matches!(target_arch.as_str(), "aarch64" | "arm"); + + if is_arm { builder.file(ffmpeg_ram_dir.join("ffmpeg_ram_decode.cpp")); } else { println!( diff --git a/libs/hwcodec/cpp/common/platform/linux/linux.cpp b/libs/hwcodec/cpp/common/platform/linux/linux.cpp index 2d60c9ce..c9036d20 100644 --- a/libs/hwcodec/cpp/common/platform/linux/linux.cpp +++ b/libs/hwcodec/cpp/common/platform/linux/linux.cpp @@ -107,10 +107,19 @@ int linux_support_rkmpp() { // Returns 0 if a M2M capable device is found, -1 otherwise int linux_support_v4l2m2m() { // Check common V4L2 M2M device paths used by various ARM SoCs + // /dev/video10 - Standard on many SoCs + // /dev/video11 - Standard on many SoCs (often decoder) + // /dev/video0 - Some platforms (like RPi) might use this + // /dev/video1 - Alternate RPi path + // /dev/video2 - Alternate path + // /dev/video32 - Some Allwinner/Rockchip legacy const char *m2m_devices[] = { - "/dev/video10", // Common M2M encoder device - "/dev/video11", // Common M2M decoder device - "/dev/video0", // Some SoCs use video0 for M2M + "/dev/video10", + "/dev/video11", + "/dev/video0", + "/dev/video1", + "/dev/video2", + "/dev/video32", }; for (size_t i = 0; i < sizeof(m2m_devices) / sizeof(m2m_devices[0]); i++) { diff --git a/libs/hwcodec/cpp/common/util.cpp b/libs/hwcodec/cpp/common/util.cpp index a65d5a7f..0418e337 100644 --- a/libs/hwcodec/cpp/common/util.cpp +++ b/libs/hwcodec/cpp/common/util.cpp @@ -10,11 +10,19 @@ extern "C" { #include "common.h" -#include "common.h" - #define LOG_MODULE "UTIL" #include "log.h" +#ifndef FF_PROFILE_H264_BASELINE +#define FF_PROFILE_H264_BASELINE 66 +#endif +#ifndef FF_PROFILE_H264_HIGH +#define FF_PROFILE_H264_HIGH 100 +#endif +#ifndef FF_PROFILE_HEVC_MAIN +#define FF_PROFILE_HEVC_MAIN 1 +#endif + namespace { // Helper function: check if encoder is software H264 (libx264) @@ -147,11 +155,11 @@ bool set_lantency_free(void *priv_data, const std::string &name) { // V4L2 M2M hardware encoder - minimize buffer latency if (name.find("v4l2m2m") != std::string::npos) { // Minimize number of output buffers for lower latency - if ((ret = av_opt_set_int(priv_data, "num_output_buffers", 2, 0)) < 0) { + if ((ret = av_opt_set_int(priv_data, "num_output_buffers", 4, 0)) < 0) { LOG_WARN(std::string("v4l2m2m set num_output_buffers failed, ret = ") + av_err2str(ret)); // Not fatal } - if ((ret = av_opt_set_int(priv_data, "num_capture_buffers", 2, 0)) < 0) { + if ((ret = av_opt_set_int(priv_data, "num_capture_buffers", 4, 0)) < 0) { LOG_WARN(std::string("v4l2m2m set num_capture_buffers failed, ret = ") + av_err2str(ret)); // Not fatal } diff --git a/libs/hwcodec/cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp b/libs/hwcodec/cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp index 52a6e2a6..b4387686 100644 --- a/libs/hwcodec/cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp +++ b/libs/hwcodec/cpp/ffmpeg_ram/ffmpeg_ram_decode.cpp @@ -55,7 +55,11 @@ public: callback_ = callback; if (name_.find("rkmpp") != std::string::npos) { +#ifdef AV_HWDEVICE_TYPE_RKMPP hw_device_type_ = AV_HWDEVICE_TYPE_RKMPP; +#else + set_last_error("RKMPP support not compiled in FFmpeg"); +#endif } } diff --git a/libs/hwcodec/src/ffmpeg_ram/encode.rs b/libs/hwcodec/src/ffmpeg_ram/encode.rs index dff0a135..17c34442 100644 --- a/libs/hwcodec/src/ffmpeg_ram/encode.rs +++ b/libs/hwcodec/src/ffmpeg_ram/encode.rs @@ -353,40 +353,43 @@ impl Encoder { let mut passed = false; let mut last_err: Option = None; - let max_attempts = 1; + let max_attempts = if codec.name.contains("v4l2m2m") { + 5 + } else { + 1 + }; for attempt in 0..max_attempts { + encoder.request_keyframe(); let pts = (attempt as i64) * 33; // 33ms is an approximation for 30 FPS (1000 / 30) let start = std::time::Instant::now(); match encoder.encode(&yuv, pts) { Ok(frames) => { let elapsed = start.elapsed().as_millis(); - if frames.len() == 1 { - if frames[0].key == 1 && elapsed < TEST_TIMEOUT_MS as _ { - debug!( - "Encoder {} test passed on attempt {}", - codec.name, - attempt + 1 - ); - res.push(codec.clone()); - passed = true; - break; - } else { - debug!( - "Encoder {} test failed on attempt {} - key: {}, timeout: {}ms", - codec.name, - attempt + 1, - frames[0].key, - elapsed - ); - } - } else { + if frames.len() >= 1 && elapsed < TEST_TIMEOUT_MS as _ { debug!( - "Encoder {} test failed on attempt {} - wrong frame count: {}", + "Encoder {} test passed on attempt {} (frames: {})", codec.name, attempt + 1, frames.len() ); + res.push(codec.clone()); + passed = true; + break; + } else if frames.is_empty() { + debug!( + "Encoder {} test produced no output on attempt {}", + codec.name, + attempt + 1 + ); + } else { + debug!( + "Encoder {} test failed on attempt {} - frames: {}, timeout: {}ms", + codec.name, + attempt + 1, + frames.len(), + elapsed + ); } } Err(err) => { diff --git a/web/src/views/SettingsView.vue b/web/src/views/SettingsView.vue index 98e6fa40..7fca4b7f 100644 --- a/web/src/views/SettingsView.vue +++ b/web/src/views/SettingsView.vue @@ -1323,6 +1323,7 @@ onMounted(async () => {
diff --git a/web/src/views/SetupView.vue b/web/src/views/SetupView.vue index 90df3085..c177a3a7 100644 --- a/web/src/views/SetupView.vue +++ b/web/src/views/SetupView.vue @@ -319,6 +319,10 @@ watch(hidBackend, (newBackend) => { if (newBackend === 'otg' && !otgUdc.value && devices.value.udc.length > 0) { otgUdc.value = devices.value.udc[0]?.name || '' } + if (newBackend === 'none') { + ch9329Port.value = '' + otgUdc.value = '' + } }) onMounted(async () => { @@ -341,6 +345,11 @@ onMounted(async () => { otgUdc.value = result.udc[0].name } + // If no HID devices exist, default to disabled to avoid blocking setup + if (result.serial.length === 0 && result.udc.length === 0) { + hidBackend.value = 'none' + } + // Auto-select audio device if available (and no video device to trigger watch) if (result.audio.length > 0 && !audioDevice.value) { // Prefer HDMI audio device @@ -357,6 +366,10 @@ onMounted(async () => { // Use defaults } + if (devices.value.serial.length === 0 && devices.value.udc.length === 0) { + hidBackend.value = 'none' + } + // Load encoder backends try { const codecsResult = await streamApi.getCodecs() @@ -864,6 +877,7 @@ const stepIcons = [User, Video, Keyboard, Puzzle] CH9329 ({{ t('setup.serialHid') }}) USB OTG + {{ t('setup.disableHid') }}
@@ -931,6 +945,10 @@ const stepIcons = [User, Video, Keyboard, Puzzle]

+ +

+ {{ t('setup.hidDisabledHint') }} +

From d78c6ed0472c7a1f23fae919dd9a44d0209c6fca Mon Sep 17 00:00:00 2001 From: a15355447898a Date: Fri, 23 Jan 2026 21:20:48 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E5=9B=9E=E6=BB=9Adocker=E6=9E=84=E5=BB=BA?= =?UTF-8?q?=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- build/Dockerfile.runtime | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/build/Dockerfile.runtime b/build/Dockerfile.runtime index 36a0e7ef..44617adf 100644 --- a/build/Dockerfile.runtime +++ b/build/Dockerfile.runtime @@ -1,37 +1,38 @@ # One-KVM Runtime Image # This Dockerfile only packages pre-compiled binaries (no compilation) # Used after cross-compiling with `cross build` -# Using Arch Linux base to match rolling glibc on build hosts. +# Using Debian 11 for maximum compatibility (GLIBC 2.31) ARG TARGETPLATFORM=linux/amd64 -FROM lsiobase/arch +FROM debian:11-slim ARG TARGETPLATFORM # Install runtime dependencies in a single layer # All codec libraries (libx264, libx265, libopus) are now statically linked # Only hardware acceleration drivers and core system libraries remain dynamic -RUN pacman -Syu --noconfirm --needed \ +RUN apt-get update && \ + apt-get install -y --no-install-recommends \ + # Core runtime (all platforms) - no codec libs needed ca-certificates \ - systemd-libs \ - alsa-lib \ - libv4l \ - libyuv \ - ffmpeg \ + libudev1 \ + libasound2 \ + # v4l2 is handled by kernel, minimal userspace needed + libv4l-0 \ && \ # Platform-specific hardware acceleration if [ "$TARGETPLATFORM" = "linux/amd64" ]; then \ - pacman -S --noconfirm --needed \ - libva libx11 libxcb libxau libxdmcp libmfx; \ + apt-get install -y --no-install-recommends \ + libva2 libva-drm2 libva-x11-2 libx11-6 libxcb1 libxau6 libxdmcp6 libmfx1; \ elif [ "$TARGETPLATFORM" = "linux/arm64" ]; then \ - pacman -S --noconfirm --needed \ - libdrm libva; \ + apt-get install -y --no-install-recommends \ + libdrm2 libva2; \ elif [ "$TARGETPLATFORM" = "linux/arm/v7" ]; then \ - pacman -S --noconfirm --needed \ - libdrm libva; \ + apt-get install -y --no-install-recommends \ + libdrm2 libva2; \ fi && \ - pacman -Scc --noconfirm && \ + rm -rf /var/lib/apt/lists/* && \ mkdir -p /etc/one-kvm/ventoy # Copy init script From 176e71c79e2d42655b9ce85f14b089184a962eb7 Mon Sep 17 00:00:00 2001 From: ayaya <62456287+a15355447898a@users.noreply.github.com> Date: Fri, 23 Jan 2026 21:24:22 +0800 Subject: [PATCH 4/4] =?UTF-8?q?=E4=BF=AE=E6=94=B9readme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 54ad79dd..8ead0e9c 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ - **VAAPI**:Intel/AMD GPU - **RKMPP**:Rockchip SoC -- **V4L2 M2M**:通用硬件编码器(尚未实现) +- **V4L2 M2M**:RaspberryPi - **软件编码**:CPU 编码 ### 扩展能力 @@ -291,4 +291,4 @@ sudo apt install ./one-kvm_*_*.deb ![林枫云](https://docs.one-kvm.cn/img/36076FEFF0898A80EBD5756D28F4076C.png) -林枫云主营国内外地域的精品线路业务服务器、高主频游戏服务器和大带宽服务器。 \ No newline at end of file +林枫云主营国内外地域的精品线路业务服务器、高主频游戏服务器和大带宽服务器。