WWDC Quick Look 💓 By SwiftGGTeam
Create a more responsive camera experience

Create a more responsive camera experience

元の動画を見る

ハイライト

iOS 17 では AVCapturePhotoOutput に遅延写真処理、ゼロシャッターラグ、レスポンシブキャプチャの 3 つの新 API が導入され、Deep Fusion の最高画質を維持しながら、より速い連写とより短いシャッター遅延を実現できます。

主要内容

シャッターを押したあと処理完了を待たないと次の 1 枚が撮れないのは、撮影の雰囲気を台無しにします。Deep Fusion によるディテール向上は目に見えており、羽の質感やひげの細部まで鮮明です。しかし処理は同期的で、完了するまで次の撮影を開始できません。

01:43)iOS 17 以前は、開発者は画質と速度のどちらかを選ぶ必要がありました。quality 優先度を選べば最高画質ですが shot-to-shot 時間が長くなり、balancedspeed を選べば画質を犠牲にして速度を得ます。

Apple の今年の解決策は、処理をカメラセッション終了後に延期することです。

遅延写真処理

01:43)遅延写真処理(Deferred Photo Processing)の核心は、撮影時に軽量なプロキシ写真を返してユーザーが撮影を続けられるようにし、本当の Deep Fusion 処理はバックグラウンドで行い、ユーザーがカメラアプリを終了した後に実行することです。

このプロキシ写真はプレースホルダーとしてフォトライブラリに保存されます。ユーザーが後で表示や共有する際、システムはオンデマンドで処理を完了するか、デバイスがアイドル時にバックグラウンドで自動完了します。

ゼロシャッターラグ

16:03)もう一つのよくある課題はシャッター遅延です。シャッターを押したときのファインダー画面と、実際に撮れた画面が異なります。30fps では各フレームは 33 ミリ秒しか表示されませんが、ベストショットを逃すのに十分です。

ゼロシャッターラグ(Zero Shutter Lag)はリングバッファで過去のフレームデータを保持します。シャッターを押すと、カメラは「時間を遡り」、押した瞬間のフレームをバッファから取り出して写真を合成します。

レスポンシブキャプチャ

19:44)レスポンシブキャプチャ(Responsive Capture)では撮影フェーズと処理フェーズを重ねられます。1 枚目がまだ処理中でも、2 枚目の撮影リクエストを開始できます。連写速度が大幅に向上します。

高速撮影優先度(Fast Capture Prioritization)と組み合わせると、ユーザーが素早く連写していると検出し、画質を最高からバランスに自動で下げ、安定した shot-to-shot 時間を維持します。

ビデオエフェクトとリアクションジェスチャー

27:07)macOS Sonoma ではビデオエフェクトがコントロールセンターから専用メニューに移動しました。Portrait と Studio Light エフェクトは強度を調整可能になりました。新しいリアクション(Reactions)はジェスチャートリガーに対応し、親指立て、親指下げ、ハート、ピースサインなどで、ビデオ上に風船、花火、レーザーなどのアニメーションを描画します。

詳細

遅延写真処理の有効化

05:46AVCapturePhotoOutput の設定時に遅延処理を確認して有効化します:

// 遅延写真処理に対応しているか確認
if photoOutput.isAutoDeferredPhotoDeliverySupported {
    photoOutput.isAutoDeferredPhotoDeliveryEnabled = true
}

キーポイント:

  • isAutoDeferredPhotoDeliverySupported で現在のデバイスが対応しているか確認
  • isAutoDeferredPhotoDeliveryEnabled をオンにすると、カメラが遅延処理に適した写真を自動判定
  • 枚ごとの設定は不要。システムが自動処理

プロキシ写真のフォトライブラリへの保存

07:42)撮影完了後、新しいプロキシコールバックで写真を保存します:

