Jelajahi Sumber

Merge branch 'demo'

* demo:
  视频播放缩略图进度条
harry 3 tahun lalu
induk
melakukan
3d9ac5a477

+ 21 - 0
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/changeVoice_h.imageset/Contents.json

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

TEMPAT SAMPAH
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/changeVoice_h.imageset/changeVoice_h@3x.png


TEMPAT SAMPAH
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/changeVoice_n.imageset/changeVoice_n@3x.png


TEMPAT SAMPAH
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/withdraw_h.imageset/withdraw_h@3x.png


TEMPAT SAMPAH
BFRecordScreenKit/Assets/BFRecordScreenKit.xcassets/withdraw_n.imageset/withdraw_n@3x.png


+ 3 - 1
BFRecordScreenKit/Classes/BFRSComm.swift

@@ -19,4 +19,6 @@ func currentBundle() -> Bundle? {
     return Bundle.current(moduleName: "BFRecordScreenKit", isAssets: false)
 }
 
-let ThemeStyleGreen = UIColor.hexColor(hexadecimal: "#28BE67")
+func ThemeStyleGreen() -> UIColor {
+    return UIColor.hexColor(hexadecimal: "#28BE67")
+}

+ 25 - 13
BFRecordScreenKit/Classes/BFRecordScreenController.swift

