Video hosted by Apple at devstreaming-cdn.apple.com

Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2026-303
$eventId
ID of event: wwdc2026
$eventContentId
ID of session without event part: 303
$eventShortId
Shortened ID of event: wwdc26
$year
Year of session: 2026
$extension
Extension of original filename: mp4
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC26 • Session 303

Build a responsive camera app that launches quickly

Photos & Camera • iOS • 25:20

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.

Speaker: Jake Baron

Open in Apple Developer site

Transcript

Hello, my name is Jake - I’m an engineer on the Camera Performance Team. Welcome to “Build a responsive camera app that launches quickly”. When launch is slow, people notice. From years of optimizing the native Camera.app, I’ve learned that the single most important factor in making a camera launch feel fast is how quickly the preview frame appears on the display. I want to capture a cool shot of my dominoes but I forgot to launch my camera before the dominoes were already falling. I’ve placed a red domino in the middle, so it’s essential that I launch and capture the moment just before the red domino falls.

As the app launches, there’s a period of blank preview. By the time preview begins rendering, I’ve already missed the red domino tumbling over. Having the preview render shortly after the app has launched allows customers to capture a quick action shot, ensuring they don’t miss the moment. I’ll help you build a camera app designed for performance. In this video, I’ll talk about 4 main topics to enhance performance. First, I’ll discuss how to accelerate a camera launch experience, so preview is up and running without a hitch.

Then, I’ll talk about best practices for rendering preview, so no frames are dropped. Third, I’ll touch on APIs that help sustain performance, even in challenging environments. Lastly, I’ll introduce a new API, designed to offer deterministic file-write performance for high data rate video captures. I’ll start with fast launch.

There are 4 stages of a camera app launch sequence. First, the app launches. This covers the time for the linker to load the binary, run static initializers, and create UIScenes, plus anything else the app does before creating a capture session. Second the session is configured and started. Initializing the capture session, committing the configuration, and starting the session all take time and system resources.

Third, once the session is started, all AVCaptureOutput objects initialize. This time varies with the number of outputs and their quality settings. Finally, preview begins streaming and frames start flowing to the app. I’ll walk through specific optimizations for each of these stages. The app’s UI plays an important role in the camera launch experience. When designing a launch flow, split the work into two phases: resources critical for launching and displaying preview and resources that can be created after preview is running.

Take AVCam for example — the classic sample camera app for AVFoundation . There are several UI elements: a camera preview, a shutter button, an image well and a mode picker. The camera preview is the most critical UI element for someone the moment they launch the app because this is what makes the camera feel like its ready to use. The image well and the mode picker aren’t needed before preview renders, so this work should wait until after preview starts.

UI elements aren’t the only factor in launch time. Any resource created before preview has rendered will influence launch time. Applying these 2 phases to AVCam, I create the shutter button and preview on launch, but fade-in all other UI elements after launch finishes. Now that the app’s impact to launch is reduced, I’ll focus on how AVCaptureSession and its related objects impact the next stage — session configuration.

Configuring and starting AVCaptureSession takes a lot of system resources and allocations that directly impact app launch. A typical AVCaptureSession consists of an AVCaptureDeviceInput, usually the Camera or Microphone. AVCaptureConnection wires the capture device to the outputs. In this example, I want two outputs - one for preview and one for capture. The AVCaptureVideoPreviewLayer is the output for displaying the preview, while the AVCapturePhotoOutput serves as the output for image captures. These objects together power an app’s camera experience.

Because AVCaptureSession coordinates all the capture objects, I want to create it first, as soon as the main thread finishes UI setup. Creating AVCaptureSession blocks the main thread. To avoid a hang, create it in parallel with UI initialization. When displaying preview on launch, dispatch AVCaptureSession creation off the main thread. This allows the session’s setup to run in the background while the app’s UIScene is being created.

Committing multiple configurations extends launch time. Commit a single configuration up front to avoid lengthy reconfigurations during launch. startRunning and stopRunning on AVCaptureSession are blocking calls. Don’t call them on the main thread, or the app will hang. Next, I’ll cover the most expensive part of camera launch — initializing AVCaptureOutputs.

Initializing AVCaptureOutputs noticeably slows down launch. To render preview, the app only needs a preview layer or one output initialized. Outputs like the MovieFileOutput and PhotoOutput aren’t needed for preview. To reduce time spent initializing outputs, adopt the Deferred start API, available in iOS 26 and later. Deferred start lets apps put off output initialization until launch has finished. In this launch sequence, all AVCaptureOutputs initialize before the first preview frame renders.

The idea with deferred start is to postpone any output that isn’t needed for launch until after preview has started. With deferred start, the launch sequence changes. The app launches, configures the session and starts it. Now only the preview output initializes before the first frame displays. The system then either runs the deferred initialization automatically, when conditions allow, or waits for the app to signal when it’s a good time. Every AVCaptureOutput and AVCaptureVideoPreviewLayer has an isDeferredStartEnabled property. Set it to true to defer that output. To optimize for launch, defer all outputs except the output used to render preview.

