Error : 'NSInternalInconsistencyException', reason: 'outputURL cannot be NULL'

Error : 'NSInternalInconsistencyException', reason: 'outputURL cannot be NULL'

我尝试合并我从图库中选择的 2 个视频和音频。但是当我按下合并所有按钮时,我崩溃了。我的错误是 'NSInternalInconsistencyException', reason: 'outputURL cannot be NULL'

请帮助我。我被击中了超过 3 个小时。但无法找到我所缺少的解决方案

我想我在这方面犯了错误,比如路径:

    // 4 - Get path
    let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
    var dateFormatter = NSDateFormatter()
    dateFormatter.dateStyle = .LongStyle
    dateFormatter.timeStyle = .ShortStyle
    let date = dateFormatter.stringFromDate(NSDate())
    // let savePath = documentDirectory.URLByAppendingPathComponent("mergeVideo-\(date).mov")

 let savePath = (documentDirectory as NSString).stringByAppendingPathComponent("mergeVideo-\(date).mov")

这里是我合并所有按钮点击扩展的完整代码:

@IBAction func MergeAll(sender: AnyObject) {
        if let firstAsset = firstAsset, secondAsset = secondAsset {
           // activityMonitor.startAnimating()

            // 1 - Create AVMutableComposition object. This object will hold your AVMutableCompositionTrack instances.
            var mixComposition = AVMutableComposition()

            // 2 - Create two video tracks
            var firstTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
                preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
            do {
                try firstTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, firstAsset.duration),
                    ofTrack: firstAsset.tracksWithMediaType(AVMediaTypeVideo)[0] ,
                    atTime: kCMTimeZero)
            } catch _ {
            }

            var secondTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo,
                preferredTrackID: Int32(kCMPersistentTrackID_Invalid))
            do {
                try secondTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, secondAsset.duration),
                    ofTrack: secondAsset.tracksWithMediaType(AVMediaTypeVideo)[0] ,
                    atTime: firstAsset.duration)
            } catch _ {
            }


            var mainInstruction = AVMutableVideoCompositionInstruction()
            mainInstruction.timeRange = CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration))

            let firstInstruction = videoCompositionInstructionForTrack(firstTrack, asset: firstAsset)
            firstInstruction.setOpacity(0.0, atTime: firstAsset.duration)
            let secondInstruction = videoCompositionInstructionForTrack(secondTrack, asset: secondAsset)

            mainInstruction.layerInstructions = [firstInstruction, secondInstruction]
            let mainComposition = AVMutableVideoComposition()
            mainComposition.instructions = [mainInstruction]
            mainComposition.frameDuration = CMTimeMake(1, 30)
            mainComposition.renderSize = CGSize(width: UIScreen.mainScreen().bounds.width, height: UIScreen.mainScreen().bounds.height)

            // 3 - Audio track
            if let loadedAudioAsset = audioAsset {
                let audioTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: 0)
                do {
                    try audioTrack.insertTimeRange(CMTimeRangeMake(kCMTimeZero, CMTimeAdd(firstAsset.duration, secondAsset.duration)),
                        ofTrack: loadedAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] ,
                        atTime: kCMTimeZero)
                } catch _ {
                }
            }

            // 4 - Get path
            let documentDirectory = NSSearchPathForDirectoriesInDomains(.DocumentDirectory, .UserDomainMask, true)[0]
            var dateFormatter = NSDateFormatter()
            dateFormatter.dateStyle = .LongStyle
            dateFormatter.timeStyle = .ShortStyle
            let date = dateFormatter.stringFromDate(NSDate())
            // let savePath = documentDirectory.URLByAppendingPathComponent("mergeVideo-\(date).mov")

         let savePath = (documentDirectory as NSString).stringByAppendingPathComponent("mergeVideo-\(date).mov")

            ///let savePath = documentDirectory.stringByAppendingPathComponent("mergeVideo-\(date).mov")



           // let completeMovie = documentDirectory.stringByAppendingPathComponent("movie.mov")


            let url = NSURL(fileURLWithPath: savePath)

            // 5 - Create Exporter
            let exporter = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
            //exporter!.outputURL = url
            exporter!.outputFileType = AVFileTypeQuickTimeMovie
            exporter!.shouldOptimizeForNetworkUse = true
            exporter!.videoComposition = mainComposition

            // 6 - Perform the Export
            exporter!.exportAsynchronouslyWithCompletionHandler() {
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.exportDidFinish(exporter!)
                })
            }
        }
    }

}

