初始化完整的采集管线(同步,不启动采集)。 # Arguments `device_id` — 由 `AvfDriver::list_devices` 返回的 `DeviceInfo.id` `config` — 采集配置(分辨率、FPS 等)
(device_id: &str, config: CameraConfig)
| 78 | /// * `device_id` — 由 `AvfDriver::list_devices` 返回的 `DeviceInfo.id` |
| 79 | /// * `config` — 采集配置(分辨率、FPS 等) |
| 80 | pub fn new(device_id: &str, config: CameraConfig) -> Result<Self> { |
| 81 | unsafe { |
| 82 | // 创建 Session |
| 83 | let session = AVCaptureSession::new(); |
| 84 | |
| 85 | // 开始修改配置 |
| 86 | session.beginConfiguration(); |
| 87 | |
| 88 | // 查找设备 |
| 89 | let device = AVCaptureDevice::deviceWithUniqueID(&NSString::from_str(device_id)) |
| 90 | .ok_or_else(|| anyhow!("Device ID not found: {}", device_id))?; |
| 91 | |
| 92 | // 根据 config 选择最合适的分辨率 Preset |
| 93 | let preset = select_best_preset(&session, &config); |
| 94 | session.setSessionPreset(preset); |
| 95 | |
| 96 | // 配置 FPS (用 catch 包裹,因为如果申请了设备不支持的 FPS 会抛出 Objective-C 异常) |
| 97 | if let Some((fps, _priority)) = config.fps_req { |
| 98 | if device.lockForConfiguration().is_ok() { |
| 99 | let device_ref = std::panic::AssertUnwindSafe(&device); |
| 100 | let result = catch(|| { |
| 101 | let duration = CMTime { |
| 102 | value: 1, |
| 103 | timescale: fps as i32, |
| 104 | flags: CMTimeFlags::Valid, |
| 105 | epoch: 0, |
| 106 | }; |
| 107 | device_ref.setActiveVideoMinFrameDuration(duration); |
| 108 | device_ref.setActiveVideoMaxFrameDuration(duration); |
| 109 | }); |
| 110 | if let Err(e) = result { |
| 111 | println!("Warning: Failed to set FPS to {fps}. Device might not support it at this resolution. Exception: {:?}", e); |
| 112 | } |
| 113 | device.unlockForConfiguration(); |
| 114 | } |
| 115 | } |
| 116 | |
| 117 | // ⑥ 包装为 Input 并添加到 Session |
| 118 | let input = AVCaptureDeviceInput::deviceInputWithDevice_error(&device) |
| 119 | .map_err(|e| anyhow!("Failed to create capture input: {:?}", e))?; |
| 120 | |
| 121 | if session.canAddInput(&input) { |
| 122 | session.addInput(&input); |
| 123 | } else { |
| 124 | session.commitConfiguration(); |
| 125 | return Err(anyhow!("Cannot add input to session")); |
| 126 | } |
| 127 | |
| 128 | // ⑥ 创建 Output,并配置像素格式和丢帧策略 |
| 129 | let output = AVCaptureVideoDataOutput::new(); |
| 130 | |
| 131 | // 强制请求 32BGRA,避免后续 CPU YUV→RGB 转换的高昂开销 |
| 132 | // kCVPixelBufferPixelFormatTypeKey = "PixelFormatType" |
| 133 | { |
| 134 | use objc2::runtime::AnyObject; |
| 135 | use objc2_foundation::{NSCopying, NSDictionary, NSObjectProtocol}; |
| 136 | |
| 137 | let key = NSString::from_str("PixelFormatType"); |
nothing calls this directly
no test coverage detected