There are two ways to specify when deferred start runs: automatic start and manual start. Apps recompiled against the iOS 26 and later SDKs use automatic mode by default. The automaticallyRunsDeferredStart property is set to true when in this mode. In automatic mode, the system picks the best time to initialize the deferred outputs. This happens shortly after preview appears on the device. The session sends two delegate callbacks so the app knows when deferred start begins and ends. SessionWillRunDeferredStart fires before output initialization begins and SessionDidRunDeferredStart fires after it completes. Now, I’ll show how to adopt this.

First, I’ll create a class that handles the delegate callbacks from the deferred start API. SessionWillRunDeferredStart is called before deferred start begins. This is a good place to create any background resources the app needs. SessionDidRunDeferredStart is called after deferred start completes. At this point, all capture outputs are initialized and ready to use. Now, I’ll add deferred start to the captureSession.

During configuration, set automaticallyRunsDeferredStart to true on AVCaptureSession. Remember: if your app recompiled against iOS 26 and later, this is automatically set to true for you. Next, enable deferred start on every output that isn’t required for launch. Here, I defer the photo capture output and use the video preview layer to render preview.

Then, I’ll attach the delegate callback class from earlier to the capture session. The session is now configured, so I’ll commit the configuration and call startRunning. For apps that want finer control, the deferred start API also offers a manual mode, with runDeferredStartWhenNeeded. In manual mode, the app tells the system when to begin deferred start. This is useful for apps that want to read preferences or setup UI before the heavy initialization begins or for apps using VideoDataOutput to render preview, which I’ll discuss in more detail, later in this video.

With manual mode, the sequence changes. Once the app finishes start up work, such as creating non-critical resources, call runDeferredStartWhenNeeded on the capture session. This tells the system it can run deferred start. To opt into manual mode, set automaticallyRunsDeferredStart on AVCaptureSession to false. In this example, I want to render preview myself, using AVCaptureVideoDataOutput. So I’ll disable deferred start on this output. I’ll leave the rest of the code the same as the previous example.

Next, I need to decide when to run deferred start on the deferred output. To do that, I’ll track whether the first frame has been presented. Here, I’m using a CAMetalLayer. Once the first frame is presented, I’ll setup any non-critical UI elements and tell AVCaptureSession to run deferred start on the postponed outputs. After the first frame is presented, no special handling is needed.

To verify the launch is faster with deferred start, I set up a light board in the lab. My goal is to compare the difference in position of the LED pattern in preview. The phone on the right has deferred start enabled; the one on the left doesn’t. I want to capture the pattern when both the red and green LEDs are on screen. I screenshotted the moment when one device successfully shows preview. The deferred start phone on the right is clearly able to capture the expanding pattern. By the time the phone without deferred start finishes launching, the green LEDs have nearly faded out, missing that clear separation.

I also timed the launch sequence on both phones. Without deferred start, the app launch was close to a second. With deferred start, launch is cut in half! That’s a 2 times faster launch! This is a massive step forward in launch times! Preview is up and running faster than ever! For complex capture sessions, apps may see an even bigger improvement!

Deferring AVCapturePhotoOutput does have a catch. Preview starts much sooner, but the time to the first capture stays the same. Because the photo output is deferred, the system has to finish initializing it before a capture can begin. Preview is up quickly, but someone can still miss the shot. To solve this problem, set “isResponsiveCaptureEnabled” to true on AVCapturePhotoOutput. This property adds buffering between starting a capture and when processing begins, so people can capture the moment even if the photo output isn’t fully ready yet. The green phone enables responsive capture in conjunction with deferred start. As the dominoes fall, I quickly launch and take a picture.

The green phone allowed me to get a perfect shot of the dominoes, while the purple phone missed the moment. To learn more about how to use responsive capture and how to capture stunning, high resolution images, watch “Implement high resolution photo capture” from WWDC26. Once preview is running, keeping a steady frame rate and cadence is essential — otherwise the camera feels laggy. Next, I’ll share best practices for rendering preview.

Revisiting the session architecture from earlier, the easiest way to render preview is with AVCaptureVideoPreviewLayer. It shows exactly what the camera sees, directly in the app’s UI. AVCaptureVideoPreviewLayer is optimized for rendering preview. No need to process video frames in the app. AVCaptureVideoPreviewLayer does this automatically, handling tricky situations such as HDR tone-mapping. It also keeps CPU and GPU overhead low, which saves power and leaves more headroom for the UI.

And it’s tuned for low-latency preview, so the app shows what the camera sees with very little delay. As a trade-off for simplicity, AVCaptureVideoPreviewLayer does not allow for per-frame access. For apps that want more control over preview rendering, then AVCaptureVideoDataOutput is the better choice. AVCaptureVideoDataOutput takes the place of AVCaptureVideoPreviewLayer in the session architecture, and becomes the primary output for displaying frames on the device.

