Explorar o código

Merge branch 'demo'

* demo:
  修改视频缩略图进度逻辑
  视频缩略图进度展示

# Conflicts:
#	BFRecordScreenKit/Classes/BFRecordScreenController.swift
harry %!s(int64=3) %!d(string=hai) anos
pai
achega
860bd0d72c

+ 71 - 50
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)
@@ -227,7 +207,36 @@ public class BFRecordScreenController: BFBaseViewController {
         btn.addTarget(self, action: #selector(drawPin), for: .touchUpInside)
         return btn
     }()
- 
+     
+    lazy var progressThumV : BFVideoThumbProgressView = {
+        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
+                }
+                if sself.isNormalPlaying || sself.isRecording {
+                    sself.pause()
+                    sself.isDragingProgressSlder = true
+                }
+                sself.changeProgress(progress: process)
+            }
+        }
+        vv.dragEndHandle = { [weak self] process in
+            
+            guard let sself = self else {
+                return
+            }
+            sself.changeProgress(progress: process)
+
+            sself.isDragingProgressSlder = false
+            sself.currentPlayRecordIndex = -1
+            sself.hadPrepareToPlayRecord = false
+        }
+        vv.isHidden = true
+        return vv
+    }()
+    
     //MARK: ------------------ 生命周期
     deinit {
         cleanMovieTarget()
@@ -259,18 +268,18 @@ public class BFRecordScreenController: BFBaseViewController {
         
         view.addSubview(playBtn)
         view.addSubview(bottomeView)
-        view.addSubview(progreddL)
         view.addSubview(avatarView)
         view.addSubview(openCameraBtn)
         view.addSubview(drawPinBtn)
         
+        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)
         }
@@ -280,15 +289,22 @@ public class BFRecordScreenController: BFBaseViewController {
             BFLog(message: "新录制完成::::\(materialsModel?.locationPath ?? "")")
         }
         
+        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)
@@ -304,21 +320,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)
-        }
-        
- 
+         
         openCameraBtn.snp.makeConstraints { make in
             make.right.equalToSuperview().offset(-12)
             make.top.equalToSuperview().offset(98)
@@ -333,7 +343,6 @@ public class BFRecordScreenController: BFBaseViewController {
             make.height.equalTo(124)
         }
  
-        
         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);
         
@@ -343,8 +352,17 @@ public class BFRecordScreenController: BFBaseViewController {
         
     }
     
+//    public override func viewWillLayoutSubviews() {
+//        super.viewWillLayoutSubviews()
+//
+//    }
+    
     // MARK: - 按钮事件响应
     
+    public override func backBtnClick() {
+        pause()
+    }
+    
     // 触发拖曳手势后,执行的动作
     @objc func pan(recognizer: UIPanGestureRecognizer) {
         // 设置 UIView 新的位置
@@ -669,8 +687,10 @@ public class BFRecordScreenController: BFBaseViewController {
                 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)
+                        self?.progressThumV.videoAsset = urlass
+                        self?.progressThumV.isHidden = false
+//                        self?.progessSildeBackV.setNeedsLayout()
+//                        self?.progessSildeBackV.layoutIfNeeded()
                     }
                 }
             })
@@ -713,8 +733,8 @@ 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
                     }
                 }
             } as? NSKeyValueObservation
@@ -751,11 +771,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)
-            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()
-//                }
+            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
+
             }
         }
     }

+ 18 - 13
BFRecordScreenKit/Classes/BFVideoThumbImageFetchHelper.swift

@@ -11,15 +11,24 @@ import BFCommonKit
 
 /// 视频分解成帧
 /// - parameter fileUrl                 : 视频地址
-/// - parameter fps                     : 自定义帧数 每秒内取的帧数
+/// - parameter fps                          : 自定义帧数 每秒内取的帧数
+/// - parameter range                     : 获取其中几张连续视频帧
 /// - parameter splitCompleteClosure    : 回调
