Jelajahi Sumber

摄像头合成功能

harry 3 tahun lalu
induk
melakukan
43695ce7ac
1 mengubah file dengan 215 tambahan dan 156 penghapusan
  1. 215 156
      BFRecordScreenKit/Classes/BFRecordExport.swift

+ 215 - 156
BFRecordScreenKit/Classes/BFRecordExport.swift

@@ -29,6 +29,10 @@ public class BFRecordExport {
     public var originSoundVolumn: Float = 1.0 // 无录音时原声大小
     public var originSoundInRecordVolumn: Float = 0.0 // 录音时原声大小
 
+    var titleStickers = [PQEditSubTitleModel]()
+    var voiceList = [PQEditVisionTrackMaterialsModel]()
+    var videoStickers = [PQEditVisionTrackMaterialsModel]()
+    
     public var data: [BFRecordItemModel]? {
         didSet {
             if data?.count ?? 0 > 0 {
@@ -57,10 +61,11 @@ public class BFRecordExport {
         // 1,背景视频素材
         if let itemModels = data {
             var totalDur = 0.0
-            var titleStickers = [PQEditSubTitleModel]()
-            var voiceList = [PQEditVisionTrackMaterialsModel]()
-            var videoStickers = [PQEditVisionTrackMaterialsModel]()
 
+            titleStickers.removeAll()
+            voiceList.removeAll()
+            videoStickers.removeAll()
+            
             // 切割视频素材
             for (_, itemModel) in itemModels.enumerated() {
                 // 保留录音部分时,是否按录音顺序合成最终视频;
@@ -77,28 +82,114 @@ public class BFRecordExport {
                         model1.timelineIn < model2.timelineIn
                     }
                 }
-
-                if itemModel.mediaType == .Image {
-                    // 图片素材
-                    if !synthesisAll, itemModel.voiceStickers.count == 0 {
-                        // 图片无录音在保留模式里不合成
-                        continue
+                
+                switch itemModel.mediaType {
+                case .Image:
+                    totalDur += parseImage(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
+                    
+                case .some(.Video):
+                    let dur = parseVideo(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
+                    if dur >=  0 {
+                        totalDur += dur
+                    }else{
+                        // -1 时出错
+                        return
                     }
+                case .some(.Camera):
+                    totalDur += parseCamera(synthesisAll: synthesisAll, itemModel: itemModel, totalDur: totalDur)
+                    
+                case .none:
+                    break
+                }
+
+                // 视频处理
+
+            }
+            beginExport(synthesisAll: synthesisAll)
+        }
+    }
+    
+    func parseImage(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double{
+        if !synthesisAll, itemModel.voiceStickers.count == 0 {
+            // 图片无录音在保留模式里不合成
+            return 0
+        }
 
-                    var duration = itemModel.materialDuraion.seconds
-                    if itemModel.voiceStickers.count == 0 {
-                        // 图片无录音保持2s
-                        duration = 2
-                        let voice = PQEditVisionTrackMaterialsModel()
-                        voice.model_in = 0.0
-                        voice.out = 2.0
-                        voice.aptDuration = 2.0
+        var duration = itemModel.materialDuraion.seconds
+        if itemModel.voiceStickers.count == 0 {
+            // 图片无录音保持2s
+            duration = 2
+            let voice = PQEditVisionTrackMaterialsModel()
+            voice.model_in = 0.0
+            voice.out = 2.0
+            voice.aptDuration = 2.0
 //                        voice.voiceType = VOICETYPT.None.rawValue
-                        voice.volumeGain = 100
-                        voiceList.append(voice)
-                    } else {
-                        //
-                        for mod in itemModel.voiceStickers {
+            voice.volumeGain = 100
+            voiceList.append(voice)
+        } else {
+            //
+            for mod in itemModel.voiceStickers {
+                let sticker = PQEditVisionTrackMaterialsModel()
+                sticker.model_in = 0
+                sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
+                sticker.timelineIn = totalDur + mod.startCMTime.seconds
+                sticker.timelineOut = totalDur + mod.endCMTime.seconds
+                sticker.aptDuration = sticker.out
+                sticker.duration = sticker.out
+                sticker.locationPath = mod.wavFilePath
+                sticker.volumeGain = 100 // Float64(model.volume)
+                voiceList.append(sticker)
+            }
+        }
+
+        let sticker = splitBaseMaterial(timelineIn: totalDur, model_in: 0, duration: duration)
+        sticker.originalData = itemModel.coverImg?.pngData()
+        sticker.volumeGain = 0
+        sticker.type = StickerType.IMAGE.rawValue
+        videoStickers.append(sticker)
+        BFLog(1, message: "image sticker - timIn:\(sticker.timelineIn), modIn:\(sticker.model_in), dur:\(duration)")
+
+        for titleS in itemModel.titleStickers {
+//                        let leng = titleS.timelineOut - titleS.timelineIn
+            let newTitleSticker = PQEditSubTitleModel()
+            titleStickers.append(newTitleSticker)
+            newTitleSticker.text = titleS.text
+            newTitleSticker.setting = titleS.setting
+            newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
+            newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
+        }
+        
+        return duration
+    }
+    
+    func parseVideo(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double {
+        
+        var subDur = 0.0
+
+        if let localPath = itemModel.localPath {
+            if !FileManager.default.fileExists(atPath: localPath) {
+                let error = NSError(domain: "err", code: ExportError.FileNotExist.rawValue, userInfo: ["msg": "file not exist"])
+                exportCompletion?(error as Error, nil)
+                return subDur
+            }
+
+//                    voiceList.append(contentsOf: itemModel.voiceStickers)
+
+            if synthesisAll {
+                let drangs = itemModel.dealedDurationRanges
+                for srange in drangs {
+                    let range = srange.range
+                    let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
+                    sticker.locationPath = localPath
+                    sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
+                    videoStickers.append(sticker)
+                    subDur += range.duration.seconds
+
+                    if srange.isRecord {
+                        // 处理voice
+                        if let mod = itemModel.voiceStickers.first(where: { m in
+                            m.startCMTime.seconds == range.start.seconds
+                        }) {
                             let sticker = PQEditVisionTrackMaterialsModel()
                             sticker.model_in = 0
                             sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
@@ -111,152 +202,118 @@ public class BFRecordExport {
                             voiceList.append(sticker)
                         }
                     }
+                }
 
-                    let sticker = splitBaseMaterial(timelineIn: totalDur, model_in: 0, duration: duration)
-                    sticker.originalData = itemModel.coverImg?.pngData()
-                    sticker.volumeGain = 0
-                    sticker.type = StickerType.IMAGE.rawValue
-                    videoStickers.append(sticker)
-                    BFLog(1, message: "image sticker - timIn:\(sticker.timelineIn), modIn:\(sticker.model_in), dur:\(duration)")
-
-                    for titleS in itemModel.titleStickers {
-//                        let leng = titleS.timelineOut - titleS.timelineIn
-                        let newTitleSticker = PQEditSubTitleModel()
-                        titleStickers.append(newTitleSticker)
-                        newTitleSticker.text = titleS.text
-                        newTitleSticker.setting = titleS.setting
-                        newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
-                        newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
-                    }
+                for titleS in itemModel.titleStickers {
+                    let newTitleSticker = PQEditSubTitleModel()
+                    titleStickers.append(newTitleSticker)
+                    newTitleSticker.text = titleS.text
+                    newTitleSticker.setting = titleS.setting
+                    newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
+                    newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
+                }
 
-                    totalDur += duration
-                    continue
-                }else if itemModel.mediaType == .Camera {
-                    videoStickers.append(contentsOf: itemModel.videoStickers)
-                    //
-                    for mod in itemModel.voiceStickers {
-                        let sticker = PQEditVisionTrackMaterialsModel()
-                        sticker.model_in = 0
-                        sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
-                        sticker.timelineIn = totalDur + mod.startCMTime.seconds
-                        sticker.timelineOut = totalDur + mod.endCMTime.seconds
-                        sticker.aptDuration = sticker.out
-                        sticker.duration = sticker.out
-                        sticker.locationPath = mod.wavFilePath
-                        sticker.volumeGain = 100 // Float64(model.volume)
-                        voiceList.append(sticker)
-                    }
-                    
-                    continue
+            } else {
+                // 只保留录音部分
+                var drangs = itemModel.dealedDurationRanges.filter { srange in
+                    srange.isRecord == true
                 }
 
-                // 视频处理
-                if let localPath = itemModel.localPath {
-                    if !FileManager.default.fileExists(atPath: localPath) {
-                        let error = NSError(domain: "err", code: ExportError.FileNotExist.rawValue, userInfo: ["msg": "file not exist"])
-                        exportCompletion?(error as Error, nil)
-                        return
+                let needSort = false
+                if needSort {
+                    drangs.sort { range1, range2 in
+                        range1.index < range2.index
                     }
+                }
 
-//                    voiceList.append(contentsOf: itemModel.voiceStickers)
-
-                    if synthesisAll {
-                        var subDur = 0.0
-                        let drangs = itemModel.dealedDurationRanges
-                        for srange in drangs {
-                            let range = srange.range
-                            let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
-                            sticker.locationPath = localPath
-                            sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
-                            videoStickers.append(sticker)
-                            subDur += range.duration.seconds
-
-                            if srange.isRecord {
-                                // 处理voice
-                                if let mod = itemModel.voiceStickers.first(where: { m in
-                                    m.startCMTime.seconds == range.start.seconds
-                                }) {
-                                    let sticker = PQEditVisionTrackMaterialsModel()
-                                    sticker.model_in = 0
-                                    sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
-                                    sticker.timelineIn = totalDur + mod.startCMTime.seconds
-                                    sticker.timelineOut = totalDur + mod.endCMTime.seconds
-                                    sticker.aptDuration = sticker.out
-                                    sticker.duration = sticker.out
-                                    sticker.locationPath = mod.wavFilePath
-                                    sticker.volumeGain = 100 // Float64(model.volume)
-                                    voiceList.append(sticker)
-                                }
-                            }
-                        }
-
-                        for titleS in itemModel.titleStickers {
-                            let newTitleSticker = PQEditSubTitleModel()
-                            titleStickers.append(newTitleSticker)
-                            newTitleSticker.text = titleS.text
-                            newTitleSticker.setting = titleS.setting
-                            newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
-                            newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
-                        }
-
-                        totalDur += subDur
-                    } else {
-                        // 只保留录音部分
-                        var subDur = 0.0
-                        var drangs = itemModel.dealedDurationRanges.filter { srange in
-                            srange.isRecord == true
-                        }
-
-                        if needSort {
-                            drangs.sort { range1, range2 in
-                                range1.index < range2.index
-                            }
-                        }
+                for (index, srange) in drangs.enumerated() {
+                    let range = srange.range
+                    let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
+                    sticker.locationPath = localPath
+                    sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
+                    videoStickers.append(sticker)
 
-                        for (index, srange) in drangs.enumerated() {
-                            let range = srange.range
-                            let sticker = splitBaseMaterial(timelineIn: totalDur + subDur, model_in: range.start.seconds, duration: range.duration.seconds)
-                            sticker.locationPath = localPath
-                            sticker.volumeGain = Float64(srange.isRecord ? originSoundInRecordVolumn * 100 : originSoundVolumn * 100)
-                            videoStickers.append(sticker)
-
-                            let voiceSticker = itemModel.voiceStickers[index]
-                            let voice = PQEditVisionTrackMaterialsModel()
-                            voice.model_in = 0
-                            voice.out = voiceSticker.endCMTime.seconds - voiceSticker.startCMTime.seconds
-                            voice.timelineIn = totalDur + subDur
-                            voice.timelineOut = totalDur + subDur + voice.out
-                            voice.aptDuration = voice.out
-                            voice.duration = voice.out
-                            voice.locationPath = voiceSticker.wavFilePath
-                            voice.volumeGain = 100 // Float64(model.volume)
-                            voiceList.append(voice)
-
-                            let titleModels = itemModel.titleStickers.filter { mod in
-                                mod.recordId == voiceSticker.recordId
-                            }
-                            
-                            // 字幕的时间点是以相关录音的原点为坐标计算的。
-                            for titleS in titleModels {
-                                let newTitleSticker = PQEditSubTitleModel()
-                                titleStickers.append(newTitleSticker)
-                                newTitleSticker.text = titleS.text
-                                newTitleSticker.setting = titleS.setting
-                                newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur + subDur , preferredTimescale: 1000) - voiceSticker.startCMTime
-                                newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur + subDur, preferredTimescale: 1000) - voiceSticker.startCMTime
-                                BFLog(1, message: "timein - \(newTitleSticker.timelineIn), out - \(newTitleSticker.timelineOut)")
-                            }
-                            subDur += range.duration.seconds
-                        }
-                        
-                        totalDur += subDur
+                    let voiceSticker = itemModel.voiceStickers[index]
+                    let voice = PQEditVisionTrackMaterialsModel()
+                    voice.model_in = 0
+                    voice.out = voiceSticker.endCMTime.seconds - voiceSticker.startCMTime.seconds
+                    voice.timelineIn = totalDur + subDur
+                    voice.timelineOut = totalDur + subDur + voice.out
+                    voice.aptDuration = voice.out
+                    voice.duration = voice.out
+                    voice.locationPath = voiceSticker.wavFilePath
+                    voice.volumeGain = 100 // Float64(model.volume)
+                    voiceList.append(voice)
+
+                    let titleModels = itemModel.titleStickers.filter { mod in
+                        mod.recordId == voiceSticker.recordId
                     }
+                    
+                    // 字幕的时间点是以相关录音的原点为坐标计算的。
+                    for titleS in titleModels {
+                        let newTitleSticker = PQEditSubTitleModel()
+                        titleStickers.append(newTitleSticker)
+                        newTitleSticker.text = titleS.text
+                        newTitleSticker.setting = titleS.setting
+                        newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur + subDur , preferredTimescale: 1000) - voiceSticker.startCMTime
+                        newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur + subDur, preferredTimescale: 1000) - voiceSticker.startCMTime
+                        BFLog(1, message: "timein - \(newTitleSticker.timelineIn), out - \(newTitleSticker.timelineOut)")
+                    }
+                    subDur += range.duration.seconds
                 }
             }
-            beginExport(synthesisAll: synthesisAll, videoStickers: videoStickers, voiceList: voiceList, titleStickers: titleStickers)
         }
+        return subDur
     }
 
+    func parseCamera(synthesisAll: Bool, itemModel: BFRecordItemModel, totalDur:Double) -> Double {
+        
+        var duration = itemModel.materialDuraion.seconds
+
+        // 视频分解
+        for mod in itemModel.videoStickers {
+            let sticker = PQEditVisionTrackMaterialsModel()
+            sticker.type = StickerType.VIDEO.rawValue
+            sticker.canvasFillType = stickerContentMode.aspectFitStr.rawValue
+            sticker.model_in = 0
+            sticker.out = (mod.timelineCMOut - mod.timelineCMIn).seconds
+            sticker.timelineIn = totalDur + mod.timelineCMIn.seconds
+            sticker.timelineOut = totalDur + mod.timelineCMOut.seconds
+            sticker.aptDuration = sticker.out
+            sticker.duration = sticker.out
+            sticker.locationPath = mod.locationPath.replacingOccurrences(of: documensDirectory, with: "")
+            sticker.volumeGain = 1 // Float64(model.volume)
+            videoStickers.append(sticker)
+        }
+        
+        // 音频分解
+        for mod in itemModel.voiceStickers {
+            let sticker = PQEditVisionTrackMaterialsModel()
+            sticker.model_in = 0
+            sticker.type = StickerType.VOICE.rawValue
+            sticker.out = mod.endCMTime.seconds - mod.startCMTime.seconds
+            sticker.timelineIn = totalDur + mod.startCMTime.seconds
+            sticker.timelineOut = totalDur + mod.endCMTime.seconds
+            sticker.aptDuration = sticker.out
+            sticker.duration = sticker.out
+            sticker.locationPath = mod.wavFilePath
+            sticker.volumeGain = 100 // Float64(model.volume)
+            voiceList.append(sticker)
+        }
+        
+        // 字幕分解
+        for titleS in itemModel.titleStickers {
+            let newTitleSticker = PQEditSubTitleModel()
+            titleStickers.append(newTitleSticker)
+            newTitleSticker.text = titleS.text
+            newTitleSticker.setting = titleS.setting
+            newTitleSticker.timelineIn = titleS.timelineIn + CMTime(seconds: totalDur, preferredTimescale: 1000)
+            newTitleSticker.timelineOut = titleS.timelineOut + CMTime(seconds: totalDur, preferredTimescale: 1000)
+        }
+        
+        return duration
+    }
+    
     public func cancelExport() {
         exporter?.cancel()
         
@@ -304,7 +361,7 @@ public class BFRecordExport {
 
     // 因为titleStickers 是传递过来的,会修改timelinein,需要重新生成,以免影响原来的数据
     // voiceList是考虑到图片有时候没有录音,在保留全部时,需要添加一个2秒的空sticker
-    func beginExport(synthesisAll: Bool, videoStickers: [PQEditVisionTrackMaterialsModel], voiceList: [PQEditVisionTrackMaterialsModel], titleStickers: [PQEditSubTitleModel]) {
+    func beginExport(synthesisAll: Bool) {
         // 输出视频地址
 //        exprotVideo()
 //        return;
@@ -350,6 +407,8 @@ public class BFRecordExport {
                         return partialResult + (srange.isRecord ? srange.range.duration.seconds : 0)
                     }
                 }
+            }else  if itemModell.mediaType == .Camera {
+                modelDuraion = itemModell.materialDuraion.seconds
             }
             return (partialResult ?? 0) + modelDuraion
         }) else {