AVCaptureVideoDataOutput gives more control over the flow of preview, enabling apps to process individual frames. It also lets the app apply a custom UI overlay on each frame. And per-frame processing makes it easier to integrate with Metal and to analyze frame data. Use AVCaptureVideoPreviewLayer when you just need to show the camera feed. And remember, apps using AVCaptureVideoPreviewLayer are opted into automatic deferred start when recompiled against iOS 26 and later.

Use AVCaptureVideoDataOutput when per-frame processing is the priority. Deferred start doesn’t apply automatically with AVCaptureVideoDataOutput, so adopt manual deferred start to get the same launch gains. When rendering preview, keep per-frame work short. This helps avoid frame drops and keeps the experience fluid. As the device heats up, performance gets harder to maintain, because the system throttles to adapt.

Monitor the session’s performance and adjust to system conditions for a sustainable experience. Next, I’ll cover APIs that let your app monitor performance and adapt to system conditions. Revisiting the architecture from earlier, there’s a capture session, a photo output, and a preview layer. This is a fairly basic setup, but it grows in complexity as an app adds more cameras or input devices.

As complexity grows, so does the performance cost. Understanding the capture session’s cost helps you design for a sustainable experience. The hardwareCost API returns a value between 0 and 1. It tells you what share of the session’s hardware is actively in use. A value above 1 means the system can’t support the configuration.

Several things contribute to this cost. The number of cameras used. The active formats of the source devices, such as using 1080p or 4K. The frame rate of the source device’s formats. hardwareCost assumes the format’s max frame rate, so if you’re running at a lower frame rate, like 30 frames per second instead of 60 frames per second, use the frame-rate override property to reduce the cost. And lastly, the use of binned formats. Binned formats use less hardware bandwidth since these formats group pixels.

The systemPressureCost API also returns a value between 0 and 1. It represents the cost of the session’s current configuration. When it goes above 1, the configuration is unsustainable. To adjust to the current system state, monitor the systemPressureState property of AVCaptureDevice. As the system pressure state increases, consider reducing the capture device’s frame rate, or throttling any use of the GPU or Apple Neural Engine, or minimizing UI work. Use the hardwareCost and systemPressureState API after initial session setup.

After committing the configuration, check that the hardwareCost doesn’t exceed the device’s capabilities. Once hardwareCost is at or below 1, observe AVCaptureDevice’s systemPressureState and register a handler for state changes. Use this handler to adapt using the techniques I just covered. Video capture is also sensitive to performance issues once the device enters a pressured state.

Traditional file-system input/output is variable, because the system is juggling competing operations, memory fragmentation, and device storage wear. This means file input/output behavior is non-deterministic. High data-rate video captures, like ProRes, need sustained high-bandwidth input/output to record smoothly without dropping frames. To address this challenge, use AVProVideoStorage, new in iOS 27! This class tracks and manages pre-allocated storage for high data rate video captures. It’s a system-wide resource that all apps share.

AVProVideoStorage works with the existing movie-recording APIs. Applications opt in by setting usesProVideoStorage on AVCaptureMovieFileOutput or on AVAssetWriter when using AVCaptureVideoDataOutput to record content. The system handles allocation and file input / output so write performance stays consistent for high data-rate codecs. Camera Settings is updated so people can control how much storage to allocate. The remainingCapacity method reports how much storage is left. That value decreases during a recording and stops decreasing when the recording stops.

Use the openSettings method to take someone from your app to the settings UI. To use AVProVideoStorage, first check that the storage is supported. AVProVideoStorage is a singleton, so use the shared method to obtain the instance of this object. Next, create the MovieFileOutput, AVCaptureSession, AVCaptureConnections and select the format for recording.

Use the new isProVideoStorageSupported method on AVCaptureMovieFileOutput to check for compatibility. Before recording, confirm the storage is not busy resizing or servicing file creation or deletion requests. Finally, turn on ProVideoStorage on the movieOutput and start recording. During capture, the recording is written to the pre-allocated storage, and then moved to the specified location once the capture finishes. As I mentioned before, this feature also works great with AVAssetWriter.

I covered ways to optimize a camera app for launch, best practices for rendering preview, APIs for sustained performance, and how to get deterministic file-write speeds for ProRes captures. Adopt deferred start with the quality photo output — you’ll keep launch fast and get gorgeous image quality too. Analyze performance in other parts of your camera app. Use Instruments and Xcode to measure, identify and fix performance issues. And remember: most of the time you’re developing your app at a desk or in a controlled environment, but people use your app in the real world.

Test and measure performance in all conditions — like on a hot, sunny day. Lastly, watch “Create a more responsive camera experience” from WWDC23 and “Implement high resolution photo capture” from WWDC26 to learn how to integrate capture responsiveness into your app. Performance isn’t just a feature, it’s the foundation of a great camera experience. Keep optimizing and keep capturing. Thanks for watching!