title: AVAssetExportSession not working on devices, but working on simulator (AVFoundationErrorDomain Code = -11800, Unknown Error code -12780)
body: <p><strong>EDIT:</strong> To make things easier to anyone interested in checking out this problem, I added a demo project to <a href="https://github.com/alanpridestar/AVAssetExportSessionErrorDemo" rel="nofollow noreferrer">this github repository.</a></p>
  
  <p><strong>Issue</strong></p>
  
  <p>I've seen several questions that had the same error, but none of the solutions found there helped me. Figured I'd try my luck. </p>
  
  <p>I'm trying to export a video as is, mainly to learn about AVFoundation and AVAssetExportSession. My export works perfectly fine on the simulator, but does not work on any iOS device I've tried (namely an iPhone X and an iPhone XR running iOS 12 each). I Mainly followed a Ray Wenderleich tutorial found on this link to perform the Video Exporting: <a href="https://www.raywenderlich.com/2734-avfoundation-tutorial-adding-overlays-and-animations-to-videos" rel="nofollow noreferrer">https://www.raywenderlich.com/2734-avfoundation-tutorial-adding-overlays-and-animations-to-videos</a></p>
  
  <p>Would appreciate any help on the topic. My code is as follows:</p>
  
  <p>Retrieving the URL of a video I've added to the App Bundle called Demo.mp4:</p>
  
  <pre><code>@objc func export() {
      let urlString = Bundle.main.path(forResource: "Demo", ofType: ".mp4")!
      let url = URL(fileURLWithPath: urlString)
      ExportManager.shared.exportWithAVFoundation(url:url) { (outputUrl, errorString) in
          if let outputUrl = outputUrl {
              self.playVideo(url: outputUrl)
          } else if let errorString = errorString {
              print("ERROR: \(errorString)")
          }
      }
  }
  </code></pre>
  
  <p>My Exporting function in ExportManager is as follows (Sorry quite long)</p>
  
  <pre><code>func exportWithAVFoundation(url: URL, completion: @escaping (_ outputUrl: URL?, _ errorString: String?) -&gt; ()) {
      let asset = AVAsset(url: url)
      print("URL IS \(url)")
      guard let avAssetTrack = asset.tracks(withMediaType: .video).first else {
          completion(nil, "Couldn't Create Asset Track")
          return
      }
  
      let mutableComposition = AVMutableComposition()
      guard let videoTrack = mutableComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid) else { return }
      try? videoTrack.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: avAssetTrack, at: .zero)
      videoTrack.preferredTransform = avAssetTrack.preferredTransform
  
      if let audioAssetTrack = asset.tracks(withMediaType: .audio).first {
          let audioTrack = mutableComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid)
          try? audioTrack?.insertTimeRange(CMTimeRange(start: .zero, duration: asset.duration), of: audioAssetTrack, at: .zero)
      }
  
      let mainInstruction = AVMutableVideoCompositionInstruction()
      mainInstruction.timeRange = CMTimeRange(start: .zero, duration: asset.duration)
  
      let videoLayerInstruction = AVMutableVideoCompositionLayerInstruction(assetTrack: videoTrack)
  
      // Fix video orientation
      var videoAssetOrientation = UIImage.Orientation.up
      var isVideoAssetPortrait = false
      let videoTransform = avAssetTrack.preferredTransform
  
      switch (videoTransform.a, videoTransform.b, videoTransform.c, videoTransform.c) {
      case (0, 1.0, -1.0, 0):
          videoAssetOrientation = .right
          isVideoAssetPortrait = true
      case(0, -1.0, 1.0, 0):
          videoAssetOrientation = .left
          isVideoAssetPortrait = true
      case(1.0, 0, 0, 1.0):
          videoAssetOrientation = .up
      case(-1.0, 0, 0, -1.0):
          videoAssetOrientation = .down
      default:
          break
      }
  
      var naturalSize = avAssetTrack.naturalSize
      switch (videoAssetOrientation, isVideoAssetPortrait) {
      case (.right, true):
          naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
      case (.left, true):
          naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
      case (.leftMirrored, true):
          naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
      case (.rightMirrored, true):
          naturalSize = CGSize(width: avAssetTrack.naturalSize.height, height: avAssetTrack.naturalSize.width)
      default:
          break
      }
  
      videoLayerInstruction.setTransform(avAssetTrack.preferredTransform, at: .zero)
      videoLayerInstruction.setOpacity(0, at: asset.duration)
  
      mainInstruction.layerInstructions = [videoLayerInstruction]
  
      let mainCompositionInstruction = AVMutableVideoComposition()
  
      mainCompositionInstruction.renderSize = naturalSize
      mainCompositionInstruction.instructions = [mainInstruction]
      mainCompositionInstruction.frameDuration = CMTimeMake(value: 1, timescale: 30);
  
      let documentsDirectoryURL = createPath()
  
      guard let exporter = AVAssetExportSession(asset: mutableComposition, presetName: AVAssetExportPresetHighestQuality) else {
          print("Couldnt create AVAssetExportSession")
  
          completion(nil, "Couldn't Create AVAssetExportSession")
          return
      }
  
      exporter.outputURL = documentsDirectoryURL
      exporter.outputFileType = .mov
      exporter.shouldOptimizeForNetworkUse = true
      exporter.videoComposition = mainCompositionInstruction
  
      exporter.exportAsynchronously {
          if let error = exporter.error {
              print(error)
              completion(nil, error.localizedDescription)
              return
          }
  
          completion(exporter.outputURL, nil)
          print("Finished Exporting")
      }
  }
  </code></pre>
  
  <p>Some things I've tried to do have been to add an AudioTrack to the composition (which I didn't include previously). Hasn't helped it work on an actual device, but at least my exported video has audio now.</p>
  
  <p>I also tried to change the Preset Quality to Passthrough as opposed to Highest Quality, as I read from other threads that this could help, but to no avail.</p>
  
  <p><strong>EDIT</strong>: </p>
  
  <p>Added createPath function:</p>
  
  <pre><code>func createPath() -&gt; URL {
      let paths = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)
      let documentDirectory = paths.first!
      let myPathDocs = documentDirectory.appending("FinalVideo.mov")
      let url = URL(fileURLWithPath: myPathDocs)
  
      if FileManager.default.fileExists(atPath: myPathDocs) {
          try? FileManager.default.removeItem(atPath: myPathDocs)
      }
  
      return url
  }
  </code></pre>
  
  <p>Note: 
  createPath() just creates a valid path in the directory to save the exported video in. If a file exists at that path prior to exporting, it gets deleted. </p>