Browse Source

Merge branch 'dev' of https://git.yishihui.com/iOS/BFRecordScreenKit into dev

* 'dev' of https://git.yishihui.com/iOS/BFRecordScreenKit:
  录制视频模式播放中如果有发音人使用 变时数据
  添加保存变音数据变量
  loading ui 界面
  1,添加 loading view 2,有字幕数据后 添加到转换缓存  3,XXXX 如果有发音人音频播放时使用发音人数据  4, 添加判断任务是否都完成方法, 5, 接收转换完成的音频数据 model
  loading 界面用的资源
胡志强 3 years ago
parent
commit
0717ac401e

+ 23 - 0
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/LoadingClose.imageset/Contents.json

@@ -0,0 +1,23 @@
+{
+  "images" : [
+    {
+      "filename" : "LoadingClose.png",
+      "idiom" : "universal",
+      "scale" : "1x"
+    },
+    {
+      "filename" : "LoadingClose@2x.png",
+      "idiom" : "universal",
+      "scale" : "2x"
+    },
+    {
+      "filename" : "LoadingClose@3x.png",
+      "idiom" : "universal",
+      "scale" : "3x"
+    }
+  ],
+  "info" : {
+    "author" : "xcode",
+    "version" : 1
+  }
+}

BIN
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/LoadingClose.imageset/LoadingClose.png


BIN
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/LoadingClose.imageset/LoadingClose@2x.png


BIN
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/LoadingClose.imageset/LoadingClose@3x.png


BIN
BFRecordScreenKit/Assets/stuckPoint_edit_loading.gif


+ 13 - 1
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenCameraManager.swift

@@ -24,6 +24,7 @@ import BFUIKit
 import BFMediaKit
 import CoreMedia
 import UIKit
+import SwiftUI
 
 
 let vpath = recordVideosDirectory + "camera_writer.mov"
