Swift: 3 first merging N audio tracks
var mergeAudioURL = NSURL() func mergeAudioFiles(audioFileUrls: NSArray) { let composition = AVMutableComposition() for i in 0 ..< audioFileUrls.count { let compositionAudioTrack :AVMutableCompositionTrack = composition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: CMPersistentTrackID()) let asset = AVURLAsset(url: (audioFileUrls[i] as! NSURL) as URL) let track = asset.tracks(withMediaType: AVMediaTypeAudio)[0] let timeRange = CMTimeRange(start: CMTimeMake(0, 600), duration: track.timeRange.duration) try! compositionAudioTrack.insertTimeRange(timeRange, of: track, at: composition.duration) } let documentDirectoryURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first! as NSURL self.mergeAudioURL = documentDirectoryURL.appendingPathComponent("Merge Audio.m4a")! as URL as NSURL let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetAppleM4A) assetExport?.outputFileType = AVFileTypeAppleM4A assetExport?.outputURL = mergeAudioURL as URL removeFileAtURLIfExists(url: mergeAudioURL) assetExport?.exportAsynchronously(completionHandler: { switch assetExport!.status { case AVAssetExportSessionStatus.failed: print("failed \(assetExport?.error)") case AVAssetExportSessionStatus.cancelled: print("cancelled \(assetExport?.error)") case AVAssetExportSessionStatus.unknown: print("unknown\(assetExport?.error)") case AVAssetExportSessionStatus.waiting: print("waiting\(assetExport?.error)") case AVAssetExportSessionStatus.exporting: print("exporting\(assetExport?.error)") default: print("-----Merge audio exportation complete.\(self.mergeAudioURL)") } }) }
then combine audio with video
var mergedAudioVideoURl = NSURL() func mergeMutableVideoWithAudio(videoUrl:NSURL, audioUrl:NSURL){ let mixComposition : AVMutableComposition = AVMutableComposition() var mutableCompositionVideoTrack : [AVMutableCompositionTrack] = [] var mutableCompositionAudioTrack : [AVMutableCompositionTrack] = [] let totalVideoCompositionInstruction : AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction() //start merge let aVideoAsset : AVAsset = AVAsset(url: videoUrl as URL) let aAudioAsset : AVAsset = AVAsset(url: audioUrl as URL) mutableCompositionVideoTrack.append(mixComposition.addMutableTrack(withMediaType: AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)) mutableCompositionAudioTrack.append( mixComposition.addMutableTrack(withMediaType: AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)) let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracks(withMediaType: AVMediaTypeVideo)[0] let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracks(withMediaType: AVMediaTypeAudio)[0] do{ try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: kCMTimeZero) try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: kCMTimeZero) }catch{ } totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration ) let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition() mutableVideoComposition.frameDuration = CMTimeMake(1, 30) mutableVideoComposition.renderSize = CGSize(width: 1280, height: 720) mergedAudioVideoURl = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/FinalVideo.mp4") let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)! assetExport.outputFileType = AVFileTypeMPEG4 assetExport.outputURL = mergedAudioVideoURl as URL removeFileAtURLIfExists(url: mergedAudioVideoURl) assetExport.shouldOptimizeForNetworkUse = true assetExport.exportAsynchronously { () -> Void in switch assetExport.status { case AVAssetExportSessionStatus.completed: print("-----Merge mutable video with trimmed audio exportation complete.\(self.mergedAudioVideoURl)") case AVAssetExportSessionStatus.failed: print("failed \(assetExport.error)") case AVAssetExportSessionStatus.cancelled: print("cancelled \(assetExport.error)") default: print("complete") } } } func removeFileAtURLIfExists(url: NSURL) { if let filePath = url.path { let fileManager = FileManager.default if fileManager.fileExists(atPath: filePath) { do{ try fileManager.removeItem(atPath: filePath) } catch let error as NSError { print("-----Couldn't remove existing destination file: \(error)") } } } }
source share