我尝试合并我从图库中选择的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")
这里我的完整代码Merge all按钮点击扩展名:
@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。
请帮我解决。我得到了同样的错误。我已经在我的另一个同事职位上问了这个疑问。但是没有解决方案。请解决这个错误。谢谢!
更新:
答案 0 :(得分:1)
您已评论
exporter!.outputURL = url
@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)
})