@@ -440,7 +441,18 @@ class BFRecordScreenCameraManager : BFRecordScreenBaseManager{
     
     func playRecordVoice(needPlay:Bool = true){
         // 播放音频
-        if let mod = recordItem?.voiceStickers.first(where: { m in
+        var useVoiceStickers = [PQVoiceModel]()
+        if((recordItem?.voiceChangeStickers.count ?? 0) > 0){
+            useVoiceStickers = recordItem?.voiceChangeStickers ?? [PQVoiceModel]()
+        }else{
+            useVoiceStickers = recordItem?.voiceStickers ?? [PQVoiceModel]()
+        }
+        
+        for model in useVoiceStickers {
+            BFLog(message: " 时间范围:\(model.startCMTime.seconds) 到 \(model.endCMTime.seconds) \(currentAssetProgress.seconds)")
+        }
+       
+        if let mod = useVoiceStickers.first(where: { m in
             CMTimeCompare(m.startCMTime, currentAssetProgress + CMTime(seconds: 0.033, preferredTimescale: 1000)) <= 0 && CMTimeCompare(m.endCMTime, (currentAssetProgress + CMTime(seconds: 0.033, preferredTimescale: 1000))) > 0
         }){
             recordPlayer?.replaceCurrentItem(with: AVPlayerItem(url: URL(fileURLWithPath: mod.wavFilePath)))

+ 93 - 5
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenController.swift

@@ -91,6 +91,15 @@ public class BFRecordScreenController: BFBaseViewController {
     // MARK: - 录制参数
     public var assets = [PHAsset]()
     
+    /// 显示数据处理中加载动画
+    lazy var loadingView: BFLoadingView = {
+        var loadingView = BFLoadingView(frame: CGRect(x: 0, y: 0, width: cScreenWidth, height: cScreenHeigth))
+        loadingView.isHidden = true
+       
+        return loadingView
+    }()
+
+    
     var currItemModelIndex = 0 {
         didSet{
             if currItemModelIndex < 0 || currItemModelIndex >= itemModels.count{
@@ -808,12 +817,20 @@ public class BFRecordScreenController: BFBaseViewController {
             guard let wself = self else { return }
           
             if actionType == .VoiceSettingActionConfirm{//要生成真实音频文件
+                wself.tts?.stopTTS("")
                 BFLog(2, message: "确认选择发音人操作")
                 wself.mSelectVoiced = selectVoice
                 wself.voiceSettingView.flushSelectVoiceStatus(voiceStatue: .isSelected)
                 if(wself.mSelectVoiced != nil){
-                    wself.tts?.startTTS("", taskId: "", isAudition: false,fontName: selectVoice?.voice ?? "")
+                    //显示 UI
                     wself.voiceIconView.setNetImage(url: "\(wself.mSelectVoiced?.avatarUrl ?? "")")
+                    if(!wself.voiceChangeStickerFinish(itemIndex: wself.currItemModelIndex)){
+
+                        wself.loadingView.loading()
+                    }
+                    //静默转换语音
+                    wself.tts?.runNextTask()
+                 
                     
                 }else{
                     wself.voiceIconView.image = nil
@@ -858,7 +875,9 @@ public class BFRecordScreenController: BFBaseViewController {
             }
             
         }
-    }
+         
+        UIApplication.shared.keyWindow?.addSubview(loadingView)
+}
     
     func layoutsubview() {
         bottomeView.snp.makeConstraints { make in
@@ -1025,6 +1044,19 @@ public class BFRecordScreenController: BFBaseViewController {
 //                BFLog(1, message: "添加字幕数据 timelineIn \(newSubtitle.timelineIn.seconds) timelineOut \(newSubtitle.timelineOut.seconds) text: \(newSubtitle.text)")
                 newSubtitle.setting = wself.subtitleSettingView.subtitle.setting
                 tempItem?.titleStickers.append(newSubtitle)
+                
+                //add by ak 有字幕&设置发音人 添加到转换缓存
+                if(wself.mSelectVoiced != nil){
+                    let ttsModel = BFTTSTaskModel.init()
+                    ttsModel.timelineIn = newSubtitle.timelineIn
+                    ttsModel.timelineOut = newSubtitle.timelineOut
+                    ttsModel.fontName = wself.mSelectVoiced?.voice ?? ""
+                    ttsModel.recordId = recordId ?? ""
+                    ttsModel.tTtaskId = getUniqueId(desc: "tTtaskId")
+                    ttsModel.text = showText
+                    wself.tts?.pushTaskCache(ttsModel)
+                }
+                
             }
         }
 
@@ -1899,8 +1931,17 @@ public class BFRecordScreenController: BFBaseViewController {
 //                assetPlayer.volume = noSpeakVolume
 //            }
 //        }
+        
+        //add by ak 使用的音频数据
+        var  useVoiceStickers = [PQVoiceModel]()
+        if(itemModels[currItemModelIndex].voiceChangeStickers.count > 0){
+            useVoiceStickers = itemModels[currItemModelIndex].voiceChangeStickers
+        }else{
+            useVoiceStickers = itemModels[currItemModelIndex].voiceStickers
+        }
+        
 
-        if itemModels[currItemModelIndex].voiceStickers.first(where: { m in
+        if useVoiceStickers.first(where: { m in
             CMTimeCompare(m.startCMTime, currentT) <= 0 && CMTimeCompare(currentT, m.endCMTime) <= 0
         }) != nil {
             if assetPlayer.volume != haveSpeakVolume {
@@ -1918,7 +1959,7 @@ public class BFRecordScreenController: BFBaseViewController {
         }
 
         // 先排序,再查找下一个需要播放的录音
-        let list = itemModels[currItemModelIndex].voiceStickers.sorted { m1, m2 in
+        let list = useVoiceStickers.sorted { m1, m2 in
             CMTimeCompare(m1.startCMTime, m2.startCMTime) < 0
         }
         let (shouldPlayRecordIndex, recordedAudio) = list.enumerated().first { model in
@@ -2725,7 +2766,7 @@ public extension BFRecordScreenController {
     }
 }
 
-// MARK: - TTS 试听回调
+// MARK: - TTS 试听&转语音回调
 extension BFRecordScreenController: BFTTSManagerDelegte{
     public func playerDidStart() {
         BFLog(message: "试听开始播放")
@@ -2735,4 +2776,51 @@ extension BFRecordScreenController: BFTTSManagerDelegte{
         BFLog(message: "试听播放完成")
         voiceSettingView.flushSelectVoiceStatus(voiceStatue: .isSelected)
     }
+    
+    public func ttsFinish(_ model:BFTTSTaskModel){
+        BFLog(message: "文字转语音完成recordId:\(model.recordId) tttaskid:\(model.tTtaskId)")
+        
+        let voice = PQVoiceModel.init()
+        voice.wavFilePath = model.wavFilePath
+        voice.startCMTime = model.timelineIn
+        voice.endCMTime = model.timelineOut
+        itemModels[currItemModelIndex].voiceChangeStickers.append(voice)
+        
+        //
+        loadingView.titleL.text = "变音中 \(itemModels[currItemModelIndex].voiceChangeStickers.count / itemModels[currItemModelIndex].titleStickers.count)%"
+        
+    }
+    
+    /// 查看发音人文件是否已经全都完成,如果没有完成不能进行预览,合成操作
+    /// - Parameter itemIndex: 段落 ID ,不传值是所有段落
+    /// - Returns: 是否全都完成
+    func voiceChangeStickerFinish(itemIndex:Int = -100) -> Bool{
+        if(mSelectVoiced == nil){
+            return true
+        }
+        
+        var isFinish = true
+        //所有任务数也就是字幕的个数
+        var AllCount = 0
+        //完成的任务数(已经有发音人地址的)
+        var FinishCount = 0
+
+        if(itemIndex >= 0){//只查看当前段落
+            AllCount = itemModels[currItemModelIndex].titleStickers.count
+            FinishCount = itemModels[currItemModelIndex].voiceChangeStickers.count
+          
+        }else{//所有段落
+            for itemModel in itemModels{
+                AllCount += itemModel.titleStickers.count
+                FinishCount += itemModel.voiceChangeStickers.count
+            }
+        }
+        BFLog(message: "总任务数:\(AllCount) 已经完成数:\(FinishCount)")
+        if(FinishCount < AllCount){
+            isFinish = false
+        }
+     
+        return isFinish
+    }
+ 
 }

+ 98 - 0
BFRecordScreenKit/Classes/RecordScreen/View/BFLoadingView.swift

@@ -0,0 +1,98 @@
+//
+//  BFLoadingView.swift
+//  BFRecordScreenKit
+//
+//  Created by ak on 2022/2/17.
+//
+
+import BFCommonKit
+import BFUIKit
+import Kingfisher
+import UIKit
+
+class BFLoadingView: UIView {
+    var cancelHandle: ((_ sender: UIButton) -> Void)?
+
+    // gif每一帧图
+    public var gifImages: [UIImage]?
+    // gif播放时长
+    public var duration: Double?
+
+    public lazy var loadingImage: UIImageView = {
+        let loadingImage = UIImageView()
+        loadingImage.tintColor = UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)
+        return loadingImage
+    }()
+
+    lazy var closedBtn: UIButton = {
+        let closedBtn = UIButton(type: .custom)
+        closedBtn.frame = CGRect(x: 13, y: 43, width: cDefaultMargin * 3, height: cDefaultMargin * 3)
+        closedBtn.setImage(imageInRecordScreenKit(by: "LoadingClose"), for: .normal)
+        closedBtn.addTarget(self, action: #selector(removeView), for: .touchUpInside)
+        return closedBtn
+    }()
+
+    lazy var titleL: UILabel = {
+        let l = UILabel()
+        l.text = "变音中 10%"
+        l.textAlignment = .center
+        l.textColor = UIColor.hexColor(hexadecimal: "#389AFF")
+        l.font = UIFont.systemFont(ofSize: 16)
+
+        return l
+    }()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+        backgroundColor = UIColor(red: 0, green: 0, blue: 0, alpha: 0.7)
+        addSubview(loadingImage)
+        addSubview(closedBtn)
+        addSubview(titleL)
+
+        let data = try? Data(contentsOf: URL(fileURLWithPath: currentBundle()!.path(forResource: "stuckPoint_edit_loading", ofType: ".gif")!))
+        if data != nil {
+            PQPHAssetVideoParaseUtil.parasGIFImage(data: data!, isRenderingColor: UIColor.hexColor(hexadecimal: BFConfig.shared.styleColor.rawValue)) { [weak self] _, images, duration in
+                self?.gifImages = images
+                self?.duration = duration
+            }
+        }
+    }
+
+    required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        // 334 * 307
+        let imageW: CGFloat = 90
+        let imageH: CGFloat = 90
+        loadingImage.frame = CGRect(x: (frame.width - imageW) / 2, y: (frame.height - imageW) / 2, width: imageW, height: imageH)
+
+        titleL.frame = CGRect(x: (cScreenWidth - 88) / 2, y: loadingImage.frame.maxY + 10, width: 88, height: 22)
+    }
+
+    /// 开始加载
+    public func loading() {
+        if loadingImage.superview == nil {
+            addSubview(loadingImage)
+        }
+        isHidden = false
+        loadingImage.displayGIF(data: nil, images: gifImages, repeatCount: .max, duration: duration ?? 2)
+    }
+
+    /// 停止加载
+    public func endLoading() {
+        loadingImage.removePlayGIF()
+    }
+
+    @objc public func removeView() {
+        loadingImage.removePlayGIF()
+        loadingImage.removeFromSuperview()
+        removeFromSuperview()
+    }
+
+    deinit {
+        BFLog(message: "销毁加载中视图")
+    }
+}

+ 2 - 0
BFRecordScreenKit/Classes/RecordScreen/ViewModel/BFRecordItemModel.swift

@@ -31,6 +31,8 @@ public class BFRecordItemModel: NSObject {
     var fetchPlayItemCallBack: ((BFRecordItemModel?) -> Void)?
     var dealedDurationRanges = [SplitRecordRange]() // 录音切割的时间区间,合成导出时计算
     public var voiceStickers = [PQVoiceModel]() //
+    //add by ak 保存有发音人转后的语音
+    public var voiceChangeStickers = [PQVoiceModel]() //
     public var videoStickers = [PQEditVisionTrackMaterialsModel]() // 合成导出时计算
 //    public var imageStickers = [PQEditVisionTrackMaterialsModel]() //
     public var titleStickers = [PQEditSubTitleModel]() // 字幕贴纸