2026 Audio & VideoPhotos & Camera
WWDC26 · 25 min · Audio & Video / Photos & Camera
Build a responsive camera app that launches quickly
Discover how to build a camera app that launches instantly so people never miss the perfect shot. Explore how to optimize the entire camera launch sequence — from app startup to first preview frame. Ensure your app has a polished camera experience by learning about new API’s that deliver faster launches, and best practices for smooth preview rendering and maintaining sustainable performance.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 8 snippets
Automatic deferred start delegate
import AVFoundation
class DeferredStartDelegate: NSObject, AVCaptureSessionDeferredStartDelegate {
func sessionWillRunDeferredStart(_ session: AVCaptureSession)
{
// This is called before deferred start begins for the deferred outputs
}
func sessionDidRunDeferredStart(_ session: AVCaptureSession)
{
// This is called after deferred start completes for all outputs
}
} Adopt automatic deferred start
import AVFoundation
let captureSession = AVCaptureSession()
captureSession.beginConfiguration()
captureSession.automaticallyRunsDeferredStart = true
let videoPreviewLayer = AVCaptureVideoPreviewLayer(session: captureSession)
videoPreviewLayer.isDeferredStartEnabled = false
let photoOutput = AVCapturePhotoOutput()
photoOutput.isDeferredStartEnabled = true
captureSession.addOutput(photoOutput)
captureSession.setDeferredStartDelegate(deferredStartDelegate, deferredStartDelegateCallbackQueue: sessionQueue)
captureSession.commitConfiguration()
captureSession.startRunning() Adopt manual deferred start
import AVFoundation
let captureSession = AVCaptureSession()
captureSession.beginConfiguration()
captureSession.automaticallyRunsDeferredStart = false
let videoOutput = AVCaptureVideoDataOutput()
captureSession.addOutput(videoOutput)
videoOutput.isDeferredStartEnabled = false
let photoOutput = AVCapturePhotoOutput()
photoOutput.isDeferredStartEnabled = true
captureSession.addOutput(photoOutput)
captureSession.setDeferredStartDelegate(deferredStartDelegate, deferredStartDelegateCallbackQueue: sessionQueue)
captureSession.commitConfiguration()
captureSession.startRunning() Manage runDeferredStartWhenNeeded
import AVFoundation
import QuartzCore
private var firstFramePresented = false
guard let drawable = layer.nextDrawable()
if (!firstFramePresented) {
drawable.addPresentedHandler({ drawable in
// Set up postponed UI elements
captureSession.runDeferredStartWhenNeeded()
})
firstFramePresented = true
} Enable responsive capture
import AVFoundation
func configurePhotoOutput(for session: AVCaptureSession, device: AVCaptureDevice) {
let photoOutput = AVCapturePhotoOutput()
guard session.canAddOutput(photoOutput) else { return }
session.addOutput(photoOutput)
photoOutput.maxPhotoQualityPrioritization = .quality
// Responsive capture lets the photo output capture immediately
photoOutput.isResponsiveCaptureEnabled = photoOutput.isResponsiveCaptureSupported
} Monitor for system pressure
import AVFoundation
let captureSession = AVCaptureSession()
let device = activeVideoInput?.device
captureSession.beginConfiguration()
// ...
captureSession.commitConfiguration()
guard captureSession.hardwareCost <= 1.0 else {
print("hardwareCost \(captureSession.hardwareCost) — cannot start session. Reconfiguring.")
setupLowCostConfiguration()
}
captureSession.startRunning()
let systemPressureObserver = device?.observe(\.systemPressureState,
options: [.initial, .new],
changeHandler: { /* Handle state change */ }) Manage pro video storage
import AVFoundation
func configureProVideoStorage() {
guard AVProVideoStorage.isSupported else { return }
let storage = AVProVideoStorage.shared
guard storage.remainingCapacity != 0 else {
storage.openSettings()
return
}
} Adopt AVProVideoStorage for deterministic file write speeds
import AVFoundation
guard AVProVideoStorage.isSupported else { return }
guard let pvs = AVProVideoStorage.shared else { return }
// Configure and set up AVCaptureSession, AVCaptureConnections and format
// ...
let movieOutput = AVCaptureMovieFileOutput()
guard movieOutput.isProVideoStorageSupported else { return }
guard !pvs.isBusy else { return }
let movieFileURL = FileManager.default.temporaryDirectory
.appendingPathComponent(UUID().uuidString)
.appendingPathExtension("mov")
movieOutput.usesProVideoStorage = true // Also available with AVAssetWriter
movieOutput.startRecording(to: movieFileURL, recordingDelegate: delegate) Resources
Related sessions
-
18 min -
35 min