|
@@ -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)
|
|
|
}
|
|
|
}
|