func photoOutput(_ output: AVCapturePhotoOutput,
                 didFinishCapturingDeferredPhotoProxy deferredPhotoProxy: AVCaptureDeferredPhotoProxy?,
                 error: Error?) {
    guard error == nil, let proxy = deferredPhotoProxy else { return }
    
    PHPhotoLibrary.shared().performChanges {
        let request = PHAssetCreationRequest.forAsset()
        request.addResource(with: .photoProxy,
                           data: proxy.fileDataRepresentation()!,
                           options: nil)
    } completionHandler: { success, error in
        // 完了コールバックを処理
    }
}

キーポイント:

  • didFinishCapturingDeferredPhotoProxy コールバックでプロキシ写真を受信
  • PHAssetResourceType.photoProxy で PhotoKit に遅延処理が必要な写真であることを伝える
  • アプリがサスペンドされてデータが失われないよう、プロキシデータは速やかにフォトライブラリへ保存

処理中の写真のリクエスト

09:43)ユーザーが処理中の写真を表示する際、二次劣化画像を有効にできます:

let options = PHImageRequestOptions()
options.allowSecondaryDegradedImage = true

PHImageManager.default().requestImage(for: asset,
                                       targetSize: targetSize,
                                       contentMode: .aspectFit,
                                       options: options) { image, info in
    if let info = info {
        if info[PHImageResultIsDegradedKey] as? Bool == true {
            // 中間品質の画像を表示
        } else {
            // 最終画像を表示
        }
    }
}

キーポイント:

  • allowSecondaryDegradedImage は低品質プレースホルダーと最終画像の間に中品質画像を提供
  • 2 つの劣化画像はどちらも PHImageResultIsDegradedKey でマークされる
  • 最終画像にはこのフラグは付かない

ゼロシャッターラグ

18:24)ゼロシャッターラグは iOS 17 でデフォルト有効。iOS 17 SDK にリンクしたアプリは自動で対応。無効にする場合:

// 対応状況を確認
if photoOutput.isZeroShutterLagSupported {
    photoOutput.isZeroShutterLagEnabled = false // デフォルトは true
}

キーポイント:

  • isHighestPhotoQualitySupported が true の preset/format のみ対応
  • フラッシュ、手動露出、ブラケット露出、マルチカメラ同期撮影はゼロシャッターラグ非対応
  • タップイベントから capturePhoto 呼び出しまでの遅延を最小化

レスポンシブキャプチャとレディネスコーディネータ

21:31)レスポンシブキャプチャを有効化:

// 先にゼロシャッターラグを有効化する必要があります
if photoOutput.isResponsiveCaptureSupported {
    photoOutput.isResponsiveCaptureEnabled = true
}

// 高速撮影優先度
if photoOutput.isFastCapturePrioritizationSupported {
    photoOutput.isFastCapturePrioritizationEnabled = true
}

レディネスコーディネータでシャッターボタンの状態を管理:

let readinessCoordinator = AVCapturePhotoOutputReadinessCoordinator(photoOutput: photoOutput)
readinessCoordinator.delegate = self

// 撮影前にコーディネーターへ通知
readinessCoordinator.startTrackingCaptureRequest(using: photoSettings)
photoOutput.capturePhoto(with: photoSettings, delegate: self)

// デリゲートメソッドを実装
func readinessCoordinator(_ coordinator: AVCapturePhotoOutputReadinessCoordinator,
                         captureReadinessDidChange captureReadiness: AVCapturePhotoOutput.CaptureReadiness) {
    switch captureReadiness {
    case .ready:
        shutterButton.isEnabled = true
    case .notReadyMomentarily:
        shutterButton.isEnabled = false
    case .notReadyWaitingForCapture:
        shutterButton.isEnabled = false // フラッシュ充電中
    case .notReadyWaitingForProcessing:
        shutterButton.isEnabled = false // 処理中
    default:
        break
    }
}

キーポイント:

  • AVCapturePhotoOutputReadinessCoordinator が撮影レディ状態の変化を監視
  • .notReadyWaitingForCapture はセンサーからのフレーム取得待ち(フラッシュなど)
  • .notReadyWaitingForProcessing は処理中
  • レスポンシブキャプチャを使わなくてもレディネスコーディネータは利用可能

