fix: 树莓派gstreamer pipeline报错

This commit is contained in:
grabbit 2025-04-05 16:45:51 +08:00
parent 94cf574161
commit 40f17315a9

View File

@ -1,6 +1,7 @@
use anyhow::{anyhow, Context, Result};
use log::{debug, error, info, warn};
use std::path::Path;
use std::sync::{Arc, Mutex};
use opencv::{core, prelude::*, videoio};
@ -9,7 +10,7 @@ use crate::camera::{ExposureMode, Resolution};
/// OpenCV camera driver
pub struct OpenCVCamera {
/// The VideoCapture instance
capture: videoio::VideoCapture,
capture: Arc<Mutex<videoio::VideoCapture>>,
/// Camera width
width: u32,
/// Camera height
@ -42,7 +43,7 @@ impl OpenCVCamera {
);
Ok(Self {
capture,
capture: Arc::new(Mutex::new(capture)),
width,
height,
is_streaming: false,
@ -101,13 +102,16 @@ impl OpenCVCamera {
pub fn set_format(&mut self, resolution: Resolution) -> Result<()> {
let (width, height) = resolution.dimensions();
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
// Set resolution
self.capture.set(videoio::CAP_PROP_FRAME_WIDTH, width as f64)?;
self.capture.set(videoio::CAP_PROP_FRAME_HEIGHT, height as f64)?;
capture_guard.set(videoio::CAP_PROP_FRAME_WIDTH, width as f64)?;
capture_guard.set(videoio::CAP_PROP_FRAME_HEIGHT, height as f64)?;
// Read back actual resolution (might be different from requested)
let actual_width = self.capture.get(videoio::CAP_PROP_FRAME_WIDTH)? as u32;
let actual_height = self.capture.get(videoio::CAP_PROP_FRAME_HEIGHT)? as u32;
let actual_width = capture_guard.get(videoio::CAP_PROP_FRAME_WIDTH)? as u32;
let actual_height = capture_guard.get(videoio::CAP_PROP_FRAME_HEIGHT)? as u32;
if actual_width != width || actual_height != height {
warn!(
@ -126,10 +130,13 @@ impl OpenCVCamera {
/// Set the camera frame rate
pub fn set_fps(&mut self, fps: u32) -> Result<()> {
self.capture.set(videoio::CAP_PROP_FPS, fps as f64)?;
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
capture_guard.set(videoio::CAP_PROP_FPS, fps as f64)?;
// Read back actual FPS
let actual_fps = self.capture.get(videoio::CAP_PROP_FPS)?;
let actual_fps = capture_guard.get(videoio::CAP_PROP_FPS)?;
if (actual_fps - fps as f64).abs() > 0.1 {
warn!("Requested {} fps but got {} fps", fps, actual_fps);
@ -142,19 +149,22 @@ impl OpenCVCamera {
/// Set camera exposure mode and value
pub fn set_exposure(&mut self, mode: ExposureMode) -> Result<()> {
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
match mode {
ExposureMode::Auto => {
// Set auto exposure mode
self.capture.set(videoio::CAP_PROP_AUTO_EXPOSURE, 0.75)?; // 0.75 is auto mode in OpenCV
capture_guard.set(videoio::CAP_PROP_AUTO_EXPOSURE, 0.75)?; // 0.75 is auto mode in OpenCV
info!("Set camera exposure: Auto");
},
ExposureMode::Manual(exposure_time) => {
// First disable auto exposure
self.capture.set(videoio::CAP_PROP_AUTO_EXPOSURE, 0.25)?; // 0.25 is manual mode in OpenCV
capture_guard.set(videoio::CAP_PROP_AUTO_EXPOSURE, 0.25)?; // 0.25 is manual mode in OpenCV
// Then set exposure value - might need conversion based on camera
let exposure_value = exposure_time as f64 / 10000.0; // Convert microseconds to OpenCV units
self.capture.set(videoio::CAP_PROP_EXPOSURE, exposure_value)?;
capture_guard.set(videoio::CAP_PROP_EXPOSURE, exposure_value)?;
info!("Set camera exposure: Manual ({})", exposure_time);
}
@ -165,9 +175,12 @@ impl OpenCVCamera {
/// Set camera gain (ISO)
pub fn set_gain(&mut self, gain: u8) -> Result<()> {
self.capture.set(videoio::CAP_PROP_GAIN, gain as f64)?;
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
let actual_gain = self.capture.get(videoio::CAP_PROP_GAIN)?;
capture_guard.set(videoio::CAP_PROP_GAIN, gain as f64)?;
let actual_gain = capture_guard.get(videoio::CAP_PROP_GAIN)?;
info!("Set camera gain: {} (actual: {})", gain, actual_gain);
Ok(())
@ -175,10 +188,13 @@ impl OpenCVCamera {
/// Lock focus at infinity (if supported)
pub fn lock_focus_at_infinity(&mut self) -> Result<()> {
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
// First, set focus mode to manual
if self.capture.set(videoio::CAP_PROP_AUTOFOCUS, 0.0).is_ok() {
if capture_guard.set(videoio::CAP_PROP_AUTOFOCUS, 0.0).is_ok() {
// Then set focus to infinity (typically maximum value)
if self.capture.set(videoio::CAP_PROP_FOCUS, 1.0).is_ok() {
if capture_guard.set(videoio::CAP_PROP_FOCUS, 1.0).is_ok() {
info!("Locked focus at infinity");
return Ok(());
}
@ -190,59 +206,20 @@ impl OpenCVCamera {
/// Start streaming from the camera
pub fn start_streaming(&mut self) -> Result<OpenCVCaptureStream> {
// Ensure capture is opened
if !self.capture.is_opened()? {
return Err(anyhow!("Camera is not open"));
}
#[cfg(target_os = "linux")]
// 获取互斥锁守卫检查相机是否打开
{
// For Linux device files like /dev/video0
if self.device.starts_with("/dev/video") {
if let Some(num_str) = self.device.strip_prefix("/dev/video") {
if let Ok(device_index) = num_str.parse::<i32>() {
// 使用V4L2创建摄像头流
info!("Starting stream using V4L2: device index {}", device_index);
let mut stream_capture = videoio::VideoCapture::new(device_index, videoio::CAP_V4L2)?;
// 应用相同的设置
stream_capture.set(videoio::CAP_PROP_FRAME_WIDTH, self.width as f64)?;
stream_capture.set(videoio::CAP_PROP_FRAME_HEIGHT, self.height as f64)?;
stream_capture.set(videoio::CAP_PROP_FPS, 30.0)?; // 使用固定30fps或从设置获取
if !stream_capture.is_opened()? {
return Err(anyhow!("Failed to open V4L2 camera stream"));
}
self.is_streaming = true;
info!("Started camera streaming with V4L2");
return Ok(OpenCVCaptureStream {
capture: stream_capture,
});
}
}
let capture_guard = self.capture.lock().unwrap();
if !capture_guard.is_opened()? {
return Err(anyhow!("Camera is not open"));
}
}
// For non-Linux platforms, use regular approach
// Create a separate VideoCapture for the stream to avoid concurrent access issues
let device = self.device.clone();
let mut stream_capture = Self::create_capture_from_path(&device)?;
// Apply the same settings
stream_capture.set(videoio::CAP_PROP_FRAME_WIDTH, self.width as f64)?;
stream_capture.set(videoio::CAP_PROP_FRAME_HEIGHT, self.height as f64)?;
if !stream_capture.is_opened()? {
return Err(anyhow!("Failed to open camera stream"));
}
self.is_streaming = true;
info!("Started camera streaming");
// 使用同一个相机实例来避免重复打开设备
Ok(OpenCVCaptureStream {
capture: stream_capture,
capture: self.capture.clone(),
})
}
@ -271,14 +248,18 @@ impl OpenCVCamera {
/// Wrapper around OpenCV VideoCapture for streaming
pub struct OpenCVCaptureStream {
capture: videoio::VideoCapture,
capture: Arc<Mutex<videoio::VideoCapture>>,
}
impl OpenCVCaptureStream {
/// Capture a single frame from the camera
pub fn capture_frame(&mut self) -> Result<core::Mat> {
let mut frame = core::Mat::default();
if self.capture.read(&mut frame)? {
// 获取互斥锁守卫
let mut capture_guard = self.capture.lock().unwrap();
if capture_guard.read(&mut frame)? {
if frame.empty() {
return Err(anyhow!("Captured frame is empty"));
}