mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-03-16 07:56:38 +08:00
feat: 支持树莓派 v4l2m2m 编码器探测
This commit is contained in:
@@ -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 {}",
|
||||
|
||||
Reference in New Issue
Block a user