瀏覽代碼

修改视频缩略图进度逻辑

harry 3 年之前
父節點
當前提交
aa48ac00d8

+ 41 - 47
BFRecordScreenKit/Classes/BFRecordScreenController.swift

@@ -98,7 +98,7 @@ public class BFRecordScreenController: BFBaseViewController {
     var avplayerTimeObserver: NSKeyValueObservation?
 
     lazy var progreddL : UILabel = {
-        let l = UILabel(frame: CGRect(x: 0, y: cDevice_iPhoneStatusBarHei, width: cScreenWidth, height: 14))
+        let l = UILabel()
         l.textAlignment = .center
         l.font = UIFont.systemFont(ofSize: 10)
         l.textColor = .white
@@ -140,31 +140,11 @@ public class BFRecordScreenController: BFBaseViewController {
     
     lazy var progessSildeBackV : UIView = {
         let vv = UIView()
-        vv.backgroundColor = UIColor.hexColor(hexadecimal: "#303030")
+        vv.backgroundColor = .orange // .clear
         
         return vv
     }()
     
-    lazy var progessSilde:BFPlayerSlider = {
-        let sliderView = BFPlayerSlider()
-        let tjbV = UIView(frame: CGRect(x: 0, y: 0, width: 4, height: 16))
-        tjbV.backgroundColor = .white
-        let thbImage = tjbV.graphicsGetImage()//UIImage(named: "icon_point")
-        sliderView.setMinimumTrackImage(thbImage, for: .normal)
-        sliderView.setMaximumTrackImage(thbImage, for: .normal)
-        sliderView.setThumbImage(thbImage, for: .highlighted)
-        sliderView.setThumbImage(thbImage, for: .normal)
-        sliderView.maximumTrackTintColor = .clear // UIColor.hexColor(hexadecimal: "#303030")
-        sliderView.minimumTrackTintColor = .clear //UIColor.hexColor(hexadecimal: "#303030")
-//        sliderView.minimumTrackTintColor = UIColor.hexColor(hexadecimal: "#FA6400")
-        sliderView.addTarget(self, action: #selector(sliderTouchBegan(sender:)), for: .touchDown)
-        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_n"), for: .normal)
@@ -208,8 +188,8 @@ public class BFRecordScreenController: BFBaseViewController {
     }()
     
     lazy var progressThumV : BFVideoThumbProgressView = {
-        let vv = BFVideoThumbProgressView(frame: CGRect(x: 0, y: 20, width: cScreenWidth, height: 50), videoAsset: self.avasset!)
-        vv.dragScrollProgressHandle = { process in
+        let vv = BFVideoThumbProgressView(frame: CGRect(x: 0, y: 54, width: cScreenWidth, height: 50))
+        vv.dragScrollProgressHandle = {[weak self] process in
             DispatchQueue.main.async {[weak self] in
                 guard let sself = self else {
                     return
@@ -232,6 +212,7 @@ public class BFRecordScreenController: BFBaseViewController {
             sself.currentPlayRecordIndex = -1
             sself.hadPrepareToPlayRecord = false
         }
+        vv.isHidden = true
         return vv
     }()
     
@@ -266,27 +247,34 @@ public class BFRecordScreenController: BFBaseViewController {
         
         view.addSubview(playBtn)
         view.addSubview(bottomeView)
-        view.addSubview(progreddL)
+        bottomeView.addSubview(progreddL)
 //        view.addSubview(toolV)
         bottomeView.addSubview(recordBtn)
-        bottomeView.addSubview(progessSildeBackV)
-        bottomeView.addSubview(progessSilde)
         bottomeView.addSubview(withDrawBtn)
         bottomeView.addSubview(changeVoiceBtn)
-        
+        bottomeView.addSubview(progressThumV)
+        progressThumV.addSubview(progessSildeBackV)
+
         if checkStatus() {
             try? AVAudioSession.sharedInstance().setCategory(.playAndRecord, options: .defaultToSpeaker)
         }
         
+        layoutsubview()
     }
-    
-    public override func viewWillLayoutSubviews() {
-        super.viewWillLayoutSubviews()
+    func layoutsubview() {
+
         bottomeView.snp.makeConstraints { make in
             make.left.bottom.right.equalToSuperview()
             make.height.equalTo(adapterWidth(width: 220))
         }
         
+        progreddL.snp.makeConstraints { make in
+            make.width.equalTo(100)
+            make.centerX.equalToSuperview()
+            make.bottom.equalTo(progressThumV.snp.top)
+            make.height.equalTo(18)
+        }
+        
         withDrawBtn.snp.makeConstraints { make in
             make.left.equalToSuperview()
             make.width.height.equalTo(65)
@@ -302,21 +290,15 @@ public class BFRecordScreenController: BFBaseViewController {
             make.right.equalTo(changeVoiceBtn.snp.left)
             make.height.equalTo(42)
             make.top.equalTo(withDrawBtn).offset(6)
-            
         }
         
         progessSildeBackV.snp.makeConstraints { make in
-            make.left.width.equalTo(recordBtn)
-            make.top.equalTo(recordBtn).offset(-30)
+            make.left.equalToSuperview()
+            make.right.equalToSuperview()
+            make.bottom.equalToSuperview()
             make.height.equalTo(8)
         }
         
-        progessSilde.snp.makeConstraints { make in
-            make.left.right.centerY.equalTo(progessSildeBackV)
-            make.height.equalTo(20)
-        }
-        
-        
         withDrawBtn.imageEdgeInsets = UIEdgeInsets(top: -withDrawBtn.imageView!.height, left: 0, bottom: 0, right: -withDrawBtn.titleLabel!.width);
         withDrawBtn.titleEdgeInsets = UIEdgeInsets(top: withDrawBtn.titleLabel!.height + 2, left: -withDrawBtn.imageView!.width, bottom: 0, right: 0);
         
@@ -325,8 +307,17 @@ public class BFRecordScreenController: BFBaseViewController {
         
     }
     
+//    public override func viewWillLayoutSubviews() {
+//        super.viewWillLayoutSubviews()
+//
+//    }
+    
     // MARK: - 按钮事件响应
     
+    public override func backBtnClick() {
+        pause()
+    }
+    
     // 触发拖曳手势后,执行的动作
     @objc func pan(recognizer: UIPanGestureRecognizer) {
         // 设置 UIView 新的位置
@@ -616,7 +607,10 @@ public class BFRecordScreenController: BFBaseViewController {
                 if let urlass = asset as? AVURLAsset {
                     self?.avasset = urlass
                     DispatchQueue.main.async {[weak self] in
-                        self?.bottomeView.addSubview(self!.progressThumV)
+                        self?.progressThumV.videoAsset = urlass
+                        self?.progressThumV.isHidden = false
+//                        self?.progessSildeBackV.setNeedsLayout()
+//                        self?.progessSildeBackV.layoutIfNeeded()
                     }
                 }
             })
@@ -659,8 +653,7 @@ public class BFRecordScreenController: BFBaseViewController {
                 BFLog(1, message: "curr:\(CMTimeGetSeconds(time))")
                 if CMTimeGetSeconds(item.duration) > 0, !(self?.isDragingProgressSlder ?? false) {
                     DispatchQueue.main.async { [weak self] in
-                        self?.progessSilde.value = Float(CMTimeGetSeconds(time) / CMTimeGetSeconds(item.duration))
-                        self?.progreddL.text = String(format: "%.2f / %.2f", CMTimeGetSeconds(time), CMTimeGetSeconds(item.duration))
+                        self?.progreddL.text = String(format: "%.2f", CMTimeGetSeconds(time), CMTimeGetSeconds(item.duration))
                         self?.progressThumV.progress = time.seconds
                     }
                 }
@@ -698,11 +691,12 @@ public class BFRecordScreenController: BFBaseViewController {
     func changeProgress(progress:Float) {
         if let duration = assetPlayer?.currentItem?.duration {
             self.currentAssetProgress = CMTime(value: CMTimeValue(progress * Float(CMTimeGetSeconds(duration)) * 100), timescale: 100)
+            DispatchQueue.main.async {[weak self] in
+                self!.progreddL.text = String(format: "%.2f", CMTimeGetSeconds(self!.currentAssetProgress))
+            }
+
             assetPlayer!.seek(to: self.currentAssetProgress, toleranceBefore: CMTime(value: 1, timescale: 1000), toleranceAfter: CMTime(value: 1, timescale: 1000)) { finished in
-//                if finished{
-//                    BFLog(1, message: "拖动成功 \(progress)")
-//                    self?.movie?.startProcessing()
-//                }
+
             }
         }
     }

+ 11 - 14
BFRecordScreenKit/Classes/BFVideoThumbImageFetchHelper.swift

@@ -11,9 +11,10 @@ import BFCommonKit
 
 /// 视频分解成帧
 /// - parameter fileUrl                 : 视频地址
-/// - parameter fps                     : 自定义帧数 每秒内取的帧数
+/// - parameter fps                          : 自定义帧数 每秒内取的帧数
+/// - parameter range                     : 获取其中几张连续视频帧
 /// - parameter splitCompleteClosure    : 回调
-func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, range:NSRange? = nil, splitCompleteClosure:@escaping ((Bool, [UIImage]?) -> Void)) {
+func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Double, range:NSRange? = nil, splitCompleteClosure:@escaping (([UIImage]) -> Void)) {
     var splitImages = [UIImage]()
     
     var times = [NSValue]()
@@ -22,12 +23,12 @@ func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, range:NSRange? = nil,
     var end = Int(urlAsset.duration.seconds * Float64(fps))
     
     if range != nil {
-        start = range!.location
-        end = start + range!.length
+        start = min(range!.location, end)
+        end = min(start + range!.length, end)
     }
     
     for i in start...end {
-        let timeValue = NSValue(time: CMTimeMake(value: Int64(i), timescale: Int32(fps)) )
+        let timeValue = NSValue(time: CMTimeMake(value: Int64(i * 1000), timescale: Int32(fps * 1000)) )
         
         times.append(timeValue)
     }
@@ -41,27 +42,23 @@ func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, range:NSRange? = nil,
     //获取每一帧的图片
     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")
+            BFLog(1, message: "splitVideo: cancel")
 
         case AVAssetImageGenerator.Result.failed:
-            BFLog(1, message: "aaa: failed")
+            BFLog(1, message: "splitVideo: 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
+//            BFLog(1, message: "aaa: \(requestedTime.seconds) - \(actualTime.seconds)")
         @unknown default:
             break
         }
         if cocu == timesCount { //最后一帧时 回调赋值
-            splitCompleteClosure(isSuccess, splitImages)
-            BFLog(1, message: "aaa: complete")
+            splitCompleteClosure(splitImages)
+            BFLog(1, message: "splitVideo: complete")
 
         }
     }

+ 51 - 35
BFRecordScreenKit/Classes/BFVideoThumbProgressView.swift

@@ -12,10 +12,48 @@ import BFCommonKit
 import SnapKit
 
 class BFVideoThumbProgressView: UIView {
-    var videoAsset : AVURLAsset?
+    var videoAsset : AVURLAsset? {
+        didSet{
+            if let videoAsset = videoAsset {
+                let dur = videoAsset.duration.seconds
+                if dur > 0{
+                    let fps = Double(fetchThumbStrategy.frameNumberOfVideo(assetDuration: dur)) / dur
+                    
+                    splitVideoFileUrlFps(urlAsset: videoAsset, fps: fps) {[weak self] images in
+                        if images.count > 0{
+                            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
+                                        iv.clipsToBounds = true
+                                        sself.progressView.addSubview(iv)
+                                        iv.snp.makeConstraints { make in
+                                            make.left.equalTo(CGFloat(i) * sself.thumbImageWidth + sself.width * 0.5)
+                                            make.top.height.equalToSuperview()
+                                            make.width.equalTo(sself.thumbImageWidth)
+                                        }
+                                    }
+                                    sself.progressView.contentSize = CGSize(width: CGFloat(images.count) *  sself.thumbImageWidth + sself.width, height: sself.height)
+                                }
+                            }
+                        }
+                    }
+                    
+                }
+            }
+        }
+    }
+    
     var dragScrollProgressHandle : ((Float) -> Void)?
     var dragEndHandle : ((Float) -> Void)?
     var isDrag = false
+    
+    let thumbImageWidth = 70.0
+    
+    let fetchThumbStrategy : BFVideoThumbProgressStrategyProtocol = BFVideoThumbProgressStrategy()
+    
     var progress:Double = 0 {
         didSet{
             if let second = self.videoAsset?.duration.seconds, second > 0 {
@@ -27,9 +65,19 @@ class BFVideoThumbProgressView: UIView {
     
     var thumbImgs = [UIImage]()
     
-    init(frame: CGRect, videoAsset:AVURLAsset) {
+    lazy var progressView : UIScrollView = {
+        let sv = UIScrollView()
+        sv.bounces = false
+        sv.backgroundColor = .clear
+        sv.decelerationRate = .fast
+        sv.showsHorizontalScrollIndicator = false
+        sv.delegate = self
+        
+        return sv
+    }()
+
+    override init(frame: CGRect) {
         super.init(frame: frame)
-        self.videoAsset = videoAsset
         addSubview(progressView)
         
         let line = UIView()
@@ -42,44 +90,12 @@ class BFVideoThumbProgressView: UIView {
             make.center.height.equalToSuperview()
         }
         
-        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
-                            iv.clipsToBounds = true
-                            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
-        sv.delegate = self
-        
-        return sv
-    }()
-    
     override func layoutSubviews() {
         super.layoutSubviews()
         progressView.snp.makeConstraints { make in

+ 34 - 0
BFVideoThumbProgressStrategy.swift

@@ -0,0 +1,34 @@
+//
+//  BFVideoThumbProgressStrategy.swift
+//  BFRecordScreenKit
+//
+//  Created by 胡志强 on 2021/12/6.
+//
+
+import Foundation
+import AVFoundation
+
+protocol BFVideoThumbProgressStrategyProtocol {
+    
+    // 根据视频时长获取需要的缩略图数量
+    func frameNumberOfVideo(assetDuration: Double) -> Int
+}
+
+class BFVideoThumbProgressStrategy : BFVideoThumbProgressStrategyProtocol {
+
+    func frameNumberOfVideo(assetDuration: Double) -> Int {
+        var count = -1
+        
+        if assetDuration > 0 && assetDuration <= 10 {
+            count = 5
+        }else if assetDuration >= 10 && assetDuration < 60 {
+            count = 10
+        }else if assetDuration >= 60 && assetDuration < 300 {
+            count = 20
+        }else if assetDuration >= 300{
+            count = 30
+        }
+        
+        return count
+    }
+}