How Palmier Pro's Export Pipeline Handles Timeline Composition and Format Conversion
Palmier Pro's export pipeline operates in two distinct phases: first composing raw media tracks into an AVMutableComposition with synchronized audio mixes and custom video compositions, then converting the assembled asset to the target format using either AVAssetExportSession for video codecs or XMLExporter for Final Cut Pro and Premiere interchange formats.
Palmier Pro is an open-source Swift framework for building professional video editing applications, maintained in the palmier-io/palmier-pro repository. Understanding how its export pipeline handles timeline composition and format conversion is essential for developers integrating custom export workflows or troubleshooting media processing bottlenecks. The architecture cleanly separates timeline assembly from encoding concerns, enabling support for everything from H.264 MP4s to FCPXML interchange files.
Export Entry Point and Format Routing
The export process begins in Sources/PalmierPro/Export/ExportService.swift, where the export method acts as a router between video encoding and XML serialization paths.
// Sources/PalmierPro/Export/ExportService.swift
func export(
timeline: Timeline,
resolver: MediaResolver,
format: ExportFormat,
resolution: ExportResolution,
fcpxmlVersion: FCPXMLVersion = .default,
missingMediaRefs: Set<String> = [],
outputURL: URL,
acquireSlot: Bool = true
) async {
// XML-only formats return early
if format == .xml || format == .fcpxml {
try await XMLExporter.export(timeline: timeline,
resolver: resolver,
outputURL: outputURL)
return
}
// … otherwise build a full AVFoundation composition
let prepared = try await makeExportSession(
timeline: timeline, resolver: resolver,
format: format, resolution: resolution,
missingMediaRefs: missingMediaRefs)
// Export logic continues...
}
According to the Palmier Pro source code at lines 32-71, the method immediately shortcuts to XMLExporter for .xml or .fcpxml formats. For video formats like .h264, .h265, or .prores, it proceeds to makeExportSession, which orchestrates the timeline composition phase before handing off to AVAssetExportSession.
Timeline Composition Phase
The timeline composition phase transforms the abstract timeline model into a concrete AVMutableComposition ready for encoding. This logic lives in Sources/PalmierPro/Preview/CompositionBuilder.swift.
Source Asset Loading and Validation
The CompositionBuilder.build method (lines 34-124) first validates timeline dimensions and frame rate, then iterates through each track to assemble media. For each clip, it resolves the source URL and handles type-specific processing:
- Images are converted to video via
ImageVideoGenerator - Lottie animations are rendered via
LottieVideoGenerator - Video files are optionally processed through
AlphaVideoNormalizerfor premultiplied alpha channels
// Sources/PalmierPro/Preview/CompositionBuilder.swift
static func build(
timeline: Timeline,
resolveURL: @Sendable (String) -> URL?,
resolveSourceSize: @Sendable (String) -> CGSize? = { _ in nil },
missingMediaRefs: Set<String> = [],
renderSize: CGSize
) async throws -> CompositionResult {
// 1️⃣ Validate timeline dimensions & FPS
// 2️⃣ Iterate each track, filter out text clips (handled later)
// 3️⃣ Load source assets and insert into composition tracks...
}
Track Assembly and Gap Handling
For each valid media reference, the pipeline inserts the clip into the composition track using insertClip (lines 104-148). This method handles:
- Gap insertion for empty timeline regions
- Speed scaling via
scaleTimeRangefor time-stretched clips - Track mapping that records natural sizes and transforms for later visual processing
The builder also guarantees a valid video output by inserting an opaque black background track via insertBlackBackground (lines 52-78), ensuring the composition never results in an empty video track even when processing audio-only sources.
Visual Composition and Audio Mixing
After track assembly, buildVisuals (lines 80-124) constructs the final deliverables:
AVMutableAudioMixwith precise volume ramps and mute handling per clipAVVideoCompositionutilizing aCustomVideoCompositorfor transform, opacity, and crop operations- Layer plans that map clip boundaries to
CompositorInstructionobjects
The compositorInstructions method (lines 36-98) splits the timeline at every clip boundary, generating instructions that the CustomVideoCompositor uses to blend layers correctly.
Format Conversion Phase
Once composition is complete, the pipeline enters the format conversion phase, diverging based on the selected ExportFormat.
Video Export via AVAssetExportSession
For H.264, H.265, and ProRes formats, ExportService creates an AVAssetExportSession configured via exportPresetName(format:resolution:) at lines 68-90:
private func exportPresetName(format: ExportFormat, resolution: ExportResolution) -> String {
switch format {
case .h264:
switch resolution {
case .r720p: return AVAssetExportPreset1280x720
case .r1080p: return AVAssetExportPreset1920x1080
case .r4k: return AVAssetExportPreset3840x2160
case .r1440p, .matchTimeline: return AVAssetExportPresetHighestQuality
}
case .prores:
return AVAssetExportPresetAppleProRes422LPCM
// ...
}
}
The session receives the composed asset, applies the selected preset, and exports to the specified outputURL with the appropriate file extension (.mp4 for H.264/H.265, .mov for ProRes).
XML Export for Professional Workflows
When exporting to Final Cut Pro or Premiere formats, the pipeline bypasses AVFoundation composition entirely. As implemented in Sources/PalmierPro/Export/ExportService.swift at lines 41-46, the method invokes XMLExporter.export (located in Sources/PalmierPro/Export/XMLExporter.swift) to serialize the timeline structure directly to .xml (XMEML) or .fcpxml format.
Text Overlay Rendering
Text clips require special handling because they are not inserted into the AVMutableComposition tracks. During export, TextLayerController.buildForExport creates a Core Animation layer hierarchy based on the timeline's text clips. The export method then wraps this in an AVVideoCompositionCoreAnimationTool (lines 105-112 in ExportService.swift):
let (parent, videoLayer) = TextLayerController.buildForExport(
timeline: timeline, fps: timeline.fps, renderSize: renderSize)
let animationTool = AVVideoCompositionCoreAnimationTool(
postProcessingAsVideoLayer: videoLayer, in: parent)
session.videoComposition = ExportService.addingAnimationTool(animationTool,
to: prepared.session.videoComposition)
This ensures text overlays render correctly into the final video file even though they exist outside the standard media track structure.
Error Handling and Media Status
The pipeline tracks two specific failure categories during composition:
offlineMediaRefs– Clips whose media reference could not be resolved (missing files)unprocessableMediaRefs– Clips that resolved but failed processing (corrupt files or unsupported codecs)
Both sets are collected in CompositionBuilder (lines 50-53) and bubble up through ExportService, allowing the UI to report specific problematic assets without crashing the entire export operation.
Summary
Palmier Pro's export architecture demonstrates a clean separation of concerns across distinct phases:
- Composition occurs in
CompositionBuilder, generatingAVMutableComposition, audio mixes, and video compositions with custom compositor instructions - Format routing happens in
ExportService, dispatching XML formats toXMLExporterwhile video formats proceed throughAVAssetExportSession - Text rendering leverages
AVVideoCompositionCoreAnimationToolto bake text overlays into the final output - Error resilience tracks offline and unprocessable media references throughout the pipeline for detailed user feedback
Frequently Asked Questions
What is the difference between video export and XML export in Palmier Pro?
Video export (H.264, H.265, ProRes) requires building a full AVMutableComposition with audio mixes and video compositions, then encoding via AVAssetExportSession. XML export (.xml or .fcpxml) bypasses composition entirely, serializing the timeline structure directly through XMLExporter for interchange with Final Cut Pro or Premiere.
How does Palmier Pro handle text overlays during export?
Text clips are rendered using AVVideoCompositionCoreAnimationTool. The TextLayerController.buildForExport method creates a Core Animation layer hierarchy that is attached to the AVAssetExportSession as a post-processing video layer, ensuring text renders correctly without being part of the composition tracks.
What happens when media files are missing during export?
The pipeline collects missing references in the offlineMediaRefs set during the CompositionBuilder phase. These are bubbled up through ExportService, allowing the application to report specific missing files to the user while potentially continuing with other valid media.
Why does the export pipeline insert a black background track?
The insertBlackBackground method (lines 52-78 in CompositionBuilder.swift) guarantees a non-empty video track even when all source clips are audio-only. This prevents AVAssetExportSession from failing due to missing video tracks and ensures consistent output across all timeline configurations.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →