AVAssetExportSession on macOS: Compatibility, Cancellation, and Finalization
Build reliable AVFoundation exports with explicit preset compatibility, modern async cancellation, temporary outputs, progress states, and verified publication.
AVAssetExportSession converts an asset into an output representation supported by an export preset and file type. It does not guarantee that every source track, codec, metadata item, or edit can be preserved in every destination. A reliable exporter asks AVFoundation about compatibility, owns its output path and cancellation policy, and does not publish a partial file as a successful result.
The preferred high-level flow for current SDKs is asynchronous: determine whether a preset can produce the requested file type, create a session, and call export(to:as:). Older callback-based configuration properties and exportAsynchronously are deprecated in current documentation. If supporting older deployment targets, isolate compatibility code behind a well-tested adapter and do not mix old and new export paths in one ambiguous state machine.
Validate the conversion before allocating output
An AVAsset describes media and may require asynchronous loading of properties. Do not assume a file extension proves the underlying container or that an asset is fully local. A remote or protected source can fail while AVFoundation loads tracks or reads samples. Check that the asset exposes the information the export operation needs and keep source-access errors separate from output-encoding errors.
Presets express an output quality or size policy; they are not a one-to-one promise about a specific codec profile. File type and preset compatibility must be tested for the actual asset. The session’s supported output types and AVFoundation’s compatibility query are authoritative for the current configuration, not a hard-coded list copied from a different Mac or OS release.
import AVFoundation
import Foundation
func exportMovie(_ asset: AVAsset, to temporaryURL: URL) async throws {
let preset = AVAssetExportPresetHighestQuality
let outputType: AVFileType = .mov
guard await AVAssetExportSession.compatibility(
ofExportPreset: preset,
with: asset,
outputFileType: outputType
) else {
throw ExportError.unsupportedCombination
}
guard let session = AVAssetExportSession(
asset: asset,
presetName: preset
) else {
throw ExportError.couldNotCreateSession
}
try await session.export(to: temporaryURL, as: outputType)
}
enum ExportError: Error {
case unsupportedCombination
case couldNotCreateSession
}
The caller supplies a unique temporary destination in a location the app can write. After export succeeds, perform any required validation and move or rename the result into its final product location. If export throws, remove or quarantine the temporary output according to the app’s recovery policy. Do not overwrite the original source unless the product has an explicit replacement flow and a recoverable backup.
Treat the export as a stateful operation
Model an export with a stable job ID and states such as validating, preparing, exporting, validating output, publishing, cancelled, and failed. Prevent a second job from accidentally reusing the same destination. Persist enough metadata to explain which source, preset, file type, time range, and app configuration produced the output, while avoiding logging private media content.
The asynchronous export method throws when it cannot complete, including cancellation. A cancelled task should not be shown as successful merely because a file exists at the destination. Cancellation is a request to stop work, not an atomic transaction guarantee for your product’s final path. This is why a unique temporary path and an explicit publication step are useful: only after success can the app make the result visible under its final name.
Current AVFoundation APIs expose export state updates. Treat progress as a user-interface estimate, not a guarantee of linear work or a durable checkpoint. Display a distinct preparing phase if the session has not started meaningful progress; do not animate a percentage to 100 before output validation has finished. Cancellation UI should disable duplicate requests and should await the operation’s completion before declaring temporary resources reusable.
For older callback APIs, the completion handler may run on an arbitrary queue. Transfer state to the appropriate actor or queue before touching AppKit or SwiftUI state. Avoid capturing a window controller strongly for an export that can outlive the window. Keep the export job in a longer-lived coordinator if the user can close the initiating document while work continues.
Time ranges, tracks, metadata, and edits
When exporting a time range, derive the range from the asset’s actual timeline and validate its duration and start. Media can use nonzero start times, gaps, or different track durations. A selection expressed in wall-clock seconds is not automatically a valid CMTimeRange for every composition. Convert carefully and handle indefinite or invalid times before creating a range.
An export preset can remove or transform tracks and metadata. If the product promises to preserve captions, alternate audio, rotation, color characteristics, location metadata, or other side data, test those requirements explicitly. Use the relevant AVFoundation composition, metadata filtering, audio mix, or lower-level writing APIs when high-level export cannot express the required behavior. Do not tell users that an export is lossless merely because the quality preset is named “highest quality.”
For edits that combine clips, transitions, or overlays, construct and validate the composition before export. Keep render instructions and source asset ownership alive for the session’s full duration. A successful session is evidence that AVFoundation wrote the requested output; it is not evidence that every product-specific visual or sound expectation was met. Decode a sample of the result and run media-specific acceptance checks.
Resource limits and failure cases
Exports can consume significant CPU, GPU, memory, and disk. Estimate available destination space where possible, reserve a bounded temporary location, and handle disk-full errors. A file-length limit can constrain certain export configurations, but it is not a substitute for capacity planning. For long jobs, provide cancellation and avoid running an unbounded number of exports concurrently.
Treat source and destination paths separately. If the source is in a security-scoped location, retain and balance the access scope for the duration of the asynchronous read. If the destination is cloud-backed or removable, a successful write operation may still need a product-level availability check before the UI claims the file is safely local. Do not move a partially written file into a synchronized destination and then infer upload completion from the local rename.
Classify errors by stage: source loading, unsupported preset/file type, session creation, export execution, cancellation, post-export validation, and final publication. Keep the underlying error domain and code for diagnostics. Make retries idempotent by using a new temporary destination and cleaning up the previous attempt. A retry should not create duplicate visible exports.
Verification and acceptance criteria
Build a fixture matrix for the formats the product claims to support: different containers, video and audio codecs, variable frame rates, multiple tracks, rotation, HDR if applicable, long and short clips, and malformed or truncated inputs. For each fixture, record the preset, output type, compatibility result, duration, dimensions, track inventory, file size, and export outcome. Test both local and remote sources if supported.
Exercise cancellation before export, during encoding, while waiting on I/O, and just before publication. Simulate no space, destination permission loss, source removal, network interruption, application termination, and a stale user selection. Confirm that an old job cannot replace a newer export and that failure cleanup never deletes the original media. Measure cold and warm latency, peak memory, CPU/GPU use, output duration, and progress-reporting delay.
AVAssetExportSession supplies an encoding workflow, not an application transaction. Compatibility checks, job ownership, bounded storage, cancellation handling, output validation, and atomic publication are the responsibilities that make an export reliable.
Keep source access and output identity stable
An export job should capture the exact source asset and requested edit revision at submission time. If a document changes while its export is running, decide whether the job exports the captured revision or is cancelled and restarted. Do not read mutable UI selection again midway through an asynchronous operation; otherwise the output can combine configuration from two different user actions.
For a user-selected source outside the app container, keep any required security-scoped access active for the complete period in which AVFoundation reads it. Balance that scope on every completion, error, and cancellation path. Likewise, acquire destination access before creating the temporary file and do not assume a path remains writable after a removable volume is ejected or a cloud provider changes availability.
Use a job record that binds source identity, asset revision, preset, file type, time range, and destination to one export attempt. When retrying, create a new attempt ID and temporary destination while retaining the previous failure information. This makes it possible to distinguish “same input retried” from “a different export request” and prevents a late completion from replacing a newer result.
Preserve and inspect important media properties
List the product’s preservation requirements before selecting the high-level export path. If the use case depends on metadata, subtitles, alternate language tracks, channel layout, color properties, chapter markers, or edit lists, inspect the exported asset rather than trusting the output file’s extension. Verify duration, track count, transform, and a sample decode after export. A metadata filter or composition change can be intentional, but it should be visible in the application’s export policy.
Do not infer source quality from the output size or selected preset. Lossy recompression can reduce quality even when the preset is named for high quality. If fidelity is the primary requirement, verify the specific codec and output settings that AVFoundation exposes for the target OS, or select a lower-level writer when the high-level exporter cannot express the contract. Test HDR and color-managed outputs on displays and decoders that represent the supported customer path.
Related:
- AVPlayer on macOS: Item Readiness, Time Observers, and Playback State
- AVCaptureSession on macOS: Device Setup, Frame Delivery, and Interruption Recovery
Sources: