# How ExportService Handles Different Export Formats in Palmier Pro

> Discover how Palmier Pro's ExportService manages XML and video exports. Learn about its use of XMLExporter and AVAssetExportSession with hardware acceleration.

- Repository: [Palmier/palmier-pro](https://github.com/palmier-io/palmier-pro)
- Tags: internals
- Published: 2026-06-23

---

**The `ExportService` class centralizes export logic in Palmier Pro by routing XML exports through a dedicated `XMLExporter` while processing video formats (H.264, H.265, and ProRes) through `AVAssetExportSession` with hardware-accelerated presets mapped via `exportPresetName(format:resolution:)`.**

The Palmier Pro repository manages all export operations within [`Sources/PalmierPro/Export/ExportService.swift`](https://github.com/palmier-io/palmier-pro/blob/main/Sources/PalmierPro/Export/ExportService.swift). This service accepts an `ExportFormat` enum—defining `h264`, `h265`, `prores`, and `xml` cases—alongside a target resolution and output URL, then executes format-specific branching logic to ensure optimal file generation.

## Export Format Architecture

The `ExportFormat` enum defines both the file extension and the AVFoundation type required for each supported format. According to the source code at lines 4-21, each case provides a `utType` property that maps to `AVFileType` for video exports, while the `xml` case returns `nil` to trigger the specialized XML pipeline.

```swift
enum ExportFormat {
    case h264, h265, prores, xml
    var fileExtension: String { … }
    var utType: AVFileType? { … }
}

```

## XML Export: The Fast Path

When the service receives `format == .xml`, it bypasses AVFoundation entirely. At lines 90-99, the `export()` method immediately delegates to `XMLExporter.export(...)`, which generates a Final Cut Pro 7 compatible XMEML-4 file using a pure-Swift XML builder.

This path sets `progress = 1.0` instantly upon completion, avoiding the overhead of video composition and encoding. The `ExportResolution` parameter is ignored for XML exports, as the XML contains only metadata and edit decision lists rather than rendered pixels.

## Video Export: AVAssetExportSession Pipeline

For H.264, H.265, and ProRes formats, `ExportService` enters a comprehensive export pipeline that leverages `AVAssetExportSession`. The process begins at lines 102-107 by setting `isExporting = true` and resetting progress tracking.

The service constructs the export session through `makeExportSession(...)`, which builds an `AVComposition` via `CompositionBuilder.build` and selects an appropriate preset based on the format and resolution combination.

### Format-Specific Preset Mapping

The private method `exportPresetName(format:resolution:)` (lines 64-87) maps each format and resolution to a specific AVFoundation preset string:

- **H.264**: Uses `AVAssetExportPreset1280x720` for 720p, `AVAssetExportPreset1920x1080` for 1080p, `AVAssetExportPreset3840x2160` for 4K, and `AVAssetExportPresetHighestQuality` for 2K or native resolutions.
- **H.265 (HEVC)**: Maps to `AVAssetExportPresetHEVCHighestQuality` for 720p and 2K/native, `AVAssetExportPresetHEVC1920x1080` for 1080p, and `AVAssetExportPresetHEVC3840x2160` for 4K.
- **ProRes**: Applies `AVAssetExportPresetAppleProRes422LPCM` uniformly across all resolutions, ensuring professional-grade quality with LPCM audio.

### File Preparation and Progress Monitoring

Before writing, the service removes any existing file at the output URL (lines 25-27) because `AVAssetExportSession` cannot overwrite existing files. It then initiates a lightweight `Task` that polls `session.progress` every 200 milliseconds to update the observable `progress` property (lines 29-35).

The actual export executes at lines 38-40 using `session.export(to:outputURL, as:fileType)`, where `fileType` derives from `format.utType`.

## Error Handling and Cancellation

The service distinguishes between user cancellation and system failures. When catching errors at lines 45-60, it checks for `NSUserCancelledError` to handle cancellation gracefully, while other errors trigger `Log.export.error` logging and storage in `self.error`.

Two specific error types can bubble up during initialization:
- `ExportError.invalidFormat` occurs if a format's `utType` is unexpectedly `nil`.
- `ExportError.unsupportedPreset` triggers when the system cannot create the requested export preset.

## Code Examples

### Exporting to H.264 at 1080p

```swift
let service = ExportService()
await service.export(
    timeline: myTimeline,
    resolver: myResolver,
    format: .h264,
    resolution: .r1080p,
    outputURL: URL(fileURLWithPath: "/Users/me/Movies/project.mp4")
)
// Progress observable via service.progress

```

This invocation creates an `AVAssetExportSession` configured with `AVAssetExportPreset1920x1080`.

### Generating Final Cut Pro XML

```swift
let service = ExportService()
await service.export(
    timeline: myTimeline,
    resolver: myResolver,
    format: .xml,
    resolution: .native, // Ignored for XML
    outputURL: URL(fileURLWithPath: "/Users/me/Exports/project.xml")
)

```

The service detects `.xml` and routes to `XMLExporter.export`, completing instantly with `progress` set to 1.0.

### Handling Export Errors

```swift
await service.export(…)
if let error = service.error {
    print("Export failed: \(error)")
}

```

Errors are captured in `service.error` and logged through the `Log.export` channel.

## Summary

- **Branching Logic**: `ExportService` separates XML exports (handled by [`XMLExporter.swift`](https://github.com/palmier-io/palmier-pro/blob/main/XMLExporter.swift)) from video exports (using `AVAssetExportSession`).
- **Preset Mapping**: Format and resolution combinations map to specific AVFoundation presets via `exportPresetName(format:resolution:)`.
- **Progress Tracking**: A 200ms polling Task updates the `progress` property during video exports.
- **Error Safety**: The service validates `utType` before export and handles file-overwrite constraints by deleting existing files first.
- **Hardware Acceleration**: Video formats leverage macOS 26 hardware encoders through standardized AVFoundation presets.

## Frequently Asked Questions

### What is the difference between XML and video export paths in ExportService?

Video exports require `AVAssetExportSession` initialization, composition building, and asynchronous encoding with progress monitoring. XML exports follow a synchronous path through `XMLExporter.export`, which generates a Final Cut Pro 7 compatible XMEML file without creating any AVFoundation sessions, resulting in immediate completion.

### How does ExportService handle unsupported format combinations?

If the `ExportFormat` enum produces a `nil` `utType` (which only occurs for XML, handled separately), the service throws `ExportError.invalidFormat`. If the system cannot create an export preset for the requested format and resolution, `ExportError.unsupportedPreset` bubbles up from `makeExportSession`.

### Why does ExportService delete the output file before exporting?

`AVAssetExportSession` throws an error when attempting to write to a path that already exists. At lines 25-27, `ExportService` preemptively removes existing files using `FileManager.default.removeItem(at:outputURL)` to ensure the export operation can proceed without manual cleanup.

### Does ProRes export support different quality presets per resolution?

No. According to the implementation in `exportPresetName(format:resolution:)`, ProRes exports use `AVAssetExportPresetAppleProRes422LPCM` for all resolutions. This Apple preset provides consistent 422 quality with LPCM audio regardless of the target resolution parameter.