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...");
|
||||
|
||||
// 为测试帧创建一个新的临时相机实例,而不是使用主实例
|
||||
let test_frame_result = {
|
||||
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
|
||||
};
|
||||
// 直接使用已打开的主相机实例捕获测试帧,避免同时打开两个相机实例
|
||||
let test_frame_result = camera.capture_test_frame();
|
||||
|
||||
// 处理测试帧结果
|
||||
match test_frame_result {
|
||||
@ -177,66 +164,23 @@ impl CameraController {
|
||||
.as_mut()
|
||||
.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;
|
||||
|
||||
// 重新创建相机实例
|
||||
let mut new_camera = match OpenCVCamera::open(&self.settings.device) {
|
||||
Ok(camera) => camera,
|
||||
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);
|
||||
// 确保相机没有在流式传输
|
||||
if camera_ref.is_streaming() {
|
||||
camera_ref.stop_streaming()?;
|
||||
|
||||
// 等待资源释放
|
||||
tokio::time::sleep(tokio::time::Duration::from_millis(300)).await;
|
||||
}
|
||||
|
||||
// Start the camera streaming
|
||||
// 直接使用现有实例启动流
|
||||
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 {
|
||||
Ok(stream) => stream,
|
||||
|
||||
@ -377,57 +377,31 @@ impl OpenCVCamera {
|
||||
info!("Using GStreamer pipeline streaming approach");
|
||||
}
|
||||
|
||||
// Create a separate VideoCapture for the stream to avoid concurrent access issues
|
||||
let device = self.device.clone();
|
||||
let stream_capture_result = Self::create_capture_from_path(&device);
|
||||
// 重要改变:尝试直接使用当前相机的VideoCapture实例来捕获帧
|
||||
// 这样可以避免同时打开两个引用同一相机的VideoCapture实例
|
||||
info!("Using existing camera instance for streaming");
|
||||
|
||||
let mut stream_capture = match stream_capture_result {
|
||||
Ok(cap) => cap,
|
||||
Err(e) => {
|
||||
error!("Failed to create stream capture: {}", e);
|
||||
|
||||
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);
|
||||
}
|
||||
// 捕获一个测试帧,确保相机能正常工作
|
||||
let mut test_frame = core::Mat::default();
|
||||
if !self.capture.read(&mut test_frame)? {
|
||||
return Err(anyhow!("Failed to read test frame from camera"));
|
||||
}
|
||||
|
||||
// 确保流被正确打开
|
||||
match stream_capture.is_opened() {
|
||||
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));
|
||||
}
|
||||
if test_frame.empty() {
|
||||
return Err(anyhow!("Test frame is empty"));
|
||||
}
|
||||
|
||||
info!("Test frame captured successfully, size: {}x{}", test_frame.cols(), test_frame.rows());
|
||||
|
||||
// 直接使用现有的capture创建流
|
||||
self.is_streaming = true;
|
||||
info!("Started camera streaming successfully");
|
||||
info!("Camera streaming started successfully using existing capture");
|
||||
|
||||
// 创建共享相机实例的流
|
||||
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
|
||||
pub struct OpenCVCaptureStream {
|
||||
capture: videoio::VideoCapture,
|
||||
device: String,
|
||||
}
|
||||
|
||||
impl OpenCVCaptureStream {
|
||||
@ -514,6 +489,14 @@ impl OpenCVCaptureStream {
|
||||
impl Drop for OpenCVCaptureStream {
|
||||
fn drop(&mut self) {
|
||||
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