// // VideoComposer.swift // dubbing_lib // // Created by weihong huang on 2020/9/18. // import Foundation import AVFoundation class VideoComposer { var videoUrl: URL var musicUrl: URL init(videoUrl: URL, musicUrl: URL){ self.videoUrl = videoUrl self.musicUrl = musicUrl } func compose(_ output: URL, onSuccess successBlock: (()->())?, onFail failBlock:((_ message: String)->())? ) { //初始化合成器 let composition = AVMutableComposition() var videoTimeRange:CMTimeRange? //为合成器添加视频轨道 let videoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid) let videoAsset = AVURLAsset(url: videoUrl, options: nil) videoTimeRange = CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration) do { try videoTrack?.insertTimeRange(videoTimeRange!, of: videoAsset.tracks(withMediaType: AVMediaType.video).first!, at: CMTime.zero) } catch { DispatchQueue.main.async(execute: { failBlock?("Fail on load video") }) return } //添加音乐轨道 let musicTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid) let musicAsset = AVURLAsset(url: musicUrl, options: nil) let musicTimeRange = videoTimeRange ?? CMTimeRangeMake(start: CMTime.zero, duration: musicAsset.duration) do { try musicTrack?.insertTimeRange(musicTimeRange, of: musicAsset.tracks(withMediaType: AVMediaType.audio).first!, at: CMTime.zero) print("创建音乐音轨成功") } catch { print("创建音乐音轨失败") } let manager = FileManager.default do { try manager.removeItem(at: output) print("删除旧输出成功") } catch { print("删除旧输出失败") } //输出到文件 if let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) { assetExport.outputFileType = AVFileType.mp4 assetExport.outputURL = output assetExport.shouldOptimizeForNetworkUse = true assetExport.exportAsynchronously(completionHandler: { if((assetExport.error) != nil){ print(assetExport.error!) DispatchQueue.main.async(execute: { failBlock?("Something wrong on composition") }) }else{ successBlock?() } return }) } else { DispatchQueue.main.async(execute: { failBlock?("Something wrong on composition") }) } } }