azrosen92 azrosen92 - 1 year ago 192
Swift Question

Saving Videos with AVMutableComposition and AVAssetExportSession in Swift 3

I'm attempting to build a small toy iOS app that merges two video assets from the user's photos library. I've gotten to the point where I have merged the videos using an

instance and now I need to export the composition. I am doing so with the following code:

func saveEditedComposition(_ composition: AVMutableComposition) {
let documentDirectory = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0]
let savePath = (documentDirectory as NSString).strings(byAppendingPaths: [""])[0]
let url = NSURL(fileURLWithPath: savePath)

// Set up exporter
guard let exporter = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else { return }
exporter.outputURL = url as URL
exporter.outputFileType = AVFileTypeQuickTimeMovie
exporter.shouldOptimizeForNetworkUse = true

// Perform the export
exporter.exportAsynchronously(completionHandler: { () -> Void in
// Upon completion of the export, {
if exporter.status == .completed {
let fetchResult = PHAsset.fetchAssets(withALAssetURLs: [exporter.outputURL!], options: nil))
let phAsset = fetchResult.firstObject! // Crashes here, returning nil.

The problem is, when the completionHandler is run, I am able to see that my exporter has completed without error (
if exporter.status == .completed {
), but when I try to access the asset at
, it returns an empty
. Can anyone see what I'm doing wrong here?

Answer Source

You're exporting the video to the file system (the Documents directory), yet fetching from the camera roll/ALAssetsLibrary.

It depends on what you need to do with the exported file. If it needs to be in the ALAssetsLibrary, you can use

ALAssetsLibrary().writeVideoAtPath(toSavedPhotosAlbum: exporter.outputURL!) { alAssetURL, error in      

However ALAssetsLibrary is now deprecated and you are supposed to use PHPhotoLibrary. I don't know the Photos framework, but I think it works like this:

var placeHolder: PHObjectPlaceholder?

    let changeRequest = PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: exporter.outputURL!)
    if let changeRequest = changeRequest {
        // maybe set date, location & favouriteness here?
        placeHolder = changeRequest.placeholderForCreatedAsset
}) { success, error in
    placeHolder?.localIdentifier    // should identify asset from now on?

If you don't need the video to live in the camera roll, then you can work directly with the file in exporter.outputURL!.

Recommended from our users: Dynamic Network Monitoring from WhatsUp Gold from IPSwitch. Free Download