fix: 树莓派gstreamer pipeline报错
This commit is contained in:
parent
5fc78d7ef9
commit
d1d3cbfdab
@ -102,21 +102,8 @@ impl CameraController {
|
|||||||
// 尝试拍摄测试帧以确保相机设置正确
|
// 尝试拍摄测试帧以确保相机设置正确
|
||||||
info!("Testing camera by capturing a test frame...");
|
info!("Testing camera by capturing a test frame...");
|
||||||
|
|
||||||
// 为测试帧创建一个新的临时相机实例,而不是使用主实例
|
// 直接使用已打开的主相机实例捕获测试帧,避免同时打开两个相机实例
|
||||||
let test_frame_result = {
|
let test_frame_result = camera.capture_test_frame();
|
||||||
info!("Creating temporary camera instance for test frame");
|
|
||||||
let mut test_camera = OpenCVCamera::open(&self.settings.device)
|
|
||||||
.context("Failed to open temporary camera for test frame")?;
|
|
||||||
|
|
||||||
// 应用最小必要设置
|
|
||||||
let _ = test_camera.set_format(self.settings.resolution);
|
|
||||||
|
|
||||||
// 捕获测试帧
|
|
||||||
let result = test_camera.capture_test_frame();
|
|
||||||
|
|
||||||
// test_camera将在此作用域结束时自动释放
|
|
||||||
result
|
|
||||||
};
|
|
||||||
|
|
||||||
// 处理测试帧结果
|
// 处理测试帧结果
|
||||||
match test_frame_result {
|
match test_frame_result {
|
||||||
@ -177,66 +164,23 @@ impl CameraController {
|
|||||||
.as_mut()
|
.as_mut()
|
||||||
.ok_or_else(|| anyhow::anyhow!("Camera not initialized"))?;
|
.ok_or_else(|| anyhow::anyhow!("Camera not initialized"))?;
|
||||||
|
|
||||||
// 先释放当前相机实例,以确保没有资源冲突
|
// 使用已有的相机实例,避免资源冲突
|
||||||
self.camera = None;
|
let camera_ref = self
|
||||||
|
.camera
|
||||||
|
.as_mut()
|
||||||
|
.ok_or_else(|| anyhow::anyhow!("Camera not initialized"))?;
|
||||||
|
|
||||||
// 等待一小段时间以确保资源被完全释放
|
// 确保相机没有在流式传输
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(500)).await;
|
if camera_ref.is_streaming() {
|
||||||
|
camera_ref.stop_streaming()?;
|
||||||
// 重新创建相机实例
|
|
||||||
let mut new_camera = match OpenCVCamera::open(&self.settings.device) {
|
// 等待资源释放
|
||||||
Ok(camera) => camera,
|
tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
|
||||||
Err(e) => {
|
}
|
||||||
error!("Failed to reopen camera for streaming: {}", e);
|
|
||||||
|
|
||||||
// 尝试使用不同的方法打开相机
|
|
||||||
let device_busy = e.to_string().contains("busy") || e.to_string().contains("已被占用");
|
|
||||||
|
|
||||||
if device_busy {
|
|
||||||
warn!("Camera device is busy. Attempting to force release the device...");
|
|
||||||
|
|
||||||
// 使用v4l2-ctl尝试重置设备
|
|
||||||
if let Ok(device_path) = extract_device_path(&self.settings.device) {
|
|
||||||
info!("Trying to reset device: {}", device_path);
|
|
||||||
|
|
||||||
match std::process::Command::new("v4l2-ctl")
|
|
||||||
.args(&["--device", &device_path, "--set-ctrl=power_line_frequency=0"])
|
|
||||||
.output()
|
|
||||||
{
|
|
||||||
Ok(_) => info!("Device reset command sent to {}", device_path),
|
|
||||||
Err(e) => warn!("Failed to reset device: {}", e)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 等待设备重置
|
|
||||||
tokio::time::sleep(tokio::time::Duration::from_millis(1000)).await;
|
|
||||||
|
|
||||||
// 再次尝试打开设备
|
|
||||||
match OpenCVCamera::open(&self.settings.device) {
|
|
||||||
Ok(camera) => {
|
|
||||||
info!("Successfully reopened camera after reset");
|
|
||||||
camera
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
error!("Still failed to open camera after reset: {}", e);
|
|
||||||
return Err(anyhow::anyhow!("Failed to open camera for streaming: {}", e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(anyhow::anyhow!("Failed to extract device path from: {}", self.settings.device));
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return Err(anyhow::anyhow!("Failed to open camera for streaming: {}", e));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 应用基本设置
|
|
||||||
let _ = new_camera.set_format(self.settings.resolution);
|
|
||||||
let _ = new_camera.set_fps(self.settings.fps);
|
|
||||||
|
|
||||||
// Start the camera streaming
|
// 直接使用现有实例启动流
|
||||||
info!("Starting camera streaming with device: {}", self.settings.device);
|
info!("Starting camera streaming with device: {}", self.settings.device);
|
||||||
let stream_result = new_camera.start_streaming();
|
let stream_result = camera_ref.start_streaming();
|
||||||
|
|
||||||
let mut stream = match stream_result {
|
let mut stream = match stream_result {
|
||||||
Ok(stream) => stream,
|
Ok(stream) => stream,
|
||||||
|
|||||||
@ -377,57 +377,31 @@ impl OpenCVCamera {
|
|||||||
info!("Using GStreamer pipeline streaming approach");
|
info!("Using GStreamer pipeline streaming approach");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create a separate VideoCapture for the stream to avoid concurrent access issues
|
// 重要改变:尝试直接使用当前相机的VideoCapture实例来捕获帧
|
||||||
let device = self.device.clone();
|
// 这样可以避免同时打开两个引用同一相机的VideoCapture实例
|
||||||
let stream_capture_result = Self::create_capture_from_path(&device);
|
info!("Using existing camera instance for streaming");
|
||||||
|
|
||||||
let mut stream_capture = match stream_capture_result {
|
// 捕获一个测试帧,确保相机能正常工作
|
||||||
Ok(cap) => cap,
|
let mut test_frame = core::Mat::default();
|
||||||
Err(e) => {
|
if !self.capture.read(&mut test_frame)? {
|
||||||
error!("Failed to create stream capture: {}", e);
|
return Err(anyhow!("Failed to read test frame from camera"));
|
||||||
|
|
||||||
if is_gstreamer_pipeline {
|
|
||||||
error!("GStreamer pipeline error. This could indicate:");
|
|
||||||
error!("1. GStreamer is not properly installed");
|
|
||||||
error!("2. Pipeline syntax is incorrect");
|
|
||||||
error!("3. The specified video device doesn't exist");
|
|
||||||
error!("4. OpenCV was not compiled with GStreamer support");
|
|
||||||
}
|
|
||||||
|
|
||||||
return Err(anyhow!("Failed to create stream capture: {}", e));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Apply the same settings if not using a GStreamer pipeline
|
|
||||||
// (GStreamer pipeline already has configuration in the pipeline string)
|
|
||||||
if !is_gstreamer_pipeline {
|
|
||||||
// 尝试设置分辨率,但不抛出失败异常
|
|
||||||
if let Err(e) = stream_capture.set(videoio::CAP_PROP_FRAME_WIDTH, self.width as f64) {
|
|
||||||
warn!("Failed to set stream width (non-critical): {}", e);
|
|
||||||
}
|
|
||||||
|
|
||||||
if let Err(e) = stream_capture.set(videoio::CAP_PROP_FRAME_HEIGHT, self.height as f64) {
|
|
||||||
warn!("Failed to set stream height (non-critical): {}", e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 确保流被正确打开
|
if test_frame.empty() {
|
||||||
match stream_capture.is_opened() {
|
return Err(anyhow!("Test frame is empty"));
|
||||||
Ok(is_open) => {
|
|
||||||
if !is_open {
|
|
||||||
return Err(anyhow!("Failed to open camera stream - camera reports not opened"));
|
|
||||||
}
|
|
||||||
},
|
|
||||||
Err(e) => {
|
|
||||||
return Err(anyhow!("Failed to check if camera stream is open: {}", e));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
info!("Test frame captured successfully, size: {}x{}", test_frame.cols(), test_frame.rows());
|
||||||
|
|
||||||
|
// 直接使用现有的capture创建流
|
||||||
self.is_streaming = true;
|
self.is_streaming = true;
|
||||||
info!("Started camera streaming successfully");
|
info!("Camera streaming started successfully using existing capture");
|
||||||
|
|
||||||
|
// 创建共享相机实例的流
|
||||||
Ok(OpenCVCaptureStream {
|
Ok(OpenCVCaptureStream {
|
||||||
capture: stream_capture,
|
// 由于只有一个实例可以访问摄像头,我们需要使用Arc+Mutex来共享访问
|
||||||
|
capture: self.capture.clone(),
|
||||||
|
device: self.device.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -494,6 +468,7 @@ impl OpenCVCamera {
|
|||||||
/// Wrapper around OpenCV VideoCapture for streaming
|
/// Wrapper around OpenCV VideoCapture for streaming
|
||||||
pub struct OpenCVCaptureStream {
|
pub struct OpenCVCaptureStream {
|
||||||
capture: videoio::VideoCapture,
|
capture: videoio::VideoCapture,
|
||||||
|
device: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl OpenCVCaptureStream {
|
impl OpenCVCaptureStream {
|
||||||
@ -514,6 +489,14 @@ impl OpenCVCaptureStream {
|
|||||||
impl Drop for OpenCVCaptureStream {
|
impl Drop for OpenCVCaptureStream {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
debug!("OpenCV capture stream dropped");
|
debug!("OpenCV capture stream dropped");
|
||||||
|
|
||||||
|
// 尝试重置设备以便下次能正常访问
|
||||||
|
if self.device.starts_with("/dev/video") {
|
||||||
|
debug!("Attempting to reset video device on stream drop: {}", self.device);
|
||||||
|
let _ = std::process::Command::new("v4l2-ctl")
|
||||||
|
.args(&["--device", &self.device, "--set-ctrl=power_line_frequency=0"])
|
||||||
|
.output();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user