mcpField
I
iphone-duo-camera

iphone-duo-camera

github.com/mirzaaghazadeh开发250560 次安装今天更新
代码仓库

关于 iphone-duo-camera

面向 iPhone Duo 相机应用开发者的技能指南,讲解双前置摄像头的选择、朝向判断与画面处理。重点是利用方向协调器在设备开合和翻转时选择合适摄像头。

主要功能

  1. 01比较虚拟与独立摄像头方案
  2. 02按显示视图判断摄像头朝向
  3. 03跨 Actor 传递摄像头描述符
  4. 04处理镜像、预览比例与旋转

适用场景

  1. 01为 iPhone Duo 实现自拍摄像头切换
  2. 02设备开合时重新配置采集会话
  3. 03同步双显示器上的摄像头方向
  4. 04调整预览画面并保持图像正向

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/mirzaaghazadeh/iphone-duo-skills --skill iphone-duo-camera

安装后在 Claude Code 中输入/iphone-duo-camera确认已加载。

详细介绍

iPhone Duo 上的相机

iPhone Duo 是第一款配备两颗前置相机的 iPhone。两颗相机都是方形传感器,视场角超广:一颗位于外屏上,另一颗位于内屏下方——这是 iPhone 上首款屏下相机。

这带来了以往任何 iPhone 都没有的问题。“前置”不再意味着“朝向用户”。

先选择策略

后续的一切都取决于这个选择。

虚拟前置相机——自动,但功能有限

按常规方式发现前置相机——创建一个 AVCaptureDevice.DiscoverySession,请求位置为 .front,设备类型为 Wide 或 Ultra Wide——在 iPhone Duo 上会解析为一颗新的虚拟前置相机。它会自动在两颗实体相机之间切换:设备打开时使用内置相机,设备合上时使用外置相机。

它始终使用最合适的相机,你无需编写切换代码。

代价是它只提供两颗实体相机都支持的功能:

  • 最高 1080p、60 fps
  • 不支持深度

如果应用需要 4K、高帧率或任何基于深度的功能,这就不够了。

单独使用相机——功能完整,切换由你负责

通过内置的外置超广角和内置的内置超广角设备类型,分别指定每颗相机:

内置(屏下)外置
最高视频规格1080p @ 60 fps4K @ 120 fps
深度支持支持

功能完整,但现在设备打开或合上时,必须由你切换相机。这就引出了棘手的问题。

相机实际朝向哪里?

AVCaptureDevice 一直都有固定的 position——在 iPhone 上为 .back 或 .front。iPhone Duo 的两颗前置相机都报告为 .front。这个属性描述相机在硬件上的位置;而在显示屏可以朝向相反方向的设备上,它已无法告诉你相机相对于正在查看界面的用户朝向哪里。

以下三种情况可以说明这一点:

  • 用户正在查看内屏,而应用正在串流外置前置相机——这是一颗朝向用户相反方向的“前置”相机。
  • 相机正在串流时设备合上,同一颗相机转向,直接朝向用户。
  • 设备处于打开状态且已翻转,因此一颗后置相机此时成了自拍相机。
AVCaptureDeviceDirectionCoordinator

AVCaptureDeviceDirectionCoordinator(位于 AVKit)可以回答真正的问题:相对于指定视图,哪些相机此刻朝向前方。使用三项内容创建一个协调器——应用的 UIView、要监控的设备类型,以及变更处理程序——它就会在设备移动时持续更新状态。

由于它锚定到一个视图,因此报告的朝向是相对于该视图所在的显示屏而言的。视图位于外屏时,外置前置相机朝向前方,后置相机朝向后方。打开设备后,视图移至内屏,处理程序会触发;此时内置前置相机朝向前方,而外置前置相机和后置相机都朝向后方。

同时驱动两个显示屏? 每个视图创建一个协调器。每个协调器都相对于自身所在的显示屏进行报告,因此,同一颗后置相机对于外屏视图的协调器而言朝向前方,对于内屏视图的协调器而言则朝向后方。这是正确的,并不矛盾——这正是该 API 的意义所在。(双显示屏相机界面使用场景配件 API;请参阅 ../iphone-duo-hinge-and-scenes/SKILL.md。)

