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 {
|
let device = if is_raspberry_pi {
|
||||||
// 使用特定的GStreamer pipeline字符串在树莓派上适配摄像头
|
// 使用更简单的GStreamer pipeline,尝试不同配置方式和格式
|
||||||
// 这个pipeline使用v4l2src作为源,并确保正确初始化
|
// 此pipeline尝试放宽限制,避免严格的格式约束
|
||||||
"v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=30/1 ! videoconvert ! appsink".to_string()
|
"v4l2src ! videoconvert ! appsink".to_string()
|
||||||
} else if std::env::consts::OS == "linux" {
|
} else if std::env::consts::OS == "linux" {
|
||||||
"/dev/video0".to_string()
|
"/dev/video0".to_string()
|
||||||
} else if std::env::consts::OS == "macos" {
|
} else if std::env::consts::OS == "macos" {
|
||||||
|
|||||||
@ -111,17 +111,10 @@ impl CameraController {
|
|||||||
// 在树莓派上但没有使用GStreamer pipeline,尝试使用pipeline重新初始化
|
// 在树莓派上但没有使用GStreamer pipeline,尝试使用pipeline重新初始化
|
||||||
warn!("Running on Raspberry Pi without GStreamer pipeline. Attempting to reinitialize with GStreamer...");
|
warn!("Running on Raspberry Pi without GStreamer pipeline. Attempting to reinitialize with GStreamer...");
|
||||||
|
|
||||||
// 创建GStreamer pipeline
|
// 创建更简单的GStreamer pipeline
|
||||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||||
.unwrap_or("0");
|
|
||||||
|
|
||||||
let pipeline = format!(
|
info!("Trying simple GStreamer pipeline: {}", pipeline);
|
||||||
"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);
|
|
||||||
self.settings.device = pipeline;
|
self.settings.device = pipeline;
|
||||||
|
|
||||||
// 使用 Box::pin 来解决递归 async 调用问题
|
// 使用 Box::pin 来解决递归 async 调用问题
|
||||||
@ -189,17 +182,10 @@ impl CameraController {
|
|||||||
// 关闭当前相机
|
// 关闭当前相机
|
||||||
self.camera = None;
|
self.camera = None;
|
||||||
|
|
||||||
// 创建GStreamer pipeline
|
// 创建更简单的GStreamer pipeline
|
||||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||||
.unwrap_or("0");
|
|
||||||
|
|
||||||
let pipeline = format!(
|
info!("Trying simple GStreamer pipeline: {}", pipeline);
|
||||||
"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);
|
|
||||||
self.settings.device = pipeline;
|
self.settings.device = pipeline;
|
||||||
|
|
||||||
// 重新初始化相机
|
// 重新初始化相机
|
||||||
@ -299,15 +285,10 @@ impl CameraController {
|
|||||||
let use_gstreamer = is_raspberry_pi && !device.contains("!");
|
let use_gstreamer = is_raspberry_pi && !device.contains("!");
|
||||||
|
|
||||||
if use_gstreamer {
|
if use_gstreamer {
|
||||||
// 创建GStreamer pipeline
|
// 创建更简单的GStreamer pipeline
|
||||||
let device_num = device.strip_prefix("/dev/video").unwrap_or("0");
|
let pipeline = "v4l2src ! videoconvert ! appsink".to_string();
|
||||||
|
|
||||||
let pipeline = format!(
|
error!("Raspberry Pi detected - trying simple GStreamer pipeline: {}", pipeline);
|
||||||
"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);
|
|
||||||
|
|
||||||
// 尝试使用GStreamer打开摄像头
|
// 尝试使用GStreamer打开摄像头
|
||||||
match OpenCVCamera::open(&pipeline) {
|
match OpenCVCamera::open(&pipeline) {
|
||||||
|
|||||||
@ -54,29 +54,115 @@ impl OpenCVCamera {
|
|||||||
fn create_capture_from_path(path_str: &str) -> Result<videoio::VideoCapture> {
|
fn create_capture_from_path(path_str: &str) -> Result<videoio::VideoCapture> {
|
||||||
info!("Attempting to open camera with path/pipeline: {}", path_str);
|
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 (通常包含感叹号)
|
// 检测是否为GStreamer pipeline (通常包含感叹号)
|
||||||
if path_str.contains("!") {
|
if path_str.contains("!") {
|
||||||
info!("Detected GStreamer pipeline, using from_file with GSTREAMER backend");
|
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) {
|
match videoio::VideoCapture::from_file(path_str, videoio::CAP_GSTREAMER) {
|
||||||
Ok(cap) => {
|
Ok(cap) => {
|
||||||
if cap.is_opened()? {
|
if cap.is_opened().unwrap_or(false) {
|
||||||
info!("Successfully opened GStreamer pipeline");
|
info!("Successfully opened GStreamer pipeline");
|
||||||
return Ok(cap);
|
return Ok(cap);
|
||||||
} else {
|
} else {
|
||||||
warn!("GStreamer pipeline opened but not ready, will try alternative methods");
|
warn!("GStreamer pipeline opened but not ready");
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
warn!("Failed to open with GStreamer: {}. Will try alternative methods.", 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
|
// Try to parse as integer index first
|
||||||
if let Ok(device_index) = path_str.parse::<i32>() {
|
if let Ok(device_index) = path_str.parse::<i32>() {
|
||||||
info!("Opening camera by index: {}", device_index);
|
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
|
// 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);
|
info!("Using generic file opening method for: {}", path_str);
|
||||||
let cap = videoio::VideoCapture::from_file(path_str, videoio::CAP_ANY)?;
|
let cap = videoio::VideoCapture::from_file(path_str, videoio::CAP_ANY)?;
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user