合并音频和视频 Swift

Posted

技术标签:

【中文标题】合并音频和视频 Swift【英文标题】:Merging audio and video 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)")

【问题讨论】:

【参考方案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)

以上是关于合并音频和视频 Swift的主要内容,如果未能解决你的问题,请参考以下文章

如何在合并音频和视频时循环播放音频

使用 ffmpeg 合并视频和音频。循环播放视频和音频[关闭]

ffmpeg合并音频和视频

如何在ffmpeg中合并音频和两个视频文件?

C# windows phone - 合并音频和视频文件

将音频视频与ffmpeg合并时如何提高结果视频的质量?