iosswiftavfoundationavassetexportsession

Can't export a MOV using AVAssetExportSession


Very confused on how to export a mov file. Keep getting the error:

Error Domain=AVFoundationErrorDomain Code=-11838 "Operation Stopped

At first I started with AVAssets but that ended up giving me and some other devs trouble when exporting. So I ended up going down the route of using AVMutableComposition but that didn't work out for me as well. So now below is the code that I hoped would work but currently doesn't.

The URL points to a Firebase asset.

func exportVideo(_ url: URL) async throws -> URL?{
    let fileManager = FileManager.default
    let item = AVPlayerItem(url: url)
    
    guard try await item.asset.load(.isExportable) else { return nil }
    let videoComp = item.videoComposition
    guard let exporter = AVAssetExportSession(asset: item.asset, presetName: AVAssetExportPresetHighestQuality),
        exporter.supportedFileTypes.contains(AVFileType.mov) else {
        return nil
    }
    
    // The location in which we will store the video
    guard let outputURL = fileManager.containerURL(
        forSecurityApplicationGroupIdentifier: "group.example"
    )?.appendingPathComponent(currentOutfit + ".mov") else  { return nil }
    
    // Check whether the file exists in cache
    guard !fileManager.fileExists(atPath: outputURL.path()) else {
        return outputURL
    }
    
    // Assign the location in where to save the video
    exporter.outputURL = outputURL
    
    // export video to mov
    exporter.outputFileType = AVFileType.mov
    
    exporter.shouldOptimizeForNetworkUse = true
    
    exporter.videoComposition = videoComp
    
    do {
        if #available(iOS 18, *) {
            try await exporter.export(to: outputURL, as: AVFileType.mov)
        } else {
            exporter.exportAsynchronously(completionHandler: {
                print("export Status: \(String(describing: exporter.status))")
                print("export Error: \(String(describing: exporter.error))")
            })
        }
        // return the newly saved video url location
        return outputURL
    } catch {
        print("export error: \(error)")
    }
    
    return nil
}

Solution

  • Try this approach based on Apple example code Exporting video to alternative formats

    Make sure your "...forSecurityApplicationGroupIdentifier: group.example" is registered with your Apple Developer account and setup in your "Signing & Capabilities" -> "App Groups capability"

    On macOS Sequoia 15.5, using Xcode 16.4, target iOS-18.5, successfully tested on real iOS device and MacCatalyst.

    
    struct ContentView: View {
          let url = URL(string: "https://sample-videos.com/video321/mp4/720/big_buck_bunny_720p_1mb.mp4")!
    
        var body: some View {
            Text("Exporting Video…")
                .task {
                    do {
                        let result = try await exportVideo(url)
                        print("✅ Exported to: \(String(describing: result))")
                    } catch {
                        print("❌ Export failed: \(error)")
                    }
                }
        }
        
        func exportVideo(_ url: URL) async throws -> URL? {
            let currentOutfit = "exportedfile"
            
            guard let outputURL = FileManager.default.containerURL(
                forSecurityApplicationGroupIdentifier: "group.example"
            )?.appendingPathComponent(currentOutfit + ".mov")
            else  {
                return nil
            }
    
            let video = AVURLAsset(url: url)
    
            guard await AVAssetExportSession.compatibility(ofExportPreset:
                                                            AVAssetExportPresetHighestQuality,
                                                           with: video,
                                                           outputFileType: AVFileType.mov) else {
                print("The ExportPreset can't export the video to the output file type.")
                return nil
            }
            
            // Create and configure the export session.
            guard let exportSession = AVAssetExportSession(asset: video,
                                                           presetName: AVAssetExportPresetHighestQuality) else {
                print("Failed to create export session.")
                return nil
            }
            exportSession.outputFileType = AVFileType.mov
            exportSession.outputURL = outputURL
            
            // Convert the video to the output file type and export it to the output URL.
            await exportSession.export()
            return outputURL
        }
    }