fix: 树莓派gstreamer pipeline报错
This commit is contained in:
parent
94cf574161
commit
40f17315a9
@ -1,6 +1,7 @@
|
|||||||
use anyhow::{anyhow, Context, Result};
|
use anyhow::{anyhow, Context, Result};
|
||||||
use log::{debug, error, info, warn};
|
use log::{debug, error, info, warn};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
use opencv::{core, prelude::*, videoio};
|
use opencv::{core, prelude::*, videoio};
|
||||||
|
|
||||||
@ -9,7 +10,7 @@ use crate::camera::{ExposureMode, Resolution};
|
|||||||
/// OpenCV camera driver
|
/// OpenCV camera driver
|
||||||
pub struct OpenCVCamera {
|
pub struct OpenCVCamera {
|
||||||
/// The VideoCapture instance
|
/// The VideoCapture instance
|
||||||
capture: videoio::VideoCapture,
|
capture: Arc<Mutex<videoio::VideoCapture>>,
|
||||||
/// Camera width
|
/// Camera width
|
||||||
width: u32,
|
width: u32,
|
||||||
/// Camera height
|
/// Camera height
|
||||||
@ -42,7 +43,7 @@ impl OpenCVCamera {
|
|||||||
);
|
);
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
capture,
|
capture: Arc::new(Mutex::new(capture)),
|
||||||
width,
|
width,
|
||||||
height,
|
height,
|
||||||
is_streaming: false,
|
is_streaming: false,
|
||||||
@ -101,13 +102,16 @@ impl OpenCVCamera {
|
|||||||
pub fn set_format(&mut self, resolution: Resolution) -> Result<()> {
|
pub fn set_format(&mut self, resolution: Resolution) -> Result<()> {
|
||||||
let (width, height) = resolution.dimensions();
|
let (width, height) = resolution.dimensions();
|
||||||
|
|
||||||
|
// 获取互斥锁守卫
|
||||||
|
let mut capture_guard = self.capture.lock().unwrap();
|
||||||
|
|
||||||
// Set resolution
|
// Set resolution
|
||||||
self.capture.set(videoio::CAP_PROP_FRAME_WIDTH, width as f64)?;
|
capture_guard.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_HEIGHT, height as f64)?;
|
||||||
|
|
||||||
// Read back actual resolution (might be different from requested)
|
// Read back actual resolution (might be different from requested)
|
||||||
let actual_width = self.capture.get(videoio::CAP_PROP_FRAME_WIDTH)? as u32;
|
let actual_width = capture_guard.get(videoio::CAP_PROP_FRAME_WIDTH)? as u32;
|
||||||
let actual_height = self.capture.get(videoio::CAP_PROP_FRAME_HEIGHT)? as u32;
|
let actual_height = capture_guard.get(videoio::CAP_PROP_FRAME_HEIGHT)? as u32;
|
||||||
|
|
||||||
if actual_width != width || actual_height != height {
|
if actual_width != width || actual_height != height {
|
||||||
warn!(
|
warn!(
|
||||||
@ -126,10 +130,13 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Set the camera frame rate
|
/// Set the camera frame rate
|
||||||
pub fn set_fps(&mut self, fps: u32) -> Result<()> {
|
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
|
// 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 {
|
if (actual_fps - fps as f64).abs() > 0.1 {
|
||||||
warn!("Requested {} fps but got {} fps", fps, actual_fps);
|
warn!("Requested {} fps but got {} fps", fps, actual_fps);
|
||||||
@ -142,19 +149,22 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Set camera exposure mode and value
|
/// Set camera exposure mode and value
|
||||||
pub fn set_exposure(&mut self, mode: ExposureMode) -> Result<()> {
|
pub fn set_exposure(&mut self, mode: ExposureMode) -> Result<()> {
|
||||||
|
// 获取互斥锁守卫
|
||||||
|
let mut capture_guard = self.capture.lock().unwrap();
|
||||||
|
|
||||||
match mode {
|
match mode {
|
||||||
ExposureMode::Auto => {
|
ExposureMode::Auto => {
|
||||||
// Set auto exposure mode
|
// 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");
|
info!("Set camera exposure: Auto");
|
||||||
},
|
},
|
||||||
ExposureMode::Manual(exposure_time) => {
|
ExposureMode::Manual(exposure_time) => {
|
||||||
// First disable auto exposure
|
// 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
|
// Then set exposure value - might need conversion based on camera
|
||||||
let exposure_value = exposure_time as f64 / 10000.0; // Convert microseconds to OpenCV units
|
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);
|
info!("Set camera exposure: Manual ({})", exposure_time);
|
||||||
}
|
}
|
||||||
@ -165,9 +175,12 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Set camera gain (ISO)
|
/// Set camera gain (ISO)
|
||||||
pub fn set_gain(&mut self, gain: u8) -> Result<()> {
|
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);
|
info!("Set camera gain: {} (actual: {})", gain, actual_gain);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -175,10 +188,13 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Lock focus at infinity (if supported)
|
/// Lock focus at infinity (if supported)
|
||||||
pub fn lock_focus_at_infinity(&mut self) -> Result<()> {
|
pub fn lock_focus_at_infinity(&mut self) -> Result<()> {
|
||||||
|
// 获取互斥锁守卫
|
||||||
|
let mut capture_guard = self.capture.lock().unwrap();
|
||||||
|
|
||||||
// First, set focus mode to manual
|
// 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)
|
// 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");
|
info!("Locked focus at infinity");
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
@ -190,59 +206,20 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Start streaming from the camera
|
/// Start streaming from the camera
|
||||||
pub fn start_streaming(&mut self) -> Result<OpenCVCaptureStream> {
|
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
|
let capture_guard = self.capture.lock().unwrap();
|
||||||
if self.device.starts_with("/dev/video") {
|
if !capture_guard.is_opened()? {
|
||||||
if let Some(num_str) = self.device.strip_prefix("/dev/video") {
|
return Err(anyhow!("Camera is not open"));
|
||||||
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,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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;
|
self.is_streaming = true;
|
||||||
info!("Started camera streaming");
|
info!("Started camera streaming");
|
||||||
|
|
||||||
|
// 使用同一个相机实例来避免重复打开设备
|
||||||
Ok(OpenCVCaptureStream {
|
Ok(OpenCVCaptureStream {
|
||||||
capture: stream_capture,
|
capture: self.capture.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -271,14 +248,18 @@ impl OpenCVCamera {
|
|||||||
|
|
||||||
/// Wrapper around OpenCV VideoCapture for streaming
|
/// Wrapper around OpenCV VideoCapture for streaming
|
||||||
pub struct OpenCVCaptureStream {
|
pub struct OpenCVCaptureStream {
|
||||||
capture: videoio::VideoCapture,
|
capture: Arc<Mutex<videoio::VideoCapture>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenCVCaptureStream {
|
impl OpenCVCaptureStream {
|
||||||
/// Capture a single frame from the camera
|
/// Capture a single frame from the camera
|
||||||
pub fn capture_frame(&mut self) -> Result<core::Mat> {
|
pub fn capture_frame(&mut self) -> Result<core::Mat> {
|
||||||
let mut frame = core::Mat::default();
|
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() {
|
if frame.empty() {
|
||||||
return Err(anyhow!("Captured frame is empty"));
|
return Err(anyhow!("Captured frame is empty"));
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user