Browse Source

Merge branch 'dev' of https://git.yishihui.com/iOS/BFRecordScreenKit into dev
合并代码

jsonwang 3 years ago
parent
commit
21e4a312db

+ 2 - 8
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenBaseManager.swift

@@ -21,14 +21,8 @@ class BFRecordScreenBaseManager : NSObject{
     var progreddL : UILabel?
     var progressThumV: BFVideoThumbProgressView?
     
-    var recordItem : BFRecordItemModel?{
-        didSet{
-              //mdf by ak 这里先注释上否则会导致 BFRecordScreenController 类加的fetchPlayItemCallBack 不会被调用不能执行转换操作
-//            recordItem?.fetchPlayItemCallBack = {[weak self] model in
-//                self?.resetEnv()
-//            }
-        }
-    }
+    var recordItem : BFRecordItemModel?
+    
     var playView : GPUImageView?
     var filter = GPUImageFilter()
     

+ 60 - 25
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenCameraManager.swift

@@ -35,6 +35,12 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
     var rendView = GPUImageView()
     var cameraProgressV: BFCameraProgressView?
     
+    override var recordItem : BFRecordItemModel? {
+        didSet{
+            cameraProgressV?.recordItem = recordItem
+        }
+    }
+
     // 录制完成回调
     var hasInitCallBack : (()->Void)?
     var cameraFlipHandle : ((Bool) -> Void)?
@@ -46,6 +52,9 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
     // 用于打开摄像头初始流程
     static var initOpenCamera : Bool = true
     
+    // timer循环每次录制增长的时长
+    var increaseTime :CMTime = .zero
+    
     var currPlayTime : CMTime = .zero
     fileprivate var timerr:Timer?
     
@@ -130,7 +139,6 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
             cShowHUB(superView: nil, msg: "option_fail_camera".BFLocale)
             return
         }
-        cameraProgressV?.recordItem = recordItem
         resetThumbImg()
         
         initplayer()
@@ -212,7 +220,14 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
         
         // 为了第一时间能更新collection view数据
         if !BFRecordScreenCameraManager.initOpenCamera{
-            recordItem?.videoStickers.append(videoModel)
+            // 将model插入正确位置
+            if let index = recordItem?.videoStickers.firstIndex(where: { mod in
+                mod.timelineCMOut.seconds - currentAssetProgress.seconds > 0.7
+            }) {
+                recordItem?.videoStickers.insert(videoModel, at: index)
+            }else {
+                recordItem?.videoStickers.append(videoModel)
+            }
             progreddL?.isHidden = false
             cameraProgressV?.isHidden = false
         }
@@ -227,6 +242,7 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
 
             let currDur = CMTime(seconds: wself.videoModel.timelineCMIn.seconds + movieWrite.duration.seconds, preferredTimescale: 1000)
             if CMTimeCompare(currDur, wself.currentAssetProgress) > 0 {
+                wself.increaseTime = currDur - wself.currentAssetProgress
                 wself.currentAssetProgress = currDur
                 wself.videoModel.timelineCMOut = currDur
                 wself.recordProgressCallBack?(currDur)
@@ -250,6 +266,7 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
             }
             let cameraSuccess = wself.recordFinishedResult && ((wself.videoModel.timelineCMOut - wself.videoModel.timelineCMIn).seconds > 1)
             if cameraSuccess {
+                wself.increaseTime = wself.videoModel.timelineCMOut - wself.currentAssetProgress
                 wself.currentAssetProgress = wself.videoModel.timelineCMOut
                 wself.recordEndCallBack?(true, wself.videoModel)
                 wself.updateUI(progress: wself.currentAssetProgress)
@@ -258,7 +275,6 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
                 }
             }else {
                 wself.videoModel.locationPath = "nil"
-                wself.revertLast()
                 wself.recordEndCallBack?(false, nil)
             }
         }
@@ -287,10 +303,6 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
                         cShowHUB(superView: nil, msg: "shoot_tips_least".BFLocale)
                     }
                     wself.gropQueue.leave()
-                    DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {[weak self] in
-                        guard let wself = self else { return }
-                        wself.updateUI(progress:  wself.currentAssetProgress)
-                    }
 
                 }
             }
@@ -483,14 +495,18 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
 
             let tt = currentAssetProgress - currPlayTime
             BFLog(1, message: "asset - tt: \(tt.seconds), curr:\(currentAssetProgress.seconds)")