extension ViewController: UIImagePickerControllerDelegate {
    func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {
        let mediaType = info[UIImagePickerControllerMediaType] as! NSString
        dismissViewControllerAnimated(true, completion: nil)

        if mediaType == kUTTypeMovie {
            // let avAsset = AVAsset.assetWithURL(info[UIImagePickerControllerMediaURL] as! NSURL)


            let avAsset = AVAsset(URL: info[UIImagePickerControllerMediaURL] as! NSURL)
            var message = ""
            if loadingAssetOne {
                message = "Video one loaded"
                firstAsset = avAsset
            } else {
                message = "Video two loaded"
                secondAsset = avAsset
            }
            let alert = UIAlertController(title: "Asset Loaded", message: message, preferredStyle: .Alert)
            alert.addAction(UIAlertAction(title: "OK", style: UIAlertActionStyle.Cancel, handler: nil))
            presentViewController(alert, animated: true, completion: nil)
        }
    }

}

extension ViewController: UINavigationControllerDelegate {

}

extension ViewController: MPMediaPickerControllerDelegate {
    func mediaPicker(mediaPicker: MPMediaPickerController, didPickMediaItems mediaItemCollection: MPMediaItemCollection) {
        let selectedSongs = mediaItemCollection.items
        if selectedSongs.count > 0 {
            let song = selectedSongs[0]
            if let url = song.valueForProperty(MPMediaItemPropertyAssetURL) as? NSURL {
                audioAsset = AVAsset(URL: url)
                //let avAsset = AVAsset(URL: info[UIImagePickerControllerMediaURL] as! NSURL)
                dismissViewControllerAnimated(true, completion: nil)
                let alert = UIAlertController(title: "Asset Loaded", message: "Audio Loaded", preferredStyle: .Alert)
                alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler:nil))
                presentViewController(alert, animated: true, completion: nil)
            } else {
                dismissViewControllerAnimated(true, completion: nil)
                let alert = UIAlertController(title: "Asset Not Available", message: "Audio Not Loaded", preferredStyle: .Alert)
                alert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler:nil))
                presentViewController(alert, animated: true, completion: nil)
            }
        } else {
            dismissViewControllerAnimated(true, completion: nil)
        }
    }

    func mediaPickerDidCancel(mediaPicker: MPMediaPickerController) {
        dismissViewControllerAnimated(true, completion: nil)
    }
}

我正在学习一个教程 This Tutorial

请帮我解决。我收到同样的错误。我已经向我的另一位同事提出了这个疑问 post.but 没有解决方案。请解决此问题 error.Thanks!

已更新:

您有评论

exporter!.outputURL = url

in @IBAction func MergeAll(sender: AnyObject) 表示合并视频的输出路径为空。所以系统找不到保存视频的路径

这可能是问题所在。只需注释掉并尝试。

也替换代码

//exporter!.outputURL = url
        exporter!.outputFileType = AVFileTypeQuickTimeMovie
        exporter!.shouldOptimizeForNetworkUse = true
        exporter!.videoComposition = mainComposition

exporter!.exportAsynchronouslyWithCompletionHandler() {
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    self.exportDidFinish(exporter!)
                })

exporter.outputURL = url
exporter.outputFileType = AVFileTypeQuickTimeMovie
exporter.shouldOptimizeForNetworkUse = true
exporter.videoComposition = mainComposition

exporter.exportAsynchronouslyWithCompletionHandler() {
    dispatch_async(dispatch_get_main_queue(), { () -> Void in
      self.exportDidFinish(exporter)
    })