Pārlūkot izejas kodu

add 多素材支持

wenweiwei 3 gadi atpakaļ
vecāks
revīzija
bb9dc20c43

+ 10 - 3
BFRecordScreenKit/Classes/BFRecordItemModel.swift

@@ -28,7 +28,9 @@ public class BFRecordItemModel: NSObject {
     public var videoStickers = [PQEditVisionTrackMaterialsModel]() // 合成导出时计算
     public var imageStickers = [PQEditVisionTrackMaterialsModel]() //
     public var titleStickers = [PQEditSubTitleModel]() // 字幕贴纸
-    public var coverImg: UIImage?
+    public var coverImg: UIImage? // 封面图
+    public var playItem: AVPlayerItem? // 视频playerItem
+    public var mediaType: StickerType?
     public var index = 0
     public var width = 0
     public var height = 0
@@ -36,7 +38,11 @@ public class BFRecordItemModel: NSObject {
     func initOriginData(phasset: PHAsset) {
         width = phasset.pixelWidth
         height = phasset.pixelHeight
-
+        if phasset.mediaType == .image {
+            mediaType = .IMAGE
+        } else if phasset.mediaType == .video {
+            mediaType = .VIDEO
+        }
         fetchCoverImage(phasset)
         fetchPlayItem(phasset)
         fetchAVUrlAsset(phasset)
@@ -53,8 +59,8 @@ public class BFRecordItemModel: NSObject {
                                               options: option) { [weak self] image, _ in
             // 设置首帧/封面
             if image != nil {
-                self?.fetchCoverImg?(image!)
                 self?.coverImg = image
+                self?.fetchCoverImg?(image!)
             }
         }
     }
@@ -71,6 +77,7 @@ public class BFRecordItemModel: NSObject {
                     cShowHUB(superView: nil, msg: "视频获取失败:\(self?.index ?? 0)")
                     return
                 }
+                self?.playItem = item
                 self?.fetchPlayItem?(item)
             })
         }

+ 123 - 49
BFRecordScreenKit/Classes/RecordScreen/Controller/BFRecordScreenController.swift

