|
@@ -75,10 +75,6 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
if isSuccess, let sticker = sticker{
|
|
if isSuccess, let sticker = sticker{
|
|
wself.rscurrentManager.currentAssetProgress = sticker.timelineCMOut
|
|
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)")
|
|
// BFLog(1, message: "camera:\(sticker.timelineCMIn.seconds) ~ \(sticker.timelineCMOut.seconds)")
|
|
}else{
|
|
}else{
|
|
wself.withdrawAction()
|
|
wself.withdrawAction()
|
|
@@ -171,7 +167,6 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
rscurrentManager.progreddL = progreddL
|
|
rscurrentManager.progreddL = progreddL
|
|
rscurrentManager.recordPlayer = recordPlayer
|
|
rscurrentManager.recordPlayer = recordPlayer
|
|
rscurrentManager.progressThumV = progressThumV
|
|
rscurrentManager.progressThumV = progressThumV
|
|
- progressThumV.recordItem = itemModel
|
|
|
|
rscurrentManager.recordItem = itemModel
|
|
rscurrentManager.recordItem = itemModel
|
|
rscurrentManager.resetEnv()
|
|
rscurrentManager.resetEnv()
|
|
if currMediaType == .Video {
|
|
if currMediaType == .Video {
|
|
@@ -1104,109 +1099,97 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
if let model = voideModel, FileManager.default.fileExists(atPath: model.wavFilePath ?? "") {
|
|
if let model = voideModel, FileManager.default.fileExists(atPath: model.wavFilePath ?? "") {
|
|
// 加入到语音数组里
|
|
// 加入到语音数组里
|
|
-
|
|
|
|
model.endCMTime = wself.currentAssetProgress
|
|
model.endCMTime = wself.currentAssetProgress
|
|
-// BFLog(1, message: "录音地址:\((model.wavFilePath ?? "").replacingOccurrences(of: documensDirectory, with: ""))")
|
|
|
|
|
|
+
|
|
BFLog(1, message: " 文件时长record:\(wself.rscmanager.recordItem?.voiceStickers.count ?? 0), \(model.startCMTime.seconds) -- \(model.endCMTime.seconds), dur: \(model.endCMTime.seconds - model.startCMTime.seconds)")
|
|
BFLog(1, message: " 文件时长record:\(wself.rscmanager.recordItem?.voiceStickers.count ?? 0), \(model.startCMTime.seconds) -- \(model.endCMTime.seconds), dur: \(model.endCMTime.seconds - model.startCMTime.seconds)")
|
|
- wself.recordFinished((model.endCMTime.seconds - model.startCMTime.seconds) >= 1)
|
|
|
|
-
|
|
|
|
|
|
+
|
|
/// 注:录音机回调的录音时长大于一秒,而业务逻辑计算的会小于一秒
|
|
/// 注:录音机回调的录音时长大于一秒,而业务逻辑计算的会小于一秒
|
|
if (model.endCMTime.seconds - model.startCMTime.seconds) < 1 {
|
|
if (model.endCMTime.seconds - model.startCMTime.seconds) < 1 {
|
|
// 取消录制
|
|
// 取消录制
|
|
|
|
+ wself.recordFinished(false)
|
|
return
|
|
return
|
|
}
|
|
}
|
|
- // ********** 开始处理冲突的录制部分
|
|
|
|
- let newRange = CMTimeRange(start: model.startCMTime, end: model.endCMTime)
|
|
|
|
-
|
|
|
|
- var deletedVoices = [PQVoiceModel]()
|
|
|
|
- // 要删除的字幕
|
|
|
|
- var deletedTitlesTemp = [PQEditSubTitleModel]()
|
|
|
|
-
|
|
|
|
- // 查找要删除的音频和字幕数据
|
|
|
|
- for m in wself.itemModels[wself.currItemModelIndex].voiceStickers {
|
|
|
|
- let originRange = CMTimeRange(start: m.startCMTime, end: CMTime(seconds: m.endCMTime.seconds - 0.02, preferredTimescale: 1000))
|
|
|
|
- if CMTimeRangeGetIntersection(originRange, otherRange: newRange).duration.seconds > 0 {
|
|
|
|
- deletedVoices.append(m)
|
|
|
|
- deletedTitlesTemp += wself.deleteTitles(voiceModel: m)
|
|
|
|
- continue
|
|
|
|
|
|
+
|
|
|
|
+ if wself.currMediaType == .Video {
|
|
|
|
+ // ********** 开始处理冲突的录制部分
|
|
|
|
+ wself.overrideRecordDeal(model: model)
|
|
|
|
+
|
|
|
|
+ }else if wself.currMediaType == .Image {
|
|
|
|
+
|
|
|
|
+ if let recordItem = wself.rsimanager.recordItem {
|
|
|
|
+
|
|
|
|
+ let duration = model.endCMTime - model.startCMTime
|
|
|
|
+
|
|
|
|
+ recordItem.voiceStickers.forEach({ mod in
|
|
|
|
+ if mod.startCMTime.seconds >= model.startCMTime.seconds {
|
|
|
|
+ mod.startCMTime = mod.startCMTime + duration
|
|
|
|
+ mod.endCMTime = mod.endCMTime + duration
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ recordItem.voiceChangeStickers.forEach({ mod in
|
|
|
|
+ if mod.startCMTime.seconds >= model.startCMTime.seconds {
|
|
|
|
+ mod.startCMTime = mod.startCMTime + duration
|
|
|
|
+ mod.endCMTime = mod.endCMTime + duration
|
|
|
|
+ }
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ recordItem.titleStickers.forEach({ mod in
|
|
|
|
+ if mod.timelineIn.seconds >= model.startCMTime.seconds {
|
|
|
|
+ mod.timelineIn = mod.timelineIn + duration
|
|
|
|
+ mod.timelineOut = mod.timelineOut + duration
|
|
|
|
+ }
|
|
|
|
+ })
|
|
}
|
|
}
|
|
}
|
|
}
|
|
- // 删除冲突的音频
|
|
|
|
- deletedVoices.forEach { m in
|
|
|
|
- wself.itemModels[wself.currItemModelIndex].voiceStickers.removeAll { tempM in
|
|
|
|
- m.wavFilePath == tempM.wavFilePath
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ wself.itemModels[wself.currItemModelIndex].voiceStickers.append(model)
|
|
|
|
+ wself.itemModels[wself.currItemModelIndex].voiceStickers.sort { m1, m2 in
|
|
|
|
+ m1.startCMTime.seconds < m2.startCMTime.seconds
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ // 录制结束manager处理
|
|
|
|
+ wself.recordFinished(true)
|
|
|
|
|
|
- wself.itemModels[wself.currItemModelIndex].voiceStickers.append(model)
|
|
|
|
// 录制结束回调给主工程页面(埋点之类功能)
|
|
// 录制结束回调给主工程页面(埋点之类功能)
|
|
wself.recordEndHandle?(model)
|
|
wself.recordEndHandle?(model)
|
|
- // 如果是图片素材同时有需要删除的录音时需要调整录音文件开始结束时间
|
|
|
|
- // warning: 图片录制的时候应该只能在结尾处录制
|
|
|
|
- if wself.currMediaType == .Image {
|
|
|
|
- if deletedVoices.count > 0 {
|
|
|
|
- // 如果是图片先排序在计算区间
|
|
|
|
- wself.itemModels[wself.currItemModelIndex].voiceStickers = wself.itemModels[wself.currItemModelIndex].voiceStickers.sorted { voice1, voice2 in
|
|
|
|
- voice1.startCMTime.seconds < voice2.startCMTime.seconds
|
|
|
|
- }
|
|
|
|
- for (index, item) in wself.itemModels[wself.currItemModelIndex].voiceStickers.enumerated() {
|
|
|
|
- if index > 0 {
|
|
|
|
- // 注:开始时间减去duration or 等一前一段录音的结束时间
|
|
|
|
- let tempDuration = item.endCMTime.seconds - item.startCMTime.seconds
|
|
|
|
- item.startCMTime = CMTime(seconds: wself.itemModels[wself.currItemModelIndex].voiceStickers[index - 1].endCMTime.seconds, preferredTimescale: 1000)
|
|
|
|
- item.endCMTime = CMTime(seconds: item.startCMTime.seconds + tempDuration, preferredTimescale: 1000)
|
|
|
|
- }
|
|
|
|
- BFLog(1, message: "录制结束重新排序录音文件:\(index)-\(item.wavFilePath ?? "")-\(item.startCMTime.seconds)-\(item.endCMTime.seconds)-\(item.endCMTime.seconds - item.startCMTime.seconds)")
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- }
|
|
|
|
- // ***********处理冲突的录音部分资源 end
|
|
|
|
|
|
|
|
if wself.currMediaType != .Video {
|
|
if wself.currMediaType != .Video {
|
|
- var duration: CMTime = .zero
|
|
|
|
- if wself.currMediaType == .Image{
|
|
|
|
- wself.itemModels[wself.currItemModelIndex].voiceStickers.forEach { temp in
|
|
|
|
- BFLog(1, message: "录制结束-最终:\(temp.wavFilePath ?? "")-\(temp.startCMTime.seconds)-\(temp.endCMTime.seconds)-\(temp.endCMTime.seconds - temp.startCMTime.seconds)")
|
|
|
|
- temp.duration = "\(temp.endCMTime.seconds - temp.startCMTime.seconds)"
|
|
|
|
- duration = duration + temp.endCMTime - temp.startCMTime
|
|
|
|
- }
|
|
|
|
- wself.itemModels[wself.currItemModelIndex].materialDuraion = duration
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
wself.isEndPlay = true
|
|
wself.isEndPlay = true
|
|
- // 录制结束显示播放按钮
|
|
|
|
- if wself.currMediaType == .Camera {
|
|
|
|
- wself.playBtn.isSelected = true
|
|
|
|
- wself.playBtn.isHidden = true
|
|
|
|
- }else {
|
|
|
|
- wself.playBtn.isSelected = wself.itemModels[wself.currItemModelIndex].voiceStickers.count <= 0
|
|
|
|
- wself.playBtn.isHidden = wself.playBtn.isSelected
|
|
|
|
- }
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
DispatchQueue.main.async { [weak self] in
|
|
DispatchQueue.main.async { [weak self] in
|
|
guard let wself = self else { return }
|
|
guard let wself = self else { return }
|
|
|
|
|
|
- // 录音完,重绘撤销按钮,更新录音按钮,
|
|
|
|
|
|
+ // 更新playbtn按钮状态
|
|
|
|
+ wself.updatePlayBtnStatus()
|
|
|
|
+
|
|
|
|
+ // 更新录音按钮状态
|
|
|
|
+ wself.updateRecordBtnStatus(false)
|
|
|
|
+
|
|
|
|
+ // 录音完,更新撤销按钮
|
|
wself.changeWithDrawBtnLayout(2)
|
|
wself.changeWithDrawBtnLayout(2)
|
|
|
|
+
|
|
// 注:在录制结束时矫正当前位置,避免跟指针无法对其
|
|
// 注:在录制结束时矫正当前位置,避免跟指针无法对其
|
|
wself.indirectionView?.resetCurrentItem(start: model.startCMTime.seconds, end: model.endCMTime.seconds)
|
|
wself.indirectionView?.resetCurrentItem(start: model.startCMTime.seconds, end: model.endCMTime.seconds)
|
|
- if deletedVoices.count > 0 {
|
|
|
|
- /// 重绘录音进度视图
|
|
|
|
- wself.resetAllIndirectionView()
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
|
|
+ // 重置底部蓝色录音条
|
|
|
|
+ wself.resetAllIndirectionView()
|
|
|
|
+
|
|
// 矫正进度
|
|
// 矫正进度
|
|
wself.resetCurrentProgress()
|
|
wself.resetCurrentProgress()
|
|
- wself.deleteRecordBtn.isHidden = true
|
|
|
|
- wself.recordBtn.isHidden = (wself.currMediaType != .Video && (wself.isEndPlay )) ? false : (wself.isEndPlay )
|
|
|
|
}
|
|
}
|
|
|
|
+
|
|
wself.currentPlayRecordIndex = -3 // 刚录音完,不需要播放录音
|
|
wself.currentPlayRecordIndex = -3 // 刚录音完,不需要播放录音
|
|
BFLog(3, message: "重置播放index-\(#function) = \(wself.currentPlayRecordIndex)")
|
|
BFLog(3, message: "重置播放index-\(#function) = \(wself.currentPlayRecordIndex)")
|
|
recorderManager?.voiceModel = nil
|
|
recorderManager?.voiceModel = nil
|
|
|
|
+
|
|
} else {
|
|
} else {
|
|
wself.rscurrentManager.recordFinished(isSuccess: false)
|
|
wself.rscurrentManager.recordFinished(isSuccess: false)
|
|
BFLog(2, message: "数据出错!!!!\(voideModel?.wavFilePath ?? "")")
|
|
BFLog(2, message: "数据出错!!!!\(voideModel?.wavFilePath ?? "")")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
recorderManager?.cancelRecordHandle = { [weak self] voiceModel in
|
|
recorderManager?.cancelRecordHandle = { [weak self] voiceModel in
|
|
guard let wself = self else { return }
|
|
guard let wself = self else { return }
|
|
// 取消录制
|
|
// 取消录制
|
|
@@ -1231,7 +1214,6 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
cShowHUB(superView: wself.view, msg: msg)
|
|
cShowHUB(superView: wself.view, msg: msg)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
-
|
|
|
|
}
|
|
}
|
|
|
|
|
|
@objc func editSubtitle() {
|
|
@objc func editSubtitle() {
|
|
@@ -1832,15 +1814,18 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
case .Video:
|
|
case .Video:
|
|
playBtn.isSelected = false
|
|
playBtn.isSelected = false
|
|
- playBtn.isHidden = false
|
|
|
|
|
|
+ playBtn.isHidden = playBtn.isSelected
|
|
|
|
+
|
|
case .Camera:
|
|
case .Camera:
|
|
playBtn.isSelected = isEndPlay ? true : ((rscmanager.recordItem?.voiceStickers.count ?? -1) <= 0)
|
|
playBtn.isSelected = isEndPlay ? true : ((rscmanager.recordItem?.voiceStickers.count ?? -1) <= 0)
|
|
playBtn.isHidden = playBtn.isSelected
|
|
playBtn.isHidden = playBtn.isSelected
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
- func updateRecordBtnStatus(_ show:Bool? = nil){
|
|
|
|
- let su = show ?? false
|
|
|
|
|
|
+ /// 更新录音按钮状态
|
|
|
|
+ /// - Parameter hidden: 是否隐藏
|
|
|
|
+ func updateRecordBtnStatus(_ hidden:Bool? = nil){
|
|
|
|
+ let su = hidden ?? false
|
|
switch currMediaType {
|
|
switch currMediaType {
|
|
case .Image:
|
|
case .Image:
|
|
recordBtn.isHidden = (isEndPlay || canInsertVideo) ? false : su
|
|
recordBtn.isHidden = (isEndPlay || canInsertVideo) ? false : su
|
|
@@ -1887,7 +1872,6 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
changeWithDrawBtnLayout(event.type)
|
|
changeWithDrawBtnLayout(event.type)
|
|
} else {
|
|
} else {
|
|
changeWithDrawBtnLayout(0)
|
|
changeWithDrawBtnLayout(0)
|
|
- withDrawBtn.isEnabled = false
|
|
|
|
}
|
|
}
|
|
searchStopAtRecordRange()
|
|
searchStopAtRecordRange()
|
|
let itemModel = itemModels[currItemModelIndex]
|
|
let itemModel = itemModels[currItemModelIndex]
|
|
@@ -1899,14 +1883,34 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
rscmanager.cameraProgressV?.progressView.contentOffset = CGPoint(x: currentAssetProgress.seconds * 70.0 / 5.0, y: 0)
|
|
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
|
|
|
|
- }
|
|
|
|
|
|
+
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ func overrideRecordDeal(model: PQVoiceModel){
|
|
|
|
+ // ********** 开始处理冲突的录制部分
|
|
|
|
+ let newRange = CMTimeRange(start: model.startCMTime, end: model.endCMTime)
|
|
|
|
+
|
|
|
|
+ var deletedVoices = [PQVoiceModel]()
|
|
|
|
+ // 要删除的字幕
|
|
|
|
+ var deletedTitlesTemp = [PQEditSubTitleModel]()
|
|
|
|
+
|
|
|
|
+ // 查找要删除的音频和字幕数据
|
|
|
|
+ for m in itemModels[currItemModelIndex].voiceStickers {
|
|
|
|
+ let originRange = CMTimeRange(start: m.startCMTime, end: CMTime(seconds: m.endCMTime.seconds - 0.02, preferredTimescale: 1000))
|
|
|
|
+ if CMTimeRangeGetIntersection(originRange, otherRange: newRange).duration.seconds > 0 {
|
|
|
|
+ deletedVoices.append(m)
|
|
|
|
+ deletedTitlesTemp += deleteTitles(voiceModel: m)
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ // 删除冲突的音频
|
|
|
|
+ deletedVoices.forEach { m in
|
|
|
|
+ itemModels[currItemModelIndex].voiceStickers.removeAll { tempM in
|
|
|
|
+ m.wavFilePath == tempM.wavFilePath
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
|
|
// MARK: - 权限申请
|
|
// MARK: - 权限申请
|
|
|
|
|
|
@@ -2369,7 +2373,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
}
|
|
}
|
|
|
|
|
|
if isRecording {
|
|
if isRecording {
|
|
- let startTime = recorderManager?.voiceModel?.startCMTime.seconds ?? 0
|
|
|
|
|
|
+ let startTime = recorderManager?.voiceModel?.startCMTime ?? .zero
|
|
let progress = (currentAssetProgress - (recorderManager?.voiceModel?.startCMTime ?? .zero)).seconds // - ratioX
|
|
let progress = (currentAssetProgress - (recorderManager?.voiceModel?.startCMTime ?? .zero)).seconds // - ratioX
|
|
// 使用播放器的进度来画线,因为进度是跟着播放器来了
|
|
// 使用播放器的进度来画线,因为进度是跟着播放器来了
|
|
DispatchQueue.main.async { [weak self] in
|
|
DispatchQueue.main.async { [weak self] in
|
|
@@ -2385,11 +2389,15 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
|
|
|
|
// 撤销按钮修改title,重绘
|
|
// 撤销按钮修改title,重绘
|
|
func changeWithDrawBtnLayout(_ type: Int) {
|
|
func changeWithDrawBtnLayout(_ type: Int) {
|
|
|
|
+ withDrawBtn.isEnabled = true
|
|
switch type {
|
|
switch type {
|
|
case 3:
|
|
case 3:
|
|
withDrawBtn.setTitle("record_recover".BFLocale, for: .normal)
|
|
withDrawBtn.setTitle("record_recover".BFLocale, for: .normal)
|
|
case 2:
|
|
case 2:
|
|
withDrawBtn.setTitle("record_undo".BFLocale, for: .normal)
|
|
withDrawBtn.setTitle("record_undo".BFLocale, for: .normal)
|
|
|
|
+ case 0:
|
|
|
|
+ withDrawBtn.isEnabled = false
|
|
|
|
+ fallthrough
|
|
default:
|
|
default:
|
|
withDrawBtn.setTitle("record_back".BFLocale, for: .normal)
|
|
withDrawBtn.setTitle("record_back".BFLocale, for: .normal)
|
|
}
|
|
}
|
|
@@ -2481,7 +2489,7 @@ public class BFRecordScreenController: BFBaseViewController {
|
|
// 注:视频无法以录制进度驱动,因当录音开始录音时播放器还未播放,导致进度不一致
|
|
// 注:视频无法以录制进度驱动,因当录音开始录音时播放器还未播放,导致进度不一致
|
|
// 注:在录制停止时,视频播放器进度依然在走,误差在80毫秒左右
|
|
// 注:在录制停止时,视频播放器进度依然在走,误差在80毫秒左右
|
|
if isRecording, currMediaType == .Image {
|
|
if isRecording, currMediaType == .Image {
|
|
- let startTime = recorderManager?.voiceModel?.startCMTime.seconds ?? 0
|
|
|
|
|
|
+ let startTime = recorderManager?.voiceModel?.startCMTime ?? .zero
|
|
// 使用播放器的进度来画线,因为进度是跟着播放器来了
|
|
// 使用播放器的进度来画线,因为进度是跟着播放器来了
|
|
indirectionView?.setProgress(start: startTime, progress: progress)
|
|
indirectionView?.setProgress(start: startTime, progress: progress)
|
|
}
|
|
}
|