-func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, splitCompleteClosure:@escaping ((Bool, [UIImage]?) -> Void)) {
+func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Double, range:NSRange? = nil, splitCompleteClosure:@escaping (([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)) )
+    var start = 0
+    var end = Int(urlAsset.duration.seconds * Float64(fps))
+    
+    if range != nil {
+        start = min(range!.location, end)
+        end = min(start + range!.length, end)
+    }
+    
+    for i in start...end {
+        let timeValue = NSValue(time: CMTimeMake(value: Int64(i * 1000), timescale: Int32(fps * 1000)) )
         
         times.append(timeValue)
     }
@@ -33,27 +42,23 @@ func splitVideoFileUrlFps(urlAsset:AVURLAsset, fps:Float, splitCompleteClosure:@
     //获取每一帧的图片
     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")
 
         }
     }

+ 34 - 0
BFRecordScreenKit/Classes/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
+    }
+}

+ 0 - 74
BFRecordScreenKit/Classes/BFVideoThumbProgressView.swift

@@ -1,74 +0,0 @@
-//
-//  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()
-        }
-        
-    }
-}

+ 0 - 0
BFRecordScreenKit/Classes/BFIntroduceToolView.swift → BFRecordScreenKit/Classes/View/BFIntroduceToolView.swift


+ 1 - 1
BFRecordScreenKit/Classes/RecordScreen/View/BFRecordAvatarView.swift → BFRecordScreenKit/Classes/View/BFRecordAvatarView.swift

@@ -60,7 +60,7 @@ class BFRecordAvatarView: UIView {
             cropFilter.locationOfCropInPixels = Position.init(0, (1920 - 1080) / 2)
             
 //            camera  --> cropFilter --> conertFilter --> renderView
-            camera --> cropFilter --> conertFilter --> renderView
+//            camera  --> cropFilter --> conertFilter --> renderView
         } catch {
             fatalError("Could not initialize rendering pipeline: \(error)")
         }

+ 137 - 0
BFRecordScreenKit/Classes/View/BFVideoThumbProgressView.swift

@@ -0,0 +1,137 @@
+//
+//  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? {
+        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 {
+                let w = progressView.contentSize.width - width
+                progressView.contentOffset = CGPoint(x: progress * w / second, y: 0)
+            }
+        }
+    }
+    
+    var thumbImgs = [UIImage]()
+    
+    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)
+        addSubview(progressView)
+        
+        let line = UIView()
+        line.backgroundColor = .white
+        line.layer.shadowColor = UIColor.black.cgColor
+        line.layer.shadowOffset = CGSize(width: 1, height: 1)
+        addSubview(line)
+        line.snp.makeConstraints { make in
+            make.width.equalTo(2)
+            make.center.height.equalToSuperview()
+        }
+        
+    }
+
+    required init?(coder: NSCoder) {
+        fatalError("init(coder:) has not been implemented")
+    }
+    
+    override func layoutSubviews() {
+        super.layoutSubviews()
+        progressView.snp.makeConstraints { make in
+            make.edges.equalToSuperview()
+        }
+        
+    }
+}
+
+extension BFVideoThumbProgressView : UIScrollViewDelegate {
+    func scrollViewDidScroll(_ scrollView: UIScrollView) {
+        if isDrag{
+            let dur = scrollView.contentOffset.x / (scrollView.contentSize.width - self.width)
+            self.dragScrollProgressHandle?(Float(dur))
+        }
+    }
+    
+    func scrollViewWillBeginDragging(_ scrollView: UIScrollView) {
+        isDrag = true
+        let dur = scrollView.contentOffset.x / (scrollView.contentSize.width - self.width)
+        self.dragScrollProgressHandle?(Float(dur))
+    }
+    
+    func scrollViewDidEndDragging(_ scrollView: UIScrollView, willDecelerate decelerate: Bool) {
+        if !decelerate {
+            let dur = scrollView.contentOffset.x / (scrollView.contentSize.width - self.width)
+            isDrag = false
+            dragEndHandle?(Float(dur))
+        }
+    }
+    
+    func scrollViewDidEndDecelerating(_ scrollView: UIScrollView) {
+        let dur = scrollView.contentOffset.x / (scrollView.contentSize.width - self.width)
+        isDrag = false
+        dragEndHandle?(Float(dur))
+
+    }
+    
+}