iphone-duo-camera について
iPhone Duo向けカメラアプリ開発者のためのガイドです。前面カメラの選択、表示視点に応じた向きの判定、プレビュー処理を説明します。
主な機能
- 01仮想カメラと個別カメラの比較
- 02ビュー基準でカメラの向きを判定
- 03カメラ記述子をアクター間で受け渡し
- 04ミラーリング、プレビュー、回転の処理
活用シーン
- 01iPhone Duoで自撮りカメラを切り替え
- 02開閉時にキャプチャセッションを再構成
- 032画面でカメラの向きを連携
- 04プレビュー調整と映像の正立維持
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ mirzaaghazadeh/ iphone-duo-skills --skill iphone-duo-cameraインストール後、Claude Code で/iphone-duo-cameraを入力して読み込まれたか確認します。
詳細
iPhone Duo のカメラ
iPhone Duo は、前面カメラを2つ搭載した初めての iPhone です。どちらも超広角の視野を持つ正方形のセンサーで、1つは外側のディスプレイに、もう1つは内側のディスプレイの下にあります。iPhone 初のディスプレイ下カメラです。
そのため、これまでの iPhone にはなかった問題が生じます。「前面」は、もはや「ユーザーに向いている」という意味ではありません。
まず方針を選ぶ
以降のすべては、この選択に左右されます。
仮想前面カメラ — 自動切り替え、機能は限定的
通常の方法で前面カメラを検出します。つまり、位置 .front と Wide または Ultra Wide のデバイスタイプを指定して AVCaptureDevice.DiscoverySession をリクエストすると、iPhone Duo では新しい仮想前面カメラが取得されます。物理カメラは自動で切り替わり、デバイスを開いているときは内側のカメラ、閉じているときは外側のカメラが使われます。
常に最適なカメラが使われるため、切り替えコードを書く必要はありません。
ただし、利用できる機能は、2つの物理カメラの両方が対応するものに限られます。
- 最大 1080p、60 fps
- 深度なし
アプリで 4K、高フレームレート、または深度ベースの機能が必要な場合、この方法では不十分です。
個別のカメラ — 全機能を利用可能、自分で切り替えが必要
内蔵の外側超広角カメラと内蔵の内側超広角カメラのデバイスタイプを使って、それぞれのカメラを指定します。
| 内側(ディスプレイ下) | 外側 | |
|---|---|---|
| 最大ビデオ | 1080p @ 60 fps | 4K @ 120 fps |
| 深度 | 対応 | 対応 |
すべての機能を利用できますが、デバイスを開閉したときにカメラを切り替えるのはあなたの役割です。ここからが難しいところです。
カメラは実際にどちらを向いているのか?
AVCaptureDevice の position は、常に固定値でした。iPhone では .back または .front です。iPhone Duo の前面カメラはどちらも .front を返します。このプロパティが示すのは、カメラがハードウェア上のどこにあるかです。ディスプレイを反対方向に向けられるデバイスでは、カメラがUI を見ている人に対してどちらを向いているかは、もはや分かりません。
次の3つの状況を考えると、この問題が具体的に分かります。
- ユーザーが内側のディスプレイを見ている一方で、アプリが外側の前面カメラの映像を配信している場合。「前面」カメラがユーザーとは反対方向を向いています。
- そのカメラで配信中にデバイスを閉じると、同じカメラが回り込んでユーザーを直接向きます。
- デバイスを開いた状態で裏返すと、背面カメラが自撮り用カメラになります。
AVCaptureDeviceDirectionCoordinator
AVCaptureDeviceDirectionCoordinator(AVKit 内)は、本当の疑問に答えてくれます。つまり、指定したビューに対して、カメラが現在どちらを向いているかを判定します。アプリの UIView、監視するデバイスタイプ、変更ハンドラーの3つを指定して作成すると、デバイスの動きに合わせて最新の状態を維持します。
ビューを基準にするため、カメラの向きは、そのビューがあるディスプレイに対する向きとして報告されます。ビューが外側のディスプレイにあるときは、外側の前面カメラが前向き、背面カメラが後ろ向きとして扱われます。デバイスを開くと、ビューは内側のディスプレイに移動し、ハンドラーが呼び出されます。すると、内側の前面カメラが前向きになり、外側の前面カメラと背面カメラは後ろ向きになります。
両方のディスプレイを同時に操作しますか? ビューごとに1つずつコーディネーターを作成してください。それぞれが自身のディスプレイを基準に報告するため、同じ背面カメラでも、外側のビューのコーディネーターに対しては前向き、内側のビューのコーディネーターに対しては後ろ向きになります。これは矛盾ではなく、まさにこの仕組みの目的です。(デュアルディスプレイのカメラ UI には、シーンアクセサリ API を使用します。詳しくは ../iphone-duo-hinge-and-scenes/SKILL.md を参照してください。)
並行処理
コーディネーターはビューに紐づいているため、メインアクターに分離されています。変更ハンドラーから AVFoundation API を直接呼び出してはいけません。
AVCaptureDevice が渡されることはありません。ハンドラーが受け取るのは AVCaptureDeviceDirectionMap で、追跡対象のカメラを次の 2 つの配列に分類します。
var forwardFacingDeviceDescriptors: [AVCaptureDeviceDescriptor]
var backwardFacingDeviceDescriptors: [AVCaptureDeviceDescriptor]
同じマップは、コーディネーターの deviceDirections プロパティからいつでも読み取れるため、ハンドラー内での応答に限られるわけではありません。
AVCaptureDeviceDescriptor は、キャプチャデバイスの代わりに使える送信可能な値で、uniqueID、localizedName、deviceType、mediaTypes、position を持ちます。ディスクリプターをカメラアクターに渡し、そこで AVCaptureDevice を構築してください。これが想定された方法です。境界を越えてデバイスを渡そうとしないでください。
なお、これら 2 つの型は AVFoundation ではなく、コーディネーターと同じ AVKit にあります。最初に探す場所として AVFoundation を思い浮かべるかもしれませんが、そこにはありません。
単一のデバイスではなく 配列 が渡されるため、ハンドラーで選択する必要があります。通常は、ストリーミング対象の deviceType と一致する、前向きのディスクリプターのうち最初のものを選びます。前向きのカメラが必ず 1 台だけだと思い込まないでください。
ハンドラーで行うこと
- 現在前向きになっているカメラからストリーミングを続けられるように、
AVCaptureSessionを再構成します。 - ミラーリングを再評価します。ミラーリングは位置ではなく、向きに合わせます。背面カメラが前向きになった場合は、通常の自撮りビューのように感じられるよう、プレビューをミラーリングします。
- カメラの変更に伴う UI の更新を適用します。
プレビューの仕上げ
内側のディスプレイに背面カメラの視野全体をストリーミングすると、プレビューの周囲に余白ができます。妥当な選択肢は 2 つあります。プレビューの位置をずらして空いたスペースにコントロールを配置するか、プレビューでディスプレイ全体を埋めるかです。AVCaptureVideoPreviewLayer の videoGravity で調整します。
超広角の前面カメラをストリーミングする場合は、正方形のセンサーを活用します。AVCaptureDevice の dynamicAspectRatio を設定し、内側のディスプレイいっぱいに表示できる横長のアスペクト比を選びます。
回転。 プレビューとキャプチャを正しい向きに保つため、AVCaptureDeviceRotationCoordinator を採用してください。iPhone Duo では、アプリがディスプレイ間を移動すると更新されるため、両方のディスプレイで回転が一貫します。採用した後は、カメラセンサーの向きの補正をオフにしてください。iPhone Duo の前面カメラではすべて有効になっていますが、回転コーディネーターが処理を行うようになると重複した処理になります。
向きと回転は、それぞれ別の問題を解決する別々のコーディネーターであることに注意してください。どのカメラをストリーミングするかは向き、その出力をどの向きにするかは回転です。このデバイス向けのカメラアプリでは、通常どちらも必要です。
チェックリスト
- iOS 27.1 SDK を対象にビルドします。
- 仮想前面カメラ(自動切り替え、1080p60、深度なし)と個別のカメラ(すべての機能に対応、手動切り替え)のどちらにするか決めます。
- 個別のカメラを使う場合は、ビューごとに 1 つの
AVCaptureDeviceDirectionCoordinatorを採用します。 - 変更ハンドラーで
AVCaptureDeviceDirectionMapを読み取り、前向きのディスクリプターを選択し、セッションを再構成して、ミラーリングを再判断し、UI を更新します。アクター間ではデバイスをAVCaptureDeviceDescriptorとして渡します。 videoGravityを設定し、前面カメラでキャプチャする場合はdynamicAspectRatioも設定します。AVCaptureDeviceRotationCoordinatorを採用してから、センサーの向きの補正を無効にします。- 被写体が外側のディスプレイに何かを表示できるよう、
CameraCaptureAccessoryの採用を検討します。 - Device Hub で、セッション中にデバイスを開く、閉じる、反転する操作をテストします。
Apple の関連記事:向いている方向に基づいてカメラを選択する と カメラアプリでデバイスの回転に対応する。正方形センサー全般については、WWDC26 の iOS アプリで Center Stage 前面カメラに対応する を参照してください。