并发

协调器与视图绑定,因此会隔离到主 Actor。你的变更处理程序不得直接调用 AVFoundation API。

它不会将 AVCaptureDevice 交给你。处理程序接收的是**AVCaptureDeviceDirectionMap**,其中将跟踪到的摄像头按顺序分为两个数组:

var forwardFacingDeviceDescriptors: [AVCaptureDeviceDescriptor]
var backwardFacingDeviceDescriptors: [AVCaptureDeviceDescriptor]

你也可以随时通过协调器的 deviceDirections 属性读取同一个映射,因此不必只在处理程序中响应变化。

AVCaptureDeviceDescriptor 是可安全传递的采集设备替代对象,包含 uniqueID、localizedName、deviceType、mediaTypes 和 position。将描述符传给摄像头 Actor,并在那里创建 AVCaptureDevice。这是预期的做法;不要试图将设备跨越隔离边界传递。

请注意,这两种类型都位于 AVKit 中,与协调器相同,而不在 AVFoundation 中——尽管你可能会首先去那里查找。

由于你获得的是数组而不是单个设备,处理程序必须自行选择:通常选择第一个朝前的描述符,其 deviceType 与当前正在进行流传输的设备类型相匹配。不要假设恰好只有一个摄像头朝前。

处理程序应执行的操作
  1. 重新配置 AVCaptureSession,以继续使用当前朝前的摄像头进行流传输。
  2. 重新评估镜像效果。镜像应遵循方向而非位置:当后置摄像头变成朝前的摄像头时,应镜像预览,使其呈现常见的自拍视图。
  3. 应用摄像头变化所需的 UI 更新。

预览优化

在内屏上显示后置摄像头的完整视野会在预览周围留下额外空间。可以考虑两种做法:偏移预览,并将控件放在剩余空间中;或者让预览填满显示屏。通过 AVCaptureVideoPreviewLayer 的 videoGravity 控制此效果。

使用超广角前置摄像头进行流传输时,可充分利用方形传感器——在 AVCaptureDevice 上设置 dynamicAspectRatio,选择能填满内屏的横向宽高比。

**旋转。**采用 AVCaptureDeviceRotationCoordinator,确保预览和拍摄内容保持正向。在 iPhone Duo 上,当应用在不同显示屏之间移动时,它会更新,因此能让两个显示屏上的旋转保持一致。采用它之后,关闭摄像头传感器方向补偿——该功能在 iPhone Duo 的所有前置摄像头上均已启用,而旋转协调器接管工作后,它就成了多余的处理。

请注意,方向协调器和旋转协调器彼此独立,分别解决不同问题。要使用哪台摄像头进行流传输,属于方向问题;其输出的朝向如何,则属于旋转问题。此设备上的大多数摄像头应用都需要同时处理这两者。

检查清单

  1. 使用 iOS 27.1 SDK 进行构建。
  2. 决定使用虚拟前置摄像头(自动切换、1080p60、无深度数据)还是单独的摄像头(完整功能、手动切换)。
  3. 如果使用单独的摄像头,采用 AVCaptureDeviceDirectionCoordinator——每个视图配置一个。
  4. 在变更处理程序中,读取 AVCaptureDeviceDirectionMap,选择一个朝前的描述符,重新配置会话,重新判断镜像设置,并更新 UI。跨 Actor 传递设备时使用 AVCaptureDeviceDescriptor。
  5. 设置 videoGravity;使用前置摄像头拍摄时,还要设置 dynamicAspectRatio。
  6. 采用 AVCaptureDeviceRotationCoordinator,然后关闭传感器方向补偿。
  7. 考虑使用 CameraCaptureAccessory,以便拍摄对象能在外屏上看到画面。
  8. 在 Device Hub 中测试会话期间打开、合上和翻转设备的情况。

Apple 的相关文档:Choosing a Camera by the Direction it Faces 和 Supporting Device Rotation in Your Camera App。关于方形传感器的一般说明,请参阅 WWDC26 的 Support the Center Stage front camera in your iOS app。

评论

支持 Markdown