Browse Source

Merge branch 'master' into module

* master: (33 commits)
  1.修改filter func public
  1.update imagefilter load
  1.update image load
  添加导出真实使用时长
  使用FilterLog
  1,修改重试 BTN 变量名, 2,添加是否生成水印参数。
  视频析构数据
  合成时查找sticker优化
  支持添加data 方式初始化图片和gif
  图片支持系统相册路径
  1.迁移NX相关到Common
  fix loading的show()函数
  1.迁移NX相关到Common
  适配xcode13
  fix 循环引用
  1.fix bugs
  循环引用fix
  打开测试注释代码
  打开生成水印视频
  fix 图片无卡点数据
  ...

# Conflicts:
#	BFFramework.podspec
#	BFFramework/Classes/Stuckpoint/Controller/PQStuckPointEditerController.swift
#	BFFramework/Classes/Stuckpoint/Controller/PQStuckPointMusicContentController.swift
#	BFFramework/Classes/Stuckpoint/View/PQCustomSpeedSettingView.swift
harry 3 years ago
parent
commit
fe6f5f1029
36 changed files with 507 additions and 1761 deletions
  1. 2 1
      BFFramework.podspec
  2. 0 33
      BFFramework/Classes/BFModules/BFCategorys/BFFloat+Ext.swift
  3. 0 1
      BFFramework/Classes/BFModules/BFCategorys/UICollectionView+Ext.swift
  4. 0 0
      BFFramework/Classes/BFModules/BFCustomViews/.gitkeep
  5. 0 0
      BFFramework/Classes/BFModules/BFCustomViews/views/.gitkeep
  6. 0 17
      BFFramework/Classes/BFModules/BFCustomViews/views/BFUIButton.swift
  7. 0 99
      BFFramework/Classes/BFModules/BFCustomViews/views/BFUISlider.swift
  8. 0 114
      BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/NXBadgeControl.swift
  9. 0 28
      BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/NXBadgeView.swift
  10. 0 125
      BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UIBarButtonItem+NXBadgeView.swift
  11. 0 126
      BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UITabBarItem+NXBadgeView.swift
  12. 0 260
      BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UIView+NXBadgeView.swift
  13. 0 166
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXBubbleLayer.swift
  14. 0 23
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXContainView.swift
  15. 0 73
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXInteractiveView.swift
  16. 0 80
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXNormalBubbleView.swift
  17. 0 40
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXTextBubbleView.swift
  18. 0 184
      BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXVoiceBubbleView.swift
  19. 2 4
      BFFramework/Classes/PModels/editDarftModels/PQEditVisionTrackMaterialsModel.swift
  20. 21 21
      BFFramework/Classes/PQGPUImage/akfilters/PQGPUImageTools.swift
  21. 25 14
      BFFramework/Classes/PQGPUImage/akfilters/PQGifFilter.swift
  22. 103 82
      BFFramework/Classes/PQGPUImage/akfilters/PQImageFilter.swift
  23. 42 29
      BFFramework/Classes/PQGPUImage/akfilters/PQMovieFilter.swift
  24. 63 53
      BFFramework/Classes/PQGPUImage/akfilters/PQMovieInput.swift
  25. 1 1
      BFFramework/Classes/PQGPUImage/akfilters/PQSubTitleFilter.swift
  26. 22 5
      BFFramework/Classes/PQGPUImage/akfilters/Tools/PQCompositionExporter.swift
  27. 74 45
      BFFramework/Classes/Stuckpoint/Controller/PQStuckPointEditerController.swift
  28. 5 7
      BFFramework/Classes/Stuckpoint/Controller/PQStuckPointMaterialController.swift
  29. 18 18
      BFFramework/Classes/Stuckpoint/Controller/PQStuckPointMusicContentController.swift
  30. 39 25
      BFFramework/Classes/Stuckpoint/Controller/PQStuckPointPublicController.swift
  31. 8 4
      BFFramework/Classes/Stuckpoint/View/PQCustomSpeedSettingView.swift
  32. 15 18
      BFFramework/Classes/Stuckpoint/View/PQStuckPointLoadingView.swift
  33. 37 30
      BFFramework/Classes/Stuckpoint/ViewModel/PQGPUImagePlayerView.swift
  34. 8 8
      BFFramework/Classes/selectImage/PQUploadController.swift
  35. 3 3
      Example/Podfile
  36. 19 24
      Example/Podfile.lock

+ 2 - 1
BFFramework.podspec

@@ -59,6 +59,7 @@ TODO: Add long description of the pod here.
   s.dependency 'WechatOpenSDK-Swift'      ,'1.8.7.1'  # 微信组件
   s.dependency 'MJRefresh'                ,'3.7.2'    # 刷新组件
   s.dependency 'LMJHorizontalScrollText'  ,'2.0.2'
-  s.dependency 'TXLiteAVSDK_Player'       ,'9.1.10564' # 腾讯播放器组件
+  s.dependency 'TXLiteAVSDK_Player'       ,'9.2.10637' # 腾讯播放器组件
   s.dependency 'Bugly'                    ,'2.5.90'   #crash log 收集
+
 end

+ 0 - 33
BFFramework/Classes/BFModules/BFCategorys/BFFloat+Ext.swift

@@ -1,33 +0,0 @@
-//
-//  BFFloat+Ext.swift
-//  BFFramework
-//
-//  Created by ak on 2021/10/11.
-//
-
-import Foundation
-
-extension Float {
-    /// 准确的小数尾截取 - 没有进位
-    /*
-     // 11.999003  -> 12.0
-     var pp = 11.999003
-     String(format: "%.1f", pp)  这个方法会进行四舍五入
-     */
-    func decimalString(_ base: Self = 1) -> String {
-       return "\(self.decimalNumber(base))"
-    }
-    func decimalNumber(_ base: Self = 1) -> Float {
-        let tempCount: Self = pow(10, base)
-        let temp = self*tempCount
-        
-        let target = Self(Int(temp))
-        let stepone = target/tempCount
-        if stepone.truncatingRemainder(dividingBy: 1) == 0 {
-            return Float(String(format: "%.0f", stepone)) ?? 0.0
-        }else{
-            return stepone
-        }
-    }
-}
- 

+ 0 - 1
BFFramework/Classes/BFModules/BFCategorys/UICollectionView+Ext.swift

@@ -7,7 +7,6 @@
 //
 
 import Foundation
-import MJRefresh
 
 extension UICollectionView{
     /// 获取当前cell

+ 0 - 0
BFFramework/Classes/BFModules/BFCustomViews/.gitkeep


+ 0 - 0
BFFramework/Classes/BFModules/BFCustomViews/views/.gitkeep


+ 0 - 17
BFFramework/Classes/BFModules/BFCustomViews/views/BFUIButton.swift

@@ -1,17 +0,0 @@
-//
-//  BFUIButton.swift
-//  Alamofire
-//
-//  Created by ak on 2021/8/4.
-//  功能:默认扩大 btn 的点击范围
-
-import Foundation
-
-public class BFUIButton: UIButton {
-    //扩大点击范围 PX
-    var margin: CGFloat = 60
-    public override func point(inside point: CGPoint, with _: UIEvent?) -> Bool {
-        let area = bounds.insetBy(dx: -margin, dy: -margin) // 负值是方法响应范围
-        return area.contains(point)
-    }
-}

+ 0 - 99
BFFramework/Classes/BFModules/BFCustomViews/views/BFUISlider.swift

@@ -1,99 +0,0 @@
-//
-//  BFSlider.swift
-//  BFFramework
-//
-//  Created by ak on 2021/8/4.
-//  功能:自定义 UISlider
-
-import Foundation
-
-class BFUISlider: UISlider {
-    
-    //slider的value文本
-    var valueText:String?{
-        didSet {
-            valueLabel.text = valueText
-            valueLabel.sizeToFit()
-            
-            let trackRect = convert(bounds, to: nil)
-            let thumbRectTemp = thumbRect(forBounds: bounds, trackRect: trackRect, value: value)
-            valueLabel.center = CGPoint.init(x: (thumbRectTemp.origin.x - thumbRectTemp.origin.x + thumbRectTemp.size.width / 2), y: -self.frame.size.height)
-            
-//            CGPointMake((thumbRect.origin.x - trackRect.origin.x + thumbRect.size.width / 2), -self.frame.size.height);
-            
-//            [super trackRectForBounds:bounds];
-//           return CGRectMake(bounds.origin.x, bounds.origin.y + (bounds.size.height - 3.0) / 2, bounds.size.width, 3.0);
-       
-        }
-    }
-    override var value: Float{
-        didSet {
-            sliderValueChanged(sender: self)
-        }
-    }
-    //slider的value字体
-    var valueFont:UIFont?
-    //slider的value文本颜色
-    var valueTextColor:UIColor?
-    
-    //返回的数值是否为整形
-    var valueIsInt:Bool = false
-    
-    lazy var valueLabel:UILabel = {
-        let valueLabel = UILabel.init()
-        valueLabel.text = "0"
-        valueLabel.textColor = valueTextColor != nil ? valueTextColor : self.thumbTintColor
-        valueLabel.font = valueFont != nil ? valueFont : UIFont.systemFont(ofSize: 14);
-        valueLabel.textAlignment = .center
-        
-        return valueLabel
-        
-    }()
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        addTarget(self, action: #selector(sliderTouchDown(sender:)), for: .touchDown)
-        addTarget(self, action: #selector(sliderValueChanged(sender:)), for: .valueChanged)
-        addTarget(self, action: #selector(sliderTouchUpInside(sender:)), for: .touchUpInside)
- 
-    }
-    
-    required init?(coder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    override func layoutSubviews() {
-        super.layoutSubviews()
-        addSubview(valueLabel)
-        sliderValueChanged(sender: self)
-    }
-    
-    override func setValue(_ value: Float, animated: Bool) {
-        super.setValue(value, animated: animated)
-        sliderValueChanged(sender: self)
-    }
- 
-    //重写方法-返回进度条的bounds-修改进度条的高度
-    override func trackRect(forBounds bounds: CGRect) -> CGRect {
- 
-        let bounds = super.trackRect(forBounds: bounds)
-        return CGRect.init(origin: CGPoint.init(x: bounds.origin.x, y: bounds.origin.y + (bounds.size.height - 3.0) / 2 ), size: CGSize.init(width:  bounds.size.width, height: 3))
-    }
-    
-    @objc func sliderTouchDown(sender: BFUISlider) {
-         
-    }
-    @objc func sliderValueChanged(sender: BFUISlider) {
-        
-        if(valueIsInt){
-            valueText = "\(Int(sender.value))x"
-        }else{
-            valueText = "\(sender.value.decimalString())x"
-        }
-      
- 
-    }
-    @objc func sliderTouchUpInside(sender: BFUISlider) {
-         
-    }
-    
-}

+ 0 - 114
BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/NXBadgeControl.swift

@@ -1,114 +0,0 @@
-//
-//  NXBadgeControl.swift
-//  NXFramework-Swift
-//
-//  Created by ak on 2020/11/11.
-//
-
-
-import UIKit
-
-
-open class NXBadgeControl: UIControl {
-    
-    /// 记录Badge的偏移量 Record the offset of Badge
-    public var offset: CGPoint = CGPoint(x: 0, y: 0)
-    
-    /// Badge伸缩的方向, Default is NXBadgeViewFlexModeTail
-    public var flexMode: NXBadgeViewFlexMode = .tail
-    
-    private lazy var textLabel: UILabel = UILabel()
-    
-    private lazy var imageView: UIImageView = UIImageView()
-    
-    private var badgeViewColor: UIColor?
-    private var badgeViewHeightConstraint: NSLayoutConstraint?
-    
-    public class func `default`() -> Self {
-        return self.init(frame: .zero)
-    }
-    
-    required override public init(frame: CGRect) {
-        super.init(frame: frame)
-        setupSubviews()
-    }
-    
-    required public init?(coder aDecoder: NSCoder) {
-        super.init(coder: aDecoder)
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-    /// Set Text
-    open var text: String? {
-        didSet {
-            textLabel.text = text
-        }
-    }
-    
-    /// Set AttributedText
-    open var attributedText: NSAttributedString? {
-        didSet {
-            textLabel.attributedText = attributedText
-        }
-    }
-    
-    /// Set Font
-    open var font: UIFont? {
-        didSet {
-            textLabel.font = font
-        }
-    }
-    
-    /// Set background image
-    open var backgroundImage: UIImage? {
-        didSet {
-            imageView.image = backgroundImage
-            if let _ = backgroundImage {
-                if let constraint = heightConstraint() {
-                    badgeViewHeightConstraint = constraint
-                    removeConstraint(constraint)
-                }
-                backgroundColor = UIColor.clear
-            } else {
-                if heightConstraint() == nil, let constraint = badgeViewHeightConstraint {
-                    addConstraint(constraint)
-                }
-                backgroundColor = badgeViewColor
-            }
-        }
-    }
-    
-    open override var backgroundColor: UIColor? {
-        didSet {
-            super.backgroundColor = backgroundColor
-            if let color = backgroundColor, color != .clear {
-                badgeViewColor = backgroundColor
-            }
-        }
-    }
-    
-    private func setupSubviews() {
-        layer.masksToBounds = true
-        layer.cornerRadius = 9.0
-        translatesAutoresizingMaskIntoConstraints = false
-        backgroundColor = UIColor.red
-        textLabel.textColor = UIColor.white
-        textLabel.font = UIFont.systemFont(ofSize: 13)
-        textLabel.textAlignment = .center
-        addSubview(textLabel)
-        addSubview(imageView)
-        addLayout(with: imageView, leading: 0, trailing: 0)
-        addLayout(with: textLabel, leading: 5, trailing: -5)
-    }
-    
-    private func addLayout(with view: UIView, leading: CGFloat, trailing: CGFloat) {
-        view.translatesAutoresizingMaskIntoConstraints = false
-        let topConstraint = NSLayoutConstraint(item: view, attribute: .top, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0)
-        let leadingConstraint = NSLayoutConstraint(item: view, attribute: .leading, relatedBy: .equal, toItem: self, attribute: .leading, multiplier: 1.0, constant: leading)
-        let bottomConstraint = NSLayoutConstraint(item: view, attribute: .bottom, relatedBy: .equal, toItem: self, attribute: .bottom, multiplier: 1.0, constant: 0)
-        let trailingConstraint = NSLayoutConstraint(item: view, attribute: .trailing, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: trailing)
-        leadingConstraint.priority = UILayoutPriority(rawValue: 999)
-        trailingConstraint.priority = UILayoutPriority(rawValue: 999)
-        addConstraints([topConstraint, leadingConstraint, bottomConstraint, trailingConstraint])
-    }
-}

+ 0 - 28
BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/NXBadgeView.swift

@@ -1,28 +0,0 @@
-//
-//  NXBadgeView.swift.swift
-//  NXFramework-Swift
-//
-//  Created by ak on 2020/11/11.
-//
-
-
-import UIKit
-
-public struct NX<Base> {
-    public let base: Base
-    public init(_ base: Base) {
-        self.base = base
-    }
-}
-
-public extension NSObjectProtocol {
-    var nx: NX<Self> {
-        return NX(self)
-    }
-}
-
-public enum NXBadgeViewFlexMode {
-    case head    // 左伸缩 Head Flex    : <==●
-    case tail    // 右伸缩 Tail Flex    : ●==>
-    case middle  // 左右伸缩 Middle Flex : <=●=>
-}

+ 0 - 125
BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UIBarButtonItem+NXBadgeView.swift

@@ -1,125 +0,0 @@
-//
-//  UIBarButtonItem+NXBadgeView.swift
-//  NXFramework-Swift
-//
-//  Created by ak on 2020/11/11.
-//
-
-import UIKit
-
-public extension NX where Base: UIBarButtonItem {
-    
-    public var badgeView: NXBadgeControl {
-        return _bottomView.nx.badgeView
-    }
-    
-    /// 添加带文本内容的Badge, 默认右上角, 红色, 18pts
-    ///
-    /// Add Badge with text content, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter text: 文本字符串
-     public  func addBadge(text: String) {
-        _bottomView.nx.addBadge(text: text)
-    }
-    
-    /// 添加带数字的Badge, 默认右上角,红色,18pts
-    ///
-    /// Add the Badge with numbers, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter number: 整形数字
-     public  func addBadge(number: Int) {
-        _bottomView.nx.addBadge(number: number)
-    }
-    
-    /// 添加带颜色的小圆点, 默认右上角, 红色, 8pts
-    ///
-    /// Add small dots with color, the default upper right corner, red backgroundColor, 8pts
-    ///
-    /// - Parameter color: 颜色
-     public  func addDot(color: UIColor?) {
-        _bottomView.nx.addDot(color: color)
-    }
-    
-    /// 设置Badge的偏移量, Badge中心点默认为其父视图的右上角
-    ///
-    /// Set Badge offset, Badge center point defaults to the top right corner of its parent view
-    ///
-    /// - Parameters:
-    ///   - x: X轴偏移量 (x<0: 左移, x>0: 右移) axis offset (x <0: left, x> 0: right)
-    ///   - y: Y轴偏移量 (y<0: 上移, y>0: 下移) axis offset (Y <0: up,   y> 0: down)
-     public  func moveBadge(x: CGFloat, y: CGFloat) {
-        _bottomView.nx.moveBadge(x: x, y: y)
-    }
-    
-    /// 设置Badge伸缩的方向
-    ///
-    /// Setting the direction of Badge expansion
-    ///
-    /// NXBadgeViewFlexModeHead,    左伸缩 Head Flex    : <==●
-    /// NXBadgeViewFlexModeTail,    右伸缩 Tail Flex    : ●==>
-    /// NXBadgeViewFlexModeMiddle   左右伸缩 Middle Flex : <=●=>
-    /// - Parameter flexMode : Default is PPBadgeViewFlexModeTail
-     public  func setBadge(flexMode: NXBadgeViewFlexMode = .tail) {
-        _bottomView.nx.setBadge(flexMode: flexMode)
-    }
-    
-    /// 设置Badge的高度,因为Badge宽度是动态可变的,通过改变Badge高度,其宽度也按比例变化,方便布局
-    ///
-    /// (注意: 此方法需要将Badge添加到控件上后再调用!!!)
-    ///
-    /// Set the height of Badge, because the Badge width is dynamically and  variable.By changing the Badge height in proportion to facilitate the layout.
-    ///
-    /// (Note: this method needs to add Badge to the controls and then use it !!!)
-    ///
-    /// - Parameter points: 高度大小
-     public  func setBadge(height: CGFloat) {
-        _bottomView.nx.setBadge(height: height)
-    }
-    
-    /// 显示Badge
-     public  func showBadge() {
-        _bottomView.nx.showBadge()
-    }
-    
-    /// 隐藏Badge
-     public  func hiddenBadge() {
-        _bottomView.nx.hiddenBadge()
-    }
-    
-    // MARK: - 数字增加/减少, 注意:以下方法只适用于Badge内容为纯数字的情况
-    // MARK: - Digital increase /decrease, note: the following method applies only to cases where the Badge content is purely numeric
-    /// badge数字加1
-     public  func increase() {
-        _bottomView.nx.increase()
-    }
-    
-    /// badge数字加number
-     public  func increaseBy(number: Int) {
-        _bottomView.nx.increaseBy(number: number)
-    }
-    
-    /// badge数字加1
-     public  func decrease() {
-        _bottomView.nx.decrease()
-    }
-    
-    /// badge数字减number
-     public  func decreaseBy(number: Int) {
-        _bottomView.nx.decreaseBy(number: number)
-    }
-
-    /// 通过Xcode视图调试工具找到UIBarButtonItem的Badge所在父视图为:UIImageView
-    private var _bottomView: UIView {
-        let navigationButton = (self.base.value(forKey: "_view") as? UIView) ?? UIView()
-        let systemVersion = (UIDevice.current.systemVersion as NSString).doubleValue
-        let controlName = (systemVersion < 11.0 ? "UIImageView" : "UIButton" )
-        for subView in navigationButton.subviews {
-            if subView.isKind(of: NSClassFromString(controlName)!) {
-                subView.layer.masksToBounds = false
-                return subView
-            }
-        }
-        return navigationButton
-    }
-}
-

+ 0 - 126
BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UITabBarItem+NXBadgeView.swift

@@ -1,126 +0,0 @@
-
-//
-//  UITabBarItem+NXBadgeView.swift
-//  NXFramework-Swift
-//
-//  Created by ak on 2020/11/11.
-//
-
-import Foundation
-
-public extension NX where Base: UITabBarItem {
-    
-    var badgeView: NXBadgeControl {
-        return _bottomView.nx.badgeView
-    }
-    
-    /// 添加带文本内容的Badge, 默认右上角, 红色, 18pts
-    ///
-    /// Add Badge with text content, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter text: 文本字符串
-    func addBadge(text: String) {
-        _bottomView.nx.addBadge(text: text)
-        _bottomView.nx.moveBadge(x: 4, y: 3)
-    }
-    
-    /// 添加带数字的Badge, 默认右上角,红色,18pts
-    ///
-    /// Add the Badge with numbers, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter number: 整形数字
-    func addBadge(number: Int) {
-        _bottomView.nx.addBadge(number: number)
-        _bottomView.nx.moveBadge(x: 4, y: 3)
-    }
-    
-    /// 添加带颜色的小圆点, 默认右上角, 红色, 8pts
-    ///
-    /// Add small dots with color, the default upper right corner, red backgroundColor, 8pts
-    ///
-    /// - Parameter color: 颜色
-    func addDot(color: UIColor?) {
-        _bottomView.nx.addDot(color: color)
-    }
-    
-    /// 设置Badge的偏移量, Badge中心点默认为其父视图的右上角
-    ///
-    /// Set Badge offset, Badge center point defaults to the top right corner of its parent view
-    ///
-    /// - Parameters:
-    ///   - x: X轴偏移量 (x<0: 左移, x>0: 右移) axis offset (x <0: left, x> 0: right)
-    ///   - y: Y轴偏移量 (y<0: 上移, y>0: 下移) axis offset (Y <0: up,   y> 0: down)
-    func moveBadge(x: CGFloat, y: CGFloat) {
-        _bottomView.nx.moveBadge(x: x, y: y)
-    }
-    
-    /// 设置Badge伸缩的方向
-    ///
-    /// Setting the direction of Badge expansion
-    ///
-    /// PPBadgeViewFlexModeHead,    左伸缩 Head Flex    : <==●
-    /// PPBadgeViewFlexModeTail,    右伸缩 Tail Flex    : ●==>
-    /// PPBadgeViewFlexModeMiddle   左右伸缩 Middle Flex : <=●=>
-    /// - Parameter flexMode : Default is PPBadgeViewFlexModeTail
-    func setBadge(flexMode: NXBadgeViewFlexMode = .tail) {
-        _bottomView.nx.setBadge(flexMode: flexMode)
-    }
-    
-    /// 设置Badge的高度,因为Badge宽度是动态可变的,通过改变Badge高度,其宽度也按比例变化,方便布局
-    ///
-    /// (注意: 此方法需要将Badge添加到控件上后再调用!!!)
-    ///
-    /// Set the height of Badge, because the Badge width is dynamically and  variable.By changing the Badge height in proportion to facilitate the layout.
-    ///
-    /// (Note: this method needs to add Badge to the controls and then use it !!!)
-    ///
-    /// - Parameter height: 高度大小
-    func setBadge(height: CGFloat) {
-        _bottomView.nx.setBadge(height: height)
-    }
-    
-    
-    /// 显示Badge
-    func showBadge() {
-        _bottomView.nx.showBadge()
-    }
-    
-    /// 隐藏Badge
-    func hiddenBadge() {
-        _bottomView.nx.hiddenBadge()
-    }
-    
-    // MARK: - 数字增加/减少, 注意:以下方法只适用于Badge内容为纯数字的情况
-    // MARK: - Digital increase /decrease, note: the following method applies only to cases where the Badge content is purely numeric
-    /// badge数字加1
-    func increase() {
-        _bottomView.nx.increase()
-    }
-    
-    /// badge数字加number
-    func increaseBy(number: Int) {
-        _bottomView.nx.increaseBy(number: number)
-    }
-    
-    /// badge数字加1
-    func decrease() {
-        _bottomView.nx.decrease()
-    }
-    
-    /// badge数字减number
-    func decreaseBy(number: Int) {
-        _bottomView.nx.decreaseBy(number: number)
-    }
-    
-    /// 通过Xcode视图调试工具找到UITabBarItem原生Badge所在父视图
-    private var _bottomView: UIView {
-        let tabBarButton = (self.base.value(forKey: "_view") as? UIView) ?? UIView()
-        for subView in tabBarButton.subviews {
-            guard let superclass = subView.superclass else { return tabBarButton }
-            if superclass == NSClassFromString("UIImageView") {
-                return subView
-            }
-        }
-        return tabBarButton
-    }
-}

+ 0 - 260
BFFramework/Classes/BFModules/BFCustomViews/views/NXBadgeView/UIView+NXBadgeView.swift

@@ -1,260 +0,0 @@
-//
-//  UIView+NXBadgeView.swift
-//  NXFramework-Swift
-//
-//  Created by ak on 2020/11/11.
-//
-
-import UIKit
-
-private var kBadgeView = "kNXBadgeView"
-
-// MARK: - add Badge
-public extension NX where Base: UIView {
-    
-    var badgeView: NXBadgeControl {
-        return base.badgeView
-    }
-    
-    /// 添加带文本内容的Badge, 默认右上角, 红色, 18pts
-    ///
-    /// Add Badge with text content, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter text: 文本字符串
-    func addBadge(text: String?) {
-        showBadge()
-        base.badgeView.text = text
-        setBadge(flexMode: base.badgeView.flexMode)
-        if text == nil {
-            if base.badgeView.widthConstraint()?.relation == .equal { return }
-            base.badgeView.widthConstraint()?.isActive = false
-            let constraint = NSLayoutConstraint(item: base.badgeView, attribute: .width, relatedBy: .equal, toItem: base.badgeView, attribute: .height, multiplier: 1.0, constant: 0)
-            base.badgeView.addConstraint(constraint)
-        } else {
-            if base.badgeView.widthConstraint()?.relation == .greaterThanOrEqual { return }
-            base.badgeView.widthConstraint()?.isActive = false
-            let constraint = NSLayoutConstraint(item: base.badgeView, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: base.badgeView, attribute: .height, multiplier: 1.0, constant: 0)
-            base.badgeView.addConstraint(constraint)
-        }
-    }
-    
-    /// 添加带数字的Badge, 默认右上角,红色,18pts
-    ///
-    /// Add the Badge with numbers, the default upper right corner, red backgroundColor, 18pts
-    ///
-    /// - Parameter number: 整形数字
-    func addBadge(number: Int) {
-        if number <= 0 {
-            addBadge(text: "0")
-            hiddenBadge()
-            return
-        }
-        addBadge(text: "\(number)")
-    }
-    
-    /// 添加带颜色的小圆点, 默认右上角, 红色, 8pts
-    ///
-    /// Add small dots with color, the default upper right corner, red backgroundColor, 8pts
-    ///
-    /// - Parameter color: 颜色
-    func addDot(color: UIColor? = .red) {
-        addBadge(text: nil)
-        setBadge(height: 8.0)
-        base.badgeView.backgroundColor = color
-    }
-    
-    /// 设置Badge的偏移量, Badge中心点默认为其父视图的右上角
-    ///
-    /// Set Badge offset, Badge center point defaults to the top right corner of its parent view
-    ///
-    /// - Parameters:
-    ///   - x: X轴偏移量 (x<0: 左移, x>0: 右移) axis offset (x <0: left, x> 0: right)
-    ///   - y: Y轴偏移量 (y<0: 上移, y>0: 下移) axis offset (Y <0: up,   y> 0: down)
-    func moveBadge(x: CGFloat, y: CGFloat) {
-        base.badgeView.offset = CGPoint(x: x, y: y)
-        base.centerYConstraint(with: base.badgeView)?.constant = y
-        
-        let badgeHeight = base.badgeView.heightConstraint()?.constant ?? 0
-        switch base.badgeView.flexMode {
-        case .head:
-            base.centerXConstraint(with: base.badgeView)?.isActive = false
-            base.leadingConstraint(with: base.badgeView)?.isActive = false
-            if let constraint = base.trailingConstraint(with: base.badgeView) {
-                constraint.constant = badgeHeight * 0.5 + x
-                return
-            }
-            let trailingConstraint = NSLayoutConstraint(item: base.badgeView, attribute: .trailing, relatedBy: .equal, toItem: base, attribute: .trailing, multiplier: 1.0, constant: badgeHeight * 0.5 + x)
-            base.addConstraint(trailingConstraint)
-            
-        case .tail:
-            base.centerXConstraint(with: base.badgeView)?.isActive = false
-            base.trailingConstraint(with: base.badgeView)?.isActive = false
-            if let constraint = base.leadingConstraint(with: base.badgeView) {
-                constraint.constant = x - badgeHeight * 0.5
-                return
-            }
-            let leadingConstraint = NSLayoutConstraint(item: base.badgeView, attribute: .leading, relatedBy: .equal, toItem: base, attribute: .trailing, multiplier: 1.0, constant: x - badgeHeight * 0.5)
-            base.addConstraint(leadingConstraint)
-            
-        case .middle:
-            base.leadingConstraint(with: base.badgeView)?.isActive = false
-            base.trailingConstraint(with: base.badgeView)?.isActive = false
-            base.centerXConstraint(with: base.badgeView)?.constant = x
-            if let constraint = base.centerXConstraint(with: base.badgeView) {
-                constraint.constant = x
-                return
-            }
-            let centerXConstraint = NSLayoutConstraint(item: base.badgeView, attribute: .centerX, relatedBy: .equal, toItem: base, attribute: .centerX, multiplier: 1.0, constant: x)
-            base.addConstraint(centerXConstraint)
-        }
-    }
-    
-    /// 设置Badge伸缩的方向
-    ///
-    /// Setting the direction of Badge expansion
-    ///
-    /// NXBadgeViewFlexModeHead,    左伸缩 Head Flex    : <==●
-    /// NXBadgeViewFlexModeTail,    右伸缩 Tail Flex    : ●==>
-    /// NXBadgeViewFlexModeMiddle   左右伸缩 Middle Flex : <=●=>
-    /// - Parameter flexMode : Default is PPBadgeViewFlexModeTail
-    func setBadge(flexMode: NXBadgeViewFlexMode = .tail) {
-        base.badgeView.flexMode = flexMode
-        moveBadge(x: base.badgeView.offset.x, y: base.badgeView.offset.y)
-    }
-    
-    /// 设置Badge的高度,因为Badge宽度是动态可变的,通过改变Badge高度,其宽度也按比例变化,方便布局
-    ///
-    /// (注意: 此方法需要将Badge添加到控件上后再调用!!!)
-    ///
-    /// Set the height of Badge, because the Badge width is dynamically and  variable.By changing the Badge height in proportion to facilitate the layout.
-    ///
-    /// (Note: this method needs to add Badge to the controls and then use it !!!)
-    ///
-    /// - Parameter height: 高度大小
-    func setBadge(height: CGFloat) {
-        base.badgeView.layer.cornerRadius = height * 0.5
-        base.badgeView.heightConstraint()?.constant = height
-        moveBadge(x: base.badgeView.offset.x, y: base.badgeView.offset.y)
-    }
-    
-    /// 显示Badge
-    func showBadge() {
-        base.badgeView.isHidden = false
-    }
-    
-    /// 隐藏Badge
-    func hiddenBadge() {
-        base.badgeView.isHidden = true
-    }
-    
-    // MARK: - 数字增加/减少, 注意:以下方法只适用于Badge内容为纯数字的情况
-    // MARK: - Digital increase /decrease, note: the following method applies only to cases where the Badge content is purely numeric
-    /// badge数字加1
-    func increase() {
-        increaseBy(number: 1)
-    }
-    
-    /// badge数字加number
-    func increaseBy(number: Int) {
-        let label = base.badgeView
-        let result = (Int(label.text ?? "0") ?? 0) + number
-        if result > 0 {
-            showBadge()
-        }
-        label.text = "\(result)"
-    }
-    
-    /// badge数字加1
-    func decrease() {
-        decreaseBy(number: 1)
-    }
-    
-    /// badge数字减number
-    func decreaseBy(number: Int) {
-        let label = base.badgeView
-        let result = (Int(label.text ?? "0") ?? 0) - number
-        if (result <= 0) {
-            hiddenBadge()
-            label.text = "0"
-            return
-        }
-        label.text = "\(result)"
-    }
-}
-
-extension UIView {
-    
-      public  func addBadgeViewLayoutConstraint() {
-        badgeView.translatesAutoresizingMaskIntoConstraints = false
-        let centerXConstraint = NSLayoutConstraint(item: badgeView, attribute: .centerX, relatedBy: .equal, toItem: self, attribute: .trailing, multiplier: 1.0, constant: 0)
-        let centerYConstraint = NSLayoutConstraint(item: badgeView, attribute: .centerY, relatedBy: .equal, toItem: self, attribute: .top, multiplier: 1.0, constant: 0)
-        let widthConstraint = NSLayoutConstraint(item: badgeView, attribute: .width, relatedBy: .greaterThanOrEqual, toItem: badgeView, attribute: .height, multiplier: 1.0, constant: 0)
-        let heightConstraint = NSLayoutConstraint(item: badgeView, attribute: .height, relatedBy: .equal, toItem: nil, attribute: .notAnAttribute, multiplier: 1.0, constant: 18)
-        addConstraints([centerXConstraint, centerYConstraint])
-        badgeView.addConstraints([widthConstraint, heightConstraint])
-    }
-}
-
-// MARK: - getter/setter
-extension UIView {
-
-    public var badgeView: NXBadgeControl {
-        get {
-            if let aValue = objc_getAssociatedObject(self, &kBadgeView) as? NXBadgeControl {
-                return aValue
-            }
-            else {
-                let badgeControl = NXBadgeControl.default()
-                self.addSubview(badgeControl)
-                self.bringSubviewToFront(badgeControl)
-                self.badgeView = badgeControl
-                self.addBadgeViewLayoutConstraint()
-                return badgeControl
-            }
-        }
-        set {
-            objc_setAssociatedObject(self, &kBadgeView, newValue, objc_AssociationPolicy.OBJC_ASSOCIATION_RETAIN_NONATOMIC)
-        }
-    }
-    
-       public  func topConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .top)
-    }
-    
-       public  func leadingConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .leading)
-    }
-    
-       public  func bottomConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .bottom)
-    }
-
-       public  func trailingConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .trailing)
-    }
-    
-       public  func widthConstraint() -> NSLayoutConstraint? {
-        return constraint(with: self, attribute: .width)
-    }
-    
-       public  func heightConstraint() -> NSLayoutConstraint? {
-        return constraint(with: self, attribute: .height)
-    }
-
-       public  func centerXConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .centerX)
-    }
-    
-       public  func centerYConstraint(with item: AnyObject?) -> NSLayoutConstraint? {
-        return constraint(with: item, attribute: .centerY)
-    }
-    
-       public  func constraint(with item: AnyObject?, attribute: NSLayoutConstraint.Attribute) -> NSLayoutConstraint? {
-        for constraint in constraints {
-            if let isSame = constraint.firstItem?.isEqual(item), isSame, constraint.firstAttribute == attribute {
-                return constraint
-            }
-        }
-        return nil
-    }
-}

