fix: 树莓派gstreamer pipeline报错
This commit is contained in:
parent
94cf574161
commit
40f17315a9
@ -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"));
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user