ビデオリアクションエフェクト

29:59)iOS では Info.plist でリアクションエフェクト対応を宣言する必要があります:

<key>NSCameraReactionEffectsEnabled</key>
<true/>

または VoIP バックグラウンドモードを宣言:

<key>UIBackgroundModes</key>
<array>
    <string>voip</string>
</array>

リアクションエフェクトのトリガー:

// デバイスがリアクションエフェクトに対応しているか確認
if device.activeFormat.reactionEffectsSupported {
    // エフェクトをトリガー
    device.performEffect(for: .thumbsUp)
}

// システムアイコンを取得
let imageName = AVCaptureReactionType.thumbsUp.systemImageName
let image = UIImage(systemName: imageName)

// エフェクト実行中の状態を監視
// reactionEffectsInProgress は AVCaptureReactionEffectStatus 配列を返します

キーポイント:

  • AVCaptureReactionType には thumbsUp、thumbsDown、balloons、heart、fireworks、rain、confetti、lasers が含まれる
  • systemImageName で対応するシステムアイコンを取得
  • ジェスチャートリガーのエフェクト位置はプログラムトリガーと異なる場合がある
  • エフェクト実行中はフレームレートが 60fps から 30fps に下がる場合がある

重要ポイント

1. カメラアプリに「プロ連写モード」を追加

何を作るか: レスポンシブキャプチャ API で秒間 4〜5 枚の高速連写モードを実装。

なぜ価値があるか: 従来のカメラアプリは Deep Fusion 処理時間に制限され連写速度が限られる。レスポンシブキャプチャで処理と撮影を重ね、アクションの瞬間を逃さない。

始め方: isResponsiveCaptureEnabledisFastCapturePrioritizationEnabled を有効化し、AVCapturePhotoOutputReadinessCoordinator でシャッターボタン状態を管理。明確な撮影フィードバックを提供。

2. 「ゼロ待ち」カメラアプリを構築

何を作るか: 遅延写真処理とゼロシャッターラグを組み合わせ、シャッターを押した瞬間に撮れるカメラアプリ。

なぜ価値があるか: Deep Fusion の画質と高速連写はもはや矛盾しない。プロキシ写真は即利用可能、最終処理はバックグラウンドで完了。

始め方: AVCapturePhotoOutputisAutoDeferredPhotoDeliveryEnabled を有効化し、didFinishCapturingDeferredPhotoProxy を処理してプロキシをフォトライブラリに保存。ゼロシャッターラグはデフォルト有効で追加設定不要。

3. ビデオ通話アプリにリアクションエフェクトパネルを追加

何を作るか: ビデオ通話やライブ配信アプリにリアクションエフェクトボタンパネルを追加し、ハートや花火などを送信可能に。

なぜ価値があるか: リアクションエフェクトはシステムレベル機能で、コンピュータビジョンやアニメーション描画を自前実装する必要がない。ジェスチャーまたはアプリ内ボタンでトリガー可能。

始め方: Info.plist で NSCameraReactionEffectsEnabled を宣言し、AVCaptureReactionType.systemImageName でボタンアイコンを取得、performEffect(for:) でトリガー。KVO で reactionEffectsInProgress を監視しリモート側にエフェクトアイコンを表示。

4. スマート画質適応を実装

何を作るか: ユーザーの撮影行動に応じて画質優先度を動的調整。高速連写時は画質を下げて速度維持、単発撮影時は最高画質。

なぜ価値があるか: isFastCapturePrioritizationEnabled にロジックは組み込まれているが、UI 層でユーザーにより多くの制御を与えられる。

始め方: AVCapturePhotoOutputReadinessCoordinator の状態変化を観察し、撮影頻度と組み合わせ、設定で「速度優先」「画質優先」オプションを提供。

関連セッション

コメント

GitHub Issues · utterances