打开设备并初始化流
(id: &str, config: CameraConfig)
| 42 | |
| 43 | /// 打开设备并初始化流 |
| 44 | pub fn open(id: &str, config: CameraConfig) -> Result<(Box<dyn Stream>, DeviceControls)> { |
| 45 | // 1. 打开设备句柄 |
| 46 | let dev = v4l::Device::with_path(id).map_err(CameraError::Io)?; |
| 47 | |
| 48 | // 2. 获取格式并进行协商 (Format Negotiation) |
| 49 | let negotiated_fmt = negotiate_format(&dev, &config)?; |
| 50 | |
| 51 | // 3. 应用格式设置 (ioctl: VIDIOC_S_FMT) |
| 52 | let mut fmt = dev.format().map_err(CameraError::Io)?; |
| 53 | fmt.width = negotiated_fmt.width; |
| 54 | fmt.height = negotiated_fmt.height; |
| 55 | fmt.fourcc = |
| 56 | pixel_map::to_v4l_fourcc(negotiated_fmt.format).ok_or(CameraError::FormatNotSupported)?; |
| 57 | // 注意:FPS 设置通常需要 VIDIOC_S_PARM,这里简化处理,稍后在 Stream 初始化中设置 |
| 58 | let applied_fmt = dev.set_format(&fmt).map_err(CameraError::Io)?; |
| 59 | |
| 60 | // tracing::info!( |
| 61 | // "Camera opened: {}x{} @ {}", |
| 62 | // applied_fmt.width, |
| 63 | // applied_fmt.height, |
| 64 | // applied_fmt.fourcc |
| 65 | // ); |
| 66 | |
| 67 | // 4. 创建共享句柄 (Arc) |
| 68 | // Stream 和 Controls 都需要访问同一个 fd,但在 V4L2 中多线程访问同一个 fd 是安全的 |
| 69 | let dev_arc = Arc::new(dev); |
| 70 | |
| 71 | // 5. 初始化流 (申请 Buffer, mmap) |
| 72 | let stream = V4l2Stream::new(dev_arc.clone(), &applied_fmt, config.buffer_count)?; |
| 73 | |
| 74 | // 6. 初始化控制器 (Sensor, Lens, System) |
| 75 | let controls = create_controls(dev_arc); |
| 76 | |
| 77 | Ok((Box::new(stream), controls)) |
| 78 | } |
| 79 | |
| 80 | /// 核心:格式协商算法 |
| 81 | /// 遍历硬件支持的所有格式,计算得分,返回最佳配置 |
no test coverage detected