+ 0 - 166
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXBubbleLayer.swift

@@ -1,166 +0,0 @@
-//
-//  NXBubbleLayer.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/8/23.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import UIKit
-// 箭头方向枚举
-public enum ArrowDirection: Int {
-    case right = 0 // 指向右边, 即在圆角矩形的右边
-    case bottom = 1 // 指向下边
-    case left = 2 // 指向左边
-    case top = 3 // 指向上边
-}
-
-class NXBubbleLayer: NSObject {
-    // 矩形的圆角的半径
-    var cornerRadius: CGFloat = 8
-    // 箭头位置的圆角半径
-    var arrowRadius: CGFloat = 3
-    // 箭头的高度
-    var arrowHeight: CGFloat = 12
-    // 箭头的宽度
-    var arrowWidth: CGFloat = 30
-    // 箭头方向
-    var arrowDirection: ArrowDirection = .bottom
-    // 箭头的相对位置
-    var arrowPosition: CGFloat = 0.5
-    // 这里的size是需要mask成气泡形状的view的size
-    public var size: CGSize = CGSize.zero
-
-    /// 气泡layer 在视图层的位置
-    public var bubbleLayerRect: CGRect = .zero
-
-    init(originalSize: CGSize) {
-        size = originalSize
-    }
-
-    // 最终拿这个layer去设置mask
-    func layer() -> CAShapeLayer {
-        let layer = CAShapeLayer()
-        layer.path = bubblePath()
-        return layer
-    }
-
-    // 绘制气泡形状,获取path
-    func bubblePath() -> CGPath? {
-        UIGraphicsBeginImageContextWithOptions(size, false, 0.0)
-        let ctx = UIGraphicsGetCurrentContext()
-
-        // 获取绘图所需要的关键点
-        let points = keyPoints()
-
-        // 第一步是要画箭头的“第一个支点”所在的那个角,所以要把“笔”放在这个支点顺时针顺序的上一个点
-        // 所以把“笔”放在最后才画的矩形框的角的位置, 准备开始画箭头
-        let currentPoint = points[6]
-        ctx?.move(to: currentPoint)
-
-        // 用于 CGContextAddArcToPoint函数的变量
-        var pointA = CGPoint.zero
-        var pointB = CGPoint.zero
-        var radius: CGFloat = 0
-        var count: Int = 0
-
-        while count < 7 {
-            // 整个过程需要画七个圆角(矩形框的四个角和箭头处的三个角),所以分为七个步骤
-
-            // 箭头处的三个圆角和矩形框的四个圆角不一样
-            radius = count < 3 ? arrowRadius : cornerRadius
-
-            pointA = points[count]
-            pointB = points[(count + 1) % 7]
-            // 画矩形框最后一个角的时候,pointB就是points[0]
-
-            ctx?.addArc(tangent1End: pointA, tangent2End: pointB, radius: radius)
-
-            count = count + 1
-        }
-
-        ctx?.closePath()
-        UIGraphicsEndImageContext()
-
-        return ctx?.path?.copy()
-    }
-
-    // 关键点: 绘制气泡形状前,需要计算箭头的三个点和矩形的四个角的点的坐标
-    func keyPoints() -> [CGPoint] {
-        // 先确定箭头的三个点
-        var beginPoint = CGPoint.zero // 按顺时针画箭头时的第一个支点,例如箭头向上时的左边的支点
-        var topPoint = CGPoint.zero // 顶点
-        var endPoint = CGPoint.zero // 另外一个支点
-
-        // 箭头顶点topPoint的X坐标(或Y坐标)的范围(用来计算arrowPosition)
-        let tpXRange = size.width - 2 * cornerRadius - arrowWidth
-        let tpYRange = size.height - 2 * cornerRadius - arrowWidth
-
-        // 用于表示矩形框的位置和大小
-        var rX: CGFloat = 0
-        var rY: CGFloat = 0
-        var rWidth = size.width
-        var rHeight = size.height
-
-        // 计算箭头的位置,以及调整矩形框的位置和大小
-        switch arrowDirection {
-        case .right: // 箭头在右时
-            topPoint = CGPoint(x: size.width, y: size.height / 2 + tpYRange * (arrowPosition - 0.5))
-            beginPoint = CGPoint(x: topPoint.x - arrowHeight, y: topPoint.y - arrowWidth / 2)
-            endPoint = CGPoint(x: beginPoint.x, y: beginPoint.y + arrowWidth)
-
-            rWidth = rWidth - arrowHeight // 矩形框右边的位置“腾出”给箭头
-
-        case .bottom: // 箭头在下时
-            topPoint = CGPoint(x: size.width / 2 + tpXRange * (arrowPosition - 0.5), y: size.height)
-            beginPoint = CGPoint(x: topPoint.x + arrowWidth / 2, y: topPoint.y - arrowHeight)
-            endPoint = CGPoint(x: beginPoint.x - arrowWidth, y: beginPoint.y)
-
-            rHeight = rHeight - arrowHeight
-
-        case .left: // 箭头在左时
-            topPoint = CGPoint(x: 0, y: size.height / 2 + tpYRange * (arrowPosition - 0.5))
-            beginPoint = CGPoint(x: topPoint.x + arrowHeight, y: topPoint.y + arrowWidth / 2)
-            endPoint = CGPoint(x: beginPoint.x, y: beginPoint.y - arrowWidth)
-
-            rX = arrowHeight
-            rWidth = rWidth - arrowHeight
-
-        case .top: // 箭头在上时
-            topPoint = CGPoint(x: size.width / 2 + tpXRange * (arrowPosition - 0.5), y: 0)
-            beginPoint = CGPoint(x: topPoint.x - arrowWidth / 2, y: topPoint.y + arrowHeight)
-            endPoint = CGPoint(x: beginPoint.x + arrowWidth, y: beginPoint.y)
-
-            rY = arrowHeight
-            rHeight = rHeight - arrowHeight
-
-        default:
-            ()
-        }
-        bubbleLayerRect = CGRect(x: rX, y: rY, width: rWidth, height: rHeight)
-        // 先把箭头的三个点放进关键点数组中
-        var points = [beginPoint, topPoint, endPoint]
-
-        // 确定圆角矩形的四个点
-        let bottomRight = CGPoint(x: rX + rWidth, y: rY + rHeight) // 右下角的点
-        let bottomLeft = CGPoint(x: rX, y: rY + rHeight)
-        let topLeft = CGPoint(x: rX, y: rY)
-        let topRight = CGPoint(x: rX + rWidth, y: rY)
-
-        // 先放在一个临时数组, 放置顺序跟下面紧接着的操作有关
-        let rectPoints = [bottomRight, bottomLeft, topLeft, topRight]
-
-        // 绘制气泡形状的时候,从箭头开始,顺时针地进行
-        // 箭头向右时,画完箭头之后会先画到矩形框的右下角
-        // 所以此时先把矩形框右下角的点放进关键点数组,其他三个点按顺时针方向添加
-        // 箭头在其他方向时,以此类推
-
-        var rectPointIndex: Int = arrowDirection.rawValue
-        for _ in 0...3 {
-            points.append(rectPoints[rectPointIndex])
-            rectPointIndex = (rectPointIndex + 1) % 4
-        }
-
-        return points
-    }
-}

+ 0 - 23
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXContainView.swift

@@ -1,23 +0,0 @@
-//
-//  NXContainView.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/9/1.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import UIKit
-public class NXBubbleContainView: UIView {
-    override public func hitTest(_ point: CGPoint, with event: UIEvent?) -> UIView? {
-        var view = super.hitTest(point, with: event)
-        if view == nil {
-            subviews.forEach { subView in
-                let p = subView.convert(point, from: self)
-                if subView.bounds.contains(p) {
-                    view = subView
-                }
-            }
-        }
-        return view
-    }
-}

+ 0 - 73
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXInteractiveView.swift

@@ -1,73 +0,0 @@
-//
-//  NXInteractiveView.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/8/23.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import UIKit
-public class NXInteractiveView: UIView {
-    public var tapGestureRecognizer: UITapGestureRecognizer?
-    public var longPressGestureRecognizer: UILongPressGestureRecognizer?
-    // 点击回调
-    public var tapGestureHander: (() -> Void)?
-    // 长按回调
-    public var longPressGestureHander: (() -> Void)?
-
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        addTagGestureRecognizer()
-        addLongGestureRecogizer()
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    // 单机方法
-    private func addTagGestureRecognizer() {
-        let tap = UITapGestureRecognizer(target: self, action: #selector(tapGestureRecognizerHandler(sender:)))
-        tap.numberOfTouchesRequired = 1
-        tap.numberOfTapsRequired = 1
-        addGestureRecognizer(tap)
-        tapGestureRecognizer = tap
-    }
-
-    @objc
-    public func tapGestureRecognizerHandler(sender _: UITapGestureRecognizer) {
-        print("---- tapGestureRecognizerHandler -----")
-        if tapGestureHander != nil {
-            tapGestureHander!()
-        }
-    }
-
-    // 长按事件
-    private func addLongGestureRecogizer() {
-        let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(longGestureRecognizerHandler(sender:)))
-        longPressGestureRecognizer.numberOfTapsRequired = 1
-        longPressGestureRecognizer.numberOfTouchesRequired = 1
-        addGestureRecognizer(longPressGestureRecognizer)
-        self.longPressGestureRecognizer = longPressGestureRecognizer
-    }
-
-    @objc
-    public func longGestureRecognizerHandler(sender _: UILongPressGestureRecognizer) {
-        print("---- longGestureRecognizerHandler -----")
-        if longPressGestureHander != nil {
-            longPressGestureHander!()
-        }
-    }
-
-    public func removeTapGestureRecognizer() {
-        if let tap = tapGestureRecognizer {
-            removeGestureRecognizer(tap)
-        }
-    }
-
-    public func removeLongPressGestureRecognizer() {
-        if let long = longPressGestureRecognizer {
-            removeGestureRecognizer(long)
-        }
-    }
-}

+ 0 - 80
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXNormalBubbleView.swift

@@ -1,80 +0,0 @@
-//
-//  NXBaseBubbleView.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/8/23.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import Foundation
-import UIKit
-public class NXNormalBubbleView: NXInteractiveView {
-    let bubbleLayer = NXBubbleLayer(originalSize: .zero)
-    var currentLayer: CALayer?
-    /// 内部内容控件
-    public var containView = NXBubbleContainView(frame: .zero)
-
-    // 矩形的圆角的半径
-    public var cornerRadius: CGFloat = 8
-    // 箭头位置的圆角半径
-    public var arrowRadius: CGFloat = 3
-    // 箭头的高度
-    public var arrowHeight: CGFloat = 12
-    // 箭头的宽度
-    public var arrowWidth: CGFloat = 30
-    // 箭头方向
-    public var arrowDirection: ArrowDirection = .bottom
-    // 箭头的相对位置
-    public var arrowPosition: CGFloat = 0.5
-
-    public var bubbleColor: UIColor = .white {
-        didSet {
-            self.setNeedsLayout()
-            self.layoutIfNeeded()
-        }
-    }
-
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        addSubview(containView)
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    override public func layoutSubviews() {
-        super.layoutSubviews()
-        if let layer = currentLayer {
-            layer.removeFromSuperlayer()
-        }
-        bubbleLayer.size = frame.size
-        bubbleLayer.cornerRadius = cornerRadius
-        bubbleLayer.arrowRadius = arrowRadius
-        bubbleLayer.arrowHeight = arrowHeight
-        bubbleLayer.arrowWidth = arrowWidth
-        bubbleLayer.arrowDirection = arrowDirection
-        bubbleLayer.arrowPosition = arrowPosition
-        let layer = bubbleLayer.layer()
-        layer.fillColor = bubbleColor.cgColor
-        self.layer.insertSublayer(layer, at: 0)
-        currentLayer = layer
-        // 调整 contain坐标
-        containView.frame = bubbleLayer.bubbleLayerRect
-
-        backgroundColor = .clear
-        containView.backgroundColor = .clear
-    }
-
-    // MARK: - 重写交互层的长按和点击事件
-
-    override public func tapGestureRecognizerHandler(sender: UITapGestureRecognizer) {
-        super.tapGestureRecognizerHandler(sender: sender)
-        print("点击了普通气泡")
-    }
-
-    override public func longGestureRecognizerHandler(sender: UILongPressGestureRecognizer) {
-        super.longGestureRecognizerHandler(sender: sender)
-        print("长按了 点击了普通气泡")
-    }
-}

