mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-03-15 07:26:44 +08:00
feat: 支持树莓派 v4l2m2m 编码器探测
This commit is contained in:
@@ -28,7 +28,8 @@ serde_json = "1"
|
||||
|
||||
# Logging
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "json"] }
|
||||
tracing-subscriber = { version = "0.3", features = ["env-filter", "json", "tracing-log"] }
|
||||
tracing-log = "0.2"
|
||||
|
||||
# Error handling
|
||||
thiserror = "2"
|
||||
|
||||
@@ -162,10 +162,19 @@ 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++) {
|
||||
|
||||
@@ -147,11 +147,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
|
||||
}
|
||||
@@ -500,4 +500,4 @@ bool has_flag_could_not_find_ref_with_poc() {
|
||||
|
||||
extern "C" void hwcodec_set_flag_could_not_find_ref_with_poc() {
|
||||
util_decode::g_flag_could_not_find_ref_with_poc = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
include!(concat!(env!("OUT_DIR"), "/ffmpeg_ffi.rs"));
|
||||
|
||||
use serde_derive::{Deserialize, Serialize};
|
||||
use std::env;
|
||||
|
||||
#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize, Deserialize)]
|
||||
pub enum AVHWDeviceType {
|
||||
@@ -53,7 +54,36 @@ pub extern "C" fn hwcodec_av_log_callback(level: i32, message: *const std::os::r
|
||||
pub(crate) fn init_av_log() {
|
||||
static INIT: std::sync::Once = std::sync::Once::new();
|
||||
INIT.call_once(|| unsafe {
|
||||
av_log_set_level(AV_LOG_ERROR as i32);
|
||||
av_log_set_level(parse_ffmpeg_log_level());
|
||||
hwcodec_set_av_log_callback();
|
||||
});
|
||||
}
|
||||
|
||||
fn parse_ffmpeg_log_level() -> i32 {
|
||||
let raw = match env::var("ONE_KVM_FFMPEG_LOG") {
|
||||
Ok(value) => value,
|
||||
Err(_) => return AV_LOG_ERROR as i32,
|
||||
};
|
||||
|
||||
let value = raw.trim().to_ascii_lowercase();
|
||||
if value.is_empty() {
|
||||
return AV_LOG_ERROR as i32;
|
||||
}
|
||||
|
||||
if let Ok(level) = value.parse::<i32>() {
|
||||
return level;
|
||||
}
|
||||
|
||||
match value.as_str() {
|
||||
"quiet" => AV_LOG_QUIET as i32,
|
||||
"panic" => AV_LOG_PANIC as i32,
|
||||
"fatal" => AV_LOG_FATAL as i32,
|
||||
"error" => AV_LOG_ERROR as i32,
|
||||
"warn" | "warning" => AV_LOG_WARNING as i32,
|
||||
"info" => AV_LOG_INFO as i32,
|
||||
"verbose" => AV_LOG_VERBOSE as i32,
|
||||
"debug" => AV_LOG_DEBUG as i32,
|
||||
"trace" => AV_LOG_TRACE as i32,
|
||||
_ => AV_LOG_ERROR as i32,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -352,16 +352,46 @@ impl Encoder {
|
||||
debug!("Encoder {} created successfully", codec.name);
|
||||
let mut passed = false;
|
||||
let mut last_err: Option<i32> = None;
|
||||
let is_v4l2m2m = codec.name.contains("v4l2m2m");
|
||||
|
||||
let max_attempts = 1;
|
||||
let max_attempts = if is_v4l2m2m { 5 } else { 1 };
|
||||
for attempt in 0..max_attempts {
|
||||
if is_v4l2m2m {
|
||||
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 is_v4l2m2m {
|
||||
if !frames.is_empty() && elapsed < TEST_TIMEOUT_MS as _ {
|
||||
debug!(
|
||||
"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
|
||||
);
|
||||
}
|
||||
} else if frames.len() == 1 {
|
||||
if frames[0].key == 1 && elapsed < TEST_TIMEOUT_MS as _ {
|
||||
debug!(
|
||||
"Encoder {} test passed on attempt {}",
|
||||
|
||||
@@ -712,10 +712,13 @@ fn init_logging(level: LogLevel, verbose_count: u8) {
|
||||
let env_filter =
|
||||
tracing_subscriber::EnvFilter::try_from_default_env().unwrap_or_else(|_| filter.into());
|
||||
|
||||
tracing_subscriber::registry()
|
||||
if let Err(err) = tracing_subscriber::registry()
|
||||
.with(env_filter)
|
||||
.with(tracing_subscriber::fmt::layer())
|
||||
.init();
|
||||
.try_init()
|
||||
{
|
||||
eprintln!("failed to initialize tracing: {}", err);
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the application data directory
|
||||
|
||||
Reference in New Issue
Block a user