AVFoundation视频裁剪时出现AVFoundationErrorDomain Code=-11800错误的排查求助
大家好,我正在尝试从Photos App中选择视频并进行裁剪操作,但在执行exportSession.exportAsynchronously时遇到了错误,实在搞不清楚问题出在哪,想请各位帮忙排查下。
以下是我的完整代码:
import UIKit import AVFoundation import AVKit import Photos import PhotosUI class ViewController: UIViewController, PHPickerViewControllerDelegate { func loadVideo(url: URL) -> AVAsset? { return AVAsset(url: url) } func trimVideo(asset: AVAsset, startTime: CMTime, endTime: CMTime, completion: @escaping (URL?, Error?) -> Void) { // Create an export session with the desired output URL and preset. guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else { completion(nil, NSError(domain: "com.yourapp.trimVideo", code: 1, userInfo: [NSLocalizedDescriptionKey: "Failed to create AVAssetExportSession."])) return } let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0] let outputURL = documentsDirectory.appendingPathComponent("trimmedVideo.mp4") // Remove the existing file if it exists try? FileManager.default.removeItem(at: outputURL) exportSession.outputURL = outputURL exportSession.outputFileType = AVFileType.mp4 exportSession.shouldOptimizeForNetworkUse = true // Set the time range for trimming let timeRange = CMTimeRangeFromTimeToTime(start: startTime, end: endTime) exportSession.timeRange = timeRange // Perform the export exportSession.exportAsynchronously { switch exportSession.status { case .completed: completion(exportSession.outputURL, nil) case .failed: completion(nil, exportSession.error) case .cancelled: completion(nil, NSError(domain: "com.yourapp.trimVideo", code: 2, userInfo: [NSLocalizedDescriptionKey: "Export cancelled"])) default: break } } } override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } func picker(_ picker: PHPickerViewController, didFinishPicking results: [PHPickerResult]) { debugPrint("1") picker.dismiss(animated: true,completion: nil) debugPrint("2") guard let provider = results.first?.itemProvider else { return } debugPrint("3") if provider.hasItemConformingToTypeIdentifier(UTType.movie.identifier) { debugPrint("4") provider.loadFileRepresentation(forTypeIdentifier: UTType.movie.identifier) { [self] (videoURL, error) in debugPrint("5") cropVideo(sourceURL1: videoURL as! URL, statTime: 10, endTime: 20) } } } @IBAction func btnClicked(_ sender: Any) { var config = PHPickerConfiguration(photoLibrary: .shared()) config.selectionLimit = 1 config.filter = .videos let vc = PHPickerViewController(configuration: config) vc.delegate = self present(vc, animated: true) } func cropVideo(sourceURL1: URL, statTime:Float, endTime:Float) { debugPrint("21") let manager = FileManager.default debugPrint("22") guard let documentDirectory = try? manager.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: true) else {return} debugPrint("23") let mediaType = "mp4" debugPrint("24") if mediaType == UTType.movie.identifier || mediaType == "mp4" as String { debugPrint("25") let asset = AVAsset(url: sourceURL1 as URL) let length = Float(asset.duration.value) / Float(asset.duration.timescale) print("video length: \(length) seconds") debugPrint("26") let start = statTime let end = endTime debugPrint("27") var outputURL = documentDirectory.appendingPathComponent("output") do { debugPrint("28") try manager.createDirectory(at: outputURL, withIntermediateDirectories: true, attributes: nil) outputURL = outputURL.appendingPathComponent("\(UUID().uuidString).\(mediaType)") }catch let error { debugPrint("29") print(error) } //Remove existing file _ = try? manager.removeItem(at: outputURL) debugPrint("30") guard let exportSession = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetHighestQuality) else {return} exportSession.outputURL = outputURL exportSession.outputFileType = .mp4 debugPrint("31") let startTime = CMTime(seconds: Double(start ), preferredTimescale: 1000) let endTime = CMTime(seconds: Double(end ), preferredTimescale: 1000) let timeRange = CMTimeRange(start: startTime, end: endTime) debugPrint("32") exportSession.timeRange = timeRange exportSession.exportAsynchronously{ switch exportSession.status { case .completed: print("exported at \(outputURL)") case .failed: print("failed \(String(describing: exportSession.error))") case .cancelled: print("cancelled \(String(describing: exportSession.error))") default: break } } } } }
完整报错信息
Optional(Error Domain=AVFoundationErrorDomain Code=-11800 "The operation could not be completed" UserInfo={NSUnderlyingError=0x2818544b0 {Error Domain=NSOSStatusErrorDomain Code=-16979 "(null)"}, NSLocalizedFailureReason=An unknown error occurred (-16979), NSURL=file:///private/var/mobile/Containers/Shared/AppGroup/35D28117-572C-484E-969C-A9515EF42CDF/File%20Provider%20Storage/photospicker/version=1&uuid=6C291C6C-F254-44F5-83C2-C15980750530&mode=compatible&noloc=0.mp4, NSLocalizedDescription=The operation could not be completed})
我检查了视频资源的有效性,也确认了输出路径是可写的,但导出就是失败了,有没有大佬能帮我分析下可能的原因,或者给些排查方向?
备注:内容来源于stack exchange,提问作者Chup bae