+ 0 - 40
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXTextBubbleView.swift

@@ -1,40 +0,0 @@
-//
-//  NXTextBubbleView.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/8/23.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import SnapKit
-import UIKit
-
-class NXTextBubbleView: NXNormalBubbleView {
-    public let textLabel = UILabel(frame: .zero)
-
-    override init(frame: CGRect) {
-        super.init(frame: frame)
-        initSubViews()
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    private func initSubViews() {
-        containView.addSubview(textLabel)
-        textLabel.snp.makeConstraints { make in
-            make.edges.equalTo(UIEdgeInsets(top: 0, left: 5, bottom: 0, right: 5))
-        }
-    }
-
-    // MARK: - 重写交互层的长按和点击事件
-
-    override public func tapGestureRecognizerHandler(sender _: UITapGestureRecognizer) {
-        print("点击了文字气泡")
-    }
-
-    override public func longGestureRecognizerHandler(sender _: UILongPressGestureRecognizer) {
-        print("长按了 点击了文字气泡")
-    }
-}

+ 0 - 184
BFFramework/Classes/BFModules/BFCustomViews/views/bubbleLayer/NXVoiceBubbleView.swift

@@ -1,184 +0,0 @@
-//
-//  NXVoiceBubbleView.swift
-//  bubbleLayer_swift
-//
-//  Created by liuming on 2020/8/23.
-//  Copyright © 2020 liuming. All rights reserved.
-//
-
-import UIKit
-public class NXVoiceBubbleView: NXNormalBubbleView {
-    /// 关闭按钮
-    private let closeBtn = UIButton(type: .custom)
-    /// 声音图片
-    private let voiceImgView = UIImageView(frame: .zero)
-
-    /// 语音时间文本
-    public let durationLabel = UILabel(frame: .zero)
-    /// 语音图片序列帧动画时间
-    public var animationDuration: TimeInterval = 0.5 {
-        didSet {
-            self.initVoiceAnimation()
-        }
-    }
-
-    // 加载圈
-    lazy var activityIndicator: UIActivityIndicatorView = {
-        let activityIndicator: UIActivityIndicatorView = UIActivityIndicatorView(style:
-            .gray)
-        return activityIndicator
-    }()
-
-    /// 语音图片帧图片
-    public var animationImages: [UIImage] = Array() {
-        didSet {
-            initVoiceAnimation()
-        }
-    }
-
-    /// 语音图片动画重复次数
-    public var animationRepeatCount: Int = 1 {
-        didSet {
-            initVoiceAnimation()
-        }
-    }
-
-    /// 音频显示的总时间
-    public var duration: Float64 = 0 {
-        didSet {
-            showTime()
-            activityIndicatorStop()
-        }
-    }
-
-    public var closeBtnClickedHander: (() -> Void)?
-    override public init(frame: CGRect) {
-        super.init(frame: frame)
-        initSubviews()
-    }
-
-    required init?(coder _: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-
-    private func initSubviews() {
-        containView.addSubview(voiceImgView)
-        voiceImgView.image = UIImage(named: "icon_voice")
-
-        containView.addSubview(durationLabel)
-
-        closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .normal)
-        closeBtn.setImage(UIImage(named: "videomk_serach_clear"), for: .highlighted)
-        closeBtn.addTarget(self, action: #selector(closeBtnClicked(sender:)), for: .touchUpInside)
-        containView.addSubview(closeBtn)
-
-        containView.addSubview(activityIndicator)
-
-        // 布局
-        voiceImgView.snp.makeConstraints { maker in
-            maker.centerY.equalTo(self.containView)
-            maker.left.equalTo(self.containView).offset(10)
-            maker.width.height.equalTo(20)
-        }
-        durationLabel.snp.makeConstraints { maker in
-            maker.right.equalTo(self.containView).offset(-10)
-            maker.centerY.equalTo(self.containView)
-            maker.height.equalTo(20)
-        }
-        closeBtn.snp.makeConstraints { maker in
-
-            maker.right.equalTo(self.containView).offset(10)
-            maker.top.equalTo(self.containView).offset(-8)
-            maker.width.height.equalTo(20)
-        }
-
-        activityIndicator.snp.makeConstraints { maker in
-
-            maker.right.equalTo(self.containView).offset(-10)
-            maker.centerY.equalTo(self.containView)
-            maker.height.equalTo(20)
-        }
-    }
-
-    private func showTime() {
-        durationLabel.text = duration < 1 ? "1'" : duration.formatDurationToMS()
-    }
-
-    private func initVoiceAnimation() {
-        if animationImages.count > 0 {
-            voiceImgView.animationImages = animationImages
-            voiceImgView.animationDuration = animationDuration
-            voiceImgView.animationRepeatCount = animationRepeatCount
-        }
-    }
-
-    /// 加载圈开始动画
-    public func activityIndicatorStart() {
-        durationLabel.text = ""
-        activityIndicator.startAnimating()
-    }
-
-    /// 加载圈结束动画
-    public func activityIndicatorStop() {
-        activityIndicator.stopAnimating()
-    }
-
-    /// 开始动画
-    public func startAnimation() {
-        voiceImgView.startAnimating()
-    }
-
-    /// 结束动画
-    public func stopAnimation() {
-        voiceImgView.stopAnimating()
-    }
-
-    /// 按照中心点抖动
-    func animation() {
-        let animati = CAKeyframeAnimation(keyPath: "transform.rotation")
-        // rotation 旋转,需要添加弧度值
-        // 角度转弧度
-        animati.values = [angle2Radion(angle: -50), angle2Radion(angle: 50), angle2Radion(angle: -50)]
-        animati.repeatCount = 4
-        layer.add(animati, forKey: nil)
-    }
-
-    // MARK: - 重写交互层的长按和点击事件
-
-    override public func tapGestureRecognizerHandler(sender: UITapGestureRecognizer) {
-        super.tapGestureRecognizerHandler(sender: sender)
-        startAnimation()
-        print("点击了语音气泡")
-    }
-
-    override public func longGestureRecognizerHandler(sender: UILongPressGestureRecognizer) {
-        super.longGestureRecognizerHandler(sender: sender)
-        print("长按了 点击了语音气泡")
-        animation()
-    }
-
-    func angle2Radion(angle: Float) -> Float {
-        return angle / Float(180.0 * Double.pi)
-    }
-
-    // MARK: 关闭按钮点击事件
-
-    @objc
-    func closeBtnClicked(sender _: UIButton) {
-        print("点击了关闭按钮")
-        if let block = closeBtnClickedHander {
-            block()
-        }
-    }
-
-    override public func point(inside point: CGPoint, with _: UIEvent?) -> Bool {
-        if bounds.contains(point) {
-            return true
-        }
-        let p = convert(point, to: closeBtn)
-        if closeBtn.bounds.contains(p) {
-            return true
-        }
-        return false
-    }
-}

+ 2 - 4
BFFramework/Classes/PModels/editDarftModels/PQEditVisionTrackMaterialsModel.swift

@@ -147,10 +147,8 @@ public class PQEditVisionTrackMaterialsModel: PQEditBaseModel {
         materialDurationFit <- map["materialDurationFit"]
         materialSizeClip <- map["materialSizeClip"]
         materialPosition <- map["materialPosition"]
-//        netResUrl <- map["netResUrl"]
-//        netResCoverImageURL <- map["netResCoverImageURL"]
         locationPath <- map["locationPath"]
-
+        originalData <- map["originalData"]
         aptDuration <- map["aptDuration"]
         outSideVideoId <- map["outSideVideoId"]
         outSideChannel <- map["outSideChannel"]
@@ -309,7 +307,7 @@ public class PQEditVisionTrackMaterialsModel: PQEditBaseModel {
         temp.netResUrl = netResUrl
         temp.netResCoverImageURL = netResCoverImageURL
         temp.locationPath = locationPath
- 
+        temp.originalData = originalData
         return temp
     }
 }

+ 21 - 21
BFFramework/Classes/PQGPUImage/akfilters/PQGPUImageTools.swift

@@ -48,9 +48,9 @@ open class PQGPUImageTools: NSObject {
         glDeleteBuffers(1, &deletedVBO)
     }
 
-    // 图片转纹理集数据 XXXXX 使用方法后 返回的 imageTexture 要清空纹理,注意不清空显存会暴增     glDeleteTextures(1,&imageTexture)
+    // FilterLog XXXXX 使用方法后 返回的 imageTexture 要清空纹理,注意不清空显存会暴增     glDeleteTextures(1,&imageTexture)
     class func setupTexture(image: CGImage) -> GLuint {
-        BFLog(2, message: "图片转纹理集数据 =====width :\(image.width) height: \(image.height)")
+        FilterLog(2, message: "FilterLog =====width :\(image.width) height: \(image.height)")
 
         let widthOfImage = GLint(image.width)
         let heightOfImage = GLint(image.height)
@@ -119,7 +119,7 @@ open class PQGPUImageTools: NSObject {
                     }
                 }
             }
-            BFLog(2, message: "图片转纹理集数据2222 =====")
+            FilterLog(2, message: "FilterLog2222 =====")
 
             //        sharedImageProcessingContext.runOperationSynchronously{
             //    CFAbsoluteTime elapsedTime, startTime = CFAbsoluteTimeGetCurrent();
@@ -142,10 +142,10 @@ open class PQGPUImageTools: NSObject {
                 dataFromImageDataProvider = data
                 imageData = UnsafeMutablePointer<GLubyte>(mutating: CFDataGetBytePtr(dataFromImageDataProvider))
             }
-            BFLog(2, message: "图片转纹理集数据333333 =====")
+            FilterLog(2, message: "FilterLog333333 =====")
 
             glEnable(GLenum(GL_TEXTURE_2D))
-            BFLog(2, message: "图片转纹理集数据44444 =====")
+            FilterLog(2, message: "FilterLog44444 =====")
 
             /**
              *  GL_TEXTURE_2D表示操作2D纹理
@@ -154,10 +154,10 @@ open class PQGPUImageTools: NSObject {
              */
 
             glGenTextures(1, &textureID)
-            BFLog(2, message: "图片转纹理集数据5555 =====\(textureID)")
+            FilterLog(2, message: "FilterLog5555 =====\(textureID)")
 
             glBindTexture(GLenum(GL_TEXTURE_2D), textureID)
-            BFLog(2, message: "图片转纹理集数据6666 =====\(textureID)")
+            FilterLog(2, message: "FilterLog6666 =====\(textureID)")
 
             /**
              *  纹理过滤函数
@@ -187,29 +187,29 @@ open class PQGPUImageTools: NSObject {
              * 参数8:type
              * 参数9:纹理数据
              */
-            BFLog(2, message: "载入纹理 =====")
-            BFLog(2, message: "GL_TEXTURE_2D =====\(GL_TEXTURE_2D)")
-            BFLog(2, message: "GL_RGBA =====\(GL_RGBA)")
-            BFLog(2, message: "widthOfImage =====\(widthOfImage)")
-            BFLog(2, message: "heightOfImage =====\(heightOfImage)")
-            BFLog(2, message: "GL_UNSIGNED_BYTE =====\(GL_UNSIGNED_BYTE)")
-            BFLog(2, message: "imageData =====\(String(describing: imageData))")
-            BFLog(2, message: "GLenum(GL_TEXTURE_2D) =====\(GLenum(GL_TEXTURE_2D))")
-            BFLog(2, message: "GLenum(format) =====\(GLenum(format))")
-            BFLog(2, message: "GLenum(GL_UNSIGNED_BYTE) =====\(GLenum(GL_UNSIGNED_BYTE))")
+            FilterLog(2, message: "载入纹理 =====")
+            FilterLog(2, message: "GL_TEXTURE_2D =====\(GL_TEXTURE_2D)")
+            FilterLog(2, message: "GL_RGBA =====\(GL_RGBA)")
+            FilterLog(2, message: "widthOfImage =====\(widthOfImage)")
+            FilterLog(2, message: "heightOfImage =====\(heightOfImage)")
+            FilterLog(2, message: "GL_UNSIGNED_BYTE =====\(GL_UNSIGNED_BYTE)")
+            FilterLog(2, message: "imageData =====\(String(describing: imageData))")
+            FilterLog(2, message: "GLenum(GL_TEXTURE_2D) =====\(GLenum(GL_TEXTURE_2D))")
+            FilterLog(2, message: "GLenum(format) =====\(GLenum(format))")
+            FilterLog(2, message: "GLenum(GL_UNSIGNED_BYTE) =====\(GLenum(GL_UNSIGNED_BYTE))")
 
             glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GL_RGBA, widthToUseForTexture, heightToUseForTexture, 0, GLenum(format), GLenum(GL_UNSIGNED_BYTE), imageData)
 
             // 结束后要做清理
-            BFLog(2, message: "结束后要做清理 =====")
-            BFLog(2, message: "GLenum(GL_TEXTURE_2D) =====\(GLenum(GL_TEXTURE_2D))")
+            FilterLog(2, message: "结束后要做清理 =====")
+            FilterLog(2, message: "GLenum(GL_TEXTURE_2D) =====\(GLenum(GL_TEXTURE_2D))")
 
             glBindTexture(GLenum(GL_TEXTURE_2D), 0) // 解绑
 
-            BFLog(2, message: "结束后要做清理1111111 =====")
+            FilterLog(2, message: "结束后要做清理1111111 =====")
             imageData.deallocate()
 
-            BFLog(2, message: "textureID =====\(textureID)")
+            FilterLog(2, message: "textureID =====\(textureID)")
         }
 
         return textureID

+ 25 - 14
BFFramework/Classes/PQGPUImage/akfilters/PQGifFilter.swift

