In the previous question, the same error that I found due to incorrect saving of PathUrl, the destination URL should be as below the code, including the new video.
I was looking for the code Combine audio and video files into one video , but could not find anywhere, so after spending hours reading Apple documents, I wrote this code.
NOTE. This is verified and 100% working code for me.
Stap: 1 Import these modules into your viewController.
import UIKit import AVFoundation import AVKit import AssetsLibrary
step 2: add this function to your code
func mergeFilesWithUrl(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) let aAudioAsset : AVAsset = AVAsset(URL: audioUrl) mutableCompositionVideoTrack.append(mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)) mutableCompositionAudioTrack.append( mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)) let aVideoAssetTrack : AVAssetTrack = aVideoAsset.tracksWithMediaType(AVMediaTypeVideo)[0] let aAudioAssetTrack : AVAssetTrack = aAudioAsset.tracksWithMediaType(AVMediaTypeAudio)[0] do{ try mutableCompositionVideoTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aVideoAssetTrack, atTime: kCMTimeZero) //In my case my audio file is longer then video file so i took videoAsset duration //instead of audioAsset duration try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero) //Use this instead above line if your audiofile and video file playing durations are same // try mutableCompositionAudioTrack[0].insertTimeRange(CMTimeRangeMake(kCMTimeZero, aVideoAssetTrack.timeRange.duration), ofTrack: aAudioAssetTrack, atTime: kCMTimeZero) }catch{ } totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(kCMTimeZero,aVideoAssetTrack.timeRange.duration ) let mutableVideoComposition : AVMutableVideoComposition = AVMutableVideoComposition() mutableVideoComposition.frameDuration = CMTimeMake(1, 30) mutableVideoComposition.renderSize = CGSizeMake(1280,720) // playerItem = AVPlayerItem(asset: mixComposition) // player = AVPlayer(playerItem: playerItem!) // // // AVPlayerVC.player = player //find your video on this URl let savePathUrl : NSURL = NSURL(fileURLWithPath: NSHomeDirectory() + "/Documents/newVideo.mp4") let assetExport: AVAssetExportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)! assetExport.outputFileType = AVFileTypeMPEG4 assetExport.outputURL = savePathUrl assetExport.shouldOptimizeForNetworkUse = true assetExport.exportAsynchronouslyWithCompletionHandler { () -> Void in switch assetExport.status { case AVAssetExportSessionStatus.Completed: //Uncomment this if u want to store your video in asset //let assetsLib = ALAssetsLibrary() //assetsLib.writeVideoAtPathToSavedPhotosAlbum(savePathUrl, completionBlock: nil) print("success") case AVAssetExportSessionStatus.Failed: print("failed \(assetExport.error)") case AVAssetExportSessionStatus.Cancelled: print("cancelled \(assetExport.error)") default: print("complete") } } }
Step 3: Call the function where u want like this
let videoUrl : NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("SampleVideo", ofType: "mp4")!) let audioUrl : NSURL = NSURL(fileURLWithPath: NSBundle.mainBundle().pathForResource("SampleAudio", ofType: "mp3")!) mergeFilesWithUrl(videoUrl, audioUrl: audioUrl)
Hope this helps you and saves you time.