-            setCoverImage(mod.timelineCMOut)
-
-            avplayer.currentItem?.seek(to: tt, toleranceBefore: CMTime(value: 1, timescale: 1_000_000), toleranceAfter: CMTime(value: 1, timescale: 1_000_000), completionHandler: {[weak avplayer] _ in
-                            
+            if CMTimeCompare(tt, (avplayer.currentItem?.duration ?? .zero)) == 0 {
                 if needPlay {
-                    avplayer?.play()
+                    avplayer.play()
                 }
-            })
+            }else {
+                avplayer.currentItem?.seek(to: tt, toleranceBefore: CMTime(value: 1, timescale: 1_000_000), toleranceAfter: CMTime(value: 1, timescale: 1_000_000), completionHandler: {[weak avplayer] _ in
+                    
+                    if needPlay {
+                        avplayer?.play()
+                    }
+                })
+            }
             
             playRecordVoice(needPlay: needPlay)
         }else {
@@ -530,6 +546,8 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
             // 如果离结束大于0.7s,代表还有下一段视频
             if ((wself.recordItem?.materialDuraion ?? .zero) - wself.currentAssetProgress).seconds > 0.7 {
                 wself.findNextModel()
+                wself.setCoverImage(wself.currentAssetProgress)
+
                 wself.prepareToPlayNext()
             }else{
                 // 播放到末尾了
@@ -553,15 +571,16 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
         // 播放视频
         if let mod = recordItem?.videoStickers.first(where: { m in
             CMTimeCompare(m.timelineCMIn, currentAssetProgress) <= 0 && CMTimeCompare(m.timelineCMOut, currentAssetProgress) > 0
-        }){
+        }), (CMTimeCompare(currentAssetProgress, (recordItem?.materialDuraion ?? .zero)) < 0){
+            BFLog(1, message: "drag end:\(currentAssetProgress.seconds), mod:\(mod.timelineCMIn)")
             currPlayTime = mod.timelineCMIn
+            playerCoverIV.image = getThumbImageAtTime(urlAsset: AVURLAsset(url: URL(fileURLWithPath: mod.locationPath)), time: currentAssetProgress - currPlayTime)
+            playerCoverIV.isHidden = false
 
             avplayerReplaceItem(newItem: AVPlayerItem(url: URL(fileURLWithPath: mod.locationPath)))
-            setCoverImage(mod.timelineCMOut)
 
-            prepareToPlayNext(needPlay: false)
+//            prepareToPlayNext(needPlay: false)
         }
-        playerCoverIV.isHidden = (CMTimeCompare(currentAssetProgress, recordItem?.materialDuraion ?? .zero) >= 0)
     }
     
     
@@ -570,12 +589,11 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
         if let mod = recordItem?.videoStickers.first(where: { m in
             CMTimeCompare(m.timelineCMIn, (dur + CMTime(seconds: 0.5, preferredTimescale: 1000))) <= 0 && CMTimeCompare(m.timelineCMOut, (dur + CMTime(seconds: 0.5, preferredTimescale: 1000))) > 0
         }){
-            playerCoverIV.isHidden = false
             playerCoverIV.image = PQVideoSnapshotUtil.videoSnapshot(videoURL: URL(fileURLWithPath: mod.locationPath), time: .zero)
         }
-        playerCoverIV.isHidden = (CMTimeCompare(currentAssetProgress, recordItem?.materialDuraion ?? .zero) >= 0)
     }
     
