【问题标题】:Merging audio and video Swift合并音频和视频 Swift
【发布时间】:2016-11-03 14:51:57
【问题描述】:

我正在尝试将 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)"}})

【问题讨论】:

    标签: ios swift audio video avmutablecomposition


    【解决方案1】:

    斯威夫特: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)")
                    }
                }
            }
        }
    

    【讨论】:

    • 所以我的音频文件是 3 秒,我想将它添加到前后 30 秒的视频中,但它总是显示在前面,尝试编辑这个以尝试 mutableCompositionAudioTrack[0].insertTimeRange( CMTimeRangeMake(kCMTimeZero, 3, preferredTimescale: 1)), of: aAudioAssetTrack, at: kCMTimeZero)
    猜你喜欢
    • 1970-01-01
    • 2019-05-24
    • 1970-01-01
    • 1970-01-01
    • 2019-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多