Swift Merge audio and video files into one video

后端 未结 5 1780
闹比i
闹比i 2020-12-04 12:55

I wrote a program in Swift.I want to merge a video with an audio file, but got this error.

\"failed Error Domain=AVFoundationErrorDomain Code=-11838 \

5条回答
  •  星月不相逢
    2020-12-04 13:16

    Swift 5 version (Also repeats audio if video is larger than audio) : Just pass audio and video URLs. I have tried this with local video and remote audio url.

    func mergeVideoWithAudio(videoUrl: URL,
                                    audioUrl: URL,
                                    success: @escaping ((URL) -> Void),
                                    failure: @escaping ((Error?) -> Void)) {
    
           let mixComposition: AVMutableComposition = AVMutableComposition()
           var mutableCompositionVideoTrack: [AVMutableCompositionTrack] = []
           var mutableCompositionAudioTrack: [AVMutableCompositionTrack] = []
           let totalVideoCompositionInstruction: AVMutableVideoCompositionInstruction = AVMutableVideoCompositionInstruction()
    
           let aVideoAsset: AVAsset = AVAsset(url: videoUrl)
           let aAudioAsset: AVAsset = AVAsset(url: audioUrl)
    
           if let videoTrack = mixComposition.addMutableTrack(withMediaType: .video, preferredTrackID: kCMPersistentTrackID_Invalid), let audioTrack = mixComposition.addMutableTrack(withMediaType: .audio, preferredTrackID: kCMPersistentTrackID_Invalid) {
               mutableCompositionVideoTrack.append( videoTrack )
               mutableCompositionAudioTrack.append( audioTrack )
    
               if let aVideoAssetTrack: AVAssetTrack = aVideoAsset.tracks(withMediaType: .video).first, let aAudioAssetTrack: AVAssetTrack = aAudioAsset.tracks(withMediaType: .audio).first {
                   do {
                       try mutableCompositionVideoTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aVideoAssetTrack, at: CMTime.zero)
    
                       let videoDuration = aVideoAsset.duration
                       if CMTimeCompare(videoDuration, aAudioAsset.duration) == -1 {
                           try mutableCompositionAudioTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: CMTime.zero)
                       } else if CMTimeCompare(videoDuration, aAudioAsset.duration) == 1 {
                           var currentTime = CMTime.zero
                           while true {
                               var audioDuration = aAudioAsset.duration
                               let totalDuration = CMTimeAdd(currentTime, audioDuration)
                               if CMTimeCompare(totalDuration, videoDuration) == 1 {
                                   audioDuration = CMTimeSubtract(totalDuration, videoDuration)
                               }
                               try mutableCompositionAudioTrack.first?.insertTimeRange(CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration), of: aAudioAssetTrack, at: currentTime)
    
                               currentTime = CMTimeAdd(currentTime, audioDuration)
                               if CMTimeCompare(currentTime, videoDuration) == 1 || CMTimeCompare(currentTime, videoDuration) == 0 {
                                   break
                               }
                           }
                       }
                       videoTrack.preferredTransform = aVideoAssetTrack.preferredTransform
    
                   } catch {
                       print(error)
                   }
    
                   totalVideoCompositionInstruction.timeRange = CMTimeRangeMake(start: CMTime.zero, duration: aVideoAssetTrack.timeRange.duration)
               }
           }
    
           let mutableVideoComposition: AVMutableVideoComposition = AVMutableVideoComposition()
           mutableVideoComposition.frameDuration = CMTimeMake(value: 1, timescale: 30)
           mutableVideoComposition.renderSize = CGSize(width: 480, height: 640)
    
           if let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first {
               let outputURL = URL(fileURLWithPath: documentsPath).appendingPathComponent("\("fileName").m4v")
    
               do {
                   if FileManager.default.fileExists(atPath: outputURL.path) {
    
                       try FileManager.default.removeItem(at: outputURL)
                   }
               } catch { }
    
               if let exportSession = AVAssetExportSession(asset: mixComposition, presetName: AVAssetExportPresetHighestQuality) {
                   exportSession.outputURL = outputURL
                   exportSession.outputFileType = AVFileType.mp4
                   exportSession.shouldOptimizeForNetworkUse = true
    
                   // try to export the file and handle the status cases
                   exportSession.exportAsynchronously(completionHandler: {
                       switch exportSession.status {
                       case .failed:
                           if let error = exportSession.error {
                               failure(error)
                           }
    
                       case .cancelled:
                           if let error = exportSession.error {
                               failure(error)
                           }
    
                       default:
                           print("finished")
                           success(outputURL)
                       }
                   })
               } else {
                   failure(nil)
               }
           }
       }
    

提交回复
热议问题