@@ -29,15 +29,26 @@ open class PQGifFilter: PQBaseFilter {
     // gif 要显示的 每一帧的时间
     var delayTime: Double = 0
 
-    init(sticker: PQEditVisionTrackMaterialsModel) {
+    public init(sticker: PQEditVisionTrackMaterialsModel) {
         super.init(fragmentShader: PassthroughFragmentShader, numberOfInputs: 1)
         mSticker = sticker
 
-        BFLog(2, message: "gif file path \(mSticker?.locationPath ?? "")")
+        FilterLog(2, message: "gif file path \(mSticker?.locationPath ?? "")")
         var gifData: Data!
         autoreleasepool {
             do {
-                gifData = try Data(contentsOf: URL(fileURLWithPath: documensDirectory + (mSticker?.locationPath ?? "")))
+                
+                if(mSticker?.originalData != nil && (mSticker?.originalData?.count ?? 0) > 0){
+                    gifData = mSticker?.originalData
+                }else{
+                    var gifFilePath = (mSticker?.locationPath ?? "")
+                    if (!gifFilePath.contains("var/mobile/Media")) {
+                        gifFilePath = documensDirectory + gifFilePath
+                    }
+                    FilterLog(message: "gifFilePath is \(gifFilePath)")
+                    gifData = try Data(contentsOf: URL(fileURLWithPath: gifFilePath))
+                }
+               
             } catch {
                 print("loading gif images file error")
                 return
@@ -45,14 +56,14 @@ open class PQGifFilter: PQBaseFilter {
         }
 
         if gifData == nil {
-            BFLog(message: "gif数据有问题!")
+            FilterLog(message: "gif数据有问题!")
             return
         }
         PQPHAssetVideoParaseUtil.parasGIFImage(data: gifData) { [weak self] _, images, duration in
 
             self?.mGifImages = images ?? []
             self?.mDuration = duration ?? 0
-            BFLog(2, message: "gif 原始时长 \(String(describing: duration)) 逻辑时长: \(String(describing: self?.mSticker?.aptDuration)) 帧数:\(String(describing: images?.count))")
+            FilterLog(2, message: "gif 原始时长 \(String(describing: duration)) 逻辑时长: \(String(describing: self?.mSticker?.aptDuration)) 帧数:\(String(describing: images?.count))")
 
             if images!.count > 0 {
                 self?.gifSize = images!.first!.size
@@ -63,8 +74,8 @@ open class PQGifFilter: PQBaseFilter {
             // 不改变速度还是原速度
 
             if self?.mSticker?.materialDurationFit?.fitType == adapterMode.loopAuto.rawValue || self?.mSticker?.materialDurationFit?.fitType == adapterMode.staticFrame.rawValue {
-                self?.delayTime = self?.mDuration ?? 1 / Double(self?.mGifImages.count ?? 1)
-                BFLog(message: "正常速度每一帧的时间:\(String(describing: self?.delayTime))")
+                self?.delayTime = (self?.mDuration ?? 1) / Double(self?.mGifImages.count ?? 1)
+                FilterLog(message: "正常速度每一帧的时间:\(String(describing: self?.delayTime))")
             }
             sharedImageProcessingContext.runOperationSynchronously {
                 // ( 提前渲染一帧
@@ -80,23 +91,23 @@ open class PQGifFilter: PQBaseFilter {
     func updateImages(_ currTime: Float64) {
         autoreleasepool {
             if mGifImages.count == 0 {
-                BFLog(2, message: "gif 文件有问题 一帧都没有")
+                FilterLog(2, message: "gif 文件有问题 一帧都没有")
                 return
             }
             if delayTime <= 0 {
-                BFLog(2, message: "gif 时间计算出错")
+                FilterLog(2, message: "gif 时间计算出错")
                 return
             }
             // 判断显示哪一帧
             var gifIndex = delayTime <= 0 ? 0 : Int(((currTime >= beginTime) ? currTime - beginTime : currTime) / delayTime)
             if mSticker?.materialDurationFit?.fitType == adapterMode.staticFrame.rawValue && gifIndex >= mGifImages.count { // 定帧
-                BFLog(2, message: "定帧效果 \(gifIndex)")
+                FilterLog(2, message: "定帧效果 \(gifIndex)")
                 imageTexture = PQGPUImageTools.setupTexture(image: (mGifImages.last?.cgImage)!)
                 return
             }
 
             if gifIndex >= mGifImages.count && mSticker?.materialDurationFit?.fitType == adapterMode.loopAuto.rawValue { // 自动循环重新计算开始时间 达到循环效果
-                BFLog(2, message: "自动循环效果")
+                FilterLog(2, message: "自动循环效果")
                 gifIndex = gifIndex % mGifImages.count
             }
 
@@ -132,7 +143,7 @@ open class PQGifFilter: PQBaseFilter {
             let inputSize = inputFramebuffer.sizeForTargetOrientation(.portrait)
 
             let currTime = CMTimeGetSeconds(CMTime(value: inputFramebuffer.timingStyle.timestamp!.value, timescale: inputFramebuffer.timingStyle.timestamp!.timescale))
-            BFLog(2, message: "gif filter 当前时间: \(currTime) ")
+            FilterLog(2, message: "gif filter 当前时间: \(currTime) ")
 
             // 原有画布
             renderFramebuffer = sharedImageProcessingContext.framebufferCache.requestFramebufferWithProperties(orientation: .portrait, size: inputSize, stencil: false)
@@ -146,7 +157,7 @@ open class PQGifFilter: PQBaseFilter {
             releaseIncomingFramebuffers()
 
             if currTime >= mSticker!.timelineIn, currTime <= mSticker!.timelineOut {
-                BFLog(2, message: " 显示gif当前时间: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)  ")
+                FilterLog(2, message: " 显示gif当前时间: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)  ")
 
                 // 绘制 image
                 let textureCoordinates = PQGPUImageTools.getTextureCoordinates(sticker: mSticker!, textureSize: gifSize, cannvasSize: inputSize)
@@ -168,7 +179,7 @@ open class PQGifFilter: PQBaseFilter {
                 // XXXXXXX 清空纹理,注意不清空显存会暴增
                 glDeleteTextures(1, &imageTexture)
             } else {
-                BFLog(2, message: " 不显示gif时: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)")
+                FilterLog(2, message: " 不显示gif时: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)")
             }
         }
     }

+ 103 - 82
BFFramework/Classes/PQGPUImage/akfilters/PQImageFilter.swift

@@ -14,97 +14,114 @@ import UIKit
 open class PQImageFilter: PQBaseFilter {
     // 图片纹理
     var imageTexture: GLuint = 0
-
+    var imageVertexBuffer: GLuint = 0
     var mSticker: PQEditVisionTrackMaterialsModel?
     var newImage: UIImage?
     deinit {
-        BFLog(1, message: "image filter deinit 析构掉~")
+        FilterLog(1, message: "image filter deinit 析构掉~")
         newImage = nil
 
         if imageTexture != 0 {
             glDeleteTextures(1, &imageTexture)
             imageTexture = 0
         }
-        
+        if imageVertexBuffer != 0 {
+            PQGPUImageTools.deleteVBO(imageVertexBuffer)
+            imageVertexBuffer = 0
+        }
     }
 
-    init(sticker: PQEditVisionTrackMaterialsModel, isExport: Bool = true, showUISize: CGSize = .zero) {
+    public init(sticker: PQEditVisionTrackMaterialsModel, isExport: Bool = true, showUISize: CGSize = .zero) {
         super.init(fragmentShader: PassthroughFragmentShader, numberOfInputs: 1)
-
         mSticker = sticker
         stickerInfo = sticker
-
-        if mSticker!.locationPath.count == 0 {
-            BFLog(2, message: "图片数据为空,创建失败")
-            return
+        if sticker.originalData != nil, (sticker.originalData?.count ?? 0) > 0 {
+            newImage = UIImage(data: sticker.originalData!)
+        } else {
+            if mSticker!.locationPath.count == 0 {
+                FilterLog(2, message: "图片数据为空,创建失败")
+                return
+            }
+            var imageFilePath = mSticker?.locationPath ?? ""
+            if !imageFilePath.contains("var/mobile/Media") {
+                imageFilePath = documensDirectory + imageFilePath
+            }
+            FilterLog(message: "imageFilePath is \(imageFilePath)")
+            newImage = UIImage(contentsOfFile: imageFilePath)
         }
-//        print("mSticker path : \(String(describing: mSticker!.locationPath))")
-
-        newImage = UIImage(contentsOfFile: documensDirectory + sticker.locationPath)
-        //try find image file frome in BFFramework bundle
-        if(newImage == nil){
-            newImage = UIImage.moduleImage(named: sticker.locationPath, moduleName: "BFFramework",isAssets: false)
+        // 保证是正方向
+        UIImage.nx_fixOrientation(newImage, isFront: false).nx_scaleWithMaxLength(maxLength: 1920) { [weak self] outputImage in
+            DispatchQueue.main.async { [weak self] in
+                self?.newImage = outputImage
+                self?.preImagefilter(isExport: isExport, showUISize: showUISize)
+            }
         }
+    }
 
+    func preImagefilter(isExport: Bool = true, showUISize: CGSize = .zero) {
+        // try find image file frome in BFFramework bundle
+        if newImage == nil {
+            newImage = UIImage.moduleImage(named: stickerInfo?.locationPath ?? "", moduleName: "BFFramework", isAssets: false)
+        }
         // 如果是预览时 对原图进行缩放处理
         if !isExport {
             let maxLength = max(showUISize.width, showUISize.height)
             newImage = newImage?.nx_scaleWithMaxLength(maxLength: CGFloat(maxLength * UIScreen.main.scale))
 
-            BFLog(message: "newImage is \(newImage?.size.width ?? 0) \(newImage?.size.height ?? 0)")
- 
+            FilterLog(message: "newImage is \(newImage?.size.width ?? 0) \(newImage?.size.height ?? 0)")
         }
 
         autoreleasepool {
             if newImage == nil {
-                let filePath = documensDirectory + (mSticker?.locationPath ?? "")
-                if FileManager.default.fileExists(atPath: filePath) {
+                // 有可能是webp数据 ,使用 webp 加载
+                var imageFilePath = mSticker?.locationPath ?? ""
+                if !imageFilePath.contains("var/mobile/Media") {
+                    imageFilePath = documensDirectory + imageFilePath
+                }
+                FilterLog(message: "imageFilePath is \(imageFilePath)")
+                if FileManager.default.fileExists(atPath: imageFilePath) {
                     // 有可能是 WEBP
-                    let fileData: Data = try! Data(contentsOf: URL(fileURLWithPath: filePath))
+                    let fileData: Data = try! Data(contentsOf: URL(fileURLWithPath: imageFilePath))
                     if fileData.count != 0, fileData.isWebPFormat {
                         newImage = WebPProcessor.default.process(item: ImageProcessItem.data(fileData), options: KingfisherParsedOptionsInfo([.onlyLoadFirstFrame, .scaleFactor(1)]))
                     }
-                } else { BFLog(2, message: "文件不存在") }
+                } else { FilterLog(2, message: "文件不存在") }
             }
         }
 
         if newImage?.cgImage != nil {
-            BFLog(message: "提前加载图片。。。。timelineIn : \(String(describing: mSticker?.timelineIn)) timelineOut :\(String(describing: mSticker?.timelineOut)) \(String(describing: mSticker?.locationPath))")
+            FilterLog(message: "提前加载图片。。。。timelineIn : \(String(describing: mSticker?.timelineIn)) timelineOut :\(String(describing: mSticker?.timelineOut)) \(String(describing: mSticker?.locationPath))")
 
-//            imageTexture = PQGPUImageTools.setupTexture(image: newImage!.cgImage!)
+            //            imageTexture = PQGPUImageTools.setupTexture(image: newImage!.cgImage!)
 
-        } else { BFLog(2, message: "image filter init error image data is nil!") }
-        
-        
-        // 保证是16的公倍数
-        let aptImageSize =  NXAVUtil.aptSize(newImage!.size)
-        if (!__CGSizeEqualToSize(aptImageSize, newImage!.size))
-        {
-            BFLog(2, message: "原图大小宽度不是16的倍数 \(newImage!.size)")
-            newImage = newImage?.nx_scaleToSize(size: aptImageSize)
-            BFLog(2, message: "归16后大小 \(newImage!.size)")
+        } else { FilterLog(2, message: "image filter init error image data is nil!") }
 
+        // 保证是16的公倍数
+        let aptImageSize = NXAVUtil.aptSize(newImage?.size ?? CGSize.zero)
+        if !__CGSizeEqualToSize(aptImageSize, newImage?.size ?? CGSize.zero) {
+            FilterLog(2, message: "原图大小宽度不是16的倍数 \(newImage!.size)")
+            //            newImage = newImage?.nx_scaleToSize(size: aptImageSize)
+            FilterLog(2, message: "归16后大小 \(newImage!.size)")
         }
-
     }
 
-//    override public func newFramebufferAvailable(_ framebuffer: Framebuffer, fromSourceIndex: UInt) {
-//        super.newFramebufferAvailable(framebuffer, fromSourceIndex: fromSourceIndex)
-//
+    //    override public func newFramebufferAvailable(_ framebuffer: Framebuffer, fromSourceIndex: UInt) {
+    //        super.newFramebufferAvailable(framebuffer, fromSourceIndex: fromSourceIndex)
+    //
     ////        let currTime = CMTimeGetSeconds(CMTime(value: framebuffer.timingStyle.timestamp!.value, timescale: framebuffer.timingStyle.timestamp!.timescale))
     ////
     ////        if mSticker!.timelineIn != 0, currTime >= mSticker!.timelineIn, currTime <= mSticker!.timelineOut, imageTexture == 0 {
     ////            if newImage != nil {
     //////                imageTexture = PQGPUImageTools.setupTexture(image: newImage!.cgImage!)
-    ////            } else { BFLog(message: "image filter init error image data is nil!") }
+    ////            } else { FilterLog(message: "image filter init error image data is nil!") }
     ////        }
-//    }
+    //    }
 
-    open override func renderFrame() {
+    override open func renderFrame() {
         let inputFramebuffer: Framebuffer = inputFramebuffers[0]!
         let inputSize = inputFramebuffer.sizeForTargetOrientation(.portrait)
 
-//        print("renderFrame timestamp is \(inputFramebuffer.timingStyle)")
+        //        print("renderFrame timestamp is \(inputFramebuffer.timingStyle)")
 
         let currTime = CMTimeGetSeconds(CMTime(value: inputFramebuffer.timingStyle.timestamp!.value, timescale: inputFramebuffer.timingStyle.timestamp!.timescale))
 
@@ -120,56 +137,60 @@ open class PQImageFilter: PQBaseFilter {
         releaseIncomingFramebuffers()
 
         if newImage == nil {
-            BFLog(2, message: "图片数据有错误!!!! 检查数据\(mSticker!.locationPath)")
+            FilterLog(2, message: "图片数据有错误!!!! 检查数据\(mSticker!.locationPath)")
             return
         }
 
-        BFLog(2, message: " image filter 当前时间: \(currTime) \(newImage!.size)")
+        FilterLog(2, message: " image filter 当前时间: \(currTime) \(newImage!.size)")
 
         if currTime >= mSticker!.timelineIn && currTime <= mSticker!.timelineOut {
-        BFLog(2, message: " 显示图片当前时间: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)  \(String(describing: newImage?.size))")
-        // 取纹理坐标
-        var textureCoordinates = PQGPUImageTools.getTextureCoordinates(sticker: mSticker!, textureSize: newImage!.size, cannvasSize: inputSize)
+            FilterLog(2, message: " 显示图片当前时间: \(currTime) 开始时间:\(mSticker!.timelineIn) 结束时间:\(mSticker!.timelineOut)  \(String(describing: newImage?.size))")
+            // 取纹理坐标
+            var textureCoordinates = PQGPUImageTools.getTextureCoordinates(sticker: mSticker!, textureSize: newImage!.size, cannvasSize: inputSize)
 
-        BFLog(2, message: "textureCoordinates is \(textureCoordinates) image size :\(newImage!.size ) cannvasSize:\(inputSize)  files path is \(mSticker?.locationPath)")
+            FilterLog(2, message: "textureCoordinates is \(textureCoordinates) image size :\(newImage!.size) cannvasSize:\(inputSize)  files path is \(mSticker?.locationPath)")
 
-        // imageTexture 有可能被析构导致黑屏
-        if imageTexture == 0 && newImage?.cgImage != nil {
-            BFLog(2, message: "imageTexture is error !!!!!重新创建")
-            imageTexture = PQGPUImageTools.setupTexture(image: newImage!.cgImage!)
-        }
+            // imageTexture 有可能被析构导致黑屏
+            if imageTexture == 0 && newImage?.cgImage != nil {
+                FilterLog(2, message: "imageTexture is error !!!!!重新创建")
+                imageTexture = PQGPUImageTools.setupTexture(image: newImage!.cgImage!)
+            }
 
-        
-        //如果设置过大小位置,使用设置值,比如水印
-        if(stickerInfo?.materialPosition?.width != 0){
-           textureCoordinates = [
-                0.0, 0.0, // 1 bottom left
-                1.0, 0.0, // 2 bottom right
-                0.0, 1.0, // 3 top left
-                1.0, 1.0, // 4 top right
-            ]
-        }
-        
-        let texturePropertiesimagetwo = InputTextureProperties(textureCoordinates: textureCoordinates, texture: imageTexture)
-
-        var verticesPoint: [GLfloat] = PQGPUImageTools.getVerticesPoint(sticker: mSticker!, textureSize: newImage!.size, cannvasSize: inputSize)
-        
-        //如果设置过大小位置,使用设置值,比如水印
-        if(stickerInfo?.materialPosition?.width != 0){
-            verticesPoint = PQGPUImageTools.computeVertices(viewSize: CGSize.init(width: CGFloat(inputSize.width), height: CGFloat(inputSize.height)), _bounds: CGRect.init(x: stickerInfo?.materialPosition?.x ?? 0, y:  stickerInfo?.materialPosition?.y ?? 0, width: stickerInfo?.materialPosition?.width ?? 0, height: stickerInfo?.materialPosition?.height ?? 0))
-        }
-        
-        // 设置融合模式支持 alpha
-        glEnable(GLenum(GL_DEPTH_TEST))
-        glEnable(GLenum(GL_BLEND))
-        glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA))
-        
-        renderQuadWithShader(shader,
-                             uniformSettings: uniformSettings,
-                             vertexBufferObject: PQGPUImageTools.NXGenerateVBO(for: verticesPoint),
-                             
-                             inputTextures: [texturePropertiesimagetwo])
+            // 如果设置过大小位置,使用设置值,比如水印
+            if stickerInfo?.materialPosition?.width != 0 {
+                textureCoordinates = [
+                    0.0, 0.0, // 1 bottom left
+                    1.0, 0.0, // 2 bottom right
+                    0.0, 1.0, // 3 top left
+                    1.0, 1.0, // 4 top right
+                ]
+            }
+
+            let texturePropertiesimagetwo = InputTextureProperties(textureCoordinates: textureCoordinates, texture: imageTexture)
+
+            var verticesPoint: [GLfloat] = PQGPUImageTools.getVerticesPoint(sticker: mSticker!, textureSize: newImage!.size, cannvasSize: inputSize)
+
+            // 如果设置过大小位置,使用设置值,比如水印
+            if stickerInfo?.materialPosition?.width != 0 {
+                verticesPoint = PQGPUImageTools.computeVertices(viewSize: CGSize(width: CGFloat(inputSize.width), height: CGFloat(inputSize.height)), _bounds: CGRect(x: stickerInfo?.materialPosition?.x ?? 0, y: stickerInfo?.materialPosition?.y ?? 0, width: stickerInfo?.materialPosition?.width ?? 0, height: stickerInfo?.materialPosition?.height ?? 0))
+            }
+
+            // 设置融合模式支持 alpha
+            glEnable(GLenum(GL_DEPTH_TEST))
+            glEnable(GLenum(GL_BLEND))
+            glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA))
+
+            imageVertexBuffer = PQGPUImageTools.NXGenerateVBO(for: verticesPoint)
+
+            renderQuadWithShader(shader,
+                                 uniformSettings: uniformSettings,
+                                 vertexBufferObject: imageVertexBuffer, inputTextures: [texturePropertiesimagetwo])
             releaseIncomingFramebuffers()
+
+            if imageVertexBuffer != 0 {
+                PQGPUImageTools.deleteVBO(imageVertexBuffer)
+                imageVertexBuffer = 0
+            }
         }
     }
 }

+ 42 - 29
BFFramework/Classes/PQGPUImage/akfilters/PQMovieFilter.swift

@@ -53,7 +53,7 @@ import Foundation
 import UIKit
 import BFUIKit
 
-class PQMovieFilter: PQBaseFilter {
+open class PQMovieFilter: PQBaseFilter {
     public var runBenchmark = false
 
     public weak var delegate: MovieInputDelegate?
@@ -112,9 +112,11 @@ class PQMovieFilter: PQBaseFilter {
     
     // 当前帧 id
     var framebufferIndex:Int = 0
+    
+    var imageVertexBuffer: GLuint = 0
 
     deinit {
-        BFLog(1, message: "movie filter release")
+        FilterLog(1, message: "movie filter release")
         clearData()
     }
 
@@ -123,6 +125,11 @@ class PQMovieFilter: PQBaseFilter {
         if assetReader != nil {
             assetReader?.cancelReading()
         }
+        
+        if(imageVertexBuffer != 0){
+            PQGPUImageTools.deleteVBO(imageVertexBuffer)
+            imageVertexBuffer = 0
+        }
     }
 
     public init(url: URL) {
@@ -140,7 +147,7 @@ class PQMovieFilter: PQBaseFilter {
         super.init(fragmentShader: PassthroughFragmentShader, numberOfInputs: 1)
         moveSticker = movieSticker
         stickerInfo = movieSticker
-        BFLog(2, message: "资源裁剪的 开始时间\(moveSticker!.model_in)  结束时间: \(moveSticker!.out)")
+        FilterLog(2, message: "资源裁剪的 开始时间\(moveSticker!.model_in)  结束时间: \(moveSticker!.out)")
         if moveSticker!.videoIsCrop() {
             requestedStartTime = CMTimeMake(value: Int64(moveSticker!.model_in) * Int64(BASE_FILTER_TIMESCALE), timescale: BASE_FILTER_TIMESCALE)
         }
@@ -155,14 +162,14 @@ class PQMovieFilter: PQBaseFilter {
             if (!videoFilePath.contains("var/mobile/Media")) && (!videoFilePath.contains("BFFramework_Resources.bundle")) {
                 videoFilePath = documensDirectory + videoFilePath
             }
-            BFLog(2, message: "视频地址 \(String(describing: videoFilePath))")
+            FilterLog(2, message: "视频地址 \(String(describing: videoFilePath))")
             try loadAsset(url: URL(fileURLWithPath: videoFilePath), videoComposition: nil)
 
         } catch {
             NXLog(message: "load asset  with error: \(error)")
         }
 
-        BFLog(2, message: " move FILTER 初始化 开始显示时间:\(movieSticker.timelineIn) 结束显示时间:\(movieSticker.timelineOut)  裁剪开始时间:\(movieSticker.model_in)  裁剪结束时间:\(movieSticker.out)  路径:\(String(describing: movieSticker.locationPath)) 时长 \(CMTimeGetSeconds(asset?.duration ?? .zero))")
+        FilterLog(2, message: " move FILTER 初始化 开始显示时间:\(movieSticker.timelineIn) 结束显示时间:\(movieSticker.timelineOut)  裁剪开始时间:\(movieSticker.model_in)  裁剪结束时间:\(movieSticker.out)  路径:\(String(describing: movieSticker.locationPath)) 时长 \(CMTimeGetSeconds(asset?.duration ?? .zero))")
 
         startReading()
 //
@@ -187,7 +194,7 @@ class PQMovieFilter: PQBaseFilter {
         inputSize = inputFramebuffer.sizeForTargetOrientation(.portrait)
 
         currentTime = CMTime(value: inputFramebuffer.timingStyle.timestamp!.value, timescale: inputFramebuffer.timingStyle.timestamp!.timescale)
-        BFLog(2, message: "wwwwwwwww duration is currentSampleTime is \(CMTimeGetSeconds(currentTime))")
+        FilterLog(2, message: "wwwwwwwww duration is currentSampleTime is \(CMTimeGetSeconds(currentTime))")
 
         renderFramebuffer = sharedImageProcessingContext.framebufferCache.requestFramebufferWithProperties(orientation: mImageOrientation, size: inputSize, stencil: false)
 
@@ -199,10 +206,10 @@ class PQMovieFilter: PQBaseFilter {
                              vertexBufferObject: sharedImageProcessingContext.standardImageVBO, inputTextures: [textureProperties])
         releaseIncomingFramebuffers()
 
-        BFLog(2, message: "开始显示 movefilter 了 开始\(String(describing: moveSticker?.timelineIn)) 结束 :\(String(describing: moveSticker?.timelineOut)) currentTime \(CMTimeGetSeconds(currentTime)) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) ")
+        FilterLog(2, message: "开始显示 movefilter 了 开始\(String(describing: moveSticker?.timelineIn)) 结束 :\(String(describing: moveSticker?.timelineOut)) currentTime \(CMTimeGetSeconds(currentTime)) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) ")
 
         if enableSeek {
-            BFLog(2, message: "seek 到 \(CMTimeGetSeconds(currentTime))  ")
+            FilterLog(2, message: "seek 到 \(CMTimeGetSeconds(currentTime))  ")
             resetRangeTime(startTime: currentTime)
             enableSeek = false
         }
@@ -226,7 +233,7 @@ class PQMovieFilter: PQBaseFilter {
         var showtimeStamp = CMTime(value:targetTime, timescale: BASE_FILTER_TIMESCALE)
         showtimeStamp = CMTimeAdd(showtimeStamp, stickerModelIn)
 
-        BFLog(message: "showtimeStamp is \(CMTimeGetSeconds(showtimeStamp))")
+        FilterLog(message: "showtimeStamp is \(CMTimeGetSeconds(showtimeStamp))")
         readNextVideoFrame(showTimeStamp: showtimeStamp)
     
         framebufferIndex = framebufferIndex + 1
@@ -237,7 +244,7 @@ class PQMovieFilter: PQBaseFilter {
     // 原视频角度类型
     func moveAssetRotation() -> NXGPUImageRotationMode {
         let Angle: Int = PQPHAssetVideoParaseUtil.videoRotationAngle(assert: asset!)
-//        BFLog(2, message: "原视频素材Angle is \(Angle)")
+//        FilterLog(2, message: "原视频素材Angle is \(Angle)")
         // see https://my.oschina.net/NycoWang/blog/904105
         switch Angle {
         case -90, 270:
@@ -262,14 +269,14 @@ class PQMovieFilter: PQBaseFilter {
             stickerFPS = asset!.tracks(withMediaType: .video).first?.nominalFrameRate ?? 0.0
             let bitRate = asset!.tracks(withMediaType: .video).first?.estimatedDataRate
 
-            BFLog(2, message: "move filter asset  fps is \(String(describing: stickerFPS))  bit rate is \(bitRate ?? 0)")
+            FilterLog(2, message: "move filter asset  fps is \(String(describing: stickerFPS))  bit rate is \(bitRate ?? 0)")
 
             self.videoComposition = videoComposition
             self.playAtActualSpeed = playAtActualSpeed
 
             yuvConversionShader = crashOnShaderCompileFailure("MovieInput") { try sharedImageProcessingContext.programForVertexShader(defaultVertexShaderForInputs(2), fragmentShader: YUVConversionFullRangeFragmentShader) }
             self.audioSettings = audioSettings
-        } else { BFLog(2, message: "asset is nil") }
+        } else { FilterLog(2, message: "asset is nil") }
     }
 
     // MARK: -
@@ -286,7 +293,7 @@ class PQMovieFilter: PQBaseFilter {
             let videoTrack: AVAssetTrack = asset!.tracks(withMediaType: .video).first!
 
             videoSize = videoTrack.naturalSize
-            BFLog(2, message: "视频大小为 : \(videoSize)")
+            FilterLog(2, message: "视频大小为 : \(videoSize)")
 
             if videoComposition == nil {
                 let readerVideoTrackOutput = AVAssetReaderTrackOutput(track: asset!.tracks(withMediaType: .video).first!, outputSettings: outputSettings)
@@ -300,7 +307,7 @@ class PQMovieFilter: PQBaseFilter {
             }
             assetReader!.timeRange = CMTimeRange(start: CMTime(value: Int64((moveSticker?.model_in ?? 0) * Float64(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE), duration: CMTimeMake(value: Int64(((moveSticker?.out ?? 0) - (moveSticker?.model_in ?? 0)) * Float64(BASE_FILTER_TIMESCALE)), timescale: BASE_FILTER_TIMESCALE))
 
-            BFLog(2, message: "set   assetReader!.timeRange is \(assetReader!.timeRange)")
+            FilterLog(2, message: "set   assetReader!.timeRange is \(assetReader!.timeRange)")
 
             return assetReader
         } catch {
@@ -310,7 +317,7 @@ class PQMovieFilter: PQBaseFilter {
     }
 
     open func startReading() {
-        BFLog(2, message: "开始初始化")
+        FilterLog(2, message: "开始初始化")
         mach_timebase_info(&timebaseInfo)
 
         assetReader?.cancelReading()
@@ -337,7 +344,7 @@ class PQMovieFilter: PQBaseFilter {
 
     // 设置解码开始时间
     func resetRangeTime(startTime: CMTime = .zero) {
-        BFLog(2, message: "\(String(describing: moveSticker?.locationPath)) 取帧的时间 \(CMTimeGetSeconds(requestedStartTime ?? .zero))")
+        FilterLog(2, message: "\(String(describing: moveSticker?.locationPath)) 取帧的时间 \(CMTimeGetSeconds(requestedStartTime ?? .zero))")
         requestedStartTime = startTime
         startReading()
     }
@@ -353,12 +360,12 @@ class PQMovieFilter: PQBaseFilter {
 
         // 最后一帧的PTS > 要显示的目标时间 就不从解码器要数据,直接返回 view 不刷新 只有慢速时会调用
 //        if CMTimeGetSeconds(targetTimeStamp) >= CMTimeGetSeconds(showTimeStamp) + (stickerInfo?.model_in ?? 0) && CMTimeGetSeconds(targetTimeStamp) != 0 {
-            BFLog(2, message: "28797speedRate  目标显示时间 \(String(format: "%.6f", (CMTimeGetSeconds(showTimeStamp)))) 最后显示的时间 \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp))) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) speedRate is \(stickerInfo!.speedRate)")
+            FilterLog(2, message: "28797speedRate  目标显示时间 \(String(format: "%.6f", (CMTimeGetSeconds(showTimeStamp)))) 最后显示的时间 \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp))) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) speedRate is \(stickerInfo!.speedRate)")
             return
         }
 
         if assetReader == nil {
-            BFLog(2, message: "assetReader is error 出现严重错误!!!!!!!!!!!!!!")
+            FilterLog(2, message: "assetReader is error 出现严重错误!!!!!!!!!!!!!!")
             return
         }
 
@@ -379,7 +386,7 @@ class PQMovieFilter: PQBaseFilter {
             count = count + 1
             sampleBuffer = videoTrackOutput!.copyNextSampleBuffer()
             if sampleBuffer == nil {
-                BFLog(2, message: " copyNextSampleBuffer is nil error!!!")
+                FilterLog(2, message: " copyNextSampleBuffer is nil error!!!")
                 return
             }
             targetTimeStamp = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer!)
@@ -388,12 +395,12 @@ class PQMovieFilter: PQBaseFilter {
             if sampleBuffer != nil && CMTimeGetSeconds(targetTimeStamp) >= CMTimeGetSeconds(showTimeStamp) {
                 let endDecoderTime: TimeInterval = Date().timeIntervalSince1970
                 
-                BFLog(2, message: " 28797speedRate is \(stickerInfo!.speedRate) 当前主线时间为:\(String(format: "%.6f", CMTimeGetSeconds(currentTime))) 查找的帧时间为:\(String(format: "%.6f", CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out))) 要命中时间:\(CMTimeGetSeconds(showTimeStamp)) 命中时间为: \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp))) 差值\(CMTimeGetSeconds(targetTimeStamp) - (stickerInfo?.model_in ?? 0)) 查找耗时为:\(String(format: "%.6f", TimeInterval(endDecoderTime - beginDecoderTime))) 查找次数\(count)  进场时间: \(String(describing: moveSticker?.timelineIn))  裁剪开始时间:\(String(describing: moveSticker?.model_in)) 裁剪结束时间:\(String(describing: moveSticker?.out)) 原视频时长: \(CMTimeGetSeconds(asset?.duration ?? .zero))")
+                FilterLog(2, message: " 28797speedRate is \(stickerInfo!.speedRate) 当前主线时间为:\(String(format: "%.6f", CMTimeGetSeconds(currentTime))) 查找的帧时间为:\(String(format: "%.6f", CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out))) 要命中时间:\(CMTimeGetSeconds(showTimeStamp)) 命中时间为: \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp))) 差值\(CMTimeGetSeconds(targetTimeStamp) - (stickerInfo?.model_in ?? 0)) 查找耗时为:\(String(format: "%.6f", TimeInterval(endDecoderTime - beginDecoderTime))) 查找次数\(count)  进场时间: \(String(describing: moveSticker?.timelineIn))  裁剪开始时间:\(String(describing: moveSticker?.model_in)) 裁剪结束时间:\(String(describing: moveSticker?.out)) 原视频时长: \(CMTimeGetSeconds(asset?.duration ?? .zero))")
                 break
 
             }
 //            else {
-//                BFLog(2, message: "不丢帧显示  查找的帧时间为:\(String(format: "%.6f", CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out)))  命中时间为: \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp)))")
+//                FilterLog(2, message: "不丢帧显示  查找的帧时间为:\(String(format: "%.6f", CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out)))  命中时间为: \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp)))")
 ////                usleep(2)
 ////                sharedImageProcessingContext.runOperationSynchronously {
 ////                    self.renderPixelBuffler(movieFrame: CMSampleBufferGetImageBuffer(sampleBuffer!)!, withSampleTime: currentTime)
@@ -412,23 +419,23 @@ class PQMovieFilter: PQBaseFilter {
             }
             return
         } else {
-            BFLog(2, message: "sampleBuffer is  nil data is error self.assetReader?.status is \(String(describing: assetReader?.status))")
+            FilterLog(2, message: "sampleBuffer is  nil data is error self.assetReader?.status is \(String(describing: assetReader?.status))")
         }
         // 二, 已经播放完一次
         if assetReader?.status == .completed {
-            BFLog(message: "已经播放完一次")
+            FilterLog(message: "已经播放完一次")
             // 1 自动循环模式 重头开始循环
             if moveSticker?.materialDurationFit?.fitType == adapterMode.loopAuto.rawValue {
-                BFLog(2, message: "自动循环模式 重头开始循环 \(CMTimeGetSeconds(currentTime))")
+                FilterLog(2, message: "自动循环模式 重头开始循环 \(CMTimeGetSeconds(currentTime))")
 
                 startReading()
 
             } else if moveSticker?.materialDurationFit?.fitType == adapterMode.staticFrame.rawValue {
                 // 2),定帧处理
                 if lastImageBuffer != nil {
-                    BFLog(2, message: "处理显示定帧")
+                    FilterLog(2, message: "处理显示定帧")
                     let currTime = CMTimeGetSeconds(currentTime)
-                    BFLog(2, message: "process time is \(currTime)")
+                    FilterLog(2, message: "process time is \(currTime)")
                     sharedImageProcessingContext.runOperationSynchronously { [weak self] in
                         if let imgBuffer = self?.lastImageBuffer {
                             renderPixelBuffler(movieFrame: imgBuffer, withSampleTime: currentTime)
@@ -445,7 +452,7 @@ class PQMovieFilter: PQBaseFilter {
     ///   - withSampleTime: 渲染时间戳,不是帧的 PTS 是渲染的时间
     func renderPixelBuffler(movieFrame: CVPixelBuffer, withSampleTime: CMTime) {
         // NV12 会返回 2,Y分量和UV 分量, 如果buffer 是BGRA 则返回0
-        BFLog(2, message: "CVPixelBufferGetPlaneCount is \(CVPixelBufferGetPlaneCount(movieFrame))")
+        FilterLog(2, message: "CVPixelBufferGetPlaneCount is \(CVPixelBufferGetPlaneCount(movieFrame))")
 
         let bufferHeight = CVPixelBufferGetHeight(movieFrame)
         let bufferWidth = CVPixelBufferGetWidth(movieFrame)
@@ -516,7 +523,7 @@ class PQMovieFilter: PQBaseFilter {
         convertYUVToRGBAK(shader: yuvConversionShader!, luminanceFramebuffer: luminanceFramebuffer, chrominanceFramebuffer: chrominanceFramebuffer, resultFramebuffer: movieFramebuffer, colorConversionMatrix: conversionMatrix)
         CVPixelBufferUnlockBaseAddress(movieFrame, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))
 
-        BFLog(2, message: "mp4 render process time is \(CMTimeGetSeconds(withSampleTime))")
+        FilterLog(2, message: "mp4 render process time is \(CMTimeGetSeconds(withSampleTime))")
         movieFramebuffer.timingStyle = .videoFrame(timestamp: Timestamp(withSampleTime))
 
         movieFramebuffer.userInfo = framebufferUserInfo
@@ -546,11 +553,17 @@ class PQMovieFilter: PQBaseFilter {
 
         let verticesPoint: [GLfloat] = PQGPUImageTools.getVerticesPoint(sticker: moveSticker!, textureSize: (moveAssetRotation() == .rotateLeftTextureCoordinates || moveAssetRotation() == .rotateRightTextureCoordinates) ? CGSize(width: videoSize.height, height: videoSize.width) : videoSize, cannvasSize: inputSize)
 
+        imageVertexBuffer = PQGPUImageTools.NXGenerateVBO(for: verticesPoint)
         renderQuadWithShader(shader,
                              uniformSettings: uniformSettings,
-                             vertexBufferObject: PQGPUImageTools.NXGenerateVBO(for: verticesPoint),
+                             vertexBufferObject: imageVertexBuffer,
                              inputTextures: cropTextureProperties)
         releaseIncomingFramebuffers()
+        
+        if(imageVertexBuffer != 0){
+            PQGPUImageTools.deleteVBO(imageVertexBuffer)
+            imageVertexBuffer = 0
+        }
 
         luminanceFramebuffer.unlock()
         chrominanceFramebuffer.unlock()

+ 63 - 53
BFFramework/Classes/PQGPUImage/akfilters/PQMovieInput.swift

@@ -130,7 +130,10 @@ public class PQMovieInput: ImageSource {
 //    public  var seekQueue: DispatchQueue!
 
     // 是否为导出模式
-    public   var mIsExport: Bool = false
+    public var mIsExport: Bool = false
+    
+    //是否使用AVPlayer播放音乐
+    public var isUsedAVPlayer:Bool = false
     
     //打印开始时间
     var debugStartTime:CFTimeInterval?
@@ -138,7 +141,7 @@ public class PQMovieInput: ImageSource {
      // 画布的大小 注意要是偶数 要不在 IOS 13上会有绿边 自动放大到偶数
     public var mShowVidoSize: CGSize = cVideoCannvasSizeOneToOne {
         didSet {
-            BFLog(2, message: "mShowVidoSize is move input  \(mShowVidoSize)")
+            FilterLog(2, message: "mShowVidoSize is move input  \(mShowVidoSize)")
             do {
                 displayLink?.isPaused = true
                 imageFramebuffer = try Framebuffer(context: sharedImageProcessingContext, orientation: .portrait, size: GLSize(width: GLint(mShowVidoSize.width), height: GLint(mShowVidoSize.height)), textureOnly: true)
@@ -152,7 +155,7 @@ public class PQMovieInput: ImageSource {
     // 初始化方法
     public init(asset: AVAsset, videoComposition: AVVideoComposition?, audioMix: AVAudioMix?, playAtActualSpeed: Bool = false, loop: Bool = false, audioSettings: [String: Any]? = nil) throws {
         self.asset = asset
-        BFLog(2, message: "asset 资源的总时长\(asset.duration.seconds) \(asset.duration)")
+        FilterLog(2, message: "asset 资源的总时长\(asset.duration.seconds) \(asset.duration)")
         self.audioMix = audioMix
         self.audioSettings = audioSettings
         self.videoComposition = videoComposition
@@ -160,7 +163,7 @@ public class PQMovieInput: ImageSource {
         self.loop = loop
         yuvConversionShader = crashOnShaderCompileFailure("MovieInput") { try sharedImageProcessingContext.programForVertexShader(defaultVertexShaderForInputs(2), fragmentShader: YUVConversionFullRangeFragmentShader) }
         if asset.duration.seconds <= 0 {
-            BFLog(2, message: "asset 资源的总时长为0,返回")
+            FilterLog(2, message: "asset 资源的总时长为0,返回")
             return
         }
   
@@ -170,10 +173,10 @@ public class PQMovieInput: ImageSource {
 
         if #available(iOS 10, *){
             displayLink?.preferredFramesPerSecond = 30
-//            seekQueue = DispatchQueue(label: "PQ.MovieInput.seeking", qos: .userInteractive, attributes: .initiallyInactive, autoreleaseFrequency: .never, target: nil)
+ 
         }else{
             displayLink?.frameInterval = 2
-//            seekQueue = DispatchQueue(label: "PQ.MovieInput.seeking", qos: .userInteractive, attributes: [], autoreleaseFrequency: .inherit, target: nil)
+ 
         }
         // 加入循环 要使用 common 不要让级别高的卡住回调事件
         displayLink?.add(to: RunLoop.main, forMode: RunLoop.Mode.common)
@@ -197,7 +200,7 @@ public class PQMovieInput: ImageSource {
         self.audioInputStatusObserver?.invalidate()
         self.avPlayerTimeObserver?.invalidate()
 
-        BFLog(1, message: "movieinput release")
+        FilterLog(1, message: "movieinput release")
     }
 
     // MARK: -
@@ -209,7 +212,7 @@ public class PQMovieInput: ImageSource {
         isPlay = false
         beginTime = 0
         currentTime = .zero
-        BFLog(2, message: "初始化播放开始时间、\(CMTimeGetSeconds(timeRange.start)) 结束时间\(CMTimeGetSeconds(timeRange.end)) 播放总时长:\(CMTimeGetSeconds(timeRange.end) - CMTimeGetSeconds(timeRange.start))")
+        FilterLog(2, message: "初始化播放开始时间、\(CMTimeGetSeconds(timeRange.start)) 结束时间\(CMTimeGetSeconds(timeRange.end)) 播放总时长:\(CMTimeGetSeconds(timeRange.end) - CMTimeGetSeconds(timeRange.start))")
   
         playeTimeRange = timeRange
         startTime = playeTimeRange.start
@@ -219,7 +222,7 @@ public class PQMovieInput: ImageSource {
 
     @objc func displayLinkClick(_ displayLink: CADisplayLink) {
         if assetReader == nil {
-            BFLog(2, message: "self.assetReader is null !!!!!!!!!!")
+            FilterLog(2, message: "self.assetReader is null !!!!!!!!!!")
             displayLink.isPaused = true
             return
         }
@@ -237,7 +240,14 @@ public class PQMovieInput: ImageSource {
             let duration = CMTimeGetSeconds(playeTimeRange.end)
             
             if !mIsExport {
-                self.currentTime = CMTimeMakeWithSeconds(CFAbsoluteTimeGetCurrent() - self.beginTime +  CMTimeGetSeconds(startTime ?? CMTime.zero), preferredTimescale: BASE_FILTER_TIMESCALE)
+        
+               var midTime = CFAbsoluteTimeGetCurrent() - self.beginTime
+                if(midTime < 0.0001){
+                    midTime = 0
+                }
+                FilterLog(message: "CFAbsoluteTimeGetCurrent()\(CFAbsoluteTimeGetCurrent()) - self.beginTime  is:::::\(self.beginTime) 差值 \(midTime)")
+              
+                self.currentTime = CMTimeMakeWithSeconds(midTime +  CMTimeGetSeconds(startTime ?? CMTime.zero), preferredTimescale: BASE_FILTER_TIMESCALE)
             }else {
                 self.currentTime = CMTimeMakeWithSeconds(self.beginTime +  CMTimeGetSeconds(startTime ?? CMTime.zero), preferredTimescale: BASE_FILTER_TIMESCALE)
                 self.beginTime = self.beginTime + 1 / 30
@@ -247,12 +257,12 @@ public class PQMovieInput: ImageSource {
   
             let prgressValue = currTime / Float64(duration)
             
-            BFLog(2, message: "\(mIsExport) MovieOutput total frames appended:播放进行中 总用时: \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) 播放器开始时间:\(CMTimeGetSeconds(playeTimeRange.start)) 播放器原始结束时间:\(CMTimeGetSeconds(playeTimeRange.end))    总时间:\(CMTimeGetSeconds(playeTimeRange.end) - CMTimeGetSeconds(playeTimeRange.start)) 播放进度当前时间:\(currTime) 进度:\(prgressValue) 帧id \(totalFramesSent)")
+            FilterLog(2, message: "\(mIsExport) MovieOutput total frames appended:播放进行中 总用时: \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) 播放器开始时间:\(CMTimeGetSeconds(playeTimeRange.start)) 播放器原始结束时间:\(CMTimeGetSeconds(playeTimeRange.end))    总时间:\(CMTimeGetSeconds(playeTimeRange.end) - CMTimeGetSeconds(playeTimeRange.start)) 播放进度当前时间:\(currTime) 进度:\(prgressValue) 帧id \(totalFramesSent)")
             totalFramesSent += 1
     
-            BFLog(2, message: "2222222222播放进行中 总用时: \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) 播放进度当前时间:\(currTime) 总时间为:\(duration)进度:\(prgressValue) 音频时长:\(    CMTimeGetSeconds(asset.duration) )")
+            FilterLog(2, message: "2222222222播放进行中 总用时: \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) 播放进度当前时间:\(currTime) 总时间为:\(duration)进度:\(prgressValue) 音频时长:\(    CMTimeGetSeconds(asset.duration) )")
             if currTime / duration > 1{
-                BFLog(2, message: "全部播放完成 总用时为:\(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0))")
+                FilterLog(2, message: "全部播放完成 总用时为:\(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0))")
                 if(self.completion != nil){
                     self.completion?()
                 }
@@ -266,7 +276,7 @@ public class PQMovieInput: ImageSource {
                 if !mIsExport {
                     self.start(isFreeBuffer: true,timeRange: playeTimeRange)
                 }else{
-                    BFLog(message: "强制停止!!!!")
+                    FilterLog(message: "强制停止!!!!")
                     displayLink.isPaused = true
                     return
                 }
@@ -276,9 +286,9 @@ public class PQMovieInput: ImageSource {
                 self.conditionLock.lock()
                 while self.readingShouldWait {
                     self.synchronizedEncodingDebugPrint("Disable reading")
-                    BFLog(2, message: "Disable reading 开始等待 \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) ")
+                    FilterLog(2, message: "Disable reading 开始等待 \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0)) ")
                     self.conditionLock.wait()
-                    BFLog(2, message: "Enable reading  停止等待 \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0))")
+                    FilterLog(2, message: "Enable reading  停止等待 \(CFAbsoluteTimeGetCurrent() - (debugStartTime ?? 0.0))")
                 }
                 self.conditionLock.unlock()
 
@@ -311,11 +321,11 @@ public class PQMovieInput: ImageSource {
     @objc public func start(isFreeBuffer: Bool, isExport: Bool = false,timeRange:CMTimeRange = CMTimeRange.init()) {
         
         debugStartTime = CFAbsoluteTimeGetCurrent()
-        BFLog(2, message: "开始播放的系统时钟时间 \(String(describing: debugStartTime))")
+        FilterLog(2, message: "开始播放的系统时钟时间 \(String(describing: debugStartTime))")
         
         playeTimeRange = timeRange
         readerAudioTrackOutput = nil
-        BFLog(2, message: "PQMoveInput开始")
+        FilterLog(2, message: "PQMoveInput开始")
         mFreeBuffer = isFreeBuffer
         assetReader = createReader()
     
@@ -323,16 +333,16 @@ public class PQMovieInput: ImageSource {
 
         isPlay = true
         if assetReader == nil {
-            BFLog(2, message: "assetReader is null!!!!!")
+            FilterLog(2, message: "assetReader is null!!!!!")
             return
         }
 
         mIsExport = isExport
         do {
             try NSObject.catchException { [self] in
-                if(mIsExport){
+                if(!isUsedAVPlayer){
                     guard self.assetReader.startReading() else {
-                        BFLog(2, message: "ERROR: Unable to start reading: \(String(describing: self.assetReader.error))")
+                        FilterLog(2, message: "ERROR: Unable to start reading: \(String(describing: self.assetReader.error))")
                         return
                     }
                 }else{
@@ -344,19 +354,19 @@ public class PQMovieInput: ImageSource {
               
             }
         } catch {
-            BFLog(2, message: "ERROR: Unable to start reading: \(error)")
+            FilterLog(2, message: "ERROR: Unable to start reading: \(error)")
             return
         }
 
-        BFLog(2, message: "assetReader.outputs count is \(assetReader.outputs)")
+        FilterLog(2, message: "assetReader.outputs count is \(assetReader.outputs)")
         for output in assetReader.outputs {
             if output.mediaType == AVMediaType.video {
                 readerVideoTrackOutput = output
-                BFLog(2, message: " set  readerVideoTrackOutput")
+                FilterLog(2, message: " set  readerVideoTrackOutput")
             }
             if output.mediaType == AVMediaType.audio {
                 readerAudioTrackOutput = output
-                BFLog(2, message: " set  readerAudioTrackOutput")
+                FilterLog(2, message: " set  readerAudioTrackOutput")
             }
         }
 
@@ -373,11 +383,11 @@ public class PQMovieInput: ImageSource {
     }
 
     public func cancel() {
-        BFLog(2, message: "PQMoveInput取消")
+        FilterLog(2, message: "PQMoveInput取消")
         isPlay = false
 
         // 将定时器移除主循环
-        displayLink?.remove(from: RunLoop.main, forMode: RunLoop.Mode.default)
+        displayLink?.remove(from: RunLoop.main, forMode: RunLoop.Mode.common)
         // 停止定时器
         displayLink?.invalidate()
         displayLink = nil
@@ -388,7 +398,7 @@ public class PQMovieInput: ImageSource {
     }
 
     public func resume() {
-        BFLog(2, message: "PQMoveInput恢复播放")
+        FilterLog(2, message: "PQMoveInput恢复播放")
         mFreeBuffer = false
         isPlay = true
         if !mIsExport{
@@ -403,15 +413,15 @@ public class PQMovieInput: ImageSource {
 
     public func pause() {
         if !isPlay {
-            BFLog(2, message: "还不是播放状态")
+            FilterLog(2, message: "还不是播放状态")
             return
         }
 
         if displayLink == nil {
-            BFLog(2, message: "displayLink is erorr displaye bug !!!!")
+            FilterLog(2, message: "displayLink is erorr displaye bug !!!!")
             return
         }
-        BFLog(2, message: "PQMoveInput暂停 displayLink.timestamp:  \(displayLink!.timestamp)")
+        FilterLog(2, message: "PQMoveInput暂停 displayLink.timestamp:  \(displayLink!.timestamp)")
         isPlay = false
 
         // 暂停帧的刷新 true:停 ; false:开始
@@ -427,7 +437,7 @@ public class PQMovieInput: ImageSource {
             startTime = currentTime
         }
 
-        BFLog(2, message: "暂停时间:\(currTime)")
+        FilterLog(2, message: "暂停时间:\(currTime)")
 
         beginTime = 0
         
@@ -443,10 +453,10 @@ public class PQMovieInput: ImageSource {
     func createReader() -> AVAssetReader? {
         do {
             let assetReader = try AVAssetReader(asset: asset)
-            BFLog(2, message: "assetReader init \(assetReader)  asset url is \(asset)")
+            FilterLog(2, message: "assetReader init \(assetReader)  asset url is \(asset)")
             if audioMix == nil {
                 if let audioTrack = asset.tracks(withMediaType: .audio).first, let _ = audioEncodingTarget {
-                    BFLog(1, message: "audioTrack start \(audioTrack.timeRange.start) \(audioTrack.timeRange.duration.value)")
+                    FilterLog(1, message: "audioTrack start \(audioTrack.timeRange.start) \(audioTrack.timeRange.duration.value)")
 
                     let readerAudioTrackOutput = AVAssetReaderTrackOutput(track: audioTrack, outputSettings: audioSettings)
                     readerAudioTrackOutput.alwaysCopiesSampleData = false
@@ -457,7 +467,7 @@ public class PQMovieInput: ImageSource {
                 }
 
             } else {
-                BFLog(2, message: "self.asset.tracks is \(asset.tracks.count)")
+                FilterLog(2, message: "self.asset.tracks is \(asset.tracks.count)")
                 let readerAudioTrackOutput = AVAssetReaderAudioMixOutput(audioTracks: asset.tracks(withMediaType: .audio), audioSettings: audioSettings)
                 readerAudioTrackOutput.audioMix = audioMix
                 readerAudioTrackOutput.alwaysCopiesSampleData = false
@@ -465,21 +475,21 @@ public class PQMovieInput: ImageSource {
             }
 
             assetReader.timeRange = playeTimeRange
-            BFLog(2, message: "初始化播放器开始时间\(CMTimeGetSeconds(assetReader.timeRange.start)) 结束时间\(CMTimeGetSeconds(assetReader.timeRange.end)) 音乐的总时长\(asset.duration.seconds)")
+            FilterLog(2, message: "初始化播放器开始时间\(CMTimeGetSeconds(assetReader.timeRange.start)) 结束时间\(CMTimeGetSeconds(assetReader.timeRange.end)) 音乐的总时长\(asset.duration.seconds)")
        
 
             actualStartTime = nil
 
             return assetReader
         } catch {
-            BFLog(2, message: "ERROR: Unable to create asset reader: \(error)")
+            FilterLog(2, message: "ERROR: Unable to create asset reader: \(error)")
         }
         return nil
     }
 
     func readNextVideoFrame(with _: AVAssetReader) {
         
-        BFLog(2, message: "视频解码状态\(assetReader.status.rawValue)")
+        FilterLog(2, message: "视频解码状态\(assetReader.status.rawValue)")
      
         autoreleasepool {
             synchronizedEncodingDebugPrint("Process frame input")
@@ -491,7 +501,7 @@ public class PQMovieInput: ImageSource {
             
     
             let prgressValue = (currTime - start) / (duration - start)
-//            BFLog(1, message: "\(mIsExport) movinput 当前时间 is \(currTime) curr当前进度:\(prgressValue)")
+//            FilterLog(1, message: "\(mIsExport) movinput 当前时间 is \(currTime) curr当前进度:\(prgressValue)")
             progress?(currTime, duration, prgressValue)
 
             sharedImageProcessingContext.runOperationSynchronously { [weak self] in
@@ -502,13 +512,13 @@ public class PQMovieInput: ImageSource {
 
     func readNextAudioSample(with assetReader: AVAssetReader, from audioTrackOutput: AVAssetReaderOutput) {
         
-        if(!mIsExport){
-            BFLog(2, message: "不是导出模式")
+        if(isUsedAVPlayer){
+            FilterLog(2, message: "使用的 avplayer 播放模式")
             return
         }
        
         if !isPlay {
-            BFLog(2, message: "自动停到首帧的不处理音频")
+            FilterLog(2, message: "自动停到首帧的不处理音频")
             return
         }
         /*
@@ -517,35 +527,35 @@ public class PQMovieInput: ImageSource {
          case failed = 3
          case cancelled = 4
          */
-        BFLog(2, message: "音频解码状态\(assetReader.status.rawValue)")
+        FilterLog(2, message: "音频解码状态\(assetReader.status.rawValue)")
         
         autoreleasepool {
             guard let sampleBuffer = audioTrackOutput.copyNextSampleBuffer(),CMSampleBufferIsValid(sampleBuffer) else {
                 if(assetReader.status == .completed){
-                    BFLog(2, message: "提前结束的了!!!!\(String(describing: assetReader.error))")
+                    FilterLog(2, message: "提前结束的了!!!!\(String(describing: assetReader.error))")
                 }
                 if let movieOutput = synchronizedMovieOutput {
-                    BFLog(2, message: "this is runing assetWriterAudioInput  markAsFinished \(String(describing: assetReader.error)) \(assetReader)")
+                    FilterLog(2, message: "this is runing assetWriterAudioInput  markAsFinished \(String(describing: assetReader.error)) \(assetReader)")
 
                     movieOutput.movieProcessingContext.runOperationAsynchronously {
                         movieOutput.audioEncodingIsFinished = true
                         movieOutput.assetWriterAudioInput?.markAsFinished()
                     }
                 }
-                BFLog(2, message: "sampleBuffer is null 速度太快copy is error")
+                FilterLog(2, message: "sampleBuffer is null 速度太快copy is error")
                 return
             }
 
             synchronizedEncodingDebugPrint("Process audio sample input")
 
             let currentSampleTime = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer)
-            BFLog(2, message: "处理音频的时间戳 \(CMTimeGetSeconds(currentSampleTime)) 播放时间\(CMTimeGetSeconds(currentTime))")
+            FilterLog(2, message: "处理音频的时间戳 \(CMTimeGetSeconds(currentSampleTime)) 播放时间\(CMTimeGetSeconds(currentTime))")
 
             // https://www.itdaan.com/blog/2013/11/28/deb10f90970a5ea33f185c9faf2a0ab3.html
             if !mFreeBuffer {
                 audioEncodingTarget?.processAudioBuffer(sampleBuffer)
             }else{
-                BFLog(message: "不播放音频!!!!")
+                FilterLog(message: "不播放音频!!!!")
             }
         }
     }
@@ -555,7 +565,7 @@ public class PQMovieInput: ImageSource {
             let startPTime = CFAbsoluteTimeGetCurrent()
 
             imageFramebuffer.lock()
-            BFLog(message: "mIsExport:\(mIsExport) 实际设置的每一帧时间戳:\(CMTimeGetSeconds(currentTime))")
+            FilterLog(message: "mIsExport:\(mIsExport) 实际设置的每一帧时间戳:\(CMTimeGetSeconds(currentTime))")
             // 设置当前帧的时间戳
             imageFramebuffer.timingStyle = .videoFrame(timestamp: Timestamp(currentTime))
  
@@ -572,7 +582,7 @@ public class PQMovieInput: ImageSource {
                 totalFrameTimeDuringCapture += currentFrameTime
                 
                 
-                BFLog(2, message: "currentTime is \(String(format: "%.6f", CMTimeGetSeconds(currentTime))) 当前帧渲染时间 : \(String(format: "%.6f",1000.0 * currentFrameTime)) ms Average frame time : \(String(format: "%.6f", 1000.0 * totalFrameTimeDuringCapture / Double(totalFramesSent))) ms  totalFrameTimeDuringCapture is \(String(format: "%.6f",totalFrameTimeDuringCapture))")
+                FilterLog(2, message: "currentTime is \(String(format: "%.6f", CMTimeGetSeconds(currentTime))) 当前帧渲染时间 : \(String(format: "%.6f",1000.0 * currentFrameTime)) ms Average frame time : \(String(format: "%.6f", 1000.0 * totalFrameTimeDuringCapture / Double(totalFramesSent))) ms  totalFrameTimeDuringCapture is \(String(format: "%.6f",totalFrameTimeDuringCapture))")
              
             
 
@@ -628,7 +638,7 @@ public class PQMovieInput: ImageSource {
             conditionLock.signal()
             
         } else {
-            BFLog(1, message: "MovieOutput total frames appended 要加锁了")
+            FilterLog(1, message: "MovieOutput total frames appended 要加锁了")
             readingShouldWait = true
         }
         conditionLock.unlock()
@@ -720,7 +730,7 @@ extension PQMovieInput {
                 let range = strongSelf.musicPlayRanges?[strongSelf.indexRage]
                 playerItem.forwardPlaybackEndTime = range!.end
                 playerItem.reversePlaybackEndTime = range!.start
-//                BFLog(1, message: "curr: start ********************\(CMTimeGetSeconds(range.start)) - \(playerItem.reversePlaybackEndTime) - \(playerItem.forwardPlaybackEndTime)")
+//                FilterLog(1, message: "curr: start ********************\(CMTimeGetSeconds(range.start)) - \(playerItem.reversePlaybackEndTime) - \(playerItem.forwardPlaybackEndTime)")
                 strongSelf.avPlayer!.seek(to: playerItem.reversePlaybackEndTime) { isSuccess in
                     playerItem.seek(to: playerItem.reversePlaybackEndTime) { isSuccess in
                         strongSelf.avPlayer!.play()
@@ -733,7 +743,7 @@ extension PQMovieInput {
         
 //        avPlayerTimeObserver = avPlayer!.addPeriodicTimeObserver(forInterval: CMTime(value: 1, timescale: 4), queue: DispatchQueue.global()) {[weak self] time in
 //         //    进度监控
-//            BFLog(1, message: "cont:\(CMTimeGetSeconds(time) - CMTimeGetSeconds((self?.musicPlayRanges?.first!.start)!)), curr:\(CMTimeGetSeconds(time))")
+//            FilterLog(1, message: "cont:\(CMTimeGetSeconds(time) - CMTimeGetSeconds((self?.musicPlayRanges?.first!.start)!)), curr:\(CMTimeGetSeconds(time))")
 //        } as? NSKeyValueObservation
     }
     

+ 1 - 1
BFFramework/Classes/PQGPUImage/akfilters/PQSubTitleFilter.swift

@@ -40,7 +40,7 @@ open class PQSubTitleFilter: BasicOperation {
         clearData()
     }
 
-    init(st: [PQEditSubTitleModel], isBig: Bool = false, inputSize: CGSize) {
+   public init(st: [PQEditSubTitleModel], isBig: Bool = false, inputSize: CGSize) {
         super.init(fragmentShader: AlphaPassthroughFragmentShader, numberOfInputs: 1)
 
         isBigSubtile = isBig

+ 22 - 5
BFFramework/Classes/PQGPUImage/akfilters/Tools/PQCompositionExporter.swift

@@ -166,20 +166,34 @@ public class PQCompositionExporter {
     }
     
  
-   public  func  findShowStikcer(currTime:Float64)  {
+    public  func  findShowStikcer(currTime:Float64)  {
          
         if(mStickers?.count ?? 0 == 0){
             BFLog(message: "mStickers data is error")
             return
         }
         var currentSticker:PQEditVisionTrackMaterialsModel?
-        for sticker in mStickers! {
-            BFLog(message: "sticker in \(sticker.timelineIn) out \(sticker.timelineOut)  currTime is \(currTime)")
-            if(sticker.timelineIn <= currTime && sticker.timelineOut >= currTime){
-                currentSticker = sticker
+       
+//        for sticker in mStickers! {
+//            BFLog(message: "sticker in \(sticker.timelineIn) out \(sticker.timelineOut)  currTime is \(currTime)")
+//            if(sticker.timelineIn <= currTime && sticker.timelineOut >= currTime){
+//                currentSticker = sticker
+//                break
+//            }
+//        }
+        while true {
+            if let sticker = mStickers!.first {
+                if sticker.timelineIn <= currTime && sticker.timelineOut >= currTime {
+                    currentSticker = sticker
+                    break
+                }else{
+                    mStickers!.removeFirst()
+                }
+            }else{
                 break
             }
         }
+        
         //创建不同的filter
         if(currentSticker == nil){
             BFLog(message: "sticker data is error")
@@ -338,6 +352,9 @@ public class PQCompositionExporter {
         input?.cancel()
         output?.assetWriter.cancelWriting()
         output?.finishRecording()
+        
+        input?.removeAllTargets()
+      
     }
 
     public func handleCaption(for asset: AVAsset) {

+ 74 - 45
BFFramework/Classes/Stuckpoint/Controller/PQStuckPointEditerController.swift

@@ -13,14 +13,14 @@ public enum createStickersModel: Int {
     case createStickersModelOnlyMusic = 3 // 仅配乐
 }
 
-import BFUIKit
+import BFCommonKit
 import Foundation
 import ObjectMapper
 import Photos
 import RealmSwift
 import UIKit
 
-class PQStuckPointEditerController: BFBaseViewController {
+class PQStuckPointEditerController: PQBaseViewController {
     // 是否导出视频成功
     var isExportVideosSuccess: Bool = false
     // 是否请求卡点数据成功
@@ -57,7 +57,7 @@ class PQStuckPointEditerController: BFBaseViewController {
                     metarialData.locationPath = phAsset.localPath ?? ""
                     metarialData.selectedIndex = phAsset.selectedIndex ?? 1
                     metarialData.originalData = phAsset.originalData
-//                    metarialData.coverImageUI = phAsset.image
+                    metarialData.coverImageUI = phAsset.image
                     selectedMetarialData?.append(metarialData)
                 }
             }
@@ -119,6 +119,8 @@ class PQStuckPointEditerController: BFBaseViewController {
     var stuckPointsTemp: Array = Array<Float>.init()
     var stuckPointsTempInt64: Array = Array<Int64>.init()
 
+    //是否点击了下一步去合成
+    var isClickNextBtn:Bool = false
 
     // 下一步
     lazy var nextBtn: UIButton = {
@@ -733,6 +735,12 @@ class PQStuckPointEditerController: BFBaseViewController {
 
         PQNotification.addObserver(self, selector: #selector(enterBackground), name: UIApplication.didEnterBackgroundNotification, object: nil)
         PQNotification.addObserver(self, selector: #selector(willEnterForeground), name: UIApplication.willEnterForegroundNotification, object: nil)
+        
+        //从分享返回后从重初始化播放器
+        if(isClickNextBtn){
+            isClickNextBtn = false
+            settingPlayerView()
+        }
     }
     
     override func viewWillDisappear(_ animated: Bool) {
@@ -741,7 +749,7 @@ class PQStuckPointEditerController: BFBaseViewController {
             UIApplication.shared.isIdleTimerDisabled = false
         }
         musicNameLab.stop()
-        playerView.pause()
+        playerView.stop()
 
         musicEditBGView.pausePlayer()
         PQNotification.removeObserver(self)
@@ -921,6 +929,8 @@ class PQStuckPointEditerController: BFBaseViewController {
 
     @objc func nextBtnClick(sender _: UIButton) {
         BFLog(message: "去发布")
+     
+        isClickNextBtn = true
         playerView.pause()
         // 使用深 copy
         let json = projectModel.toJSONString(prettyPrint: false)
@@ -985,14 +995,13 @@ class PQStuckPointEditerController: BFBaseViewController {
         if projectModel.sData?.sections.count == 0 {
             let section: PQEditSectionModel = PQEditSectionModel()
             selectedMetarialData?.forEach { model in
-
-                let json = model.toJSONString(prettyPrint: false)
-                if json == nil {
-                    BFLog(message: "数据转换有问题 跳转")
-                    return
-                }
-                let tempModel: PQEditVisionTrackMaterialsModel = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)!
-                section.sectionTimeline?.visionTrack?.visionTrackMaterials.append(tempModel)
+//                let json = model.toJSONString(prettyPrint: false)
+//                if json == nil {
+//                    BFLog(message: "数据转换有问题 跳转")
+//                    return
+//                }
+//                let tempModel: PQEditVisionTrackMaterialsModel = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)!
+                section.sectionTimeline?.visionTrack?.visionTrackMaterials.append(model)
             }
             projectModel.sData?.sections.append(section)
         }
@@ -1090,7 +1099,7 @@ class PQStuckPointEditerController: BFBaseViewController {
             return
         }
 
-        let maxValue = max(videoSize.width, videoSize.height ?? 0)
+        let maxValue = max(videoSize.width, videoSize.height)
 
         if maxValue > 1920 {
             let maxRation = 1920 / maxValue
@@ -1112,7 +1121,7 @@ class PQStuckPointEditerController: BFBaseViewController {
 
         let beginTime = Date()
         dealParameter(model: currentCreateStickersModel)
-
+        
         // 更新裁剪时间条的的ui数据
         stuckPointCuttingView.videoDuration = max(CGFloat(finallyUserAudioTime), CGFloat(finallyStuckPoints.last!))
         let counn = (stuckPointMusicData?.rhythmSdata[0].pointTimes.count)! - 2
@@ -1140,7 +1149,7 @@ class PQStuckPointEditerController: BFBaseViewController {
                 // 这里的测试这个音乐播放有问题
                 //        self.playerView.updateAsset(URL(fileURLWithPath: "63930549652d74e477141e3b79c8d29a9ef8af81625053214516.mp3", relativeTo:Bundle.main.resourceURL!), videoComposition: nil, audioMixModel: nil)
 
-                self.playerView.updateAsset(URL(fileURLWithPath: documensDirectory + audioPath), videoComposition: nil, audioMixModel: nil, originMusicDuration: self.finallyUserAudioTime, clipAudioRange: self.getClipAudioRange())
+                self.playerView.updateAsset(URL(fileURLWithPath: documensDirectory + audioPath), videoComposition: nil, audioMixModel: nil, originMusicDuration: self.finallyUserAudioTime, clipAudioRange: self.getClipAudioRange(),isUsedAVPlayer: true)
 
                 // 4, 设置播放器的输出画布大小
                 self.playerView.movie?.mShowVidoSize = CGSize(width: CGFloat(self.projectModel.sData?.videoMetaData?.videoWidth ?? 0), height: CGFloat(self.projectModel.sData?.videoMetaData?.videoHeight ?? 0))
@@ -1523,20 +1532,20 @@ extension PQStuckPointEditerController {
             }
         }
 
-        for point in stuckPoints {
-            BFLog(message: "没有 start end 计算后的卡点数\(point)")
-        }
+//        for point in stuckPoints {
+//            BFLog(message: "没有 start end 计算后的卡点数\(point)")
+//        }
         // 若音乐起点至第一个卡点点位之间时长t0<0.3时,此段时长与下一个点位时长合并,故第一段卡点部分时长为t0+d
-        if Float(stuckPointMusicData?.startTime ?? 0) - (stuckPoints.first ?? 0.0) < 0.3 {
+        while (stuckPoints.first ?? 0.0) - Float(stuckPointMusicData?.startTime ?? 0) < 0.3 {
             if stuckPoints.first != nil {
                 stuckPoints.removeFirst()
             }
         }
         stuckPoints.insert(Float(stuckPointMusicData?.startTime ?? 0), at: 0)
 
-        for point in stuckPoints {
-            BFLog(message: "有 start end 计算后的卡点数\(point)")
-        }
+//        for point in stuckPoints {
+//            BFLog(message: "有 start end 计算后的卡点数\(point)")
+//        }
 
         BFLog(message: "处理节奏后 stuckPoints count is \(stuckPoints.count) seed \(seed), start time:\(stuckPoints.first ?? 0.0),end time:\(stuckPoints.last ?? 0.0) 总时长为:\((stuckPoints.last ?? 0.0) - (stuckPoints.first ?? 0.0))")
 
@@ -1598,9 +1607,7 @@ extension PQStuckPointEditerController {
                     i = i + 1
                     clipNum = clipNum + 1
                 }
-
                 // 拼接要使用的卡点信息
-
                 clipPoint(clipNum: clipNum, oldPoints: stuckPointsTemp)
             }
 
@@ -1735,11 +1742,12 @@ extension PQStuckPointEditerController {
 
             break
         }
+        
         // 拼接图片所使用的时长.选择一组图片 按图片数量计算卡点的总时长
         if selectedImageDataCount > 0 {
             clipPoint(clipNum: selectedImageDataCount - 1, oldPoints: stuckPointsTemp)
         }
-
+        
         // 全是图片时数组里放着的一定都是图片的使用的卡点
         // 定义一次循环的总时长
         var oneSelectImageDuration: Float = 0.0
@@ -1774,6 +1782,12 @@ extension PQStuckPointEditerController {
             }
         }
         
+        if finallyStuckPoints.count < 2 {
+            cShowHUB(superView: nil, msg: "视频资源导入失败,请重新选择!!")
+            exportResourceFailed()
+            return
+        }
+        
         // 设置速度选择的位置
         if speedSettingView.viewType == 1 {
             speedSettingView.setSelectItem(index: lastSpeedSelectIndex, isSettingPlayer: false)
@@ -1846,10 +1860,9 @@ extension PQStuckPointEditerController {
                     self?.dealWithDataSuccess(resetSelectIndex: resetSelectIndex)
                 } else {
                     self?.synchroMarskView.removeMarskView()
-//                    BFUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
                     cShowHUB(superView: nil, msg: "音乐信息加载失败,请重新选择音乐")
-
-//                        self?.navigationController?.popViewController(animated: true)
+//                    PQUploadRemindView.showUploadRemindView(title: nil, attributedTitle: NSAttributedString(string: "加载音乐失败,请重新选择音乐"), summary: "", confirmTitle: nil) { [weak self] _, _ in
+                        self?.navigationController?.popViewController(animated: true)
 //                    }
                 }
             }
@@ -1868,6 +1881,7 @@ extension PQStuckPointEditerController {
             exportSession.cancelExport()
         }
         var isHaveVideo: Bool = false
+        var failedExprot: Bool = false
         if selectedMetarialData != nil, (selectedMetarialData?.count ?? 0) > 0 {
             if synchroMarskView.superview == nil {
                 UIApplication.shared.keyWindow?.addSubview(synchroMarskView)
@@ -1903,23 +1917,26 @@ extension PQStuckPointEditerController {
                                         BFLog(message: "导出相册视频-error == \(error)")
                                     }
                                 }
+                                let curr = Date()
+                                let assetResources = PHAssetResource.assetResources(for: photo.asset!)
+                                if let rsc = assetResources.first(where: { res in
+                                    res.type == .video  || res.type == .pairedVideo
+                                }) {
+                                    PHAssetResourceManager.default().writeData(for: rsc, toFile: URL(fileURLWithPath: outFilePath), options: nil) { error in
+                                        if error == nil {
+                                            BFLog(message: "导出视频相exportAsynchronously \(String(describing: outFilePath)) \(Date().timeIntervalSince(curr))")
+                                            tempPhoto?.locationPath = outFilePath.replacingOccurrences(of: documensDirectory, with: "")
+                                        }else{
+                                            failedExprot = true
+                                            BFLog(message: "导出视频相exportAsynchro faile")
+                                        }
+                                        dispatchGroup.leave()
+                                    }
 
-                                do {
-                                    try FileManager.default.copyItem(atPath: fileName.replacingOccurrences(of: "file:///", with: ""), toPath: outFilePath)
-                                    print("Success to copy file.")
-                                } catch {
-                                    print("Failed to copy file.")
+                                }else {
+                                    BFLog(message: "导出视频相exportAsynchro faile")
+                                    dispatchGroup.leave()
                                 }
-
-                                tempPhoto?.locationPath = outFilePath.replacingOccurrences(of: documensDirectory, with: "")
-                                BFLog(message: "导出视频相册地址为 \(String(describing: tempPhoto?.locationPath))")
-
-                                dispatchGroup.leave()
-                            }
-                        }else {
-                            // 结束loading动画
-                            DispatchQueue.main.async {
-                                self.synchroMarskView.removeMarskView()
                             }
                         }
                     }
@@ -1927,6 +1944,11 @@ extension PQStuckPointEditerController {
             }
 
             dispatchGroup.notify(queue: DispatchQueue.main) { [weak self] in
+                if failedExprot {
+                    cShowHUB(superView: nil, msg: "视频导入失败,请返回重试")
+                    self?.exportResourceFailed()
+                    return
+                }
                 self?.isExportVideosSuccess = true
                 BFLog(message: "所有相册视频导出成功")
                 // 处理所有数据完成
@@ -1944,6 +1966,13 @@ extension PQStuckPointEditerController {
             }
         }
     }
+    
+    func exportResourceFailed(){
+        DispatchQueue.main.async {
+            self.synchroMarskView.removeMarskView()
+            self.navigationController?.popViewController(animated: true)
+        }
+    }
 
     /// 处理所有数据完成
     /// - Returns: <#description#>
@@ -2005,7 +2034,7 @@ extension PQStuckPointEditerController {
                 lastSpeedSelectIndex = 0
             }
             
-            // 如果是再创作进来的原视频的模式
+            // 如果是再创作进来的原视频的模式
             if reCreateVideoData != nil {
                 BFLog(message: "是再创作进来的 \(reCreateVideoData!.rhythmMode)")
                 switch reCreateVideoData!.rhythmMode {
@@ -2051,7 +2080,7 @@ extension PQStuckPointEditerController {
                     editModelClick(sender: speedStuckBtn, reportLog: false)
 
                 } else {
-                    // 默认进入卡点模式
+                    // 默认进入跳跃卡点模式
                     editModelClick(sender: jumpPointBtn, reportLog: false)
 
                 }

+ 5 - 7
BFFramework/Classes/Stuckpoint/Controller/PQStuckPointMaterialController.swift

@@ -218,11 +218,11 @@ public class PQStuckPointMaterialController: BFBaseViewController {
         navHeadImageView?.addSubview(choseLocalVideoBtn)
         navHeadImageView?.addSubview(choseLocalImageBtn)
         navHeadImageView?.addSubview(choseLineView)
-//        view.insertSubview(materialHeadView, belowSubview: navHeadImageView!)
         view.addSubview(bottomRemindView)
         bottomRemindView.addSubview(confirmBtn)
         bottomRemindView.addSubview(bottomRemindLab)
-        photoMaterialVc.msgType = .video
+        addChild(photoMaterialVc)
+        view.insertSubview(photoMaterialVc.view, belowSubview: bottomRemindView)
         view.bringSubviewToFront(navHeadImageView!)
         view.insertSubview(materialListView, belowSubview: bottomRemindView)
         // 卡点音乐素材选择曝光上报
@@ -311,7 +311,10 @@ public class PQStuckPointMaterialController: BFBaseViewController {
     }
 
     deinit {
+        photoMaterialVc.assetCollection = nil
+        photoMaterialVc.allPhotos = nil
         PQNotification.removeObserver(self)
+        BFLog(message: "\(self) 已销毁")
     }
 
     /// 图库选择的回调
@@ -323,12 +326,7 @@ public class PQStuckPointMaterialController: BFBaseViewController {
             changeCollecBtn.setTitle(seletedData?.title ?? "全部", for: .normal)
             changeCollecBtn.imagePosition(at: PQButtonImageEdgeInsetsStyle.right, space: cDefaultMargin / 2)
             photoMaterialVc.assetCollection = seletedData?.assetCollection
-            photoMaterialVc.msgType = photoMaterialVc.msgType
         }
-//        photoMaterialVc.msgType = .video
-//        choseLocalAllBtn.isSelected = false
-//        choseLocalVideoBtn.isSelected = true
-//        choseLocalImageBtn.isSelected = false
     }
 
     /// 点击选择的回调

+ 18 - 18
BFFramework/Classes/Stuckpoint/Controller/PQStuckPointMusicContentController.swift

@@ -7,9 +7,9 @@
 //
 
 import UIKit
-import BFUIKit
+import BFCommonKit
 
-class PQStuckPointMusicContentController: BFBaseViewController {
+class PQStuckPointMusicContentController: PQBaseViewController {
     var itemList: [Any] = Array<Any>.init() // 所有分类数据
     // 当前选择的位置
     var lastIndexPath: IndexPath?
@@ -67,21 +67,21 @@ class PQStuckPointMusicContentController: BFBaseViewController {
         }
         // 延迟scrollView上子视图的响应,所以当直接拖动UISlider时,如果此时touch时间在150ms以内,UIScrollView会认为是拖动自己,从而拦截了event,导致UISlider接收不到滑动的event
         collectionView.delaysContentTouches = false
-        collectionView.addRefreshView (type:.REFRESH_TYPE_FOOTER) {[weak self] isRefresh in
+        collectionView.addRefreshView (type:.REFRESH_TYPE_FOOTER) {[weak self, weak collectionView] isRefresh in
             if !isRefresh && self?.contentType != .catagery{
                 // 请求一下加载更多
                 if self?.refreshHandle != nil {
                     self?.refreshHandle!(isRefresh, self?.contentType ?? .catagery)
                 }
             }else{
-                collectionView.mj_footer?.endRefreshing()
+                collectionView?.mj_footer?.endRefreshing()
             }
         }
         return collectionView
     }()
 
-    lazy var emptyRemindView: BFEmptyRemindView = {
-        let emptyRemindView = BFEmptyRemindView(frame: collectionView.bounds)
+    lazy var emptyRemindView: PQEmptyRemindView = {
+        let emptyRemindView = PQEmptyRemindView(frame: collectionView.bounds)
         emptyRemindView.remindLab.font = UIFont.systemFont(ofSize: 16)
         emptyRemindView.remindLab.textColor = UIColor.hexColor(hexadecimal: "#575757")
         emptyRemindView.isHidden = true
@@ -95,8 +95,8 @@ class PQStuckPointMusicContentController: BFBaseViewController {
         return emptyRemindView
     }()
 
-    var emptyData: BFEmptyModel? = {
-        let emptyData = BFEmptyModel()
+    var emptyData: PQEmptyModel? = {
+        let emptyData = PQEmptyModel()
         emptyData.title = "暂无音乐"
         emptyData.netDisRefreshBgColor = UIColor.hexColor(hexadecimal: "#FA6400")
         emptyData.netDisTitle = "内容加载失败"
@@ -142,7 +142,7 @@ class PQStuckPointMusicContentController: BFBaseViewController {
         } else {
             itemList = itemList + musicListData
         }
-        if (contentType != .serach && musicListData.count < 20) || (contentType == .serach && musicListData.count <= 0) || itemList.first is BFEmptyModel {
+        if (contentType != .serach && musicListData.count < 20) || (contentType == .serach && musicListData.count <= 0) || itemList.first is PQEmptyModel {
             collectionView.mj_footer?.endRefreshingWithNoMoreData()
         } else {
             collectionView.mj_footer?.endRefreshing()
@@ -211,9 +211,9 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
                 }
             }
             return cell
-        } else if itemData is BFEmptyModel {
+        } else if itemData is PQEmptyModel {
             let cell = PQStuckPointSearchEmptyCell.stuckPointSearchEmptyCell(collectionView: collectionView, indexPath: indexPath)
-            cell.bgmData = itemData as? BFEmptyModel
+            cell.bgmData = itemData as? PQEmptyModel
             return cell
         } else {
             let cell = PQStuckPointMusicContentCell.stuckPointMusicContentCell(collectionView: collectionView, indexPath: indexPath)
@@ -235,7 +235,7 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
                         PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_chooseMusic, pageSource: .sp_stuck_selectSynceedUpMusic, extParams: ["musicName": (bgmData as? PQVoiceModel)?.musicName ?? "", "musicId": (bgmData as? PQVoiceModel)?.musicId ?? ""], remindmsg: "卡点视频数据上报-(点击上报:选择音乐素材)")
                     } else if self?.contentType == .serach {
                         // 点击上报:选择音乐素材
-                        PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_chooseSearchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (bgmData as? PQVoiceModel)?.musicName ?? "", "musicId": (bgmData as? PQVoiceModel)?.musicId ?? "", "isHotMusic": self?.itemList.first is BFEmptyModel], remindmsg: "卡点视频数据上报-(点击上报:选择音乐素材)")
+                        PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_chooseSearchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (bgmData as? PQVoiceModel)?.musicName ?? "", "musicId": (bgmData as? PQVoiceModel)?.musicId ?? "", "isHotMusic": self?.itemList.first is PQEmptyModel], remindmsg: "卡点视频数据上报-(点击上报:选择音乐素材)")
                     }
                 }
             }
@@ -245,10 +245,10 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
 
     func collectionView(_ collectionView: UICollectionView, layout _: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
         let itemData: Any = itemList[indexPath.item]
-        if itemData is ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)) {
-            let height: CGFloat = ((itemData as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)))?.0.count ?? 0) > 0 ? (((itemData as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)))?.1.1 ?? 0) + 35) : 0
+        if let sul = itemData as? ([PQStuckPointMusicTagsModel], ([UICollectionViewLayoutAttributes], CGFloat)) {
+            let height: CGFloat = (sul.0.count > 0) ? (sul.1.1  + 35) : 0
             return CGSize(width: collectionView.frame.width, height: height)
-        } else if itemData is BFEmptyModel {
+        }else if itemData is PQEmptyModel {
             return CGSize(width: collectionView.frame.width, height: 290)
         } else {
             return CGSize(width: collectionView.frame.width, height: cellHight)
@@ -260,7 +260,7 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
             cShowHUB(superView: nil, msg: "请有网时再试")
             return
         }
-        if !(itemList[indexPath.item] is BFEmptyModel) {
+        if !(itemList[indexPath.item] is PQEmptyModel) {
             if lastIndexPath != indexPath {
                 if contentType == .catagery {
                     (itemList[lastIndexPath?.item ?? 0] as? PQStuckPointMusicTagsModel)?.isSelected = false
@@ -298,7 +298,7 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
                 PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_auditionMusic, pageSource: .sp_stuck_selectSynceedUpMusic, extParams: ["musicName": (itemList[indexPath.item] as? PQVoiceModel)?.musicName ?? "", "musicId": (itemList[indexPath.item] as? PQVoiceModel)?.musicId ?? ""], remindmsg: "卡点视频数据上报-(点击上报:音乐素材试听)")
             } else if contentType == .serach {
                 // 点击上报:试听音乐素材
-                PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_auditionSearchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (itemList[indexPath.item] as? PQVoiceModel)?.musicName ?? "", "musicId": (itemList[indexPath.item] as? PQVoiceModel)?.musicId ?? "", "isHotMusic": itemList.first is BFEmptyModel], remindmsg: "卡点视频数据上报-(点击上报:试听音乐素材)")
+                PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonClick, objectType: .ot_click_auditionSearchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (itemList[indexPath.item] as? PQVoiceModel)?.musicName ?? "", "musicId": (itemList[indexPath.item] as? PQVoiceModel)?.musicId ?? "", "isHotMusic": itemList.first is PQEmptyModel], remindmsg: "卡点视频数据上报-(点击上报:试听音乐素材)")
             }
         } else if contentType == .catagery && (itemList[indexPath.item] is PQStuckPointMusicTagsModel) {
             // 点击上报:选择音乐分类
@@ -320,7 +320,7 @@ extension PQStuckPointMusicContentController: UICollectionViewDelegate, UICollec
                 PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonView, objectType: .ot_view_syncedUpMusic, pageSource: .sp_stuck_selectSynceedUpMusic, extParams: ["musicName": (itemData as? PQVoiceModel)?.musicName ?? "", "musicId": (itemData as? PQVoiceModel)?.musicId ?? ""], remindmsg: "卡点视频数据上报-(曝光上报:音乐素材曝光)")
             } else if contentType == .serach {
                 // 曝光上报:搜索结果音乐素材曝光
-                PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonView, objectType: .ot_view_searchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (itemData as? PQVoiceModel)?.musicName ?? "", "musicId": (itemData as? PQVoiceModel)?.musicId ?? "", "isHotMusic": itemList.first is BFEmptyModel], remindmsg: "卡点视频数据上报-(曝光上报:搜索结果音乐素材曝光)")
+                PQEventTrackViewModel.baseReportUpload(businessType: .bt_buttonView, objectType: .ot_view_searchMusic, pageSource: .sp_stuck_searchSyncedUpMusic, extParams: ["musicName": (itemData as? PQVoiceModel)?.musicName ?? "", "musicId": (itemData as? PQVoiceModel)?.musicId ?? "", "isHotMusic": itemList.first is PQEmptyModel], remindmsg: "卡点视频数据上报-(曝光上报:搜索结果音乐素材曝光)")
             }
         }
     }

+ 39 - 25
BFFramework/Classes/Stuckpoint/Controller/PQStuckPointPublicController.swift

@@ -25,7 +25,8 @@ class PQStuckPointPublicController: BFBaseViewController {
     private var isSaveProjectSuccess: Bool = false // 是否保存项目完成
     private var isUploadSuccess: Bool = false // 是否上传完成
     private var isPublicSuccess: Bool = false // 是否发布完成
-    private var exportLocalURL: URL? // 导出的地址
+    // 导出正片的地址
+    private var exportLocalURL: URL?
     // 再创作数据
     private var reCreateData: PQReCreateModel?
     // 确定上传的数据
@@ -447,16 +448,16 @@ class PQStuckPointPublicController: BFBaseViewController {
     
     // 保存重试
     lazy var saveRetryBtn: UIButton = {
-        let finishedBtn = UIButton(type: .custom)
-        finishedBtn.setTitle("重试", for: .normal)
-        finishedBtn.setTitleColor(UIColor.white, for: .normal)
-        finishedBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
-        finishedBtn.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
-        finishedBtn.tag = 97
-        finishedBtn.isHidden = true
-        finishedBtn.addCorner(corner: 5)
-        finishedBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
-        return finishedBtn
+        let saveRetryBtn = UIButton(type: .custom)
+        saveRetryBtn.setTitle("重试", for: .normal)
+        saveRetryBtn.setTitleColor(UIColor.white, for: .normal)
+        saveRetryBtn.titleLabel?.font = UIFont.systemFont(ofSize: 15, weight: .medium)
+        saveRetryBtn.backgroundColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
+        saveRetryBtn.tag = 97
+        saveRetryBtn.isHidden = true
+        saveRetryBtn.addCorner(corner: 5)
+        saveRetryBtn.addTarget(self, action: #selector(btnClick(sender:)), for: .touchUpInside)
+        return saveRetryBtn
 
     }()
 
@@ -702,9 +703,7 @@ class PQStuckPointPublicController: BFBaseViewController {
             endMovieExporter.cancel()
         }
  
-        exporter?.input?.removeAllTargets()
-        watermarkMovieExporter?.input?.removeAllTargets()
-        endMovieExporter?.input?.removeAllTargets()
+     
         avPlayer.pause()
         avPlayer.replaceCurrentItem(with: nil)
         // 点击上报:返回按钮
@@ -863,11 +862,15 @@ extension PQStuckPointPublicController {
                 BFLog(message: "拼接后音频时长\(asset.duration.seconds)  url is \(String(describing: completURL)) 用时\(CFAbsoluteTimeGetCurrent() - startMergeTime)")
                 //导出不带水印的正片
                 self?.beginExport(inputAsset: asset)
-                //导出带水印的正片
-                self?.beginExportWatermarkMovie(inputAsset:asset)
+                
+                if(PQBFConfig.shared.enableWatermarkMovie){
+                    //导出带水印的正片
+                    self?.beginExportWatermarkMovie(inputAsset:asset)
+                }
             }else{
                 cShowHUB(superView: self?.view, msg: "合成失败请重试。")
             }
+            
         }
     }
 
@@ -903,6 +906,7 @@ extension PQStuckPointPublicController {
             }
         }
         BFLog(message: "导出设置的码率为:\(orgeBitRate)")
+        let tempBeginExport =  Date().timeIntervalSince1970
         exporter.showGaussianBlur = true
         if exporter.prepare(videoSize: CGSize(width: editProjectModel?.sData?.videoMetaData?.videoWidth ?? 0, height: editProjectModel?.sData?.videoMetaData?.videoHeight ?? 0), videoAverageBitRate: orgeBitRate) {
             BFLog(message: "开始导出 \(String(describing: playeTimeRange.start)) 结束 \(String(describing: playeTimeRange.end))")
@@ -910,7 +914,7 @@ extension PQStuckPointPublicController {
             BFLog(message: "开始导出")
         }
         exporter.progressClosure = { [weak self] _, _, progress in
-            BFLog(message: "正片合成进度 \(progress)")
+            BFLog(message: "正片合成进度 \(progress*100)%")
             let useProgress = progress > 1 ? 1 : progress
             if progress > 0, Int(useProgress * 100) > (self?.exportProgrss ?? 0) {
                 // 更新进度
@@ -928,9 +932,16 @@ extension PQStuckPointPublicController {
             if !(self?.isExportSuccess ?? false) {
                 self?.isExportSuccess = true
                 self?.exportEndDate = Date().timeIntervalSince1970
-                BFLog(message: "视频导出完成-开始去发布视频 总时长为\((self?.exportEndDate ?? 0) - (self?.startExportDate ?? 0) * 1000)")
-
+                BFLog(message: "视频导出完成-开始去发布视频 总时长为\((self?.exportEndDate ?? 0) - (self?.startExportDate ?? 0) * 1000) 总用时\((self?.exportEndDate ?? 0) - tempBeginExport)")
+   
                 self?.exportLocalURL = url
+                
+                
+                // add by ak 不生成水印视频时直接自动保存系统相册,e.g. 乐活圈中会执行
+                if(!PQBFConfig.shared.enableWatermarkMovie){
+                    self?.authorizationStatus()
+                }
+       
                 /// fp2-1-1 - 请求权限
 //                self?.authorizationStatus()
                 /// fp2-2 - 保存草稿
@@ -967,7 +978,9 @@ extension PQStuckPointPublicController {
     /// - Returns: <#description#>
     func saveStuckPointVideo() {
         
-        if(saveMovieLocalURL == nil){
+        let tempSaveMoveiLocal:URL? = PQBFConfig.shared.enableWatermarkMovie ? saveMovieLocalURL : exportLocalURL
+        
+        if(tempSaveMoveiLocal == nil){
             BFLog(message: "保存相册的视频导出地址无效!!!")
             cShowHUB(superView: nil, msg: "保存相册的视频导出地址无效")
             saveVideoTipsLabel.text = "视频保存失败"
@@ -983,7 +996,7 @@ extension PQStuckPointPublicController {
             let photoLibrary = PHPhotoLibrary.shared()
             photoLibrary.performChanges({ [weak self] in
                 self?.isSaveingLocalVideo = true
-                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: (self?.saveMovieLocalURL)!)
+                PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: (tempSaveMoveiLocal)!)
             }) { [weak self] isFinished, _ in
                 self?.isSaveingLocalVideo = false
                 DispatchQueue.main.async { [weak self] in
@@ -1327,7 +1340,8 @@ extension PQStuckPointPublicController {
             bottomOprationBgView.isHidden = false
             //add by ak 发布成功后如果带片尾的视频还没有生成成功时,出提示
             self.saveRetryBtn.isHidden = true
-            if(saveMovieLocalURL == nil && self.isSaveingLocalVideo){
+            self.saveVideoTipsBgView.isHidden = false
+            if(self.isSaveingLocalVideo){
                 saveVideoTipsLabel.text = "视频保存中..."
             }else{
                 self.saveVideoTipsLabel.text = "视频已保存到相册"
@@ -1486,9 +1500,9 @@ extension PQStuckPointPublicController {
 //        emptyRemindView.isHidden = true
         emptyRemindView.emptyData = emptyData
         emptyRemindView.backgroundColor = PQBFConfig.shared.styleBackGroundColor
-        emptyRemindView.fullRefreshBloc = {[weak self] _, _ in
-            if emptyRemindView.refreshBtn.currentAttributedTitle?.string == "立即重试" {
-                emptyRemindView.isHidden = true
+        emptyRemindView.fullRefreshBloc = {[weak self, weak emptyRemindView] _, _ in
+            if emptyRemindView?.refreshBtn.currentAttributedTitle?.string == "立即重试" {
+                emptyRemindView?.isHidden = true
                 // 重试逻辑
                 if let message = msg{
                     if message.contains("token") {

+ 8 - 4
BFFramework/Classes/Stuckpoint/View/PQCustomSpeedSettingView.swift

@@ -6,14 +6,14 @@
 //  功能:自定义速度界面
 
 import Foundation
-import BFUIKit
+import BFCommonKit
 
 class PQCustomSpeedSettingView: UIView {
     // 左上角返回
     lazy var backBtn: BFUIButton = {
         let backBtn = BFUIButton(type: .custom)
         backBtn.addTarget(self, action: #selector(backClick(sender:)), for: .touchUpInside)
-        backBtn.setImage(UIImage.moduleImage(named: "customSpeedClosed", moduleName: "BFFramework", isAssets: true), for: .normal)
+        backBtn.setImage(UIImage().BF_Image(named: "customSpeedClosed"), for: .normal)
         backBtn.adjustsImageWhenHighlighted = false
         return backBtn
     }()
@@ -54,13 +54,13 @@ class PQCustomSpeedSettingView: UIView {
 
     // 提示1
     lazy var customSpeedFastView: UIImageView = {
-        let customSpeedFastView = UIImageView(image: UIImage.moduleImage(named: "customSpeedFast", moduleName: "BFFramework", isAssets: false))
+        let customSpeedFastView = UIImageView(image: UIImage().BF_Image(named: "customSpeedFast"))
         return customSpeedFastView
     }()
 
     // 提示2
     lazy var customSpeedSlowView: UIImageView = {
-        let customSpeedSlowView = UIImageView(image: UIImage.moduleImage(named: "customSpeedSlow", moduleName: "BFFramework", isAssets: false))
+        let customSpeedSlowView = UIImageView(image: UIImage().BF_Image(named: "customSpeedSlow"))
         return customSpeedSlowView
     }()
 
@@ -257,7 +257,11 @@ class PQCustomSpeedSettingView: UIView {
         if selectSpeedCallBack != nil {
             if(viewType == 1){
                 selectSpeedCallBack!(fastSlider.value.decimalNumber(), slowSlider.value.decimalNumber(), viewType,false)
+            }else if(viewType == 2){
+                //跳跃模式时 支持小数值
+                selectSpeedCallBack!(jumpSpeedSlider.value, 0, viewType,false)
             }else{
+                //循环比时都是整数
                 selectSpeedCallBack!(jumpSpeedSlider.value.decimalNumber(0), 0, viewType,false)
             }
         

+ 15 - 18
BFFramework/Classes/Stuckpoint/View/PQStuckPointLoadingView.swift

@@ -13,19 +13,15 @@ import BFUIKit
 
 class PQStuckPointLoadingView: UIView {
     var cancelHandle: ((_ sender: UIButton) -> Void)?
+    
     /// 同步进度显示
-    lazy var loadingView: UIImageView = {
-        let loadingView = UIImageView()
-        loadingView.tintColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
-        let data = try? Data(contentsOf: URL(fileURLWithPath: currentBundlePath()!.path(forResource: "stuckPoint_edit_loading", ofType: ".gif")!))
-        if data != nil {
-            PQPHAssetVideoParaseUtil.parasGIFImage(data: data!, isRenderingColor: UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)) { _, images, duration in
-                loadingView.displayGIF(data: nil, images: images, repeatCount: .max, duration: duration ?? 2)
-            }
-        }
-        return loadingView
+    lazy var loadingView: AnimatedImageView = {
+        let videoLoadingView = AnimatedImageView()
+        videoLoadingView.kf.setImage(with: URL(fileURLWithPath: Bundle.main.path(forResource: "stuckPoint_edit_loading", ofType: ".gif")!))
+        videoLoadingView.stopAnimating()
+        return videoLoadingView
     }()
-
+ 
     lazy var navBarLeftBtn: UIButton = {
         let navBarLeftBtn = UIButton(type: .custom)
         navBarLeftBtn.frame = CGRect(x: 0, y: cDevice_iPhoneStatusBarHei, width: cDefaultMargin * 4, height: cDefaultMargin * 4)
@@ -43,6 +39,7 @@ class PQStuckPointLoadingView: UIView {
         addSubViews()
         addLayout()
         
+        loadingView.startAnimating()
     }
     
     required init?(coder _: NSCoder) {
@@ -76,20 +73,20 @@ class PQStuckPointLoadingView: UIView {
             return
         }
         UIApplication.shared.keyWindow?.addSubview(self)
-        let data = try? Data(contentsOf: URL(fileURLWithPath: currentBundlePath()!.path(forResource: "stuckPoint_edit_loading", ofType: ".gif")!))
-        if data != nil {
-            PQPHAssetVideoParaseUtil.parasGIFImage(data: data!, isRenderingColor: UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)) { _, images, duration in
-                self.loadingView.displayGIF(data: nil, images: images, repeatCount: .max, duration: duration ?? 2)
-            }
-        }
+        loadingView.startAnimating()
+
     }
 
     /// 移除视图
     /// - Returns: <#description#>
     func removeMarskView() {
+        loadingView.stopAnimating()
+     
         if self.superview != nil {
             removeFromSuperview()            
         }
+      
+        BFLog(message: "removeMarskViewremoveMarskViewremoveMarskViewremoveMarskView")
     }
 
     @objc func cancelDownload(sender: UIButton) {
@@ -100,6 +97,6 @@ class PQStuckPointLoadingView: UIView {
     }
 
     deinit {
-        BFLog(message: "销毁加载中视图")
+        BFLog(message: "销毁加载中视图1111111")
     }
 }

+ 37 - 30
BFFramework/Classes/Stuckpoint/ViewModel/PQGPUImagePlayerView.swift

@@ -130,7 +130,7 @@ public class PQGPUImagePlayerView: UIView {
     var mStickers: [PQEditVisionTrackMaterialsModel]? {
         didSet {
             
-            BFLog(2, message: "设置线程为: \(Thread.current) \(OperationQueue.current?.underlyingQueue?.label as Any)")
+            FilterLog(2, message: "设置线程为: \(Thread.current) \(OperationQueue.current?.underlyingQueue?.label as Any)")
         
             configCache(beginTime: mStickers?.first?.timelineIn ?? 0)
         }
@@ -149,6 +149,9 @@ public class PQGPUImagePlayerView: UIView {
     
     //是否显示高斯
     public  var showGaussianBlur:Bool = false
+    
+    //是否使用AVPlayer播放音乐
+    public var isUsedAVPlayer:Bool = false
 
     // 渲染区view
     private lazy var renderView: RenderView = {
@@ -298,7 +301,7 @@ public class PQGPUImagePlayerView: UIView {
     // 设置画布比例
     public func resetCanvasFrame(frame: CGRect) {
         if self.frame.equalTo(frame) {
-            BFLog(2, message: "新老值一样,不重置")
+            FilterLog(2, message: "新老值一样,不重置")
             return
         }
 
@@ -310,7 +313,7 @@ public class PQGPUImagePlayerView: UIView {
             showBorderLayer()
         }
 
-        BFLog(2, message: "new frame is \(frame)")
+        FilterLog(2, message: "new frame is \(frame)")
         renderView.isHidden = true
         renderView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
         renderView.resatSize()
@@ -357,21 +360,22 @@ public class PQGPUImagePlayerView: UIView {
         stop()
         movie = nil
         speaker = nil
-        BFLog(1, message: "play view release")
+        FilterLog(1, message: "play view release")
     }
 
     /// XXXX 这里的 URL 使用的是全路径 ,如果不是全的会 crash ,方便复用 (不用处理业务的文件放在哪里)
-    public func updateAsset(_ url: URL, videoComposition: AVVideoComposition? = nil, audioMixModel: PQVoiceModel? = nil, videoStickers: [PQEditVisionTrackMaterialsModel]? = nil,originMusicDuration:Float = 0,lastPoint:Float = 0,clipAudioRange: CMTimeRange = CMTimeRange.zero ) {
+    public func updateAsset(_ url: URL, videoComposition: AVVideoComposition? = nil, audioMixModel: PQVoiceModel? = nil, videoStickers: [PQEditVisionTrackMaterialsModel]? = nil,originMusicDuration:Float = 0,lastPoint:Float = 0,clipAudioRange: CMTimeRange = CMTimeRange.zero ,isUsedAVPlayer:Bool = false) {
+        self.isUsedAVPlayer = isUsedAVPlayer
         // 每次初始化的时候设置初始值 为 nIl
         var audioMix: AVMutableAudioMix?
         var composition: AVMutableComposition?
 
         let asset = AVURLAsset(url: url, options: nil)
-        BFLog(1, message:  "播放器初始化的音频时长\(asset.duration.seconds)  url is \(url),最终使用时长\(originMusicDuration),裁剪范围\(CMTimeGetSeconds(clipAudioRange.start)) 到 \(CMTimeGetSeconds(clipAudioRange.end))")
+        FilterLog(1, message:  "播放器初始化的音频时长\(asset.duration.seconds)  url is \(url),最终使用时长\(originMusicDuration),裁剪范围\(CMTimeGetSeconds(clipAudioRange.start)) 到 \(CMTimeGetSeconds(clipAudioRange.end))")
 
         self.asset = asset
         if (audioMixModel != nil && audioMixModel?.localPath != nil) || (videoStickers != nil && (videoStickers?.count ?? 0) > 0 || originMusicDuration != 0) {
-            BFLog(2, message: "有参加混音的数据。")
+            FilterLog(2, message: "有参加混音的数据。")
             (audioMix, composition) = PQPlayerViewModel.setupAudioMix(originAsset: asset, bgmData: audioMixModel, videoStickers: videoStickers,originMusicDuration:originMusicDuration,clipAudioRange: clipAudioRange)
         } else {
             audioMix = nil
@@ -393,7 +397,7 @@ public class PQGPUImagePlayerView: UIView {
 //        }
         do {
             if composition != nil {
-                BFLog(2, message: "composition 方式初始化")
+                FilterLog(2, message: "composition 方式初始化")
                 movie = try PQMovieInput(asset: composition!, videoComposition: videoComposition, audioMix: audioMix, playAtActualSpeed: true, loop: isLoop, audioSettings: audioSettings)
 //                movie?.exportAudioUrl = url // clipAudioRange
                 var ranges = Array<CMTimeRange>()
@@ -417,6 +421,8 @@ public class PQGPUImagePlayerView: UIView {
 
             movie!.runBenchmark = false
             movie!.synchronizedEncodingDebug = false
+            
+            movie!.isUsedAVPlayer = isUsedAVPlayer
 
         } catch {
             status = .error
@@ -428,7 +434,7 @@ public class PQGPUImagePlayerView: UIView {
         movie.progress = { [weak self] currTime, duration, prgressValue in
             guard let strongSelf = self else { return }
 
-//            BFLog(1, message: " movie 进度\(currTime)")
+//            FilterLog(1, message: " movie 进度\(currTime)")
             strongSelf.changeFilter(currTime: currTime)
             strongSelf.progress?(currTime, duration, prgressValue)
 
@@ -483,11 +489,11 @@ public class PQGPUImagePlayerView: UIView {
     /// - Parameter beginTime: 开始缓存的开始时间,用在 seek操作时 老的缓存已经无效不能在使用了
     func configCache(beginTime: Float64 ) {
         cacheFilters.removeAll()
-        BFLog(2, message: "原素材 总数:\(mStickers?.count ?? 0) ")
+        FilterLog(2, message: "原素材 总数:\(mStickers?.count ?? 0) ")
        
         if mStickers?.count ?? 0 > 0 {
             for (index, currentSticker) in mStickers!.enumerated() {
-                BFLog(message: "mStickers timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) index : \(index)")
+                FilterLog(message: "mStickers timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) index : \(index)")
                //到达最大缓存数退出
                 if cacheFilters.count == cacheFiltersMaxCount {
                     break
@@ -505,7 +511,7 @@ public class PQGPUImagePlayerView: UIView {
                   
                 }
                 if showFitler != nil {
-                    BFLog(message: " 加入到缓存 的 filter timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) in :\(currentSticker.model_in) out: \(currentSticker.out) index : \(index)")
+                    FilterLog(message: " 加入到缓存 的 filter timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) in :\(currentSticker.model_in) out: \(currentSticker.out) index : \(index)")
                     cacheFilters.append(showFitler!)
                 }
 
@@ -513,7 +519,7 @@ public class PQGPUImagePlayerView: UIView {
             
             
             for (index, filter) in cacheFilters.enumerated() {
-                BFLog(2, message: " 初始化 config create currentSticker timelinein \(String(describing: filter.stickerInfo?.timelineIn)) timelineout \(String(describing: filter.stickerInfo?.timelineOut))  in :\(String(describing: filter.stickerInfo?.model_in)) out \(String(describing: filter.stickerInfo?.out))  index\(index)")
+                FilterLog(2, message: " 初始化 config create currentSticker timelinein \(String(describing: filter.stickerInfo?.timelineIn)) timelineout \(String(describing: filter.stickerInfo?.timelineOut))  in :\(String(describing: filter.stickerInfo?.model_in)) out \(String(describing: filter.stickerInfo?.out))  index\(index)")
             }
             
             if(cacheFilters.first != nil){
@@ -529,12 +535,12 @@ public class PQGPUImagePlayerView: UIView {
 
     //创建下一个filter 数据
     func createNextFilter() {
-        BFLog(2, message: "加入前 当前的缓存个数为: \(cacheFilters.count)  maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
+        FilterLog(2, message: "加入前 当前的缓存个数为: \(cacheFilters.count)  maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
           if cacheFilters.count <=  cacheFiltersMaxCount {
               let showIndex = mStickers?.firstIndex(where: { (sticker) -> Bool in
                 (cacheFilters.last?.stickerInfo == sticker)
               })
-                BFLog(2, message: "当前显示的showIndex: \(String(describing: showIndex))")
+                FilterLog(2, message: "当前显示的showIndex: \(String(describing: showIndex))")
               if ((showIndex ?? 0) + 1) < (mStickers?.count ?? 0) {
                   let currentSticker = mStickers?[(showIndex ?? 0) + 1]
                   if currentSticker != nil {
@@ -550,11 +556,11 @@ public class PQGPUImagePlayerView: UIView {
                           cacheFilters.append(showFitler!)
                       }
                   }else{
-                    BFLog(2, message: "缓存数据加入不成功!!!!!")
+                    FilterLog(2, message: "缓存数据加入不成功!!!!!")
                   }
               }
             
-            BFLog(2, message: "加入后 当前的缓存个数为: \(cacheFilters.count)  maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
+            FilterLog(2, message: "加入后 当前的缓存个数为: \(cacheFilters.count)  maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
              
           }
         
@@ -566,7 +572,7 @@ public class PQGPUImagePlayerView: UIView {
     /// - Parameter currTime: 当前播放时间
     func changeFilter(currTime: Float64) {
 //        let  starts:CFTimeInterval = CFAbsoluteTimeGetCurrent()
-        BFLog(message: " 要查找的 currTime is \(currTime)")
+        FilterLog(message: " 要查找的 currTime is \(currTime)")
         //1,删除已经显示过的 filter
         self.cacheFilters.removeAll(where: {(filter) -> Bool in
 
@@ -580,16 +586,16 @@ public class PQGPUImagePlayerView: UIView {
 
         })
         if(showIndex == nil){
-            BFLog(2, message: "缓存没有查找到?出现数据错误!!!!")
+            FilterLog(2, message: "缓存没有查找到?出现数据错误!!!!")
             return
         }
   
         let showFilter: PQBaseFilter = cacheFilters[showIndex ?? 0]
         
-        BFLog(2, message: "缓存操作   查找到命中的显示是为:\(currTime) 缓存数据timeline in :\(showFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(showFilter.stickerInfo?.timelineOut ?? 0.0) in:\(showFilter.stickerInfo?.model_in ?? 0.0) out:\(showFilter.stickerInfo?.out ?? 0.0) 缓存数 \(cacheFilters.count) index: \(String(describing: showIndex))")
+        FilterLog(2, message: "缓存操作   查找到命中的显示是为:\(currTime) 缓存数据timeline in :\(showFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(showFilter.stickerInfo?.timelineOut ?? 0.0) in:\(showFilter.stickerInfo?.model_in ?? 0.0) out:\(showFilter.stickerInfo?.out ?? 0.0) 缓存数 \(cacheFilters.count) index: \(String(describing: showIndex))")
         
         if(!(showFilter.isShow)){
-            BFLog(2, message: "showIndex当前时间为  \(currTime) showIndex is \(String(describing: showIndex)) 显示 filter timelineIn is: \(String(describing: showFilter.stickerInfo?.timelineIn)) timelineOut is: \(String(describing: showFilter.stickerInfo?.timelineOut))")
+            FilterLog(2, message: "showIndex当前时间为  \(currTime) showIndex is \(String(describing: showIndex)) 显示 filter timelineIn is: \(String(describing: showFilter.stickerInfo?.timelineIn)) timelineOut is: \(String(describing: showFilter.stickerInfo?.timelineOut))")
  
             showFilter.isShow = true
             
@@ -601,13 +607,13 @@ public class PQGPUImagePlayerView: UIView {
             //画面的比例
             let canverAspectRatio = String(format: "%.6f",(movie?.mShowVidoSize.width ?? 0.0) /  (movie?.mShowVidoSize.height ?? 0.0))
             if(showFilter.stickerInfo?.type == StickerType.IMAGE.rawValue && showGaussianBlur && Float(stickerAspectRatio) != Float(canverAspectRatio)){
-                      BFLog(2, message: "显示图片filter")
+                      FilterLog(2, message: "显示图片filter")
 //                    //高斯层
                         let  blurStickerModel:PQEditVisionTrackMaterialsModel? = showFilter.stickerInfo?.copy() as? PQEditVisionTrackMaterialsModel
                         blurStickerModel?.canvasFillType = stickerContentMode.aspectFillStr.rawValue
 
                         if blurStickerModel == nil {
-                            BFLog(2, message: "显示图片filter blurStickerModel is nil")
+                            FilterLog(2, message: "显示图片filter blurStickerModel is nil")
                             return
                         }
                         let showGaussianFitler:PQBaseFilter = PQImageFilter(sticker: blurStickerModel!, isExport: (movie?.mIsExport) ?? false, showUISize: mCanverSize)
@@ -620,7 +626,7 @@ public class PQGPUImagePlayerView: UIView {
                         iosb.addTarget(showFilter,atTargetIndex: 0)
                         showFilter.addTarget(self.renderView as ImageConsumer, atTargetIndex: 0)
                 
-                        BFLog(2, message: "filter 添加成功 注意是否添加成功。")
+                        FilterLog(2, message: "filter 添加成功 注意是否添加成功。")
                         
 //                    }
  
@@ -634,7 +640,7 @@ public class PQGPUImagePlayerView: UIView {
             }
 
         }else{
-            BFLog(2, message: " 添加过了 currTime is \(currTime) timelineIn:\(showFilter.stickerInfo?.timelineIn ?? 0.0)")
+            FilterLog(2, message: " 添加过了 currTime is \(currTime) timelineIn:\(showFilter.stickerInfo?.timelineIn ?? 0.0)")
         }
     }
 
@@ -672,7 +678,7 @@ public extension PQGPUImagePlayerView {
             self.progressLab.isHidden = false
         }
 //        guard status != .playing else {
-//            BFLog(2, message: "已经是播放状态")
+//            FilterLog(2, message: "已经是播放状态")
 //            return
 //        }
 
@@ -719,6 +725,7 @@ public extension PQGPUImagePlayerView {
         //            return
         //        }
 
+        movie?.removeAllTargets()
         movie?.cancel()
         speaker?.cancel()
         status = .stop
@@ -733,7 +740,7 @@ public extension PQGPUImagePlayerView {
 
     // 显示提示文字
     func showTip(show: Bool) {
-        BFLog(2, message: "showTip \(show)")
+        FilterLog(2, message: "showTip \(show)")
         tipLab.isHidden = !show
         if show {
             playerEmptyView.isHidden = true
@@ -773,15 +780,15 @@ public extension PQGPUImagePlayerView {
 // MARK: - RenderViewDelegate
 extension PQGPUImagePlayerView: RenderViewDelegate{
     public func willDisplayFramebuffer(renderView _: RenderView, framebuffer _: Framebuffer) {
-        BFLog(2, message: "willDisplayFramebuffer")
+        FilterLog(2, message: "willDisplayFramebuffer")
     }
 
     public func didDisplayFramebuffer(renderView _: RenderView, framebuffer: Framebuffer) {
-        BFLog(2, message: "didDisplayFramebuffer")
+        FilterLog(2, message: "didDisplayFramebuffer")
     }
 
     public func shouldDisplayNextFramebufferAfterMainThreadLoop() -> Bool {
-        BFLog(2, message: "didDisplayFramebuffer")
+        FilterLog(2, message: "didDisplayFramebuffer")
         
         return false
     }

+ 8 - 8
BFFramework/Classes/selectImage/PQUploadController.swift

@@ -539,20 +539,20 @@ extension PQUploadController: UICollectionViewDelegate, UICollectionViewDataSour
                 cell.uploadData = itemData
                 if itemData.image == nil, itemData.asset != nil {
                     cell.representedAssetIdentifier = itemData.asset?.localIdentifier
-                    imageManager.requestImage(for: itemData.asset!, targetSize: itemSize, contentMode: .aspectFill, options: nil) { image, info in
-                        if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell.representedAssetIdentifier == itemData.asset?.localIdentifier {
+                    imageManager.requestImage(for: itemData.asset!, targetSize: itemSize, contentMode: .aspectFill, options: nil) {[weak self, weak cell] image, info in
+                        if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell?.representedAssetIdentifier == itemData.asset?.localIdentifier {
                             if image != nil {
                                 itemData.image = image
-                                cell.videoImageView.image = image
+                                cell?.videoImageView.image = image
                             } else if image == nil, info?.keys.contains("PHImageResultIsInCloudKey") ?? false {
                                 let option = PHImageRequestOptions()
                                 option.isNetworkAccessAllowed = true
                                 option.resizeMode = .fast
-                                self.imageManager.requestImageData(for: itemData.asset!, options: option) { data, _, _, _ in
+                                self?.imageManager.requestImageData(for: itemData.asset!, options: option) { [weak cell] data, _, _, _ in
                                     if data != nil {
                                         let image = UIImage(data: data!)
                                         itemData.image = image
-                                        cell.videoImageView.image = image
+                                        cell?.videoImageView.image = image
                                     }
                                 }
                             }
@@ -569,10 +569,10 @@ extension PQUploadController: UICollectionViewDelegate, UICollectionViewDataSour
             let asset = itemData.categoryList.object(at: 0)
             if itemData.image == nil {
                 cell.representedAssetIdentifier = asset.localIdentifier
-                imageManager.requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil) { image, info in
-                    if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell.representedAssetIdentifier == asset.localIdentifier {
+                imageManager.requestImage(for: asset, targetSize: itemSize, contentMode: .aspectFill, options: nil) { [weak cell] image, info in
+                    if info?.keys.contains("PHImageResultIsDegradedKey") ?? false, "\(info?["PHImageResultIsDegradedKey"] ?? "0")" == "0", cell?.representedAssetIdentifier == asset.localIdentifier {
                         itemData.image = image
-                        cell.uploadData = itemData
+                        cell?.uploadData = itemData
                     }
                 }
             } else {

+ 3 - 3
Example/Podfile

@@ -5,8 +5,8 @@ platform :ios, '10.0'
 target 'BFFramework_Example' do
   source 'https://git.yishihui.com/iOS/BFSpecs.git'
   source 'https://github.com/CocoaPods/Specs.git'
-  pod 'BFCommonKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFCommonKit/'
-  pod 'BFNetRequestKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFNetRequestKit/'
-  pod 'BFMaterialKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFMaterialKit/'
+#  pod 'BFCommonKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFCommonKit/'
+#  pod 'BFNetRequestKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFNetRequestKit/'
+#  pod 'BFMaterialKit', :path => '/Users/sanw/Desktop/BytesFlow/Person/Projects/BFMaterialKit/'
   pod 'BFFramework', :path => '../'
 end

+ 19 - 24
Example/Podfile.lock

@@ -31,16 +31,16 @@ PODS:
     - KingfisherWebP (= 1.3.0)
     - Toast-Swift (= 5.0.1)
   - BFFramework (1.0.7):
-    - AliyunOSSiOS (= 2.10.10)
+    - AliyunOSSiOS
     - BFCommonKit
     - BFMaterialKit
     - BFNetRequestKit
-    - Bugly (= 2.5.90)
-    - LMJHorizontalScrollText (= 2.0.2)
-    - MJRefresh (= 3.7.2)
-    - ObjectMapper (= 4.2.0)
-    - TXLiteAVSDK_Player (= 9.1.10564)
-    - WechatOpenSDK-Swift (= 1.8.7.1)
+    - Bugly
+    - LMJHorizontalScrollText
+    - MJRefresh
+    - ObjectMapper
+    - TXLiteAVSDK_Player
+    - WechatOpenSDK-Swift
   - BFMaterialKit (0.1.6):
     - BFCommonKit
   - BFNetRequestKit (0.2.3):
@@ -71,16 +71,17 @@ PODS:
     - Realm (= 10.7.6)
   - SnapKit (5.0.1)
   - Toast-Swift (5.0.1)
-  - TXLiteAVSDK_Player (9.1.10564)
+  - TXLiteAVSDK_Player (9.2.10637)
   - WechatOpenSDK-Swift (1.8.7.1)
 
 DEPENDENCIES:
-  - BFCommonKit (from `/Users/sanw/Desktop/BytesFlow/Person/Projects/BFCommonKit/`)
   - BFFramework (from `../`)
-  - BFMaterialKit (from `/Users/sanw/Desktop/BytesFlow/Person/Projects/BFMaterialKit/`)
-  - BFNetRequestKit (from `/Users/sanw/Desktop/BytesFlow/Person/Projects/BFNetRequestKit/`)
 
 SPEC REPOS:
+  https://git.yishihui.com/iOS/BFSpecs.git:
+    - BFCommonKit
+    - BFMaterialKit
+    - BFNetRequestKit
   https://github.com/CocoaPods/Specs.git:
     - Alamofire
     - AliyunOSSiOS
@@ -101,22 +102,16 @@ SPEC REPOS:
     - WechatOpenSDK-Swift
 
 EXTERNAL SOURCES:
-  BFCommonKit:
-    :path: "/Users/sanw/Desktop/BytesFlow/Person/Projects/BFCommonKit/"
   BFFramework:
     :path: "../"
-  BFMaterialKit:
-    :path: "/Users/sanw/Desktop/BytesFlow/Person/Projects/BFMaterialKit/"
-  BFNetRequestKit:
-    :path: "/Users/sanw/Desktop/BytesFlow/Person/Projects/BFNetRequestKit/"
 
 SPEC CHECKSUMS:
   Alamofire: e447a2774a40c996748296fa2c55112fdbbc42f9
   AliyunOSSiOS: b8f1dfc229cd9abf68c8ee0cb245c2d66e00dd96
-  BFCommonKit: 61380c2c5d74333d4a60fe52a3321c937b2a1f06
-  BFFramework: 8f1f60ab704eeb51a4da6828588f8da24ab85faa
-  BFMaterialKit: 920e502d41b995c9959199e513b64ae780f52ae5
-  BFNetRequestKit: 5743bcafb3f70502137780461b53d71c05b1d01e
+  BFCommonKit: ae9792ba766f4fad177cd826554a4f6feab5f9cd
+  BFFramework: c821f4a61057287a3c60ea3ce7498ccf57542de1
+  BFMaterialKit: ee4db6e76fdb94af810bc2d098a58ec15e18b2bf
+  BFNetRequestKit: 2af2279251e5304f34ca02771f74328f62fa7b6f
   Bugly: 88bc32c0acc6fef7b74d610f0319ee7560d6b9fe
   FDFullscreenPopGesture: a8a620179e3d9c40e8e00256dcee1c1a27c6d0f0
   KeychainAccess: c0c4f7f38f6fc7bbe58f5702e25f7bd2f65abf51
@@ -130,9 +125,9 @@ SPEC CHECKSUMS:
   RealmSwift: e31c4ddbcc42ac879313d656b86f9ca539f6f4f4
   SnapKit: 97b92857e3df3a0c71833cce143274bf6ef8e5eb
   Toast-Swift: 9b6a70f28b3bf0b96c40d46c0c4b9d6639846711
-  TXLiteAVSDK_Player: b4e91267f601a9cadf265ed4a903816e995ba57a
+  TXLiteAVSDK_Player: 300e6fc7262ae095ee13b18d7d821c5fae0996f9
   WechatOpenSDK-Swift: 18a8f7b12e745c30acc013f72a9f8a25aad6e216
 
-PODFILE CHECKSUM: 0566a3fccd1ba8303834811529466910b942b3bf
+PODFILE CHECKSUM: a70d2c425de0713c3557fd13b3dec4e634e32f2a
 
-COCOAPODS: 1.10.2
+COCOAPODS: 1.11.2