AVAssetWriter error code on finishWriting

Hello guys, I constantly keep getting error code -12780 while saving the file.

Configuration is

AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: [
                AVVideoCodecKey: AVVideoCodecType.h264,
                AVVideoWidthKey: floor(UIScreen.main.bounds.width / 16) * 16,
                AVVideoHeightKey: floor(UIScreen.main.bounds.height / 16) * 16,
                AVVideoCompressionPropertiesKey: [
                    AVVideoAverageBitRateKey: 2300000,
                ],
                ])

I don't understand what NSOSStatusErrorDomain -12780 means. The localized description is The operation could not be completed.

Other than that I discovered that on my iOS 13 beta device the error code is: -17508,but still is The operation could not be completed.

Replies

iOS 13 is also giving me -17508 when trying to export video. The same code works on macOS. I can't find that error code in any headers.

I am having the same issue (and same error code -17508) using AssetWriter to finisheWriting an .mp4 file with h.264 encoding into an App group's shared folder from a ReplayKit Upload Extension.

I was not able to find -17508 anywhere, and the complete error is:


Asset Writer Error: Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-17508), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x280314d80 {Error Domain=NSOSStatusErrorDomain Code=-17508 "(null)


Any ideas, what could be the issue?


UPDATE: I figured out that in my case it was the output URL that was the problem.

I used the following code to get the output URL of the folder shared (via App Group) between my app and my extension:


let appGroupsFolderUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.mycompany")
let outputURL = appGroupsFolderUrl!.appendingPathComponent("recording.mp4")


Appears, you cannot store in that folder directly, but you need to store your file in a subfolder, e.g. like this:


let appGroupsFolderUrl = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.com.equalities")
let outputURL = appGroupsFolderUrl!.appendingPathComponent("Library/Caches/recording.mp4")


Note the Library/Caches part in the URL!


Still, it is kind of ridiculous that in 21st century development frameworks, you still get a "-17508" error that is not listed anywhere, when really what should have been returned is a proper error describing what the actually problem is.

Hi @all,


I am facing the same issues in ios 13.3 in real device it is working in ios 13.2 simulator but gives below error.


Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSLocalizedFailureReason=An unknown error occurred (-17508), NSLocalizedDescription=The operation could not be completed, NSUnderlyingError=0x2816d11d0 {Error Domain=NSOSStatusErrorDomain Code=-17508 "(null)"}}



Here is my code I want to convert .mov file to mp4.

class func encodeVideo(at videoURL: String, completionHandler: ((URL?, Error?) -> Void)?)  {
        let avAsset = AVURLAsset(url: URL.init(fileURLWithPath: videoURL), options: nil)
            
        let startDate = Date()
            
        //Create Export session
        guard let exportSession = AVAssetExportSession(asset: avAsset, presetName: AVAssetExportPresetPassthrough) else {
            completionHandler?(nil, nil)
            return
        }
            
        //Creating temp path to save the converted video
        let filename = "Video_\(Date().timeIntervalSince1970).mp4"
          // Below Folder Path used tor getting directory path
        let strfilePath = (FolderPath.temporaryDirectory.getDirectoryPath as NSString).appendingPathComponent(filename)
        let filePath = URL.init(fileURLWithPath: strfilePath)
            
        //Check if the file already exists then remove the previous file
        if FileManager.default.fileExists(atPath: filePath.path) {
            do {
                try FileManager.default.removeItem(at: filePath)
            } catch {
                completionHandler?(nil, error)
            }
        }
            
        exportSession.outputURL = filePath
        exportSession.outputFileType = AVFileType.mp4
        exportSession.shouldOptimizeForNetworkUse = true
        let start = CMTimeMakeWithSeconds(0.0, preferredTimescale: 0)
        let range = CMTimeRangeMake(start: start, duration: avAsset.duration)
        exportSession.timeRange = range
            
        exportSession.exportAsynchronously(completionHandler: {() -> Void in
            switch exportSession.status {
            case .failed:
                print(exportSession.error ?? "NO ERROR")
                completionHandler?(nil, exportSession.error)
            case .cancelled:
                print("Export canceled")
                completionHandler?(nil, nil)
            case .completed:
                //Video conversion finished
                let endDate = Date()
                    
                let time = endDate.timeIntervalSince(startDate)
                print(time)
                print("Successful!")
                print(exportSession.outputURL ?? "NO OUTPUT URL")
                completionHandler?(exportSession.outputURL, nil)
                    
                default: break
            }
                
        })
    }

As per florianSAP I was able to fix my exact same issue with changing the URL. I think you're issue is that the folder "DocumentsVideo_(timestamp)" doesn't exist. Try printing your filepath constant and ensure that you are looking at exporting to a URL that ends with Documents/videoname.mp4

We should create IntermediateDirectories in the export url.

like this:


if FileManager.default.fileExists(atPath: {DirectoryPath}) == false {

try? FileManager.default.createDirectory(atPath: {DirectoryPath}, withIntermediateDirectories: true, attributes: nil)

}

This error is mostly because you are trying to export an AVAsset. Solve this using AVMutableComposition for export. sample code for trimming a video file


let manager = FileManager.default

        guard let documentDirectory = try?  manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true)  else { print("TRIM Failed to access directory")

            return}

        let mediaType = "mp4"

        if mediaType == kUTTypeMovie as String || mediaType == "mp4" as String {

               let asset = AVAsset(url:videoURL!)

            let length = Float(asset.duration.value) / Float(asset.duration.timescale)

               print("TRIM video length: \(length) seconds")

            let composition = AVMutableComposition()

            let audioTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)!

            let videoTrack: AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)!

            var outURL_speed=documentDirectory.appendingPathComponent("output")

            var outputURL = documentDirectory.appendingPathComponent("output")

                    do {

                        try audioTrack.insertTimeRange(CMTimeRangeFromTimeToTime(start: self.startTime, end: self.endTime), of: asset.tracks(withMediaType: AVMediaType.audio)[0], at: CMTime.zero)

                        try videoTrack.insertTimeRange(CMTimeRangeFromTimeToTime(start: self.startTime, end: self.endTime), of: asset.tracks(withMediaType: AVMediaType.video)[0], at: CMTime.zero)

                     

                        try manager.createDirectory(at: outputURL, withIntermediateDirectories: true, attributes: nil)

                        outputURL = outputURL.appendingPathComponent("preVideo-\(self.postID).\(mediaType)")

                        outURL_speed = outURL_speed.appendingPathComponent("Video-\(self.postID).\(mediaType)")

                        print("TRIM output dir: \(outputURL)")

                    }catch let error {

                        print(error)

                    }



            _ = try? manager.removeItem(at: outputURL)

            

            

        

            

            guard let exportSession = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) else {return}

            

            exportSession.outputURL = outputURL

            exportSession.shouldOptimizeForNetworkUse = true

            exportSession.outputFileType = .mp4

            let timeRange = CMTimeRange(start: self.startTime, end: self.endTime)

            exportSession.timeRange = timeRange

            

            exportSession.exportAsynchronously{

                switch exportSession.status {

                case .completed:

                    print("TRIM exported at \(outputURL)")

                    self.changeSpeed(url: outputURL,outUrl:outURL_speed)

                case .failed:

                    print("TRIM failed \(exportSession.error)")



                case .cancelled:

                    print("TRIM cancelled \(exportSession.error)")



                default: break

                }

            }