mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-03-15 23:46:51 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8b17a0c48b | ||
|
|
e75f0500e2 |
@@ -1,6 +1,6 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "one-kvm"
|
name = "one-kvm"
|
||||||
version = "0.1.3"
|
version = "0.1.4"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
authors = ["SilentWind"]
|
authors = ["SilentWind"]
|
||||||
description = "A open and lightweight IP-KVM solution written in Rust"
|
description = "A open and lightweight IP-KVM solution written in Rust"
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
#include "linux.h"
|
#include "linux.h"
|
||||||
#include "../../log.h"
|
#include "../../log.h"
|
||||||
|
#include <algorithm>
|
||||||
|
#include <cctype>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <fstream>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
// Check for NVIDIA driver support by loading CUDA libraries
|
// Check for NVIDIA driver support by loading CUDA libraries
|
||||||
int linux_support_nv()
|
int linux_support_nv()
|
||||||
@@ -106,6 +110,57 @@ int linux_support_rkmpp() {
|
|||||||
// Check for V4L2 Memory-to-Memory (M2M) codec support
|
// Check for V4L2 Memory-to-Memory (M2M) codec support
|
||||||
// Returns 0 if a M2M capable device is found, -1 otherwise
|
// Returns 0 if a M2M capable device is found, -1 otherwise
|
||||||
int linux_support_v4l2m2m() {
|
int linux_support_v4l2m2m() {
|
||||||
|
auto to_lower = [](std::string value) {
|
||||||
|
std::transform(value.begin(), value.end(), value.begin(), [](unsigned char c) {
|
||||||
|
return static_cast<char>(std::tolower(c));
|
||||||
|
});
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto read_text_file = [](const char *path, std::string *out) -> bool {
|
||||||
|
std::ifstream file(path);
|
||||||
|
if (!file.is_open()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
std::getline(file, *out);
|
||||||
|
return !out->empty();
|
||||||
|
};
|
||||||
|
|
||||||
|
auto allow_video0_probe = []() -> bool {
|
||||||
|
const char *env = std::getenv("ONE_KVM_V4L2M2M_ALLOW_VIDEO0");
|
||||||
|
if (env == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (env[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return std::strcmp(env, "0") != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto is_amlogic_vdec = [&]() -> bool {
|
||||||
|
std::string name;
|
||||||
|
std::string modalias;
|
||||||
|
if (read_text_file("/sys/class/video4linux/video0/name", &name)) {
|
||||||
|
const std::string lowered = to_lower(name);
|
||||||
|
if (lowered.find("meson") != std::string::npos ||
|
||||||
|
lowered.find("vdec") != std::string::npos ||
|
||||||
|
lowered.find("decoder") != std::string::npos ||
|
||||||
|
lowered.find("video-decoder") != std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (read_text_file("/sys/class/video4linux/video0/device/modalias", &modalias)) {
|
||||||
|
const std::string lowered = to_lower(modalias);
|
||||||
|
if (lowered.find("amlogic") != std::string::npos ||
|
||||||
|
lowered.find("meson") != std::string::npos ||
|
||||||
|
lowered.find("gxl-vdec") != std::string::npos ||
|
||||||
|
lowered.find("gx-vdec") != std::string::npos) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
// Check common V4L2 M2M device paths used by various ARM SoCs
|
// Check common V4L2 M2M device paths used by various ARM SoCs
|
||||||
const char *m2m_devices[] = {
|
const char *m2m_devices[] = {
|
||||||
"/dev/video10", // Common M2M encoder device
|
"/dev/video10", // Common M2M encoder device
|
||||||
@@ -115,6 +170,13 @@ int linux_support_v4l2m2m() {
|
|||||||
|
|
||||||
for (size_t i = 0; i < sizeof(m2m_devices) / sizeof(m2m_devices[0]); i++) {
|
for (size_t i = 0; i < sizeof(m2m_devices) / sizeof(m2m_devices[0]); i++) {
|
||||||
if (access(m2m_devices[i], F_OK) == 0) {
|
if (access(m2m_devices[i], F_OK) == 0) {
|
||||||
|
if (std::strcmp(m2m_devices[i], "/dev/video0") == 0) {
|
||||||
|
if (!allow_video0_probe() && is_amlogic_vdec()) {
|
||||||
|
LOG_TRACE(std::string("V4L2 M2M: Skipping /dev/video0 (Amlogic vdec)"));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Device exists, check if it's an M2M device by trying to open it
|
// Device exists, check if it's an M2M device by trying to open it
|
||||||
int fd = open(m2m_devices[i], O_RDWR | O_NONBLOCK);
|
int fd = open(m2m_devices[i], O_RDWR | O_NONBLOCK);
|
||||||
if (fd >= 0) {
|
if (fd >= 0) {
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
use tracing::{debug, info};
|
use tracing::{debug, info, warn};
|
||||||
|
|
||||||
use hwcodec::common::{DataFormat, Quality, RateControl};
|
use hwcodec::common::{DataFormat, Quality, RateControl};
|
||||||
use hwcodec::ffmpeg::AVPixelFormat;
|
use hwcodec::ffmpeg::AVPixelFormat;
|
||||||
@@ -255,8 +255,33 @@ impl EncoderRegistry {
|
|||||||
thread_count: 1,
|
thread_count: 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Get all available encoders from hwcodec
|
const DETECT_TIMEOUT_MS: u64 = 5000;
|
||||||
let all_encoders = HwEncoder::available_encoders(ctx, None);
|
|
||||||
|
// Get all available encoders from hwcodec with a hard timeout
|
||||||
|
let all_encoders = {
|
||||||
|
use std::sync::mpsc;
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
|
info!("Encoder detection timeout: {}ms", DETECT_TIMEOUT_MS);
|
||||||
|
|
||||||
|
let (tx, rx) = mpsc::channel();
|
||||||
|
let ctx_clone = ctx.clone();
|
||||||
|
std::thread::spawn(move || {
|
||||||
|
let result = HwEncoder::available_encoders(ctx_clone, None);
|
||||||
|
let _ = tx.send(result);
|
||||||
|
});
|
||||||
|
|
||||||
|
match rx.recv_timeout(Duration::from_millis(DETECT_TIMEOUT_MS)) {
|
||||||
|
Ok(encoders) => encoders,
|
||||||
|
Err(_) => {
|
||||||
|
warn!(
|
||||||
|
"Encoder detection timed out after {}ms, skipping hardware detection",
|
||||||
|
DETECT_TIMEOUT_MS
|
||||||
|
);
|
||||||
|
Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
info!("Found {} encoders from hwcodec", all_encoders.len());
|
info!("Found {} encoders from hwcodec", all_encoders.len());
|
||||||
|
|
||||||
|
|||||||
4
web/package-lock.json
generated
4
web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@vueuse/core": "^14.1.0",
|
"@vueuse/core": "^14.1.0",
|
||||||
"class-variance-authority": "^0.7.1",
|
"class-variance-authority": "^0.7.1",
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "web",
|
"name": "web",
|
||||||
"private": true,
|
"private": true,
|
||||||
"version": "0.1.3",
|
"version": "0.1.4",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
|
|||||||
Reference in New Issue
Block a user