fix: 树莓派gstreamer pipeline报错
This commit is contained in:
parent
ddac14fb3f
commit
8733afc987
@ -128,9 +128,9 @@ fn create_demo_config() -> Config {
|
||||
|
||||
// 根据操作系统和设备类型自动选择合适的设备路径
|
||||
let device = if is_raspberry_pi {
|
||||
// 使用特定的GStreamer pipeline字符串在树莓派上适配摄像头
|
||||
// 这个pipeline使用v4l2src作为源,并确保正确初始化
|
||||
"v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=30/1 ! videoconvert ! appsink".to_string()
|
||||
// 使用更简单的GStreamer pipeline,尝试不同配置方式和格式
|
||||
// 此pipeline尝试放宽限制,避免严格的格式约束
|
||||
"v4l2src ! videoconvert ! appsink".to_string()
|
||||
} else if std::env::consts::OS == "linux" {
|
||||
"/dev/video0".to_string()
|
||||
} else if std::env::consts::OS == "macos" {
|
||||
|
||||
@ -111,17 +111,10 @@ impl CameraController {
|
||||
// 在树莓派上但没有使用GStreamer pipeline,尝试使用pipeline重新初始化
|
||||
warn!("Running on Raspberry Pi without GStreamer pipeline. Attempting to reinitialize with GStreamer...");
|
||||
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
||||
.unwrap_or("0");
|
||||
// 创建更简单的GStreamer pipeline
|
||||
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, self.settings.resolution.dimensions().0,
|
||||
self.settings.resolution.dimensions().1, self.settings.fps
|
||||
);
|
||||
|
||||
info!("Trying GStreamer pipeline: {}", pipeline);
|
||||
info!("Trying simple GStreamer pipeline: {}", pipeline);
|
||||
self.settings.device = pipeline;
|
||||
|
||||
// 使用 Box::pin 来解决递归 async 调用问题
|
||||
@ -189,17 +182,10 @@ impl CameraController {
|
||||
// 关闭当前相机
|
||||
self.camera = None;
|
||||
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
||||
.unwrap_or("0");
|
||||
// 创建更简单的GStreamer pipeline
|
||||
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, self.settings.resolution.dimensions().0,
|
||||
self.settings.resolution.dimensions().1, self.settings.fps
|
||||
);
|
||||
|
||||
info!("Trying GStreamer pipeline: {}", pipeline);
|
||||
info!("Trying simple GStreamer pipeline: {}", pipeline);
|
||||
self.settings.device = pipeline;
|
||||
|
||||
// 重新初始化相机
|
||||
@ -299,15 +285,10 @@ impl CameraController {
|
||||
let use_gstreamer = is_raspberry_pi && !device.contains("!");
|
||||
|
||||
if use_gstreamer {
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = device.strip_prefix("/dev/video").unwrap_or("0");
|
||||
// 创建更简单的GStreamer pipeline
|
||||
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, 1280, 720, fps
|
||||
);
|
||||
|
||||
error!("Raspberry Pi detected - trying GStreamer pipeline: {}", pipeline);
|
||||
error!("Raspberry Pi detected - trying simple GStreamer pipeline: {}", pipeline);
|
||||
|
||||
// 尝试使用GStreamer打开摄像头
|
||||
match OpenCVCamera::open(&pipeline) {
|
||||
|
||||
@ -54,29 +54,115 @@ impl OpenCVCamera {
|
||||
fn create_capture_from_path(path_str: &str) -> Result<videoio::VideoCapture> {
|
||||
info!("Attempting to open camera with path/pipeline: {}", path_str);
|
||||
|
||||
// 检测是否为树莓派,以提供更多调试信息
|
||||
let is_raspberry_pi = std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_raspberry_pi {
|
||||
info!("Raspberry Pi detected, will try multiple approaches to open camera");
|
||||
|
||||
// 尝试列出可用的视频设备
|
||||
match std::process::Command::new("v4l2-ctl").arg("--list-devices").output() {
|
||||
Ok(output) => {
|
||||
let devices = String::from_utf8_lossy(&output.stdout);
|
||||
info!("Available video devices:\n{}", devices);
|
||||
},
|
||||
Err(e) => warn!("Could not list video devices: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
// 检测是否为GStreamer pipeline (通常包含感叹号)
|
||||
if path_str.contains("!") {
|
||||
info!("Detected GStreamer pipeline, using from_file with GSTREAMER backend");
|
||||
// 如果是GStreamer pipeline,直接使用from_file方法并指定GSTREAMER后端
|
||||
// 如果是GStreamer pipeline,尝试几种不同的方法
|
||||
|
||||
// 先尝试使用一个非常基本的pipeline
|
||||
let simple_pipeline = "videotestsrc ! videoconvert ! appsink";
|
||||
info!("First trying a very basic test pipeline to check GStreamer: {}", simple_pipeline);
|
||||
|
||||
match videoio::VideoCapture::from_file(simple_pipeline, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened().unwrap_or(false) {
|
||||
info!("Basic GStreamer test pipeline works! Now trying the real pipeline");
|
||||
} else {
|
||||
warn!("Basic GStreamer test pipeline opened but not ready - GStreamer may not be working properly");
|
||||
}
|
||||
},
|
||||
Err(e) => warn!("Basic GStreamer test failed: {} - GStreamer may not be available", e)
|
||||
}
|
||||
|
||||
// 尝试使用原始的pipeline
|
||||
match videoio::VideoCapture::from_file(path_str, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened()? {
|
||||
if cap.is_opened().unwrap_or(false) {
|
||||
info!("Successfully opened GStreamer pipeline");
|
||||
return Ok(cap);
|
||||
} else {
|
||||
warn!("GStreamer pipeline opened but not ready, will try alternative methods");
|
||||
warn!("GStreamer pipeline opened but not ready");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Failed to open with GStreamer: {}. Will try alternative methods.", e);
|
||||
}
|
||||
}
|
||||
|
||||
// 如果在树莓派上,尝试不同格式的pipeline
|
||||
if is_raspberry_pi {
|
||||
let alternate_pipelines = [
|
||||
"v4l2src ! video/x-raw,format=YUY2 ! videoconvert ! appsink",
|
||||
"v4l2src ! video/x-raw,format=BGR ! videoconvert ! appsink",
|
||||
"v4l2src device=/dev/video0 ! videoconvert ! appsink",
|
||||
"v4l2src device=/dev/video0 ! video/x-raw,format=YUY2 ! videoconvert ! appsink"
|
||||
];
|
||||
|
||||
for pipeline in alternate_pipelines.iter() {
|
||||
info!("Trying alternate pipeline: {}", pipeline);
|
||||
match videoio::VideoCapture::from_file(pipeline, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened().unwrap_or(false) {
|
||||
info!("Success with alternate pipeline: {}", pipeline);
|
||||
return Ok(cap);
|
||||
}
|
||||
},
|
||||
Err(e) => warn!("Failed with alternate pipeline: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse as integer index first
|
||||
if let Ok(device_index) = path_str.parse::<i32>() {
|
||||
info!("Opening camera by index: {}", device_index);
|
||||
return Ok(videoio::VideoCapture::new(device_index, videoio::CAP_ANY)?);
|
||||
|
||||
// 在树莓派上,先尝试v4l2直接打开以获取更多诊断信息
|
||||
if is_raspberry_pi {
|
||||
// 检查设备是否实际存在
|
||||
if std::path::Path::new(&format!("/dev/video{}", device_index)).exists() {
|
||||
info!("Device /dev/video{} exists", device_index);
|
||||
} else {
|
||||
warn!("Device /dev/video{} does not exist!", device_index);
|
||||
}
|
||||
|
||||
// 尝试v4l2-ctl获取设备信息
|
||||
match std::process::Command::new("v4l2-ctl")
|
||||
.args(&["-d", &format!("/dev/video{}", device_index), "-D"])
|
||||
.output()
|
||||
{
|
||||
Ok(output) => {
|
||||
let info = String::from_utf8_lossy(&output.stdout);
|
||||
info!("Device info for /dev/video{}:\n{}", device_index, info);
|
||||
},
|
||||
Err(e) => warn!("Could not get device info: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
let cap = videoio::VideoCapture::new(device_index, videoio::CAP_ANY)?;
|
||||
if cap.is_opened()? {
|
||||
return Ok(cap);
|
||||
} else {
|
||||
warn!("Device index {} opened but not ready", device_index);
|
||||
}
|
||||
}
|
||||
|
||||
// Handle platform-specific device paths
|
||||
@ -129,33 +215,7 @@ impl OpenCVCamera {
|
||||
}
|
||||
}
|
||||
|
||||
// 对于树莓派,可能需要指定GSTREAMER后端
|
||||
if std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// 尝试使用带有GSTREAMER后端的方式打开
|
||||
let gst_pipeline = if path_str.starts_with("/dev/video") {
|
||||
// 如果是设备路径,转换为gstreamer pipeline
|
||||
let num_str = path_str.strip_prefix("/dev/video").unwrap_or("0");
|
||||
format!("v4l2src device={} ! video/x-raw,width=1280,height=720 ! videoconvert ! appsink", path_str)
|
||||
} else {
|
||||
path_str.to_string()
|
||||
};
|
||||
|
||||
info!("Trying to open with GStreamer on Raspberry Pi: {}", gst_pipeline);
|
||||
match videoio::VideoCapture::from_file(&gst_pipeline, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened()? {
|
||||
info!("Successfully opened camera with GStreamer on Raspberry Pi");
|
||||
return Ok(cap);
|
||||
}
|
||||
},
|
||||
Err(e) => warn!("Failed to open with GStreamer on Raspberry Pi: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
// For URLs, video files, or any other path type
|
||||
// 最后尝试使用通用文件打开方法
|
||||
info!("Using generic file opening method for: {}", path_str);
|
||||
let cap = videoio::VideoCapture::from_file(path_str, videoio::CAP_ANY)?;
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user