向AVCaptureSession添加AVCapturePhotoOutput致iPhone X预览层黑屏
问题成因
结合iPhone X的硬件特性和现有代码的执行时序问题,预览层黑屏的核心原因可以归纳为三点:
- 硬件管线的代际差异:iPhone X搭载的A11芯片是苹果第一代支持高分辨率照片并行输出的ISP,硬件管线没有为多场景输出预留足够带宽。当同时开启
.photo会话预设、高分辨率照片捕获、标准视频防抖配置时,系统会优先把ISP的通道带宽分配给照片输出任务,直接挂起预览层的实时帧通道,这个调度逻辑在后续iPhone XS及更新机型的ISP上做了优化,因此同代码在其他设备上不会出现黑屏问题。这也解释了为什么移除photoOutput的添加逻辑后,预览层可以恢复正常显示。 - 配置时序的系统兼容bug:现有代码在
captureSession.commitConfiguration()完成之后才去修改photoOutput的视频连接属性(设置防抖模式),这个操作在iPhone X运行的iOS12、iOS13系统版本中,会触发会话连接的路由错误——系统会错把AVCaptureVideoPreviewLayer绑定的帧通道,路由到photoOutput的静态照片帧缓冲区,导致预览层无法获取实时视频流,最终显示黑屏。 - 高分辨率捕获的带宽抢占:代码中强制开启了
photoOutput.isHighResolutionCaptureEnabled = true,同时把maxPhotoQualityPrioritization设为最高的.quality,在iPhone X的主摄硬件上,全像素输出的带宽已经占满了ISP的通道容量,没有多余带宽分给预览层,因此只要加上photoOutput的配置就会出现预览断流。
可落地的解决方案
不需要移除photoOutput相关的照片捕获逻辑,按照以下几点调整即可兼容iPhone X:
- 调整所有会话配置的执行时序:把连接属性的设置全部移动到
beginConfiguration和commitConfiguration的代码块内部,不要在提交会话配置完成后再修改任何输入、输出、连接的属性。也就是说,将设置preferredVideoStabilizationMode的代码,放在添加完photoOutput之后、调用commitConfiguration之前执行。 - 做机型适配的能力降级:对iPhone X及更早的机型,关闭高分辨率照片捕获开关,将
maxPhotoQualityPrioritization从.quality调整为.balanced,给预览通道预留足够的硬件带宽;iPhone XS及更新机型可以保留原有的高分辨率、最高质量的配置。 - 显式绑定预览层的视频连接:在将session赋值给
AVCaptureVideoPreviewLayer之后,主动获取previewLayer对应的视频连接,显式设置连接的方向、镜像参数,避免系统自动推断连接路由时出现通道错绑的问题。 - 补充设备校验逻辑:在初始化摄像头输入时,校验选中的
captureDevice确实为后置广角主摄,避免误将iPhone X的前置原深感摄像头作为输入设备添加——原深感摄像头虽然能通过canAddOutput的校验,但本身不支持高分辨率静态照片输出,会话启动后会直接掐断预览通道触发黑屏。
内容的提问来源于stack exchange,提问作者Isaiah Turner
相关产品推荐
相关产品推荐

