VideoComposer.swift 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. //
  2. // VideoComposer.swift
  3. // dubbing_lib
  4. //
  5. // Created by weihong huang on 2020/9/18.
  6. //
  7. import Foundation
  8. import AVFoundation
  9. class VideoComposer {
  10. var videoUrl: URL
  11. var musicUrl: URL
  12. init(videoUrl: URL, musicUrl: URL){
  13. self.videoUrl = videoUrl
  14. self.musicUrl = musicUrl
  15. }
  16. func compose(_ output: URL, onSuccess successBlock: (()->())?, onFail failBlock:((_ message: String)->())? ) {
  17. //初始化合成器
  18. let composition = AVMutableComposition()
  19. var videoTimeRange:CMTimeRange?
  20. //为合成器添加视频轨道
  21. let videoTrack = composition.addMutableTrack(withMediaType: AVMediaType.video, preferredTrackID: kCMPersistentTrackID_Invalid)
  22. let videoAsset = AVURLAsset(url: videoUrl, options: nil)
  23. videoTimeRange = CMTimeRangeMake(start: CMTime.zero, duration: videoAsset.duration)
  24. do {
  25. try videoTrack?.insertTimeRange(videoTimeRange!, of: videoAsset.tracks(withMediaType: AVMediaType.video).first!, at: CMTime.zero)
  26. }
  27. catch {
  28. DispatchQueue.main.async(execute: {
  29. failBlock?("Fail on load video")
  30. })
  31. return
  32. }
  33. //添加音乐轨道
  34. let musicTrack = composition.addMutableTrack(withMediaType: AVMediaType.audio, preferredTrackID: kCMPersistentTrackID_Invalid)
  35. let musicAsset = AVURLAsset(url: musicUrl, options: nil)
  36. let musicTimeRange = videoTimeRange ?? CMTimeRangeMake(start: CMTime.zero, duration: musicAsset.duration)
  37. do {
  38. try musicTrack?.insertTimeRange(musicTimeRange, of: musicAsset.tracks(withMediaType: AVMediaType.audio).first!, at: CMTime.zero)
  39. print("创建音乐音轨成功")
  40. }
  41. catch {
  42. print("创建音乐音轨失败")
  43. }
  44. let manager = FileManager.default
  45. do {
  46. try manager.removeItem(at: output)
  47. print("删除旧输出成功")
  48. }
  49. catch {
  50. print("删除旧输出失败")
  51. }
  52. //输出到文件
  53. if let assetExport = AVAssetExportSession(asset: composition, presetName: AVAssetExportPresetHighestQuality) {
  54. assetExport.outputFileType = AVFileType.mp4
  55. assetExport.outputURL = output
  56. assetExport.shouldOptimizeForNetworkUse = true
  57. assetExport.exportAsynchronously(completionHandler: {
  58. if((assetExport.error) != nil){
  59. print(assetExport.error!)
  60. DispatchQueue.main.async(execute: {
  61. failBlock?("Something wrong on composition")
  62. })
  63. }else{
  64. successBlock?()
  65. }
  66. return
  67. })
  68. }
  69. else {
  70. DispatchQueue.main.async(execute: {
  71. failBlock?("Something wrong on composition")
  72. })
  73. }
  74. }
  75. }