合并音频和视频Swift



我试图合并N音轨,到一个视频文件。视频为MP4格式,所有音频为m4a。

所有的准备工作都很顺利,但当出口完成时,总是失败。下面是我的代码:

func mixAudioAndVideo() {
    self.player?.pause()
    let mixComposition = AVMutableComposition()
    let paths = NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask)
    let docsDirect = paths[0]
    for audioTrack in self.audioTracks {
        let musicFile = docsDirect.URLByAppendingPathComponent(audioTrack.audioName)
        let audioAsset = AVURLAsset(URL: musicFile!, options: nil)
        let audioTimeRange = CMTimeRangeMake(audioTrack.audioTime!, audioAsset.duration)
        let compositionAudioTrack:AVMutableCompositionTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeAudio, preferredTrackID: kCMPersistentTrackID_Invalid)
        do {
            try compositionAudioTrack.insertTimeRange(audioTimeRange, ofTrack: audioAsset.tracksWithMediaType(AVMediaTypeAudio).first!, atTime: audioTrack.audioTime!)
        } catch let error {
            print(error)
        }
    }
    let videoAsset = AVURLAsset(URL: video!.movieURL, options: nil)
    let videoTimeRange = CMTimeRangeMake(kCMTimeZero, videoAsset.duration)
    let compositionVideoTrack = mixComposition.addMutableTrackWithMediaType(AVMediaTypeVideo, preferredTrackID: kCMPersistentTrackID_Invalid)
    do {
        try compositionVideoTrack.insertTimeRange(videoTimeRange, ofTrack: videoAsset.tracksWithMediaType(AVMediaTypeVideo).first!, atTime: kCMTimeZero)
    } catch let error {
        print(error)
    }
    let videoName = "video(self.audioTracks.count).mov"
    let outputFilePath = docsDirect.URLByAppendingPathComponent(videoName)
    let assetExport = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality)
    assetExport!.outputFileType = AVFileTypeQuickTimeMovie
    assetExport!.outputURL = outputFilePath!
    assetExport?.exportAsynchronouslyWithCompletionHandler({
        dispatch_async(dispatch_get_main_queue()){
            print("finished exporting (outputFilePath)")
            print("status (assetExport?.status)")
            print("error (assetExport?.error)")
            SVProgressHUD.dismiss()
        }
    })
}

和我得到的代码:

error Optional(Error Domain=NSURLErrorDomain Code=-1 "unknown error" UserInfo={NSLocalizedDescription=unknown error, NSUnderlyingError=0x170056140 {Error Domain=NSOSStatusErrorDomain Code=-12935 "(null)"}})

迅速:3 首次合并N条音轨

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)")
                }
        })
    }

然后合并音频和视频

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)")
                }
            }
        }
    }

最新更新