@@ -22,6 +22,7 @@ struct WithDrawModel {
 public class BFRecordScreenController: BFBaseViewController {
     public var nextActionHandle: (() -> Void)?
     public var closeActionHandle: (() -> Void)?
+    public var changeItemHandle: ((_ index: Int) -> Void)?
 
     // MARK: - 录制参数
 
@@ -35,7 +36,6 @@ public class BFRecordScreenController: BFBaseViewController {
         didSet {
             withDrawBtn.isHidden = isRecording
             changeVoiceBtn.isHidden = isRecording
-
             recordBtn.setTitle(isRecording ? "松手 完成" : "按住 说话", for: .normal)
             recordBtn.backgroundColor = UIColor.hexColor(hexadecimal: "#28BE67", alpha: isRecording ? 0.6 : 1)
         }
@@ -272,20 +272,18 @@ public class BFRecordScreenController: BFBaseViewController {
         return subtitleLabel
 
     }()
- 
-    //音量设置
-    lazy var audioSettingView:BFAudioSettingView = {
-        let audioSettingView = BFAudioSettingView.init(frame: CGRect.init(x: 0, y: 0, width: cScreenWidth, height: cScreenHeigth))
+
+    // 音量设置
+    lazy var audioSettingView: BFAudioSettingView = {
+        let audioSettingView = BFAudioSettingView(frame: CGRect(x: 0, y: 0, width: cScreenWidth, height: cScreenHeigth))
         audioSettingView.isHidden = true
         return audioSettingView
     }()
-    
-    
-    //录音识别文字
-    var speechTranscriberUtil:PQSpeechTranscriberUtil?
-    
-    lazy var progressThumV : BFVideoThumbProgressView = {
- 
+
+    // 录音识别文字
+    var speechTranscriberUtil: PQSpeechTranscriberUtil?
+
+    lazy var progressThumV: BFVideoThumbProgressView = {
         let vv = BFVideoThumbProgressView(frame: CGRect(x: 0, y: 54, width: cScreenWidth, height: 50))
         vv.dragStartHandle = { [weak self] in
             self?.isDragingProgressSlder = true
@@ -317,6 +315,29 @@ public class BFRecordScreenController: BFBaseViewController {
         return vv
     }()
 
+    lazy var collectionView: UICollectionView = {
+        let flowLayout = UICollectionViewFlowLayout()
+        flowLayout.minimumLineSpacing = 0
+        flowLayout.minimumInteritemSpacing = 0
+        flowLayout.scrollDirection = .horizontal
+        flowLayout.itemSize = CGSize(width: view.frame.width, height: view.frame.height)
+        let collectionView = UICollectionView(frame: CGRect(x: 0, y: 0, width: view.frame.width, height: view.frame.height), collectionViewLayout: flowLayout)
+        collectionView.register(BFImageCoverViewCell.self, forCellWithReuseIdentifier: String(describing: BFImageCoverViewCell.self))
+        collectionView.register(BFVideoCoverViewCell.self, forCellWithReuseIdentifier: String(describing: BFVideoCoverViewCell.self))
+        collectionView.isPagingEnabled = true
+        collectionView.showsVerticalScrollIndicator = false
+        collectionView.showsHorizontalScrollIndicator = false
+        collectionView.delegate = self
+        collectionView.dataSource = self
+        collectionView.backgroundColor = UIColor.clear
+        if #available(iOS 11.0, *) {
+            collectionView.contentInsetAdjustmentBehavior = .never
+        } else {
+            automaticallyAdjustsScrollViewInsets = false
+        }
+        return collectionView
+    }()
+
     // MARK: - ----------------- 生命周期
 
     deinit {
@@ -351,13 +372,12 @@ public class BFRecordScreenController: BFBaseViewController {
             self?.speechTranscriberUtil = PQSpeechTranscriberUtil(token, appid: appkey)
         }
 
-        view.backgroundColor = .lightGray
-
-        playView = GPUImageView(frame: view.bounds)
-        view.addSubview(playView!)
+        view.backgroundColor = .black
+        view.addSubview(collectionView)
+//        playView = GPUImageView(frame: view.bounds)
+//        view.addSubview(playView!)
         fetchVideo()
-
-        view.addSubview(playBtn)
+//        view.addSubview(playBtn)
         view.addSubview(bottomeView)
         view.addSubview(avatarView)
         //        view.addSubview(openCameraBtn)
@@ -368,7 +388,7 @@ public class BFRecordScreenController: BFBaseViewController {
         view.addSubview(subtitleLabel)
 
         view.addSubview(audioSettingView)
- 
+
         bottomeView.addSubview(progreddL)
         //        view.addSubview(toolV)
         bottomeView.addSubview(recordBtn)
@@ -383,15 +403,14 @@ public class BFRecordScreenController: BFBaseViewController {
         avatarView.recordEndCallBack = { [weak self] _, materialsModel in
             BFLog(message: "新录制完成::::\(materialsModel?.locationPath ?? "")")
         }
- 
-        audioSettingView.callBack = {[weak self] haveSpeak,  noHaveSpeak in
-            
+
+        audioSettingView.callBack = { [weak self] haveSpeak, noHaveSpeak in
+
             BFLog(message: "haveSpeak is\(haveSpeak),noHaveSpeak is\(noHaveSpeak)")
         }
-        
-        
-        //字幕设置回调
-        //设置默认值
+
+        // 字幕设置回调
+        // 设置默认值
         setSubtitleStyle(settingModel: subtitleSettingView.subtitle.setting)
         subtitleSettingView.subtitleSettingCallBack = { [weak self] subtitileModel in
 
@@ -590,7 +609,6 @@ public class BFRecordScreenController: BFBaseViewController {
         BFLog(message: "设置声音")
 
         audioSettingView.isHidden = false
- 
     }
 
     @objc func startRecord() {
@@ -692,7 +710,7 @@ public class BFRecordScreenController: BFBaseViewController {
     }
 
     @objc func playVideo(btn: UIButton) {
-        if btn.isSelected {
+        if !btn.isSelected {
             pause()
             searchStopAtRecordRange()
         } else {
@@ -915,25 +933,11 @@ public class BFRecordScreenController: BFBaseViewController {
 
             for (index, asset) in assets.enumerated() {
                 let itemModel = BFRecordItemModel()
-                itemModel.index = 0
+                itemModel.index = index
                 itemModel.initOriginData(phasset: asset)
-                if index == 0 {
-                    itemModel.fetchCoverImg = { [weak self] img in
-                        self?.setCoverImage(img: img)
-                    }
-                    itemModel.fetchAVUrlAsset = { [weak self] urlAsset in
-                        DispatchQueue.main.async { [weak self] in
-                            self?.progressThumV.videoAsset = urlAsset
-                            self?.progressThumV.isHidden = false
-                        }
-                    }
-                    itemModel.fetchPlayItem = { [weak self] item in
-                        self?.setAudioPlay(item: item)
-                        self?.setVideoPlay(item: item)
-                    }
-                }
                 itemModels.append(itemModel)
             }
+            collectionView.reloadData()
         }
     }
 
@@ -946,22 +950,28 @@ public class BFRecordScreenController: BFBaseViewController {
         }
     }
 
-    func setVideoPlay(item: AVPlayerItem) {
+    func setVideoPlay(item: AVPlayerItem?, imageView: GPUImageView?) {
+        guard let playerItem = item else {
+            return
+        }
+        guard let preView = imageView else {
+            return
+        }
         if movie != nil {
             cleanMovieTarget()
         }
-        movie = GPUImageMovie(playerItem: item)
+        movie = GPUImageMovie(playerItem: playerItem)
         //        movie?.runBenchmark = true
         movie?.playAtActualSpeed = true
 
         let filter = GPUImageFilter()
         movie?.addTarget(filter)
-        filter.addTarget(playView)
+        filter.addTarget(preView)
 
         movie?.startProcessing()
     }
 
-    func setAudioPlay(item: AVPlayerItem) {
+    func setAudioPlay(item: AVPlayerItem?) {
         if let playItem = assetPlayer?.currentItem {
             NotificationCenter.default.removeObserver(self, name: .AVPlayerItemDidPlayToEndTime, object: playItem)
             assetPlayer?.replaceCurrentItem(with: item)
@@ -973,7 +983,7 @@ public class BFRecordScreenController: BFBaseViewController {
 
                 self?.currentAssetProgress = time
                 BFLog(1, message: "curr:\(CMTimeGetSeconds(time))")
-                if CMTimeGetSeconds(item.duration) > 0 {
+                if CMTimeGetSeconds(item?.duration ?? CMTime.zero) > 0 {
                     DispatchQueue.main.async { [weak self] in
                         self?.progreddL.text = String(format: "%@", CMTimeGetSeconds(time).formatDurationToHMS())
                         let su = !(self?.isDragingProgressSlder ?? false) || (self?.isRecording ?? false && self?.isNormalPlaying ?? false)
@@ -1100,3 +1110,67 @@ extension BFRecordScreenController: PQSpeechTranscriberUtilDelegate {
         }
     }
 }
+
+// MARK: - Delegate
+
+/// Delegate
+extension BFRecordScreenController: UICollectionViewDelegate, UICollectionViewDataSource, UIScrollViewDelegate {
+    public func collectionView(_: UICollectionView, numberOfItemsInSection _: Int) -> Int {
+        return itemModels.count
+    }
+
+    public func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
+        let recordItem = itemModels[indexPath.item]
+        var cell: BFImageCoverViewCell!
+        if recordItem.mediaType == .VIDEO {
+            cell = BFVideoCoverViewCell.gpuVideoViewCell(collectionView: collectionView, indexPath: indexPath)
+        } else {
+            cell = BFImageCoverViewCell.gpuImageViewCell(collectionView: collectionView, indexPath: indexPath)
+        }
+        recordItem.fetchCoverImg = { [weak cell] _ in
+            cell?.addData()
+        }
+        recordItem.fetchPlayItem = { [weak self, weak cell] _ in
+            if indexPath.item == self?.currItemModelIndex {
+                self?.setAudioPlay(item: recordItem.playItem)
+                self?.setVideoPlay(item: recordItem.playItem, imageView: cell?.playView)
+            }
+        }
+        cell.btnClickHandle = { [weak self] sender, _ in
+            self?.playVideo(btn: sender)
+        }
+        cell.recordItem = recordItem
+        return cell
+    }
+
+    public func collectionView(_: UICollectionView, didSelectItemAt _: IndexPath) {}
+
+    public func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        let page = Int((scrollView.contentOffset.x + scrollView.frame.width / 2) / scrollView.frame.width)
+        if page != currItemModelIndex {
+            // 暂停
+            pause()
+            // 暂停状态
+            let lastCell: BFVideoCoverViewCell? = collectionView.cellForItem(at: IndexPath(item: currItemModelIndex, section: 0)) as? BFVideoCoverViewCell
+            lastCell?.playBtn.isSelected = false
+            // 更新当前page
+            currItemModelIndex = page
+            let recordItem = itemModels[currItemModelIndex]
+            if recordItem.mediaType == .VIDEO {
+                let currCell: BFVideoCoverViewCell? = collectionView.cellForItem(at: IndexPath(item: currItemModelIndex, section: 0)) as? BFVideoCoverViewCell
+                setAudioPlay(item: recordItem.playItem)
+                setVideoPlay(item: recordItem.playItem, imageView: currCell?.playView)
+                if changeItemHandle != nil {
+                    changeItemHandle!(currItemModelIndex)
+                }
+            }
+        }
+    }
+
+    public func updateContentOffset(index: Int) {
+        let offx = collectionView.contentOffset.x
+        if offx != collectionView.frame.width * CGFloat(index) {
+            collectionView.setContentOffset(CGPoint(x: collectionView.frame.width * CGFloat(index), y: 0), animated: true)
+        }
+    }
+}

+ 71 - 0
BFRecordScreenKit/Classes/RecordScreen/View/BFImageCoverViewCell.swift

@@ -0,0 +1,71 @@
+//
+//  BFImageCoverViewCell.swift
+//  BFRecordScreenKit
+//
+//  Created by SanW on 2021/12/15.
+//  Copyright © 2021 BytesFlow. All rights reserved.
+//
+
+import GPUImage
+import UIKit
+
+open class BFImageCoverViewCell: UICollectionViewCell {
+    var btnClickHandle:((_ sender:UIButton,_ recordItem: BFRecordItemModel?) -> Void)?
+    lazy var playView: GPUImageView = {
+        let playView = GPUImageView(frame: bounds)
+        return playView
+    }()
+
+    lazy var filter: GPUImageFilter = {
+        let filter = GPUImageFilter()
+        return filter
+    }()
+
+    lazy var picture: GPUImagePicture = {
+        let picture = GPUImagePicture()
+        return picture
+    }()
+
+    @objc public class func gpuImageViewCell(collectionView: UICollectionView, indexPath: IndexPath) -> BFImageCoverViewCell {
+        let cell: BFImageCoverViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: BFImageCoverViewCell.self), for: indexPath) as! BFImageCoverViewCell
+        return cell
+    }
+
+    public override func prepareForReuse() {
+        super.prepareForReuse()
+        filter.removeTarget(playView)
+        picture.removeTarget(filter)
+    }
+
+    override public init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.addSubview(playView)
+    }
+
+    public required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    public var recordItem: BFRecordItemModel? {
+        didSet {
+            addData()
+            addLayout()
+        }
+    }
+
+    public func addData() {
+        guard let coverImg = recordItem?.coverImg else {
+            filter.removeTarget(playView)
+            picture.removeTarget(filter)
+            return
+        }
+        picture = GPUImagePicture(image: coverImg)
+        picture.addTarget(filter)
+        filter.addTarget(playView)
+        picture.processImage()
+    }
+    
+    public func addLayout() {
+        playView.frame = contentView.bounds
+    }
+}

+ 105 - 0
BFRecordScreenKit/Classes/RecordScreen/View/BFStripSwithView.swift

@@ -0,0 +1,105 @@
+//
+//  BFStripSwithView.swift
+//  BFRecordScreenKit
+//
+//  Created by SanW on 2021/12/15.
+//  Copyright © 2021 BytesFlow. All rights reserved.
+//
+
+import BFCommonKit
+import UIKit
+
+open class BFStripSwithView: UIView {
+    public var itemClickHandle: ((_ sender: UIButton, _ index: Int) -> Void)?
+    var currentIndex: Int = 0
+    var itemSpace: CGFloat = 4
+    var itemHeight: CGFloat = 6
+    var itemNormalColor: UIColor = UIColor.white
+    var itemSelectedColor: UIColor = UIColor.hexColor(hexadecimal: "#28BE67")
+    var strips: Int = 2
+    var currentItem: UIButton?
+
+    lazy var selectedBtn: UIButton = {
+        let selectedBtn = UIButton(type: .custom)
+        return selectedBtn
+    }()
+
+    override init(frame: CGRect) {
+        super.init(frame: frame)
+    }
+
+    public required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+
+    public init(frame: CGRect, items: Int, index: Int? = nil, normalColor: UIColor? = nil, selectedColor: UIColor? = nil, space: CGFloat = 10) {
+        super.init(frame: frame)
+        strips = items
+        if normalColor != nil {
+            itemNormalColor = normalColor!
+        }
+        if selectedColor != nil {
+            itemSelectedColor = selectedColor!
+        }
+        if index != nil, (index ?? 0) < items {
+            currentIndex = index!
+        }
+        itemSpace = space
+        selectedBtn.addCorner(corner: itemHeight / 2)
+        selectedBtn.backgroundColor = itemSelectedColor
+    }
+
+    override public func layoutSubviews() {
+        super.layoutSubviews()
+        addSubviews()
+    }
+
+    private func addSubviews() {
+        if currentItem != nil {
+            return
+        }
+        subviews.forEach { view in
+            view.removeFromSuperview()
+        }
+        if strips > 0 {
+            let margin: CGFloat = (frame.width - CGFloat(strips - 1) * itemSpace) / CGFloat(strips)
+            for index in 0 ..< strips {
+                let itemBtn = UIButton(type: .custom)
+                itemBtn.frame = CGRect(x: CGFloat(index) * (itemSpace + margin), y: (frame.height - itemHeight) / 2, width: margin, height: itemHeight)
+                itemBtn.tag = index + 1
+                itemBtn.addTarget(self, action: #selector(changeSwitch(sender:)), for: .touchUpInside)
+                itemBtn.addCorner(corner: itemHeight / 2)
+                itemBtn.backgroundColor = itemNormalColor
+                if itemBtn.tag == currentIndex + 1 {
+                    currentItem = itemBtn
+                    selectedBtn.frame = itemBtn.frame
+                }
+                addSubview(itemBtn)
+            }
+            if selectedBtn.superview == nil {
+                addSubview(selectedBtn)
+            }
+            bringSubviewToFront(selectedBtn)
+        }
+    }
+
+    @objc public func changeSwitch(sender: UIButton) {
+        if sender == currentItem {
+            return
+        }
+        if itemClickHandle != nil {
+            itemClickHandle!(sender, Int(sender.tag - 1))
+        }
+    }
+
+    public func changeSwitchStatus(index: Int) {
+        let sender: UIButton? = viewWithTag(Int(index) + 1) as? UIButton
+        if sender == nil || sender == currentItem {
+            return
+        }
+        currentItem = sender
+        UIView.animate(withDuration: 0.1) { [weak self] in
+            self?.selectedBtn.center.x = CGFloat(sender!.center.x)
+        }
+    }
+}

+ 58 - 0
BFRecordScreenKit/Classes/RecordScreen/View/BFVideoCoverViewCell.swift

@@ -0,0 +1,58 @@
+//
+//  BFVideoCoverViewCell.swift
+//  BFRecordScreenKit
+//
+//  Created by SanW on 2021/12/15.
+//  Copyright © 2021 BytesFlow. All rights reserved.
+//
+
+import UIKit
+import GPUImage
+
+open class BFVideoCoverViewCell: BFImageCoverViewCell {
+    public lazy var playBtn: UIButton = {
+        let btn = UIButton(type: .custom)
+        btn.setImage(imageInRecordScreenKit(by: "preview_play"), for: .normal)
+        let vv = UIView(frame: CGRect(x: 0, y: 0, width: 1, height: 1))
+        btn.setImage(vv.graphicsGetImage(), for: .selected)
+        btn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
+        return btn
+    }()
+    
+    @objc public class func gpuVideoViewCell(collectionView: UICollectionView, indexPath: IndexPath) -> BFVideoCoverViewCell {
+        let cell: BFVideoCoverViewCell = collectionView.dequeueReusableCell(withReuseIdentifier: String(describing: BFVideoCoverViewCell.self), for: indexPath) as! BFVideoCoverViewCell
+        return cell
+    }
+
+    public override func prepareForReuse() {
+        super.prepareForReuse()
+        playBtn.isSelected = false
+    }
+
+    override public init(frame: CGRect) {
+        super.init(frame: frame)
+        contentView.addSubview(playBtn)
+    }
+    
+    public required init?(coder _: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    public override func addData() {
+        super.addData()
+
+    }
+
+    public override func addLayout() {
+        super.addLayout()
+        playBtn.frame = CGRect.init(origin: CGPoint.zero, size: CGSize.init(width: 100, height: 100))
+        playBtn.center = contentView.center
+    }
+    
+    @objc func btnClick(sender: UIButton) {
+        sender.isSelected = !sender.isSelected
+        if btnClickHandle != nil {
+            btnClickHandle!(sender,recordItem)
+        }
+    }
+}

+ 2 - 1
Example/BFRecordScreenKit.xcodeproj/project.pbxproj

@@ -177,9 +177,10 @@
 		607FACC81AFB9204008FA782 /* Project object */ = {
 			isa = PBXProject;
 			attributes = {
+				CLASSPREFIX = BF;
 				LastSwiftUpdateCheck = 0830;
 				LastUpgradeCheck = 0830;
-				ORGANIZATIONNAME = CocoaPods;
+				ORGANIZATIONNAME = BytesFlow;
 				TargetAttributes = {
 					607FACCF1AFB9204008FA782 = {
 						CreatedOnToolsVersion = 6.3.1;