物理镜头下 AVCaptureVideoDataOutput 停止缩放而预览继续,如何排查?
结论
仅凭这些现象,无法认定这是物理镜头的预期限制,也无法确认是某个 iOS 版本的系统缺陷。现有信息缺少设备型号、iOS 版本、activeFormat 和输出配置,还不足以确定根因。
先检查原始视频帧中的主体是否真的停止放大,再关闭预览尺寸缓冲区,观察问题是否仍然出现。虚拟相机没有出现问题可以作为对照,但不能据此认定物理镜头必然存在这一限制。
缩放阈值不等于停止缩放
videoZoomFactor 控制采集图像的裁剪和放大。Apple 文档说明,在较低倍率下,裁剪区域仍足以满足输出尺寸;倍率继续提高后,需要将裁剪结果放大到输出尺寸,画质会随之下降。videoZoomFactor 文档
activeFormat.videoZoomFactorUpscaleThreshold 是开始进行像素放大的阈值,达到该值后,视频数据并不应因此停止缩放。即使异常恰好从这个倍率附近开始,也只能把它作为排查线索,不能直接认定为正常行为。videoZoomFactorUpscaleThreshold 文档
缓冲区宽高保持不变,也不能证明缩放已经停止。应比较同一主体在画面中占据的像素范围,以及四周可见内容是否继续减少。
先确认差异发生在哪一层
使用固定场景和明显的中心标记,在异常阈值前后分别保存几帧未经业务裁剪或缩放的 CVPixelBuffer,并记录:
- 设置的倍率,以及随后读取的
device.videoZoomFactor。 device.minAvailableVideoZoomFactor、device.maxAvailableVideoZoomFactor。- 当前输入设备、
activeFormat、实际缓冲区宽高和帧时间戳。 automaticallyConfiguresOutputBufferDimensions、deliversPreviewSizedOutputBuffers和videoSettings。
如果原始帧仍在放大,而应用展示的视频数据输出画面没有变化,应重点检查自定义渲染、纹理更新、裁剪和缓存。帧时间戳也有助于区分是缩放停止,还是画面停留在旧帧。
比较画面时,先统一方向、镜像和显示区域比例,并检查 previewLayer.videoGravity、图层变换及额外的 UI 缩放。显示端的裁剪差异应与采集帧的视野变化分开验证。
将预览尺寸缓冲区作为独立变量测试
Apple 文档允许 AVCaptureVideoDataOutput 自动选择接近屏幕大小的缓冲区,其尺寸可能与 activeFormat 对应的完整输出尺寸不同。手动调整 deliversPreviewSizedOutputBuffers 前,需要先关闭自动尺寸配置。输出尺寸配置文档
可以在现有会话上做对照。示例假设 videoOutput 已加入会话,目标系统支持这些属性,并且代码在应用管理会话的串行队列上执行:
import AVFoundation
import CoreVideo
func disablePreviewSizedBuffers(
session: AVCaptureSession,
videoOutput: AVCaptureVideoDataOutput
) {
session.beginConfiguration()
defer { session.commitConfiguration() }
videoOutput.automaticallyConfiguresOutputBufferDimensions = false
videoOutput.deliversPreviewSizedOutputBuffers = false
videoOutput.videoSettings = [
kCVPixelBufferPixelFormatTypeKey as String:
kCVPixelFormatType_32BGRA
]
}
该配置保留 BGRA 格式,不指定宽高,用于对照预览尺寸路径。修改后,应从实际回调中读取缓冲区尺寸,不要假定其尺寸。
如果关闭后两路画面恢复一致,说明问题与输出尺寸配置或其触发的处理路径有关,但仅凭这一结果还无法确定底层原因。如果仍然复现,继续对比采集格式、连接设置和渲染过程。这段代码用于诊断,尚未确认能作为通用修复方案。
完整尺寸的 BGRA 缓冲区可能增加内存带宽和处理负担,对照测试时也要观察帧率和丢帧情况。
核对倍率设置与对照条件
确认缩放操作针对当前 AVCaptureDeviceInput.device。设置前调用 lockForConfiguration(),完成后调用 unlockForConfiguration(),并将请求值限制在当前设备可用的倍率范围内。若使用渐变缩放,应等待倍率稳定后再比较画面,避免把过渡阶段的不同帧当作持续不一致。
对比物理镜头和虚拟相机时,尽量保持帧率、输出尺寸、宽高比和连接设置一致,同时记录两者实际选中的格式。仅使用相同的 sessionPreset,不足以证明所有采集条件相同。
如何处理确认后的异常
如果倍率稳定后原始帧仍停止放大,而预览继续变化,且最小示例能够稳定复现,可以向 Apple 提交 Feedback,附上设备型号、系统版本、输入类型、采集格式、异常倍率和对照帧。
临时方案应以实测为依据。如果完整尺寸输出正常,可以评估其性能成本;如果虚拟相机满足业务对镜头选择的要求,也可以沿用已验证正常的配置。若业务要求显示画面与算法处理帧严格对应,可以考虑直接用同一份视频数据输出渲染预览。
在没有测量有效视野的情况下,不要再按 videoZoomFactor 对输出帧做一次裁剪放大,否则可能重复缩放,进一步扩大两路画面的差异。
备注:内容仅供参考。
