📸

【iOS 17】AVFoundationに追加されたAPIを試す

2023/09/09に公開

iOS 17以降で使用可能なカメラ機能を強化するためのAPIがいくつか追加されました。追加されたAPIを使用することで、高画質な写真を連続で撮影したり、シャッターラグを防ぐことができます。 本記事では追加されたAPIについて、サンプルコードを用いながら解説します。

isAutoDeferredPhotoDeliveryEnabled

撮影した写真品質と配信速度

iOS 13以降では、AVCapturePhotoSettingphotoQualityPrioritization を使用することで、撮影する写真の配信速度と画質のバランスを調整することができます。

https://developer.apple.com/documentation/avfoundation/avcapturephotosettings/3183000-photoqualityprioritization

AVCapturePhotoOutput.QualityPrioritization.speed を設定すると、写真の画質を犠牲にしますが、写真の配信速度が向上します。
AVCapturePhotoOutput.QualityPrioritization.quality を設定すると、写真の配信速度は遅くなりますが、複数の写真フレーム合成処理と写真のノイズ低減処理が行われ、ディテールが鮮明な写真を取得することができます。

問題点

AVCapturePhotoOutput.QualityPrioritization.quality を設定すると、様々な前処理が行われた高画質の写真を取得することができますが、写真の配信速度は遅くなります。

これはシャッターのタイミングを逃してしまう可能性があり、カメラアプリにとっては致命的な問題点となることがあります。

写真が配信されるまでのプロセス

写真のキャプチャ処理を実行してから、写真が配信されるまでのプロセスを見てみます。
capturePhoto で写真のキャプチャを行うと、いくつかのデリゲートメソッドがコールされます。
例えば、写真撮影が開始される直前にphotoOutput(_:willBeginCaptureFor:)がコールされます。

https://developer.apple.com/documentation/avfoundation/avcapturephotocapturedelegate/1778621-photooutput

そして、撮影した写真が生成されると、photoOutput(_:didFinishProcessingPhoto:error:)がコールされます。

https://developer.apple.com/documentation/avfoundation/avcapturephotocapturedelegate/1778618-photooutput

photoOutput(_:didFinishProcessingPhoto:error:)が完了するまで、次のcapturePhoto は実行されません。AVCapturePhotoOutput.QualityPrioritization.quality を設定すると、photoOutput(_:didFinishProcessingPhoto:error:)がコールされる間の時間が長くなり、
連続して写真を撮影することができなくなります。

問題を解決するために追加されたAPI

この問題を解決するために、isAutoDeferredPhotoDeliveryEnabled が追加されました。

https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/4155437-isautodeferredphotodeliveryenabl

isAutoDeferredPhotoDeliveryEnabledtrue にすることで、写真の生成処理を後回しにすることができ、AVCapturePhotoOutput.QualityPrioritization.quality を使用しても、連続して写真を撮影することができるようになります。この追加されたAPIは、iOS 17以上のOSをインストールしたiPhone 11 Pro 及びiPhone 11 Pro Max以降のiPhoneで利用することができます。

また、この時AVCaptureSession オブジェクトのsessionPreset にはAVCaptureSession.Preset.photo をセットする必要があります。

新たに追加されたデリゲートメソッド

プロキシ写真を扱うためのデリゲートメソッドが追加されました。

https://developer.apple.com/documentation/avfoundation/avcapturephotocapturedelegate/4155436-photooutput?changes=_8__2

photoOutput(_:didFinishCapturingDeferredPhotoProxy:error:)
はプロキシ写真の生成が完了した後にコールされるデリゲートメソッドです。isAutoDeferredPhotoProcessingEnabledtrue にすることでコールされます。

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

通常の写真をライブラリへ保存する場合と同様に、プロキシ写真をライブラリへ保存する時もPHAssetCreationRequest を使用します。そして、addResource の引数には、
iOS 17以降で使用可能な.photoProxy を使用します。addResource の引数に.photoProxyを指定することで、保存したプロキシ写真は遅延処理が行われることをPhotoKitに対して通知します。

写真生成処理を遅延させることで、AVCapturePhotoOutput.QualityPrioritization.quality を設定している状態でも、連続してcapturePhoto を実行することができるようになりました。最終的に生成される写真は、システム側が適切なタイミングを見計らって、ライブラリに保存してくれます。

isZeroShutterLagEnabled

シャッターラグ

素早く動く人や物体を撮影した時、期待していた写真を撮影することができない場合があります。
この現象はシャッターラグが原因で発生します。

写真が生成されるまでのプロセス

capturePhoto を実行すると、キャプチャ処理が開始されます。

フレーム「5」のタイミングでcapturePhoto を実行すると、カメラのパイプラインがセンサーからフレームを取り込み始め、写真の合成処理を始めます。
キャプチャされたフレームのブラケットは、フレーム「5」以降から始まり、結果として取得した写真はフレーム「6」から「9」またはそれ以降の写真になります。

問題点

例えば、スケートボーダーを撮影する時、スケートボーダーがジャンプしたタイミングでシャッターを切ったとします。

しかし、生成された写真はスケートボーダーがジャンプしているタイミングのものではなく、既に台に着地しているタイミングの写真が生成されています。

シャッターを切ったタイミング以降のフレームを使用して、写真の合成処理が行われた結果、期待する写真を取得することができませんでした。この現象はシャッターラグと言われています。

問題を解決するために追加されたAPI

この問題を解決するために、isZeroShutterLagEnabled が追加されました。

https://developer.apple.com/documentation/avfoundation/avcapturephotooutput/4172592-iszeroshutterlagenabled?changes=_5

isZeroShutterLagEnabledtrue にすることで、過去のフレームをリングバッファとして保持します。


つまり、シャッターを切ったタイミング以降のフレームで写真を合成するのではなく、シャッターを切ったタイミング以前のフレームを使用して、写真の合成処理が行われるようになります。その結果、シャッターラグを防ぐことができます。

参考資料

・Create a more responsive camera experience
https://developer.apple.com/videos/play/wwdc2023/10105/

Discussion