fix: 树莓派gstreamer pipeline报错
This commit is contained in:
parent
2cab6e8a7a
commit
ddac14fb3f
@ -121,18 +121,29 @@ async fn main() -> Result<()> {
|
||||
|
||||
/// 创建用于演示的配置
|
||||
fn create_demo_config() -> Config {
|
||||
// 根据操作系统自动选择合适的设备路径
|
||||
let device = match std::env::consts::OS {
|
||||
"linux" => "/dev/video0".to_string(),
|
||||
"macos" => "0".to_string(),
|
||||
// 检测是否为树莓派
|
||||
let is_raspberry_pi = std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false);
|
||||
|
||||
// 根据操作系统和设备类型自动选择合适的设备路径
|
||||
let device = if is_raspberry_pi {
|
||||
// 使用特定的GStreamer pipeline字符串在树莓派上适配摄像头
|
||||
// 这个pipeline使用v4l2src作为源,并确保正确初始化
|
||||
"v4l2src device=/dev/video0 ! video/x-raw,width=1280,height=720,framerate=30/1 ! videoconvert ! appsink".to_string()
|
||||
} else if std::env::consts::OS == "linux" {
|
||||
"/dev/video0".to_string()
|
||||
} else if std::env::consts::OS == "macos" {
|
||||
"0".to_string()
|
||||
} else {
|
||||
// Windows和其他操作系统通常使用索引
|
||||
_ => "0".to_string(),
|
||||
"0".to_string()
|
||||
};
|
||||
|
||||
info!("自动选择相机设备: {}", device);
|
||||
|
||||
let camera_settings = CameraSettings {
|
||||
device, // 使用根据操作系统确定的设备路径
|
||||
device, // 使用根据操作系统和设备类型确定的设备路径或pipeline
|
||||
resolution: Resolution::HD720p,
|
||||
fps: 30,
|
||||
exposure: ExposureMode::Auto,
|
||||
|
||||
@ -62,6 +62,12 @@ impl CameraController {
|
||||
|
||||
/// Initialize the camera with current settings
|
||||
pub async fn initialize(&mut self) -> Result<()> {
|
||||
// 使用私有方法实现递归安全的异步初始化
|
||||
self.initialize_impl().await
|
||||
}
|
||||
|
||||
/// 内部实现,用于避免异步递归导致的无限大小 future 问题
|
||||
async fn initialize_impl(&mut self) -> Result<()> {
|
||||
// Open the camera
|
||||
let mut camera =
|
||||
OpenCVCamera::open(&self.settings.device).context("Failed to open camera")?;
|
||||
@ -89,6 +95,55 @@ impl CameraController {
|
||||
.context("Failed to lock focus at infinity")?;
|
||||
}
|
||||
|
||||
// 尝试拍摄测试帧以确保相机设置正确
|
||||
info!("Testing camera by capturing a test frame...");
|
||||
let mut test_stream = match camera.start_streaming() {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
error!("Failed to start test stream: {}", e);
|
||||
|
||||
// 检查是否在树莓派上,以及是否已经使用GStreamer
|
||||
let is_raspberry_pi = std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_raspberry_pi && !self.settings.device.contains("!") {
|
||||
// 在树莓派上但没有使用GStreamer pipeline,尝试使用pipeline重新初始化
|
||||
warn!("Running on Raspberry Pi without GStreamer pipeline. Attempting to reinitialize with GStreamer...");
|
||||
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
||||
.unwrap_or("0");
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, self.settings.resolution.dimensions().0,
|
||||
self.settings.resolution.dimensions().1, self.settings.fps
|
||||
);
|
||||
|
||||
info!("Trying GStreamer pipeline: {}", pipeline);
|
||||
self.settings.device = pipeline;
|
||||
|
||||
// 使用 Box::pin 来解决递归 async 调用问题
|
||||
// 这样创建一个固定大小的 future
|
||||
return Box::pin(self.initialize_impl()).await;
|
||||
}
|
||||
|
||||
return Err(anyhow::anyhow!("Camera initialization failed: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
// 尝试捕获测试帧
|
||||
match test_stream.capture_frame() {
|
||||
Ok(_) => {
|
||||
info!("Successfully captured test frame - camera is working correctly");
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to capture test frame: {}", e);
|
||||
return Err(anyhow::anyhow!("Camera initialization failed: Unable to capture test frame"));
|
||||
}
|
||||
}
|
||||
|
||||
self.camera = Some(camera);
|
||||
info!("Camera initialized successfully");
|
||||
|
||||
@ -97,6 +152,12 @@ impl CameraController {
|
||||
|
||||
/// Start camera capture in a background task
|
||||
pub async fn start_capture(&mut self) -> Result<()> {
|
||||
// 使用私有方法实现递归安全的异步函数
|
||||
self.start_capture_impl().await
|
||||
}
|
||||
|
||||
/// 内部实现,用于避免异步递归导致的无限大小 future 问题
|
||||
async fn start_capture_impl(&mut self) -> Result<()> {
|
||||
if self.is_running {
|
||||
warn!("Camera capture is already running");
|
||||
return Ok(());
|
||||
@ -108,17 +169,83 @@ impl CameraController {
|
||||
.ok_or_else(|| anyhow::anyhow!("Camera not initialized"))?;
|
||||
|
||||
// Start the camera streaming
|
||||
let stream = camera
|
||||
.start_streaming()
|
||||
.context("Failed to start camera streaming")?;
|
||||
info!("Starting camera streaming with device: {}", self.settings.device);
|
||||
let stream_result = camera.start_streaming();
|
||||
|
||||
let stream = match stream_result {
|
||||
Ok(stream) => stream,
|
||||
Err(e) => {
|
||||
error!("Failed to start camera streaming: {}", e);
|
||||
|
||||
// 检测是否在树莓派上
|
||||
let is_raspberry_pi = std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false);
|
||||
|
||||
if is_raspberry_pi && !self.settings.device.contains("!") {
|
||||
// 在树莓派上但没有使用GStreamer pipeline,尝试使用pipeline重新初始化
|
||||
warn!("Running on Raspberry Pi without GStreamer pipeline. Attempting to reinitialize camera with GStreamer...");
|
||||
|
||||
// 关闭当前相机
|
||||
self.camera = None;
|
||||
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = self.settings.device.strip_prefix("/dev/video")
|
||||
.unwrap_or("0");
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, self.settings.resolution.dimensions().0,
|
||||
self.settings.resolution.dimensions().1, self.settings.fps
|
||||
);
|
||||
|
||||
info!("Trying GStreamer pipeline: {}", pipeline);
|
||||
self.settings.device = pipeline;
|
||||
|
||||
// 重新初始化相机
|
||||
match OpenCVCamera::open(&self.settings.device) {
|
||||
Ok(mut camera) => {
|
||||
// 基本配置
|
||||
let _ = camera.set_format(self.settings.resolution);
|
||||
let _ = camera.set_fps(self.settings.fps);
|
||||
|
||||
self.camera = Some(camera);
|
||||
|
||||
// 使用 Box::pin 来解决递归 async 调用问题
|
||||
return Box::pin(self.start_capture_impl()).await;
|
||||
},
|
||||
Err(e) => {
|
||||
error!("Failed to reinitialize camera with GStreamer: {}", e);
|
||||
return Err(anyhow::anyhow!("Camera streaming failed on Raspberry Pi: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Err(anyhow::anyhow!("Failed to start camera streaming: {}", e));
|
||||
}
|
||||
};
|
||||
|
||||
self.stream = Some(stream);
|
||||
self.is_running = true;
|
||||
|
||||
// 尝试捕获一个测试帧,确保流工作正常
|
||||
if let Some(mut stream_test) = self.stream.as_mut() {
|
||||
match stream_test.capture_frame() {
|
||||
Ok(_) => info!("Successfully captured test frame - camera stream is working correctly"),
|
||||
Err(e) => {
|
||||
error!("Test frame capture failed: {}", e);
|
||||
self.is_running = false;
|
||||
self.stream = None;
|
||||
return Err(anyhow::anyhow!("Camera stream test failed: {}", e));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clone necessary values for the capture task
|
||||
let frame_buffer = self.frame_buffer.clone();
|
||||
let frame_tx = self.frame_tx.clone();
|
||||
let fps = self.settings.fps;
|
||||
let device = self.settings.device.clone(); // 复制设备路径用于恢复
|
||||
let mut stream = self
|
||||
.stream
|
||||
.take()
|
||||
@ -163,26 +290,64 @@ impl CameraController {
|
||||
if consecutive_errors >= ERROR_THRESHOLD {
|
||||
error!("Too many consecutive errors ({}), attempting to reinitialize camera stream", consecutive_errors);
|
||||
|
||||
// Try to recreate the stream - this is a simplified version
|
||||
// In a real implementation, you might want to signal the main thread
|
||||
// to fully reinitialize the camera
|
||||
match OpenCVCamera::open("0") { // Note: simplified, should use original device
|
||||
Ok(mut camera) => {
|
||||
// Configure minimal settings
|
||||
let _ = camera.set_format(Resolution::HD720p);
|
||||
let _ = camera.set_fps(fps);
|
||||
|
||||
// Try to start streaming again
|
||||
match camera.start_streaming() {
|
||||
Ok(new_stream) => {
|
||||
info!("Successfully reinitialized camera stream");
|
||||
stream = new_stream;
|
||||
consecutive_errors = 0;
|
||||
},
|
||||
Err(e) => error!("Failed to restart camera streaming: {}", e)
|
||||
}
|
||||
},
|
||||
Err(e) => error!("Failed to reopen camera: {}", e)
|
||||
// 检测是否在树莓派上
|
||||
let is_raspberry_pi = std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false);
|
||||
|
||||
// 判断是否需要尝试GStreamer
|
||||
let use_gstreamer = is_raspberry_pi && !device.contains("!");
|
||||
|
||||
if use_gstreamer {
|
||||
// 创建GStreamer pipeline
|
||||
let device_num = device.strip_prefix("/dev/video").unwrap_or("0");
|
||||
|
||||
let pipeline = format!(
|
||||
"v4l2src device=/dev/video{} ! video/x-raw,width={},height={},framerate={}/1 ! videoconvert ! appsink",
|
||||
device_num, 1280, 720, fps
|
||||
);
|
||||
|
||||
error!("Raspberry Pi detected - trying GStreamer pipeline: {}", pipeline);
|
||||
|
||||
// 尝试使用GStreamer打开摄像头
|
||||
match OpenCVCamera::open(&pipeline) {
|
||||
Ok(mut camera) => {
|
||||
// 配置最低限度设置
|
||||
let _ = camera.set_format(Resolution::HD720p);
|
||||
let _ = camera.set_fps(fps);
|
||||
|
||||
// 尝试重新启动流
|
||||
match camera.start_streaming() {
|
||||
Ok(new_stream) => {
|
||||
info!("Successfully reinitialized camera stream with GStreamer");
|
||||
stream = new_stream;
|
||||
consecutive_errors = 0;
|
||||
},
|
||||
Err(e) => error!("Failed to restart camera streaming with GStreamer: {}", e)
|
||||
}
|
||||
},
|
||||
Err(e) => error!("Failed to reopen camera with GStreamer: {}", e)
|
||||
}
|
||||
} else {
|
||||
// 使用原始设备路径重新创建流
|
||||
match OpenCVCamera::open(&device) {
|
||||
Ok(mut camera) => {
|
||||
// 配置最低限度设置
|
||||
let _ = camera.set_format(Resolution::HD720p);
|
||||
let _ = camera.set_fps(fps);
|
||||
|
||||
// 尝试重新启动流
|
||||
match camera.start_streaming() {
|
||||
Ok(new_stream) => {
|
||||
info!("Successfully reinitialized camera stream");
|
||||
stream = new_stream;
|
||||
consecutive_errors = 0;
|
||||
},
|
||||
Err(e) => error!("Failed to restart camera streaming: {}", e)
|
||||
}
|
||||
},
|
||||
Err(e) => error!("Failed to reopen camera: {}", e)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -257,12 +422,12 @@ impl CameraController {
|
||||
|
||||
self.camera = Some(camera);
|
||||
} else {
|
||||
self.initialize().await?;
|
||||
self.initialize_impl().await?;
|
||||
}
|
||||
|
||||
// Restart if it was running
|
||||
if was_running {
|
||||
self.start_capture().await?;
|
||||
self.start_capture_impl().await?;
|
||||
}
|
||||
|
||||
info!("Camera settings updated");
|
||||
|
||||
@ -52,8 +52,30 @@ impl OpenCVCamera {
|
||||
|
||||
/// Create a VideoCapture instance from a path or device index
|
||||
fn create_capture_from_path(path_str: &str) -> Result<videoio::VideoCapture> {
|
||||
info!("Attempting to open camera with path/pipeline: {}", path_str);
|
||||
|
||||
// 检测是否为GStreamer pipeline (通常包含感叹号)
|
||||
if path_str.contains("!") {
|
||||
info!("Detected GStreamer pipeline, using from_file with GSTREAMER backend");
|
||||
// 如果是GStreamer pipeline,直接使用from_file方法并指定GSTREAMER后端
|
||||
match videoio::VideoCapture::from_file(path_str, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened()? {
|
||||
info!("Successfully opened GStreamer pipeline");
|
||||
return Ok(cap);
|
||||
} else {
|
||||
warn!("GStreamer pipeline opened but not ready, will try alternative methods");
|
||||
}
|
||||
},
|
||||
Err(e) => {
|
||||
warn!("Failed to open with GStreamer: {}. Will try alternative methods.", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Try to parse as integer index first
|
||||
if let Ok(device_index) = path_str.parse::<i32>() {
|
||||
info!("Opening camera by index: {}", device_index);
|
||||
return Ok(videoio::VideoCapture::new(device_index, videoio::CAP_ANY)?);
|
||||
}
|
||||
|
||||
@ -63,6 +85,21 @@ impl OpenCVCamera {
|
||||
// For Linux device files like /dev/video0
|
||||
if let Some(num_str) = path_str.strip_prefix("/dev/video") {
|
||||
if let Ok(device_index) = num_str.parse::<i32>() {
|
||||
info!("Opening Linux camera from /dev/video{}", device_index);
|
||||
|
||||
// 首先尝试V4L2后端,这在树莓派上通常最可靠
|
||||
match videoio::VideoCapture::new(device_index, videoio::CAP_V4L2) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened()? {
|
||||
info!("Successfully opened camera with V4L2 backend");
|
||||
return Ok(cap);
|
||||
}
|
||||
},
|
||||
Err(e) => warn!("Failed to open with V4L2: {}", e)
|
||||
}
|
||||
|
||||
// 回退到通用后端
|
||||
info!("Falling back to default backend");
|
||||
return Ok(videoio::VideoCapture::new(device_index, videoio::CAP_ANY)?);
|
||||
} else {
|
||||
return Err(anyhow!("Invalid device number in path: {}", path_str));
|
||||
@ -73,7 +110,6 @@ impl OpenCVCamera {
|
||||
#[cfg(target_os = "macos")]
|
||||
{
|
||||
// macOS doesn't use /dev/video* paths, but it might have a special format
|
||||
// If we get a path with "camera" or "facetime" or other macOS camera identifiers
|
||||
if path_str.contains("camera") || path_str.contains("facetime") || path_str.contains("avfoundation") {
|
||||
// For macOS, try to extract any numbers in the path
|
||||
let nums: Vec<&str> = path_str.split(|c: char| !c.is_digit(10))
|
||||
@ -82,30 +118,87 @@ impl OpenCVCamera {
|
||||
|
||||
if let Some(num_str) = nums.first() {
|
||||
if let Ok(device_index) = num_str.parse::<i32>() {
|
||||
info!("Opening macOS camera with AVFoundation: {}", device_index);
|
||||
return Ok(videoio::VideoCapture::new(device_index, videoio::CAP_AVFOUNDATION)?);
|
||||
}
|
||||
}
|
||||
|
||||
// If we can't extract a number, try device 0 with AVFoundation
|
||||
info!("Falling back to default macOS camera (index 0)");
|
||||
return Ok(videoio::VideoCapture::new(0, videoio::CAP_AVFOUNDATION)?);
|
||||
}
|
||||
}
|
||||
|
||||
// 对于树莓派,可能需要指定GSTREAMER后端
|
||||
if std::fs::read_to_string("/proc/cpuinfo")
|
||||
.map(|content| content.contains("Raspberry Pi") || content.contains("BCM"))
|
||||
.unwrap_or(false)
|
||||
{
|
||||
// 尝试使用带有GSTREAMER后端的方式打开
|
||||
let gst_pipeline = if path_str.starts_with("/dev/video") {
|
||||
// 如果是设备路径,转换为gstreamer pipeline
|
||||
let num_str = path_str.strip_prefix("/dev/video").unwrap_or("0");
|
||||
format!("v4l2src device={} ! video/x-raw,width=1280,height=720 ! videoconvert ! appsink", path_str)
|
||||
} else {
|
||||
path_str.to_string()
|
||||
};
|
||||
|
||||
info!("Trying to open with GStreamer on Raspberry Pi: {}", gst_pipeline);
|
||||
match videoio::VideoCapture::from_file(&gst_pipeline, videoio::CAP_GSTREAMER) {
|
||||
Ok(cap) => {
|
||||
if cap.is_opened()? {
|
||||
info!("Successfully opened camera with GStreamer on Raspberry Pi");
|
||||
return Ok(cap);
|
||||
}
|
||||
},
|
||||
Err(e) => warn!("Failed to open with GStreamer on Raspberry Pi: {}", e)
|
||||
}
|
||||
}
|
||||
|
||||
// For URLs, video files, or any other path type
|
||||
Ok(videoio::VideoCapture::from_file(path_str, videoio::CAP_ANY)?)
|
||||
info!("Using generic file opening method for: {}", path_str);
|
||||
let cap = videoio::VideoCapture::from_file(path_str, videoio::CAP_ANY)?;
|
||||
|
||||
if !cap.is_opened()? {
|
||||
warn!("Camera opened but not ready. This might indicate a configuration issue.");
|
||||
}
|
||||
|
||||
Ok(cap)
|
||||
}
|
||||
|
||||
/// Set the camera resolution and pixel format
|
||||
pub fn set_format(&mut self, resolution: Resolution) -> Result<()> {
|
||||
let (width, height) = resolution.dimensions();
|
||||
|
||||
// Set resolution
|
||||
self.capture.set(videoio::CAP_PROP_FRAME_WIDTH, width as f64)?;
|
||||
self.capture.set(videoio::CAP_PROP_FRAME_HEIGHT, height as f64)?;
|
||||
// 检查是否为GStreamer pipeline
|
||||
let is_gstreamer_pipeline = self.device.contains("!");
|
||||
|
||||
// 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;
|
||||
if !is_gstreamer_pipeline {
|
||||
// 对于非GStreamer,正常设置分辨率
|
||||
info!("Setting resolution to {}x{}", width, height);
|
||||
self.capture.set(videoio::CAP_PROP_FRAME_WIDTH, width as f64)?;
|
||||
self.capture.set(videoio::CAP_PROP_FRAME_HEIGHT, height as f64)?;
|
||||
} else {
|
||||
// 对于GStreamer pipeline,不需要设置分辨率,因为已经在pipeline中指定了
|
||||
info!("Using resolution from GStreamer pipeline (cannot be changed at runtime)");
|
||||
}
|
||||
|
||||
// 尝试读取实际分辨率
|
||||
let actual_width = match self.capture.get(videoio::CAP_PROP_FRAME_WIDTH) {
|
||||
Ok(w) if w > 0.0 => w as u32,
|
||||
_ => {
|
||||
warn!("Could not read actual width, using requested width");
|
||||
width
|
||||
}
|
||||
};
|
||||
|
||||
let actual_height = match self.capture.get(videoio::CAP_PROP_FRAME_HEIGHT) {
|
||||
Ok(h) if h > 0.0 => h as u32,
|
||||
_ => {
|
||||
warn!("Could not read actual height, using requested height");
|
||||
height
|
||||
}
|
||||
};
|
||||
|
||||
if actual_width != width || actual_height != height {
|
||||
warn!(
|
||||
@ -117,23 +210,42 @@ impl OpenCVCamera {
|
||||
self.width = actual_width;
|
||||
self.height = actual_height;
|
||||
|
||||
info!("Set camera format: {}×{}", self.width, self.height);
|
||||
info!("Camera format: {}×{}", self.width, self.height);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Set the camera frame rate
|
||||
pub fn set_fps(&mut self, fps: u32) -> Result<()> {
|
||||
self.capture.set(videoio::CAP_PROP_FPS, fps as f64)?;
|
||||
// 检查是否为GStreamer pipeline
|
||||
let is_gstreamer_pipeline = self.device.contains("!");
|
||||
|
||||
// Read back actual FPS
|
||||
let actual_fps = self.capture.get(videoio::CAP_PROP_FPS)?;
|
||||
if !is_gstreamer_pipeline {
|
||||
// 对于非GStreamer,正常设置FPS
|
||||
info!("Setting FPS to {}", fps);
|
||||
|
||||
if let Err(e) = self.capture.set(videoio::CAP_PROP_FPS, fps as f64) {
|
||||
warn!("Could not set FPS: {}. This might be expected for some cameras.", e);
|
||||
}
|
||||
} else {
|
||||
// 对于GStreamer pipeline,不需要设置FPS,因为已经在pipeline中指定了
|
||||
info!("Using FPS from GStreamer pipeline (cannot be changed at runtime)");
|
||||
}
|
||||
|
||||
// 尝试读取实际FPS
|
||||
let actual_fps = match self.capture.get(videoio::CAP_PROP_FPS) {
|
||||
Ok(f) if f > 0.0 => f,
|
||||
_ => {
|
||||
warn!("Could not read actual FPS, using requested FPS");
|
||||
fps as f64
|
||||
}
|
||||
};
|
||||
|
||||
if (actual_fps - fps as f64).abs() > 0.1 {
|
||||
warn!("Requested {} fps but got {} fps", fps, actual_fps);
|
||||
}
|
||||
|
||||
info!("Set camera frame rate: {} fps", actual_fps);
|
||||
info!("Camera frame rate: {} fps", actual_fps);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@ -193,20 +305,63 @@ impl OpenCVCamera {
|
||||
return Err(anyhow!("Camera is not open"));
|
||||
}
|
||||
|
||||
info!("Creating stream from device: {}", self.device);
|
||||
|
||||
// 检查是否为GStreamer pipeline
|
||||
let is_gstreamer_pipeline = self.device.contains("!");
|
||||
|
||||
if is_gstreamer_pipeline {
|
||||
info!("Using GStreamer pipeline streaming 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)?;
|
||||
let stream_capture_result = 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)?;
|
||||
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));
|
||||
}
|
||||
};
|
||||
|
||||
if !stream_capture.is_opened()? {
|
||||
return Err(anyhow!("Failed to open camera stream"));
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
|
||||
// 确保流被正确打开
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
self.is_streaming = true;
|
||||
info!("Started camera streaming");
|
||||
info!("Started camera streaming successfully");
|
||||
|
||||
Ok(OpenCVCaptureStream {
|
||||
capture: stream_capture,
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user