@@ -129,11 +129,12 @@ public class BFRecordScreenController: BFBaseViewController {
     
     lazy var recordBtn:UIButton = {
         let btn = UIButton(type: .custom)
-        btn.backgroundColor = ThemeStyleGreen
+        btn.backgroundColor = ThemeStyleGreen()
         btn.setTitle("按住 说话", for: .normal)
         btn.adjustsImageWhenHighlighted = false
         btn.addTarget(self, action: #selector(startRecord), for: .touchDown)
         btn.addTarget(self, action: #selector(endRecord), for: .touchUpInside)
+
         return btn
     }()
     
@@ -160,13 +161,14 @@ public class BFRecordScreenController: BFBaseViewController {
         sliderView.addTarget(self, action: #selector(sliderTouchEnded(sender:)), for: .touchUpInside)
         sliderView.addTarget(self, action: #selector(sliderTouchEnded(sender:)), for: .touchUpOutside)
         sliderView.addTarget(self, action: #selector(sliderTouchEnded(sender:)), for: .touchCancel)
+        sliderView.addTarget(self, action: #selector(sliderValueDidChanged(sender:)), for: .valueChanged)
         return sliderView
     }()
     
     lazy var withDrawBtn:UIButton = {
         let btn = UIButton(type: .custom)
-        btn.setImage(imageInRecordScreenKit(by: "withdraw_h"), for: .normal)
-        btn.setImage(imageInRecordScreenKit(by: "withdraw_n"), for: .highlighted)
+        btn.setImage(imageInRecordScreenKit(by: "withdraw_n"), for: .normal)
+        btn.setImage(imageInRecordScreenKit(by: "withdraw_h"), for: .highlighted)
         btn.setTitle("撤销", for: .normal)
         btn.setTitleColor(.white, for: .normal)
         btn.setTitleColor(.gray, for: .highlighted)
@@ -182,7 +184,7 @@ public class BFRecordScreenController: BFBaseViewController {
         btn.setImage(imageInRecordScreenKit(by: "changeVoice_h"), for: .highlighted)
         btn.setTitle("变声", for: .normal)
         btn.setTitleColor(.white, for: .normal)
-        btn.setTitleColor(ThemeStyleGreen, for: .highlighted)
+        btn.setTitleColor(ThemeStyleGreen(), for: .highlighted)
         btn.titleLabel?.font = UIFont.systemFont(ofSize: 12)
         btn.contentVerticalAlignment = UIControl.ContentVerticalAlignment.center;
         btn.addTarget(self, action: #selector(changeVoiceAction), for: .touchUpInside)
@@ -349,7 +351,7 @@ public class BFRecordScreenController: BFBaseViewController {
         model.volume = 100
         recorderManager.voiceModel = model
         recorderManager.startRecord(index: recordList.count)
-        movie?.startProcessing()
+//        movie?.startProcessing()
         assetPlayer?.volume = 0
         assetPlayer?.play()
     }
@@ -383,17 +385,21 @@ public class BFRecordScreenController: BFBaseViewController {
         btn.isSelected ? pause() : play()
     }
 
-    @objc public func sliderTouchBegan(sender _: UISlider) {
+    @objc func sliderTouchBegan(sender _: UISlider) {
         isDragingProgressSlder = true
         pause()
     }
 
-    @objc public func sliderTouchEnded(sender: UISlider) {
+    @objc func sliderTouchEnded(sender: UISlider) {
         changeProgress(progress: sender.value)
         isDragingProgressSlder = false
         currentPlayRecordIndex = -1
         hadPrepareToPlayRecord = false
     }
+    @objc func sliderValueDidChanged(sender: UISlider) {
+        changeProgress(progress: sender.value)
+
+    }
     
     // MARK: - 权限申请
     func checkStatus(show: Bool = true) -> Bool {
@@ -534,7 +540,7 @@ public class BFRecordScreenController: BFBaseViewController {
     func pause(){
         BFLog(1, message: "暂停播放")
         isNormalPlaying = false
-        movie?.cancelProcessing()
+//        movie?.cancelProcessing()
         assetPlayer?.pause()
         recordPlayer?.pause()
         
@@ -581,6 +587,10 @@ public class BFRecordScreenController: BFBaseViewController {
             PHCachingImageManager().requestAVAsset(forVideo: asset, options: options, resultHandler: {[weak self] (asset: AVAsset?, audioMix: AVAudioMix?, info) in
                 if let urlass = asset as? AVURLAsset {
                     self?.avasset = urlass
+                    DispatchQueue.main.async {[weak self] in
+                        let progressThumV = BFVideoThumbProgressView(frame: CGRect(x: 0, y: 20, width: cScreenWidth, height: 50), videoAsset: self!.avasset!)
+                        self?.bottomeView.addSubview(progressThumV)
+                    }
                 }
             })
         }
@@ -598,6 +608,8 @@ public class BFRecordScreenController: BFBaseViewController {
         let filter = GPUImageFilter()
         movie?.addTarget(filter)
         filter.addTarget(playView)
+        
+        movie?.startProcessing()
     }
     
     func setAudioPlay(item:AVPlayerItem){
@@ -659,10 +671,10 @@ public class BFRecordScreenController: BFBaseViewController {
         if let duration = assetPlayer?.currentItem?.duration {
             self.currentAssetProgress = CMTime(value: CMTimeValue(progress * Float(CMTimeGetSeconds(duration)) * 100), timescale: 100)
             assetPlayer!.seek(to: self.currentAssetProgress, toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000)) {[weak self] finished in
-                if finished{
-                    BFLog(1, message: "拖动成功")
-                    self?.movie?.startProcessing()
-                }
+//                if finished{
+//                    BFLog(1, message: "拖动成功")
+//                    self?.movie?.startProcessing()
+//                }
             }
         }
     }
@@ -677,7 +689,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 let height = self?.progessSildeBackV.height ?? 0
                 list.forEach { model in
                     let lineV = UIView(frame: CGRect(x: model.startTime * width / totalDur , y: 0, width: (model.endTime - model.startTime) * width / totalDur, height: height))
-                    lineV.backgroundColor = ThemeStyleGreen
+                    lineV.backgroundColor = ThemeStyleGreen()
                     self?.progessSildeBackV.addSubview(lineV)
                 }
             }

+ 80 - 0
BFRecordScreenKit/Classes/BFVideoThumbImageFetchHelper.swift

@@ -0,0 +1,80 @@
+//
+//  BFVideoThumbImageFetchHelper.swift
+//  BFRecordScreenKit
+//
+//  Created by 胡志强 on 2021/12/3.
+//
+
+import Foundation
+import AVFoundation
+import BFCommonKit
+
+/// 视频分解成帧
+/// - parameter fileUrl                 : 视频地址
+/// - parameter fps                     : 自定义帧数 每秒内取的帧数
+/// - parameter splitCompleteClosure    : 回调
+func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, splitCompleteClosure:@escaping ((Bool, [UIImage]?) -> Void)) {
+    var splitImages = [UIImage]()
+    
+    var times = [NSValue]()
+    
+    for i in 0...Int(urlAsset.duration.seconds * Float64(fps)) {
+        let timeValue = NSValue(time: CMTimeMake(value: Int64(i), timescale: Int32(fps)) )
+        
+        times.append(timeValue)
+    }
+    
+    let imgGenerator = AVAssetImageGenerator(asset: urlAsset)
+    imgGenerator.requestedTimeToleranceBefore = CMTime.zero
+    imgGenerator.requestedTimeToleranceAfter = CMTime.zero
+    
+    let timesCount = times.count
+    var cocu = 0
+    //获取每一帧的图片
+    imgGenerator.generateCGImagesAsynchronously(forTimes: times) { (requestedTime, image, actualTime, result, error) in
+        cocu += 1
+        var isSuccess = false
+        switch (result) {
+        case AVAssetImageGenerator.Result.cancelled:
+            BFLog(1, message: "aaa: cancel")
+
+        case AVAssetImageGenerator.Result.failed:
+            BFLog(1, message: "aaa: failed")
+
+        case AVAssetImageGenerator.Result.succeeded:
+            let framImg = UIImage(cgImage: image!)
+            splitImages.append(framImg)
+            BFLog(1, message: "aaa: \(requestedTime.seconds) - \(actualTime.seconds)")
+//            if (Int(requestedTime.value) == (timesCount-1)) {
+//            }
+            isSuccess = true
+        @unknown default:
+            break
+        }
+        if cocu == timesCount { //最后一帧时 回调赋值
+            splitCompleteClosure(isSuccess, splitImages)
+            BFLog(1, message: "aaa: complete")
+
+        }
+    }
+   
+}
+
+/// 视频分解成帧
+/// - parameter fileUrl                 : 视频地址
+/// - parameter fps                     : 自定义帧数 每秒内取的帧数
+/// - parameter splitCompleteClosure    : 回调
+func getThumbImageAtTime(urlAsset: AVURLAsset, time:CMTime) -> UIImage? {
+    let imgGenerator = AVAssetImageGenerator(asset: urlAsset)
+    imgGenerator.requestedTimeToleranceBefore = CMTime.zero
+    imgGenerator.requestedTimeToleranceAfter = CMTime.zero
+    
+    var cgImg = try? imgGenerator.copyCGImage(at: time, actualTime: nil)
+    if cgImg == nil  {
+        imgGenerator.requestedTimeToleranceBefore = CMTime.positiveInfinity
+        imgGenerator.requestedTimeToleranceAfter = CMTime.positiveInfinity
+        cgImg = try? imgGenerator.copyCGImage(at: time, actualTime: nil)
+    }
+
+    return cgImg == nil ? nil : UIImage(cgImage: cgImg!)
+}

+ 74 - 0
BFRecordScreenKit/Classes/BFVideoThumbProgressView.swift

@@ -0,0 +1,74 @@
+//
+//  BFVideoThumbProgressView.swift
+//  BFRecordScreenKit
+//
+//  Created by 胡志强 on 2021/12/3.
+//
+
+import Foundation
+import UIKit
+import AVFoundation
+import BFCommonKit
+import SnapKit
+
+class BFVideoThumbProgressView: UIView {
+    var videoAsset : AVURLAsset?
+    
+    var thumbImgs = [UIImage]()
+    
+    init(frame: CGRect, videoAsset:AVURLAsset) {
+        super.init(frame: frame)
+        self.videoAsset = videoAsset
+        addSubview(progressView)
+
+        splitVideoFileUrlFps(urlAsset: videoAsset, fps: 2) {[weak self] isSuccess, images in
+            if isSuccess{
+                self?.thumbImgs = images!
+                DispatchQueue.main.async {[weak self] in
+                    if let sself = self{
+                        for (i, img) in images!.enumerated() {
+                            let iv = UIImageView(image: img)
+                            iv.contentMode = .scaleAspectFill
+                            sself.progressView.addSubview(iv)
+                            iv.snp.makeConstraints { make in
+                                make.left.equalTo(CGFloat(i) * sself.height + sself.width * 0.5)
+                                make.top.height.equalToSuperview()
+                                make.width.equalTo(sself.height)
+                            }
+                        }
+                        sself.progressView.contentSize = CGSize(width: CGFloat(images!.count) *  sself.height + sself.width, height: sself.height)
+                    }
+                }
+            }
+        }
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    lazy var progressView : UIScrollView = {
+        let sv = UIScrollView()
+        sv.bounces = false
+        sv.backgroundColor = .clear
+        sv.decelerationRate = .fast
+        sv.showsHorizontalScrollIndicator = false
+        
+        
+        return sv
+    }()
+    
+    override func didMoveToWindow() {
+        super.didMoveToWindow()
+        
+        
+    }
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        progressView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+    }
+}