Преглед на файлове

多录音合成导出;
多录音回放

harry преди 3 години
родител
ревизия
1b58b70fa6

+ 81 - 40
BFRecordScreenKit/Classes/BFRecordExport.swift

@@ -22,9 +22,9 @@ public class BFRecordExport {
     // 录音段
     public var voiceList:[PQVoiceModel]? {
         didSet {
-            audioAssets = voiceList?.map({ model in
-                AVURLAsset(url: URL(fileURLWithPath: model.wavFilePath))
-            })
+//            audioAssets = voiceList?.map({ model in
+//                AVURLAsset(url: URL(fileURLWithPath: model.wavFilePath))
+//            })
             
         }
     }
@@ -54,9 +54,10 @@ public class BFRecordExport {
         bgMovieInfo.canvasFillType = stickerContentMode.aspectFitStr.rawValue
         bgMovieInfo.volumeGain = 30
         bgMovieInfo.aptDuration = bgMovieInfo.timelineOut
+        bgMovieInfo.duration = bgMovieInfo.timelineOut
         mStickers.append(bgMovieInfo)
     
-        beginExport(videoStickers: mStickers, audioAsset: self.audioAssets)
+        beginExport(videoStickers: mStickers)
     }
     
     public func cancelExport(){
@@ -109,7 +110,7 @@ public class BFRecordExport {
     }
 
     
-    func beginExport(videoStickers:[PQEditVisionTrackMaterialsModel], audioAsset: [AVURLAsset]?) {
+    func beginExport(videoStickers:[PQEditVisionTrackMaterialsModel]) {
         // 输出视频地址
 //        exprotVideo()
 //        return;
@@ -122,45 +123,44 @@ public class BFRecordExport {
         BFLog(1, message: "导出视频地址 \(outPutMP4URL)")
         
         // 处理导出
-        if (audioAsset?.count ?? 0 ) > 0 || videoStickers.count > 1 {
-            var audioUrl:URL?
-            if audioAsset?.count ?? 0 > 0 {
-                // 多音频合成
-                if let list = voiceList?.map({ model in
-                    URL(fileURLWithPath: model.wavFilePath)
-                }){
-                    if list.count == 1 {
-                        audioUrl = list.first
-                    }else {
-                        let semaphore = DispatchSemaphore(value: 0)
-                        PQPlayerViewModel.mergeAudios(urls: list) { completURL in
-                            audioUrl = completURL
-                            semaphore.signal()
-                        }
-                        _ = semaphore.wait(timeout: .now() + 5)
-                    }
-                }
-            }
-            // 每次初始化的时候设置初始值 为 nIl
-            var audioMix: AVMutableAudioMix?
-            var composition: AVMutableComposition?
-
+        if (voiceList?.count ?? 0 ) > 0 || videoStickers.count > 1 {
+//            var audioUrl:URL?
+//            if audioAsset?.count ?? 0 > 0 {
+//                // 多音频合成
+//                if let list = voiceList?.map({ model in
+//                    URL(fileURLWithPath: model.wavFilePath)
+//                }){
+//                    if list.count == 1 {
+//                        audioUrl = list.first
+//                    }else {
+//                        let semaphore = DispatchSemaphore(value: 0)
+//                        PQPlayerViewModel.mergeAudios(urls: list) { completURL in
+//                            audioUrl = completURL
+//                            semaphore.signal()
+//                        }
+//                        _ = semaphore.wait(timeout: .now() + 5)
+//                    }
+//                }
+//            }
+            let (audioMix, composition) = mergeAudio(videoStickers: videoStickers, audios: voiceList)
+            
             let filter = mStickers.map { sticker in
                 PQMovieFilter(movieSticker: sticker)
             }
             // 有
-            if let completURL = audioUrl {
-                let inputAsset = AVURLAsset(url: completURL, options: avAssertOptions)
-//                (audioMix, composition) = PQVideoEditViewModel.setupAudioMix(originAsset: inputAsset, bgmData: nil, videoStickers: videoStickers)
-                //使用原视频无音版
-                (audioMix, composition) = PQVideoEditViewModel.setupAudioMix(originAsset: inputAsset, bgmData: nil, videoStickers: nil)
-
-                if composition != nil {
-                    exporter = PQCompositionExporter(asset: composition!, videoComposition: nil, audioMix: audioMix, filters: filter, animationTool: nil, exportURL: outPutMP4URL)
-                }else {
-                    exporter = PQCompositionExporter(asset: inputAsset, videoComposition: nil, audioMix: nil, filters: filter, animationTool: nil, exportURL: outPutMP4URL)
-                }
-            }
+//            if let completURL = audioUrl {
+//                let inputAsset = AVURLAsset(url: completURL, options: avAssertOptions)
+////                (audioMix, composition) = PQVideoEditViewModel.setupAudioMix(originAsset: inputAsset, bgmData: nil, videoStickers: videoStickers)
+//                //使用原视频无音版
+//                (audioMix, composition) = PQVideoEditViewModel.setupAudioMix(originAsset: inputAsset, bgmData: nil, videoStickers: nil)
+//
+//                if composition != nil {
+//                    exporter = PQCompositionExporter(asset: composition!, videoComposition: nil, audioMix: audioMix, filters: filter, animationTool: nil, exportURL: outPutMP4URL)
+//                }else {
+//                    exporter = PQCompositionExporter(asset: inputAsset, videoComposition: nil, audioMix: nil, filters: filter, animationTool: nil, exportURL: outPutMP4URL)
+//                }
+//            }
+            exporter = PQCompositionExporter(asset: composition, videoComposition: nil, audioMix: audioMix, filters: filter, animationTool: nil, exportURL: outPutMP4URL)
             
             let size = getVideoSize()
             var orgeBitRate = Int(size.width * size.height * 3)
@@ -243,3 +243,44 @@ public class BFRecordExport {
         return size
     }
 }
+
+extension BFRecordExport {
+    func mergeAudio(videoStickers:[PQEditVisionTrackMaterialsModel], audios:[PQVoiceModel]?) -> (AVMutableAudioMix, AVMutableComposition){
+        let composition = AVMutableComposition()
+        let audioMix = AVMutableAudioMix()
+        var tempParameters = [AVMutableAudioMixInputParameters]()
+        
+        var totalDuration : Float64 = 0
+        for sticker in videoStickers {
+            if sticker.volumeGain == 0 {
+                // 如果添加了会有刺啦音
+                BFLog(message: "音频音量 为0 不添加")
+                continue
+            }
+            sticker.volumeGain = 2
+            totalDuration = max(totalDuration, sticker.duration)
+            tempParameters += PQVideoEditViewModel.dealWithMaterialTrack(stickerModel: sticker, composition: composition)
+        }
+        if let voices = audios {
+            for model in voices {
+                if model.volume == 0 {
+                    // 如果添加了会有刺啦音
+                    BFLog(message: "音频音量 为0 不添加")
+                    continue
+                }
+                let sticker = PQEditVisionTrackMaterialsModel()
+                sticker.model_in = 0
+                sticker.timelineIn = model.startTime
+                sticker.out = model.endTime
+                sticker.aptDuration = model.endTime - model.startTime
+                sticker.duration = sticker.aptDuration
+                sticker.locationPath = model.wavFilePath
+                sticker.volumeGain = 100 //Float64(model.volume)
+                tempParameters += PQVideoEditViewModel.dealWithMaterialTrack(stickerModel: sticker, composition: composition)
+            }
+        }
+        audioMix.inputParameters = tempParameters
+        return (audioMix, composition)
+    }
+    
+}

+ 0 - 3
BFRecordScreenKit/Classes/BFRecordManager.swift

@@ -22,9 +22,6 @@ class BFRecordManager {
     var beginRecordTime:Date = Date()
     var voiceModel : PQVoiceModel?
     
-    init(voideModeL:PQVoiceModel) {
-        self.voiceModel = voideModeL
-    }
     /// 录制音频
     func startRecord(index:Int){
         

+ 37 - 15
BFRecordScreenKit/Classes/BFRecordScreenController.swift

@@ -22,9 +22,9 @@ public class BFRecordScreenController: BFBaseViewController {
     // MARK: - 录制参数
     public var asset:PHAsset?
 //    var shouldPlayRecordIndex:Int = -1          // 当前应该播放的录音资源序号
-    var currentPlayRecordIndex:Int = -1         // 当前正在播放的录音资源序号
+    var currentPlayRecordIndex:Int = -1         // >= 0 :当前正在播放的录音资源序号; -3: 刚录音完,不需要播放录音; -1:初始化阶段
     var isRecording = false                     // 是否正在录音
-    var isNormalPlaying = false {               // 是否正在录音
+    var isNormalPlaying = false {               // 是否正在播放
         didSet{
             playBtn.isSelected = isNormalPlaying
         }
@@ -52,7 +52,7 @@ public class BFRecordScreenController: BFBaseViewController {
     // 录音相关
     lazy var recorderManager : BFRecordManager = {
         
-        let manager = BFRecordManager(voideModeL: PQVoiceModel())
+        let manager = BFRecordManager()
         manager.cancelRecordHandle = { error in
             
         }
@@ -62,6 +62,8 @@ public class BFRecordScreenController: BFBaseViewController {
                 let ass = AVURLAsset(url: URL(fileURLWithPath: model.wavFilePath))
                 
                 model.endTime = model.startTime + CMTimeGetSeconds(ass.duration)
+                
+                // TODO: 原逻辑要删除新录音后边的数据, 新逻辑是插入覆盖
                 while let m = self?.recordList.last{
                     if model.startTime < m.startTime {
                         self?.recordList.removeLast()
@@ -74,6 +76,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 BFLog(1, message: "添加录音文件:\(model.startTime) -- \(model.endTime)")
                 self?.recordList.append(model)
                 self?.drawOrUpdateRecordProgessLable()
+                self?.currentPlayRecordIndex = -3 // 刚录音完,不需要播放录音
             }
             
         }
@@ -309,7 +312,8 @@ public class BFRecordScreenController: BFBaseViewController {
 
         let model = PQVoiceModel()
         model.startTime = CMTimeGetSeconds(self.currentAssetProgress)
-        recorderManager.voiceModel? = model
+        model.volume = 100
+        recorderManager.voiceModel = model
         recorderManager.startRecord(index: recordList.count)
         movie?.startProcessing()
         assetPlayer?.volume = 0
@@ -355,7 +359,7 @@ public class BFRecordScreenController: BFBaseViewController {
         changeProgress(progress: sender.value)
         isDragingProgressSlder = false
         currentPlayRecordIndex = -1
-
+        hadPrepareToPlayRecord = false
     }
     
     // MARK: - 权限申请
@@ -405,6 +409,9 @@ public class BFRecordScreenController: BFBaseViewController {
     
     // MARK: - 音视频处理
     func playRecord(at currentT:CMTime){
+        if currentPlayRecordIndex == -3 { // 刚录音完,不需要播放
+            return
+        }
         let (shouldPlayRecordIndex, recordedAudio) = recordList.enumerated().first { model in
             model.1.endTime > CMTimeGetSeconds(currentT)
         } ?? (-1, nil)
@@ -417,13 +424,26 @@ public class BFRecordScreenController: BFBaseViewController {
         
         // 创建播放器
         if self.recordPlayer == nil || (self.recordPlayer?.currentItem?.asset as? AVURLAsset)?.url.lastPathComponent != (recordedAudio.wavFilePath as NSString).lastPathComponent {
-            self.recordPlayer?.pause()
-            self.recordPlayer = AVPlayer(url: URL(fileURLWithPath: recordedAudio.wavFilePath))
+            let newItem = AVPlayerItem(url: URL(fileURLWithPath: recordedAudio.wavFilePath))
+            if let player = self.recordPlayer {
+                player.pause()
+                if let playItem = player.currentItem {
+                    NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: playItem)
+                    recordPlayer?.replaceCurrentItem(with: newItem)
+                }
+            }else {
+                self.recordPlayer = AVPlayer(playerItem: newItem)
+            }
             self.recordPlayer!.volume = 1
             //                self.recordPlayer?.prepareToPlay()
             currentPlayRecordIndex = -1
             hadPrepareToPlayRecord = false
             BFLog(1, message: "录音播放器初始化(有时候不准)")
+            
+            NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: newItem, queue: .main) { [weak self] notify in
+                self?.hadPrepareToPlayRecord = false
+                self?.currentPlayRecordIndex = -1
+            }
         }
         
         synced(currentPlayRecordIndex) {
@@ -433,15 +453,17 @@ public class BFRecordScreenController: BFBaseViewController {
             {
                 // 应当开始播放了
                 // 两个逻辑:如果在播,则跳过;如果暂停拖动到中间,则seek
-                if currentPlayRecordIndex == -1 {
+                if currentPlayRecordIndex == -1 && self.isNormalPlaying{
                     let second = CMTimeGetSeconds(currentT) - recordedAudio.startTime
-                    recordPlayer?.seek(to: CMTime(value: CMTimeValue(second), timescale: 100), toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000), completionHandler: {[weak self] finished in
-                        if finished && (self?.isNormalPlaying ?? false) {
-                            DispatchQueue.main.async {[weak self] in
+                    DispatchQueue.main.async {[weak self] in
+                        self?.recordPlayer?.seek(to: CMTime(value: CMTimeValue(second), timescale: 100), toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000), completionHandler: {[weak self] finished in
+                            if finished && (self?.isNormalPlaying ?? false) {
                                 self?.recordPlayer?.play()
+                                BFLog(1, message: "录音开始播放 playing, \(second), \(CMTimeGetSeconds(self?.recordPlayer?.currentItem?.duration ?? .zero))")
+
                             }
-                        }
-                    })
+                        })
+                    }
                     currentPlayRecordIndex = shouldPlayRecordIndex
                     hadPrepareToPlayRecord = true
                     BFLog(1, message: "录音开始播放2, \(second), \(CMTimeGetSeconds(recordPlayer?.currentItem?.duration ?? .zero))")
@@ -596,9 +618,9 @@ public class BFRecordScreenController: BFBaseViewController {
 
         
         NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: assetPlayer?.currentItem, queue: .main) { [weak self] notify in
-            BFLog(message: "AVPlayerItemDidPlayToEndTime = \(notify)")
+            BFLog(1, message: "AVPlayerItemDidPlayToEndTime = \(notify)")
+            self?.isNormalPlaying = false
             self?.assetPlayer?.seek(to: CMTime.zero)
-            self?.playBtn.isSelected = false
             self?.currentPlayRecordIndex = -1
         }
     }