オリジナル情報源
概要
ライブフォトは、キャプチャの直前と直後の瞬間のモーションとサウンドを含む写真です。アプリは、AVFoundationキャプチャシステムとAVCapturePhotoOutput
クラスを使用して、ライブフォトをキャプチャして記録できます。
注意
すでにキャプチャセッション、入力設定、および写真撮影に慣れていない場合は、参照キャプチャセッションの設定とキャプチャとライブ写真。
ライブ写真キャプチャを有効にする
静止写真の場合、キャプチャセッションにはビデオ入力のみが必要ですが、ライブフォトにはサウンドが含まれているため、オーディオキャプチャデバイスをセッションに接続する必要もあります。
enum CameraError: Error { case configurationFailed // ... additional error cases ... } func configureSession() throws { captureSession.beginConfiguration() // ... add camera input and photo output ... guard let audioDevice = AVCaptureDevice.default(for: .audio), let audioDeviceInput = try? AVCaptureDeviceInput(device: audioDevice) else { throw CameraError.configurationFailed } if captureSession.canAddInput(audioDeviceInput) { captureSession.addInput(audioDeviceInput) } else { throw CameraError.configurationFailed } // ... configure photo output and start running ... captureSession.commitConfiguration() }
ビデオに組み込みのカメラデバイスを既に使用しているため(「キャプチャセッションの設定」を参照)、デフォルトのオーディオキャプチャデバイスを使用できます。システムは、カメラの位置に最適なマイク構成を自動的に使用します。
Live Photosをキャプチャするには、キャプチャパイプラインの内部再構成が必要です。これには時間がかかり、進行中のキャプチャが中断されます。最初のライブ写真を撮影する前に、AVCapturePhotoOutput
オブジェクトでライブ写真のキャプチャを有効にして、パイプラインが適切に構成されていることを確認してください。
let photoOutput = AVCapturePhotoOutput() // Attempt to add the photo output to the session. if captureSession.canAddOutput(photoOutput) { captureSession.sessionPreset = .photo captureSession.addOutput(photoOutput) } else { throw CameraError.configurationFailed } // Configure the photo output's behavior. photoOutput.isHighResolutionCaptureEnabled = true photoOutput.isLivePhotoCaptureEnabled = photoOutput.isLivePhotoCaptureSupported // Start the capture session. captureSession.startRunning()
ライブ写真をキャプチャ
写真出力がLive Photosの準備ができたら、各ショットの静止画像またはLive Photoキャプチャを選択できます。ライブフォトをキャプチャするにはAVCapturePhotoSettings
オブジェクトを作成し、ライブフォトの静止画部分の形式を選択し、ライブフォトのムービー部分を書き込むためのURLを提供します。次に、キャプチャをトリガーするためにcapturePhoto(with:delegate:)
を呼び出します:
let photoSettings = AVCapturePhotoSettings(format: [AVVideoCodecKey: AVVideoCodecType.hevc]) photoSettings.livePhotoMovieFileURL = // output url // Shoot the Live Photo, using a custom class to handle capture delegate callbacks. let captureProcessor = LivePhotoCaptureProcessor() photoOutput.capturePhoto(with: photoSettings, delegate: captureProcessor)
ライブ写真の結果を処理する
ライブフォトは、写真アプリでは1つのアセットとしてユーザーに表示されますが、実際には、メインの静止画像と、前後の瞬間のモーションとサウンドを含むムービーファイルの別々のファイルで構成されています。キャプチャシステムは、それぞれが利用可能になるとすぐに、これらの結果を個別に配信します。
このphotoOutput(_:didFinishProcessingPhoto:error:)
メソッドは、Live Photoの静止画部分をAVCapturePhoto
オブジェクトとして配信します。静止画像と動画ファイルを一緒に保存する必要があるため、以下から示すように、画像ファイルのデータをAVCapturePhotoから抽出し、動画ファイルの記録が完了するまで保持することをお勧めします。(このメソッドを使用して、UIで静止画像がキャプチャされたことを示すこともできます。)
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingPhoto photo: AVCapturePhoto, error: Error?) { guard error != nil else { print("Error capturing Live Photo still: \(error!)"); return } // Get and process the captured image data. processImage(photo.fileDataRepresentation()) }
このphotoOutput(_:didFinishProcessingLivePhotoToMovieFileAt:duration:photoDisplayTime:resolvedSettings:error:)
メソッドは後で起動し、キャプチャのトリガー時に指定したURLに完全なムービーファイルが含まれていることを示します。ライブ写真の静止画と動画の両方の部分を取得したら、それらを一緒に保存できます。
func photoOutput(_ output: AVCapturePhotoOutput, didFinishProcessingLivePhotoToMovieFileAt outputFileURL: URL, duration: CMTime, photoDisplayTime: CMTime, resolvedSettings: AVCaptureResolvedPhotoSettings, error: Error?) { guard error != nil else { print("Error capturing Live Photo movie: \(error!)"); return } guard let stillImageData = stillImageData else { return } // Save Live Photo. saveLivePhotoToPhotosLibrary(stillImageData: stillImageData, livePhotoMovieURL: outputFileURL) }
注意
キャプチャ後にLive Photosを表示するには、PHLivePhoto
およびPHLivePhotoView
を参照してください。
ライブ写真をフォトライブラリに保存する
PHAssetCreationRequest
クラスを使用して、複数のファイルのメディアで構成される単一のPhotosアセットを作成します。LivePhotoの場合、静止画像とそのペアのビデオです。キャプチャした写真の保存と同様に、そのリクエストをPHPhotoLibrary
変更ブロックでラップし、最初にアプリが写真にアクセスするユーザーの権限を持っていることを確認する必要があります。
func saveLivePhotoToPhotosLibrary(stillImageData: Data, livePhotoMovieURL: URL) { PHPhotoLibrary.requestAuthorization { status in guard status == .authorized else { return } PHPhotoLibrary.shared().performChanges({ // Add the captured photo's file data as the main resource for the Photos asset. let creationRequest = PHAssetCreationRequest.forAsset() creationRequest.addResource(with: .photo, data: stillImageData, options: nil) // Add the movie file URL as the Live Photo's paired video resource. let options = PHAssetResourceCreationOptions() options.shouldMoveFile = true creationRequest.addResource(with: .pairedVideo, fileURL: livePhotoMovieURL, options: options) }) { success, error in // Handle completion. } } }
ヒント
このshouldMoveFile
オプションを使用して、iOSがアプリのサンドボックスからシステムのフォトライブラリにムービーファイルを転送します。高価なデータのコピー操作は必要ありません。
ライブ写真の進行状況を追跡する
Live Photosをキャプチャすると、「写真キャプチャの進行状況の追跡」に示すプロセスに2つの追加ステップが追加されます。静止画の結果の配信(ステップ4)の後、写真出力はムービーキャプチャステータスを通知し(ステップ5)、ムービー結果を配信します(ステップ6) )。(最終クリーンアップはステップ7になります。)
ユーザーがシステムのカメラアプリでライブ写真をキャプチャすると、「ライブ」インジケーターが数秒間表示され、ビデオとオーディオがまだ記録されていることをユーザーに知らせます。アプリに同様のインターフェイスを提供するには、写真キャプチャデリゲートに次のメソッドを実装します。
- この
photoOutput(_:willBeginCaptureFor:)
メソッドは、キャプチャが開始したことを通知します。このメソッドを実装して、記録インジケータを表示します。 - この
photoOutput(_:didFinishRecordingLivePhotoMovieForEventualFileAt:resolvedSettings:)
メソッドは、Live Photoムービーが記録されなくなったことを通知します。このメソッドを実装して、インジケーターを非表示にします。(現時点では、ムービーファイルはまだ使用できません。)
複数のライブフォトキャプチャを同時に実行できるため、これらの方法を使用して、「処理中」のキャプチャの数を追跡し、その数がゼロに達した場合にのみインジケータを非表示にするのが最善です。
class LivePhotoCaptureProcessor: NSObject, AVCapturePhotoCaptureDelegate { // ... other PhotoCaptureDelegate methods and supporting properties ... // A handler to call when Live Photo capture begins and ends. var livePhotoStatusHandler: (Bool) -> () = { _ in } // A property for tracking in-progress captures and updating UI accordingly. var livePhotosInProgress = 0 { didSet { // Update the UI accordingly based on the value of this property } } // Call the handler when PhotoCaptureDelegate methods indicate Live Photo capture is in progress. func photoOutput(_ output: AVCapturePhotoOutput, willBeginCaptureFor resolvedSettings: AVCaptureResolvedPhotoSettings) { let capturingLivePhoto = (resolvedSettings.livePhotoMovieDimensions.width > 0 && resolvedSettings.livePhotoMovieDimensions.height > 0) livePhotoStatusHandler(capturingLivePhoto) } func photoOutput(_ output: AVCapturePhotoOutput, didFinishRecordingLivePhotoMovieForEventualFileAt outputFileURL: URL, resolvedSettings: AVCaptureResolvedPhotoSettings) { livePhotoStatusHandler(false) } }