+    // 
     override func changeRecordMaterail(){
         //
         if recordItem?.videoStickers.count ?? 0 == 0 {
@@ -624,16 +642,29 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
             guard let wself = self else { return }
             
             wself.progreddL?.text = CMTimeGetSeconds(progress).formatDurationToHMS()
-            if wself.recordItem?.thumbImgs.count ?? 0 > 0 {
-                wself.cameraProgressV?.updateCellWidth(index: wself.recordItem!.thumbImgs.count - 1, progress: progress)
+            
+            // 刷新之后的sticker
+            if wself.recordItem?.thumbImgs.count ?? 0 > 0, let sticker = wself.recordItem?.videoStickers.first(where: { mod in
+                CMTimeCompare(mod.timelineCMIn, progress) <= 0 && CMTimeCompare(mod.timelineCMOut, progress) >= 0
+            }) {
+                wself.recordItem?.videoStickers.forEach({ mod in
+                    if mod.timelineCMOut.seconds > progress.seconds {
+//                        BFLog(1, message: "insert before: \(mod.timelineCMIn.seconds)")
+                        mod.timelineCMIn = mod.timelineCMIn + wself.increaseTime
+                        mod.timelineCMOut = mod.timelineCMOut + wself.increaseTime
+//                        BFLog(1, message: "insert after: \(mod.timelineCMIn.seconds)")
+                    }
+                })
+                wself.cameraProgressV?.updateCellWidth(sticker: sticker, progress: progress)
             }
+            
         }
     }
     
     // 添加新的缩略图
-    func addNewThumb(){
+    func addNewThumb(_ img:UIImage){
         if let progressThumV = cameraProgressV {
-            progressThumV.addThumbImages()
+            progressThumV.addThumbImages(img)
         }
     }
     
@@ -668,9 +699,13 @@ extension BFRecordScreenCameraManager : GPUImageVideoCameraDelegate {
                 
                 if img != nil {
 //                    BFLog(1, message: "取一张缩略图出来 \(dur.seconds), \(wself.recordItem?.thumbImgs.count ?? 0)")
-                    wself.recordItem?.thumbImgs.append(img!)
                     wself.videoModel.thumImgs?.append(img!)
-                    wself.addNewThumb()
+                    if let videoStickers = wself.recordItem?.videoStickers {
+                        wself.recordItem?.thumbImgs = videoStickers.map({ mod in
+                            mod.thumImgs!
+                        }).flatMap{$0}
+                    }
+                    wself.addNewThumb(img!)
                 }
             }
         }

+ 71 - 186
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenController.swift

@@ -70,15 +70,17 @@ public class BFRecordScreenController: BFBaseViewController {
         
         // MARK: 摄像头结束回调
         m.recordEndCallBack = { [weak self] isSuccess, sticker in
-            guard let wself = self, let sticker = sticker else { return }
+            guard let wself = self else { return }
             
-            if isSuccess{
+            if isSuccess,  let sticker = sticker{
                 wself.rscurrentManager.currentAssetProgress = sticker.timelineCMOut
                 let dur = wself.rscmanager.recordItem?.videoStickers.reduce(0, { partialResult, mod in
                     (mod.timelineCMOut - mod.timelineCMIn).seconds + partialResult
                 })
                 wself.rscmanager.recordItem?.materialDuraion = CMTime(seconds: dur ?? 0, preferredTimescale: 1000)
 //                BFLog(1, message: "camera:\(sticker.timelineCMIn.seconds) ~ \(sticker.timelineCMOut.seconds)")
+            }else{
+                wself.withdrawAction()
             }
         }
         return m
@@ -1409,12 +1411,15 @@ public class BFRecordScreenController: BFBaseViewController {
     
         if !isDragingProgressSlder, isStopAtRecordRange != -1, isStopAtRecordRange < itemModels[currItemModelIndex].voiceStickers.count {
             let model = itemModels[currItemModelIndex].voiceStickers[isStopAtRecordRange]
-            itemModels[currItemModelIndex].voiceStickers.remove(at: isStopAtRecordRange)
-            indirectionView?.deleteItem(index: isStopAtRecordRange)
-            var event = WithDrawModel(type: 3, timestamp: currentAssetProgress, deletedVoices: [model], recordItem: rscurrentManager.recordItem!)
+
+            // 撤销记录点
+            var event = WithDrawModel(type: 3, timestamp: currentAssetProgress, recordItem: rscurrentManager.recordItem!.mutableCopy() as! BFRecordItemModel)
             event.deletedTittles = deleteTitles(voiceModel: model)
             events.append(event)
 
+            itemModels[currItemModelIndex].voiceStickers.remove(at: isStopAtRecordRange)
+            indirectionView?.deleteItem(index: isStopAtRecordRange)
+
             rscurrentManager.deleteRecord(at: currentAssetProgress)
             
             if currMediaType != .Video{
@@ -1459,7 +1464,11 @@ public class BFRecordScreenController: BFBaseViewController {
             BFLog(message: "录音机初始化错误!!!")
             return
         }
-
+        
+        // 添加撤销记录点
+        let event = WithDrawModel(type: 2, timestamp: currentAssetProgress, recordItem: rscurrentManager.recordItem!.mutableCopy() as! BFRecordItemModel)
+        events.append(event)
+        
         DispatchQueue.global().async {[weak self] in
             guard let wself = self else { return }
             
@@ -1474,9 +1483,7 @@ public class BFRecordScreenController: BFBaseViewController {
             wself.recorderManager?.startRecord()
             wself.recorderManager?.audioRecorder?.startNeoNui(wself.NeoNuiToken ?? "", appid: wself.NeoNuiAPPID ?? "")
     
-            // 添加撤销记录点
-            let event = WithDrawModel(type: 2, timestamp: model.startCMTime, recordItem: wself.rscurrentManager.recordItem!)
-            wself.events.append(event)
+
         }
 
         
@@ -1591,8 +1598,9 @@ public class BFRecordScreenController: BFBaseViewController {
                     wself.resetCurrentProgress()
                 }
             // 移除
-                
-                wself.resetAllIndirectionView()
+                if wself.currMediaType != .Camera{
+                    wself.resetAllIndirectionView()
+                }
             }
         }
         recorderManager?.voiceModel = nil
@@ -1602,170 +1610,6 @@ public class BFRecordScreenController: BFBaseViewController {
     @objc func withdrawAction() {
         pause()
         recoverRecord()
-        return
-        if let action = events.last {
-            let jumpTime = action.timestamp
-            if action.type == 2 {
-                // 撤销录制
-                if let modelIndex = itemModels[currItemModelIndex].voiceStickers.firstIndex(where: { mod in
-                    CMTimeCompare(mod.startCMTime, action.timestamp) == 0
-                }) {
-                    // 移除音频
-                    let model = itemModels[currItemModelIndex].voiceStickers[modelIndex]
-                    itemModels[currItemModelIndex].voiceStickers.remove(at: modelIndex)
-                    indirectionView?.deleteItem(index: modelIndex)
-
-                    // 删除对应字幕
-                    itemModels[currItemModelIndex].titleStickers.removeAll { m in
-                        m.audioFilePath == model.wavFilePath
-                    }
-
-                    // 恢复被覆盖的音频
-                    if let voiceTuples = action.deletedVoices{
-                        itemModels[currItemModelIndex].voiceStickers.append(contentsOf: voiceTuples)
-                        itemModels[currItemModelIndex].voiceStickers.sort { m1, m2 in
-                            CMTimeCompare(m1.startCMTime, m2.startCMTime) < 0
-                        }
-                    }
-                    
-                    // 恢复被覆盖的字幕
-                    if let titleTuples = action.deletedTittles{
-                        itemModels[currItemModelIndex].titleStickers.append(contentsOf: titleTuples)
-                        itemModels[currItemModelIndex].titleStickers.sort { m1, m2 in
-                            CMTimeCompare(m1.timelineOut, m2.timelineOut) < 0
-                        }
-                    }
-//                    jumpTime = model.startCMTime.seconds
-
-                    if currMediaType == .Image {
-                        itemModels[currItemModelIndex].materialDuraion = model.startCMTime
-                    }else if currMediaType == .Camera {
-                        let video = rscmanager.recordItem?.videoStickers.last
-                        rscmanager.revertLast(modelIndex)
-                        itemModels[currItemModelIndex].materialDuraion = video?.timelineCMIn ?? .zero
-                    }
-                }
-            } else if action.type == 3 {
-                // 恢复删除录音
-                if var tuples = action.deletedVoices{
-                    
-                    if currMediaType != .Video {
-
-                        tuples.sort { m1, m2 in
-                            CMTimeCompare(m1.startCMTime, m2.startCMTime) < 0
-                        }
-                        
-                        var firstTime = 0.0
-                        var currDuration : CMTime = .zero
-                        
-                        if currMediaType == .Camera, let first = action.deletedCameras?.first, let end = action.deletedCameras?.last {
-                            firstTime = first.timelineCMIn.seconds
-                            currDuration = (end.timelineCMOut - first.timelineCMIn)
-                        }else if currMediaType == .Image, let first = tuples.first, let end = tuples.last {
-                            firstTime = first.startCMTime.seconds
-                            currDuration = end.endCMTime - first.startCMTime
-                        }
-                        
-                        BFLog(1, message: "恢复删除时长:\(currDuration.seconds)")
-                        
-                        itemModels[currItemModelIndex].materialDuraion = itemModels[currItemModelIndex].materialDuraion + currDuration
-                        
-                        // 恢复录音的时间点
-                        let list = itemModels[currItemModelIndex].voiceStickers.filter({ mod in
-                            CMTimeCompare(mod.startCMTime, CMTime(seconds: firstTime, preferredTimescale: 1000)) >= 0
-                        })
-                    
-                        list.forEach { mod in
-                            mod.startCMTime = mod.startCMTime + currDuration
-                            mod.endCMTime = mod.endCMTime + currDuration
-                            
-                            // 恢复字幕的时间点
-                            let titlsList = itemModels[currItemModelIndex].titleStickers.filter { tm in
-                                tm.recordId == mod.recordId
-                            }
-                            
-                            for titleM in titlsList {
-                                titleM.timelineIn = titleM.timelineIn + currDuration
-                                titleM.timelineOut = titleM.timelineOut + currDuration
-                            }
-                        }
-                        
-                        if currMediaType == .Camera {
-                            rscmanager.cameraProgressV?.isHidden = false
-                            // 恢复录像的时间点
-                            _ = itemModels[currItemModelIndex].videoStickers.map { mod in
-                                if CMTimeCompare(mod.timelineCMIn, CMTime(seconds: firstTime, preferredTimescale: 1000)) >= 0{
-                                    mod.timelineCMIn = mod.timelineCMIn + currDuration
-                                    mod.timelineCMOut = mod.timelineCMOut + currDuration
-                                }
-                            }
-                            
-                            // 摄像头录制的
-                            if let videoTuple = action.deletedCameras {
-                                itemModels[currItemModelIndex].videoStickers.append(contentsOf: videoTuple)
-                                itemModels[currItemModelIndex].videoStickers.sort { m1, m2 in
-                                    CMTimeCompare(m1.timelineCMIn, m2.timelineCMIn) < 0
-                                }
-                                itemModels[currItemModelIndex].thumbImgs.removeAll()
-                                itemModels[currItemModelIndex].videoStickers.forEach { mod in
-                                    if let thumImag = mod.thumImgs{
-                                        itemModels[currItemModelIndex].thumbImgs.append(contentsOf: thumImag)
-                                    }
-                                }
-                                DispatchQueue.main.async {[weak self] in
-                                    guard let wself = self else { return }
-                                    wself.rscmanager.cameraProgressV?.resetThumIV()
-                                }
-                            }
-                        }
-                    
-                    }
-                    
-                    itemModels[currItemModelIndex].voiceStickers.append(contentsOf: tuples)
-                    itemModels[currItemModelIndex].voiceStickers.sort { m1, m2 in
-                        CMTimeCompare(m1.startCMTime, m2.startCMTime) < 0
-                    }
-                }
-                // 恢复字幕
-                
-                if let titleTuples = action.deletedTittles, titleTuples.count > 0 {
-                    itemModels[currItemModelIndex].titleStickers.append(contentsOf: titleTuples)
-                    itemModels[currItemModelIndex].titleStickers.sort { m1, m2 in
-                        CMTimeCompare(m1.timelineOut, m2.timelineOut) < 0
-                    }
-                }
-                if currMediaType == .Image {
-                    itemModels[currItemModelIndex].materialDuraion = itemModels[currItemModelIndex].voiceStickers.last?.endCMTime ?? .zero
-                }
-
-            } else {}
-            events.removeLast()
-
-            let dur = itemModels[currItemModelIndex].materialDuraion.seconds
-            changeProgress(changCMTime: (dur > 0) ? jumpTime : .zero)
-            
-            isDragingProgressSlder = false
-            currentPlayRecordIndex = -1
-            BFLog(3, message: "重置播放index-\(#function) = \(currentPlayRecordIndex)")
-            hadPrepareToPlayRecord = false
-            progressThumV.progress = jumpTime.seconds
-
-            if let event = events.last {
-                changeWithDrawBtnLayout(event.type)
-            } else {
-                changeWithDrawBtnLayout(0)
-                withDrawBtn.isEnabled = false
-            }
-            searchStopAtRecordRange()
-            let itemModel = itemModels[currItemModelIndex]
-            /// 重绘录音进度视图
-            resetAllIndirectionView()
-            // 如果是图片需重置播放按钮
-            if itemModel.mediaType != .Video {
-                playBtn.isSelected = itemModels[currItemModelIndex].voiceStickers.count <= 0
-                playBtn.isHidden = playBtn.isSelected
-            }
-        }
     }
 
     @objc func changeVoiceAction() {
@@ -1923,7 +1767,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 canInsertVideo = true
                 
                 changeProgress(changCMTime: endTime!)
-                progressThumV.progress = endTime!.seconds
+                progressThumV.progress = endTime!
                 
                 BFLog(1, message: "可以插入录音")
             }
@@ -1984,12 +1828,43 @@ public class BFRecordScreenController: BFBaseViewController {
     func recoverRecord() {
         if let action = events.last {
             // 重置播放器进度,按钮状态,缩略图展示,当前进度
-            rscurrentManager.recordItem = action.recordItem
-            changeProgress(changCMTime: action.timestamp)
-            progressThumV.progress = action.timestamp.seconds
-            searchStopAtRecordRange()
-            resetAllIndirectionView()
+            if action.type > 1 {
+                rscurrentManager.recordItem = action.recordItem
+                itemModels[currItemModelIndex] = action.recordItem
+            }
+            
+            events.removeLast()
             
+            let dur = itemModels[currItemModelIndex].materialDuraion.seconds
+            changeProgress(changCMTime: (dur > 0) ? action.timestamp : .zero)
+            
+            isDragingProgressSlder = false
+            currentPlayRecordIndex = -1
+            BFLog(3, message: "重置播放index-\(#function) = \(currentPlayRecordIndex)")
+            hadPrepareToPlayRecord = false
+            progressThumV.progress = action.timestamp
+            
+            if let event = events.last {
+                changeWithDrawBtnLayout(event.type)
+            } else {
+                changeWithDrawBtnLayout(0)
+                withDrawBtn.isEnabled = false
+            }
+            searchStopAtRecordRange()
+            let itemModel = itemModels[currItemModelIndex]
+            /// 重绘录音进度视图
+            if action.type > 1 {
+                resetAllIndirectionView()                
+            }else {
+                if currMediaType == .Camera {
+                    rscmanager.cameraProgressV?.progressView.contentOffset = CGPoint(x: currentAssetProgress.seconds * 70.0 / 5.0, y: 0)
+                }
+            }
+            // 如果是图片需重置播放按钮
+            if itemModel.mediaType != .Video {
+                playBtn.isSelected = itemModels[currItemModelIndex].voiceStickers.count <= 0
+                playBtn.isHidden = playBtn.isSelected
+            }
         }
     }
     
@@ -2112,6 +1987,8 @@ public class BFRecordScreenController: BFBaseViewController {
             hadPrepareToPlayRecord = false
             BFLog(1, message: "录音播放器初始化(有时候不准)")
             BFLog(3, message: "重置播放index-\(#function) = \(currentPlayRecordIndex)")
+            
+            //MARK:  播放器播放结束
             NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: newItem, queue: .main) { [weak self] _ in
                 guard let wself = self else {
                     BFLog(3, message: "wself为空AVPlayerItemDidPlayToEndTime")
@@ -2126,6 +2003,7 @@ public class BFRecordScreenController: BFBaseViewController {
             }
 //            recordPlayer.removeTimeObserver(recordPlayerTimeObserver as Any)
 //            recordPlayerTimeObserver?.invalidate()
+            //MARK: 声音播放器播放进度回调
             recordPlayerTimeObserver = recordPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 1000), queue: DispatchQueue.global()) { [weak self, weak recordPlayer] time in
                 guard let wself = self, let rPlay = recordPlayer else {
                     BFLog(3, message: "wself为空")
@@ -2241,12 +2119,18 @@ public class BFRecordScreenController: BFBaseViewController {
         itemModels[currItemModelIndex].titleStickers.sort { m1, m2 in
             CMTimeCompare(m1.timelineIn, m2.timelineIn) < 0
         }
-
+        itemModels[currItemModelIndex].videoStickers.sort(by: { m1, m2 in
+            m1.timelineCMIn.seconds < m2.timelineCMIn.seconds
+        })
+        itemModels[currItemModelIndex].voiceStickers.sort(by: { m1, m2 in
+            m1.startCMTime.seconds < m2.endCMTime.seconds
+        })
+        
         isNormalPlaying = true
         if isEndPlay || (currMediaType == .Image && CMTimeCompare(currentAssetProgress, itemModels[currItemModelIndex].materialDuraion) >= 0) {
             isEndPlay = false
             assetPlayer.seek(to: CMTime.zero)
-            progressThumV.progress = 0
+            progressThumV.progress = .zero
             currentPlayRecordIndex = -1
             BFLog(3, message: "重置播放index-\(#function) = \(currentPlayRecordIndex)")
 
@@ -2378,6 +2262,7 @@ public class BFRecordScreenController: BFBaseViewController {
             if avplayerTimeObserver != nil{
                 avplayerTimeObserver?.invalidate()
             }
+            //MARK: 视频播放器播放进度回调
             avplayerTimeObserver = assetPlayer.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 1000), queue: DispatchQueue.global()) { [weak self] time in
                 // 进度监控
                 guard let wself = self else { return }
@@ -2388,7 +2273,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 }
             } as? NSKeyValueObservation
         }
-
+        //MARK: 视频播放器结束回调
         NotificationCenter.default.addObserver(forName: .AVPlayerItemDidPlayToEndTime, object: assetPlayer.currentItem, queue: .main) { [weak self] _ in
             guard let wself = self else {
                 return
@@ -2429,7 +2314,7 @@ public class BFRecordScreenController: BFBaseViewController {
                     wself.progreddL.text = String(format: "%@", CMTimeGetSeconds(time).formatDurationToHMS())
                     let su = !wself.isDragingProgressSlder || wself.isRecording || wself.isNormalPlaying
                     if su { // 不拖动,正常播放和录音时更新进度条
-                        wself.progressThumV.progress = time.seconds
+                        wself.progressThumV.progress = time
                     }
                     // 更新字幕
                     if !wself.isRecording {
@@ -2856,7 +2741,7 @@ public extension BFRecordScreenController {
             }
 //            BFLog(1, message: "更新录音进度\(#function)-\(wself.currentAssetProgress.seconds ?? 0)")
             wself.progreddL.text = String(format: "%@", (wself.currentAssetProgress.seconds).formatDurationToHMS())
-            wself.progressThumV.progress = (wself.currentAssetProgress.seconds)
+            wself.progressThumV.progress = wself.currentAssetProgress
             wself.updateSubtitle(time: wself.currentAssetProgress)
         }
     }

+ 1 - 1
BFRecordScreenKit/Classes/RecordScreen/View/BFIndirectionProgressView.swift

@@ -61,7 +61,7 @@ class BFIndirectionProgressView: UIView {
         subviews.forEach { vv in
             vv.removeFromSuperview()
         }
-
+        
         items?.forEach { [weak self] model in
             _ = createItemView(minX: model.startCMTime.seconds * CGFloat(self?.percenWidth ?? 0), width: (model.endCMTime.seconds - model.startCMTime.seconds) * CGFloat(self?.percenWidth ?? 0))
         }

+ 3 - 4
BFRecordScreenKit/Classes/RecordScreen/View/Cell/BFImageCoverViewCell.swift

@@ -55,10 +55,6 @@ open class BFImageCoverViewCell: UICollectionViewCell {
         super.init(frame: frame)
         contentView.addSubview(playView)
         contentView.addSubview(playBtn)
-        
-        if(recordItem?.mediaType == .Image){
-            contentView.addSubview(playImageView)
-        }
     }
 
     public required init?(coder _: NSCoder) {
@@ -85,6 +81,9 @@ open class BFImageCoverViewCell: UICollectionViewCell {
 //        }
     
         if(recordItem?.mediaType == .Image){
+            if playImageView.superview == nil {
+                contentView.addSubview(playImageView)                
+            }
             playImageView.image = coverImg
         }else{
             playImageView.removeFromSuperview()

+ 70 - 49
BFRecordScreenKit/Classes/RecordScreen/View/ProgressView/BFCameraProgressView.swift

@@ -10,12 +10,17 @@ import BFCommonKit
 import BFUIKit
 import CoreMedia
 import UIKit
+import BFMediaKit
 
 class BFCameraProgressView: BFProgressBaseView {
     
     var imageViews = [BFThumImageView]()
     
-    var newRecord = false
+    // 判断是否需要分割线的(最后一个录音或者是超出5秒的缩略图不要分割线)
+    var newRecordLine = false
+    
+    // 上次更新缩略图长度时的时间戳
+    var lastUpdateTime : CMTime = .zero
     
     lazy var progressView: BFAutolayoutScrollView = {
         let sv = BFAutolayoutScrollView()
@@ -52,36 +57,47 @@ class BFCameraProgressView: BFProgressBaseView {
     
     /// 添加缩略图
     /// - Parameter images:
-    func addThumbImages() {
+    func addThumbImages(_ img:UIImage) {
         DispatchQueue.main.async {[weak self] in
             guard let wself = self else { return }
             
-            if let img = wself.recordItem?.thumbImgs.last {
-                let iv = BFThumImageView(image: img)
-                iv.image = img
-                iv.contentMode = .scaleAspectFill
-                iv.clipsToBounds = true
-                iv.isHiddenBord = true
-                wself.progressView.contentView.addSubview(iv)
-
-                if let lastiv = wself.imageViews.last {
-                    let wid = wself.recordItem!.videoStickers.last!.timelineCMOut.seconds * 70.0 / 5.0 - (lastiv.rightX - cScreenWidth / 2.0)
-                    let wid0 = floor(wid * UIScreen.main.scale) /  UIScreen.main.scale
-                    iv.frame = CGRect(x: lastiv.rightX, y: lastiv.y, width: wid0, height: 50)
-                    if wself.newRecord {
-                        lastiv.isHiddenBord = false
-                        wself.newRecord = false
-                    }
-                    BFLog(1, message: "frame: new \(wid0)")
-                }else{
+            let iv = BFThumImageView(image: img)
+            iv.image = img
+            iv.contentMode = .scaleAspectFill
+            iv.clipsToBounds = true
+            iv.isHiddenBord = true
+            wself.progressView.contentView.addSubview(iv)
+            
+            if let ind = wself.recordItem?.thumbImgs.firstIndex(where: { image in
+                image == img
+            }){
+                if ind == 0 {
                     iv.frame = CGRect(x: cScreenWidth / 2.0, y: 0, width: 0, height: 50)
+                }else{
+                    if wself.imageViews.count > ind - 1 {
+                        let lastiv = wself.imageViews[ind - 1]
+                        if let sticker = wself.recordItem!.videoStickers.first(where: { mod in
+                            mod.thumImgs!.contains(img)
+                        }){
+                            let wid = sticker.timelineCMOut.seconds * 70.0 / 5.0 - (lastiv.rightX - cScreenWidth / 2.0)
+                            let wid0 = floor(wid * UIScreen.main.scale) /  UIScreen.main.scale
+                            iv.frame = CGRect(x: lastiv.rightX, y: lastiv.y, width: wid0, height: 50)
+                            BFLog(1, message: "frame: new \(wid0)")
+                            if wself.newRecordLine {
+                                lastiv.isHiddenBord = false
+                                wself.newRecordLine = false
+                            }
+                            
+                        }
+                    }
                 }
-                wself.imageViews.append(iv)
-
-                wself.progressView.setNeedsLayout()
-                wself.progressView.layoutIfNeeded()
+                wself.imageViews.insert(iv, at: ind)
             }
             
+
+            wself.progressView.setNeedsLayout()
+            wself.progressView.layoutIfNeeded()
+            
         }
         
     }
@@ -127,12 +143,13 @@ class BFCameraProgressView: BFProgressBaseView {
         progressView.contentSize = CGSize(width: p.x + cScreenWidth, height: 50)
     }
     
-    func updateCellWidth(index:Int, progress:CMTime) {
-        if let sticker = recordItem?.videoStickers.first(where: { mod in
-            CMTimeCompare(mod.timelineCMIn, progress) <= 0 &&  CMTimeCompare(mod.timelineCMOut, progress) >= 0
-        }) {
-            if index < imageViews.count{
-                let lastiv = imageViews[index]
+    //
+    func updateCellWidth(sticker:PQEditVisionTrackMaterialsModel, progress:CMTime) {
+
+        if let img = sticker.thumImgs?.last {
+            if let lastiv = imageViews.first(where: { v in
+                v.image == img
+            }){
                 let wid = progress.seconds * 70.0 / 5.0 - (lastiv.x - cScreenWidth / 2.0)
                 let wid0 = min(floor(wid * UIScreen.main.scale) /  UIScreen.main.scale, 70)
                 
@@ -140,34 +157,38 @@ class BFCameraProgressView: BFProgressBaseView {
                     return
                 }
                 var frame = lastiv.frame
+                let offsetx = wid0 - frame.size.width
                 frame.size.width = wid0
                 lastiv.frame = frame
-            }
-
-            let p = CGPoint(x: progress.seconds * 70 / 5.0, y: 0)
-            progressView.contentOffset = p
-//            progressView.contentSize = CGSize(width: p.x + cScreenWidth, height: 50)
-    
-            // 刷新之后的sticker
-            recordItem?.videoStickers.forEach({ mod in
-                if mod.timelineCMOut.seconds > progress.seconds {
-                    BFLog(1, message: "insert before: \(mod.timelineCMIn)")
-                    mod.timelineCMIn = mod.timelineCMIn + (sticker.timelineCMOut - sticker.timelineCMIn)
-                    mod.timelineCMOut = mod.timelineCMOut + (sticker.timelineCMOut - sticker.timelineCMIn)
-                    BFLog(1, message: "insert after: \(mod.timelineCMIn)")
-
+                
+                imageViews.forEach { iv in
+                    if iv.rightX > lastiv.rightX, offsetx > 0 {
+                        let frame = iv.frame
+                        iv.frame = frame.offsetBy(dx: offsetx, dy: 0)
+                    }
                 }
-            })
-            if let last = recordItem?.videoStickers.last {
-                progressView.contentSize = CGSize(width: last.timelineCMOut.seconds * 70 / 5.0 + cScreenWidth, height: 50)
             }
-            BFLog(1, message: "insert contentSize: \(progressView.contentSize.width),offset: \(progressView.contentOffset.x)")
         }
         
+        let p = CGPoint(x: progress.seconds * 70 / 5.0, y: 0)
+        progressView.contentOffset = p
+        //            progressView.contentSize = CGSize(width: p.x + cScreenWidth, height: 50)
+        
+        if let last = recordItem?.videoStickers.last {
+            progressView.contentSize = CGSize(width: last.timelineCMOut.seconds * 70 / 5.0 + cScreenWidth, height: 50)
+        }
+//        BFLog(1, message: "insert contentSize: \(progressView.contentSize.width),offset: \(progressView.contentOffset.x)")
+        
     }
     
+    // 结束本次录制
     func changeSepline(img:UIImage){
-        newRecord = true
+        newRecordLine = true
+        if img != recordItem?.thumbImgs.last {
+            imageViews.first { iv in
+                iv.image == img
+            }?.isHiddenBord = false
+        }
     }
 }
 

+ 4 - 4
BFRecordScreenKit/Classes/RecordScreen/View/ProgressView/BFVideoThumbProgressView.swift

@@ -17,7 +17,7 @@ class BFVideoThumbProgressView: BFProgressBaseView {
         didSet {
             // 指针回归
 //            BFLog(1, message: "new recorditem")
-            progress = 0
+            progress = .zero
             if recordItem?.mediaType == .Video {
                 
                 DispatchQueue.main.async {[weak self] in
@@ -45,9 +45,9 @@ class BFVideoThumbProgressView: BFProgressBaseView {
 
     let fetchThumbStrategy: BFVideoThumbProgressStrategyProtocol = BFVideoThumbProgressStrategy()
 
-    var progress: Double = 0 { // 进度,秒为单位
+    var progress: CMTime = .zero { // 进度,秒为单位
         didSet {
-            updateProgress(progress: progress)
+            updateProgress(progress: progress.seconds)
         }
     }
 
@@ -204,7 +204,7 @@ class BFVideoThumbProgressView: BFProgressBaseView {
                     
                     wself.lastImg = iv
                 }
-                BFLog(1, message: "last img \(wself.lastImg), \(images.count)")
+
                 wself.progressView.contentView.setNeedsLayout()
                 wself.progressView.contentView.layoutIfNeeded()
                 if wself.recordItem?.mediaType == .Image {

+ 5 - 3
BFRecordScreenKit/Classes/BFRecordItemModel.swift → BFRecordScreenKit/Classes/RecordScreen/ViewModel/BFRecordItemModel.swift

@@ -60,13 +60,15 @@ public class BFRecordItemModel: NSObject {
 
         
         self.voiceStickers.forEach { mod in
-            new.voiceStickers.append(mod.mutableCopy() as! PQVoiceModel)
+            new.voiceStickers.append(mod.copy() as! PQVoiceModel)
         }
         self.videoStickers.forEach { mod in
-            new.videoStickers.append(mod.mutableCopy() as! PQEditVisionTrackMaterialsModel)
+            let copymod = mod.copy() as! PQEditVisionTrackMaterialsModel
+            copymod.thumImgs = mod.thumImgs
+            new.videoStickers.append(copymod)
         }
         self.titleStickers.forEach { mod in
-            new.titleStickers.append(mod.mutableCopy() as! PQEditSubTitleModel)
+            new.titleStickers.append(mod.copy() as! PQEditSubTitleModel)
         }
         new.thumbImgs.append(contentsOf: self.thumbImgs)