PQGPUImagePlayerView.swift 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. //
  2. // PQGPUImagePlayer.swift
  3. // GPUImage_iOS
  4. //
  5. // Created by ak on 2020/8/27.
  6. // Copyright © 2020 Sunset Lake Software LLC. All rights reserved.
  7. // 功能:滤镜播放器 支持音频 https://juejin.im/post/6844904024760664078 这个有用
  8. import AVFoundation
  9. import AVKit
  10. import UIKit
  11. import ObjectMapper
  12. // import GPUImage
  13. struct AVAssetKey {
  14. static let tracks = "tracks"
  15. static let duration = "duration"
  16. static let metadata = "commonMetadata"
  17. }
  18. // 播放器状态
  19. public enum PQGPUImagePlayerViewStatus: Int {
  20. case playing = 10
  21. case pause = 20
  22. case stop = 30
  23. case error = 0
  24. case unknow = -1000
  25. }
  26. public class PQGPUImagePlayerView: UIView {
  27. public private(set) var playbackTime: TimeInterval = 0 {
  28. willSet {
  29. playbackTimeChangeClosure?(newValue)
  30. }
  31. }
  32. public var mCanverSize: Size = Size(width: 0, height: 0)
  33. // 自动隐藏边框
  34. public var isAutoHiden: Bool = false
  35. // 是否显示边框
  36. public var isShowLine: Bool = true
  37. // 播放进度
  38. public var playbackTimeChangeClosure: ((_ time: TimeInterval) -> Void)?
  39. // 参数说明:1,当前时间 2,总时长 3,进度
  40. public var progress: ((Double, Double, Double) -> Void)?
  41. /// 预览区域点击回调
  42. public var renderViewOnClickHandle: (() -> Void)?
  43. public private(set) var asset: AVAsset?
  44. public var duration: TimeInterval {
  45. return asset?.duration.seconds ?? 0
  46. }
  47. public private(set) var status: PQGPUImagePlayerViewStatus = .unknow {
  48. willSet {
  49. statusChangeClosure?(newValue)
  50. }
  51. }
  52. public var statusChangeClosure: ((_ status: PQGPUImagePlayerViewStatus) -> Void)?
  53. public private(set) var isReadyToPlay = false {
  54. willSet {
  55. assetLoadClosure?(newValue)
  56. }
  57. }
  58. public var assetLoadClosure: ((_ isReadyToPlay: Bool) -> Void)?
  59. /// Called when video finished
  60. /// This closure will not called if isLoop is true
  61. public var finishedClosure: (() -> Void)?
  62. /// Set this attribute to true will print debug info
  63. public var enableDebug = false {
  64. willSet {
  65. movie?.runBenchmark = newValue
  66. }
  67. }
  68. /// Setting this attribute before the end of the video works
  69. public var isLoop = false {
  70. willSet {
  71. movie?.loop = newValue
  72. }
  73. }
  74. /// The player will control the animationLayer of animation with the property `timeOffset`
  75. /// You can set up some animations in this layer like caption
  76. public var animationLayer: CALayer? {
  77. willSet {
  78. // Set speed to 0, use timeOffset to control the animation
  79. newValue?.speed = 0
  80. newValue?.timeOffset = playbackTime
  81. }
  82. didSet {
  83. oldValue?.removeFromSuperlayer()
  84. }
  85. }
  86. /// Add filters to this array and call updateAsset(_:) method
  87. public var filters: [ImageProcessingOperation] = []
  88. public var movie: PQMovieInput?
  89. public var speaker: SpeakerOutput?
  90. /// Volumn of original sounds in AVAsset
  91. public var originVolumn: Float = 1.0 {
  92. didSet {}
  93. }
  94. public var playerLayer: AVPlayerLayer?
  95. public var player: AVPlayer?
  96. public var playerEmptyView: UIImageView!
  97. public var borderLayer: CAShapeLayer?
  98. public var mPlayeTimeRange: CMTimeRange?
  99. var mStickers: [PQEditVisionTrackMaterialsModel]? {
  100. didSet {
  101. FilterLog(message: "设置线程为: \(Thread.current) \(OperationQueue.current?.underlyingQueue?.label as Any)")
  102. configCache(beginTime: mStickers?.first?.timelineIn ?? 0)
  103. }
  104. }
  105. // 是否显示时间条
  106. var showProgressLab: Bool = true
  107. // 缓存创建filter 防止 seek 100ms 慢
  108. @Atomic var cacheFilters: Array<PQBaseFilter> = Array()
  109. // 缓存个数
  110. var cacheFiltersMaxCount: Int = 8
  111. /// Use serial queue to ensure that the picture is smooth
  112. var createFiltersQueue: DispatchQueue!
  113. //是否显示高斯
  114. public var showGaussianBlur:Bool = false
  115. // 渲染区view
  116. private lazy var renderView: RenderView = {
  117. let view = RenderView()
  118. view.backgroundColor = PQBFConfig.shared.styleBackGroundColor
  119. view.frame = self.bounds
  120. view.delegate = self
  121. let tap = UITapGestureRecognizer(target: self, action: #selector(RenderViewOnclick))
  122. view.addGestureRecognizer(tap)
  123. return view
  124. }()
  125. // 暂停播放view
  126. lazy var playView: UIImageView = {
  127. let view = UIImageView(frame: CGRect(x: (self.frame.size.width - self.frame.size.height / 3.6) / 2, y: (self.frame.size.height - self.frame.size.height / 3.6) / 2, width: self.frame.size.height / 3.6, height: self.frame.size.height / 3.6))
  128. view.image = UIImage().BF_Image(named: "gpuplayBtn").withRenderingMode(.alwaysTemplate)
  129. view.tintColor = UIColor.hexColor(hexadecimal: PQBFConfig.shared.styleColor.rawValue)
  130. view.isHidden = true
  131. return view
  132. }()
  133. // 暂停播放view
  134. lazy var playMaskView: UIView = {
  135. let playMaskView = UIView.init()
  136. playMaskView.backgroundColor = UIColor.init(red: 1, green: 1, blue: 1, alpha: 0.5)
  137. playMaskView.isUserInteractionEnabled = false
  138. playMaskView.isHidden = true
  139. return playMaskView
  140. }()
  141. // 播放进度/总时长
  142. lazy var progressLab: UILabel = {
  143. let titleLab = UILabel(frame: CGRect(x: (self.frame.size.width - 140) / 2, y: self.frame.size.height - 10 - 14, width: 140, height: 14))
  144. titleLab.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  145. titleLab.textColor = UIColor.white
  146. titleLab.textAlignment = .center
  147. titleLab.text = ""
  148. titleLab.layer.shadowColor = UIColor.black.cgColor
  149. titleLab.layer.shadowOpacity = 0.3
  150. titleLab.layer.shadowOffset = .zero
  151. titleLab.layer.shadowRadius = 1
  152. // titleLab.backgroundColor = UIColor.hexColor(hexadecimal: "#FFFFFF",alpha: 0.3)
  153. // titleLab.addCorner(corner:7)
  154. return titleLab
  155. }()
  156. lazy var tipLab: UILabel = {
  157. let tipLab = UILabel(frame: CGRect(x: (self.frame.size.width - 100) / 2, y: (self.frame.size.height - 14) / 2, width: 100, height: 14))
  158. tipLab.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  159. tipLab.textColor = UIColor.white
  160. tipLab.textAlignment = .center
  161. tipLab.text = "资源加载中..."
  162. tipLab.layer.shadowColor = UIColor.white.cgColor
  163. tipLab.layer.shadowOpacity = 0.5
  164. tipLab.layer.shadowOffset = .zero
  165. tipLab.layer.shadowRadius = 1
  166. tipLab.isHidden = true
  167. return tipLab
  168. }()
  169. required public init?(coder _: NSCoder) {
  170. fatalError("init(coder:) has not been implemented")
  171. }
  172. //进度的开始时间
  173. var showProgressStartTime:Float = 0.0
  174. override public init(frame: CGRect) {
  175. super.init(frame: frame)
  176. addSubview(renderView)
  177. addSubview(progressLab)
  178. addSubview(playMaskView)
  179. addSubview(playView)
  180. backgroundColor = PQBFConfig.shared.styleBackGroundColor
  181. playerEmptyView = UIImageView(frame: bounds)
  182. playerEmptyView.backgroundColor = .black
  183. playerEmptyView.image = UIImage().BF_Image(named: "playEmpty")
  184. playerEmptyView.contentMode = .center
  185. addSubview(playerEmptyView)
  186. addSubview(tipLab)
  187. if #available(iOS 10.0, *) {
  188. createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .default, attributes: .initiallyInactive, autoreleaseFrequency: .never, target: nil)
  189. } else {
  190. createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .userInteractive, attributes: [], autoreleaseFrequency: .inherit, target: nil)
  191. }
  192. if #available(iOS 10.0, *) {
  193. createFiltersQueue.activate()
  194. }
  195. }
  196. func showBorderLayer() {
  197. if borderLayer != nil {
  198. borderLayer?.removeFromSuperlayer()
  199. }
  200. // 线条颜色
  201. borderLayer = CAShapeLayer()
  202. borderLayer?.strokeColor = UIColor.hexColor(hexadecimal: "#FFFFFF").cgColor
  203. borderLayer?.fillColor = nil
  204. borderLayer?.path = UIBezierPath(rect: CGRect(x: 1, y: 1, width: bounds.width - 2, height: bounds.height - 2)).cgPath
  205. borderLayer?.frame = bounds
  206. borderLayer?.lineWidth = 2.0
  207. borderLayer?.lineCap = .round
  208. // 第一位是 线条长度 第二位是间距 nil时为实线
  209. if borderLayer != nil {
  210. renderView.layer.addSublayer(borderLayer!)
  211. }
  212. if isAutoHiden {
  213. borderLayer?.opacity = 0
  214. let groupAnimation = CAAnimationGroup()
  215. groupAnimation.beginTime = CACurrentMediaTime()
  216. groupAnimation.duration = 1
  217. groupAnimation.fillMode = .forwards
  218. groupAnimation.isRemovedOnCompletion = true
  219. groupAnimation.repeatCount = 3
  220. let opacity = CABasicAnimation(keyPath: "opacity")
  221. opacity.fromValue = 0
  222. opacity.toValue = 1
  223. opacity.isRemovedOnCompletion = true
  224. let opacity2 = CABasicAnimation(keyPath: "opacity")
  225. opacity2.fromValue = 1
  226. opacity2.toValue = 0
  227. opacity2.isRemovedOnCompletion = false
  228. groupAnimation.animations = [opacity, opacity2]
  229. borderLayer?.add(groupAnimation, forKey: nil)
  230. }
  231. }
  232. // 设置画布比例
  233. public func resetCanvasFrame(frame: CGRect) {
  234. if self.frame.equalTo(frame) {
  235. FilterLog(message: "新老值一样,不重置")
  236. return
  237. }
  238. self.frame = frame
  239. if isShowLine {
  240. showBorderLayer()
  241. }
  242. FilterLog(message: "new frame is \(frame)")
  243. renderView.isHidden = true
  244. renderView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
  245. renderView.resatSize()
  246. playerEmptyView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
  247. playMaskView.frame = CGRect.init(x: 0, y: 0, width: self.frame.width, height: self.frame.height)
  248. tipLab.frame = CGRect(x: (self.frame.size.width - 100) / 2, y: (self.frame.size.height - 14) / 2, width: 100, height: 14)
  249. progressLab.frame = CGRect(x: (self.frame.size.width - 140) / 2, y: self.frame.size.height - 10 - 14, width: 140, height: 14)
  250. playView.frame = CGRect(x: (self.frame.size.width - self.frame.size.height / 3.6) / 2, y: (self.frame.size.height - self.frame.size.height / 3.6) / 2, width: self.frame.size.height / 3.6, height: self.frame.size.height / 3.6)
  251. }
  252. override public func layoutSubviews() {
  253. super.layoutSubviews()
  254. }
  255. @objc func RenderViewOnclick() {
  256. if status == .playing {
  257. playView.isHidden = false
  258. playMaskView.isHidden = false
  259. pause()
  260. } else if status == .stop || status == .pause {
  261. playView.isHidden = true
  262. playMaskView.isHidden = true
  263. movie?.resume()
  264. speaker?.start()
  265. status = .playing
  266. }
  267. if renderViewOnClickHandle != nil {
  268. renderViewOnClickHandle!()
  269. }
  270. }
  271. func showPlayBtn(isHidden: Bool) {
  272. playView.isHidden = isHidden
  273. playMaskView.isHidden = isHidden
  274. }
  275. deinit {
  276. stop()
  277. movie = nil
  278. speaker = nil
  279. }
  280. /// XXXX 这里的 URL 使用的是全路径 ,如果不是全的会 crash ,方便复用 (不用处理业务的文件放在哪里)
  281. public func updateAsset(_ url: URL, videoComposition: AVVideoComposition? = nil, audioMixModel: PQVoiceModel? = nil, videoStickers: [PQEditVisionTrackMaterialsModel]? = nil,originMusicDuration:Float = 0,lastPoint:Float = 0,clipAudioRange: CMTimeRange = CMTimeRange.zero ) {
  282. // 每次初始化的时候设置初始值 为 nIl
  283. var audioMix: AVMutableAudioMix?
  284. var composition: AVMutableComposition?
  285. let asset = AVURLAsset(url: url, options: nil)
  286. FilterLog(message: "播放器初始化的音频时长\(asset.duration.seconds) url is \(url)")
  287. self.asset = asset
  288. if (audioMixModel != nil && audioMixModel?.localPath != nil) || (videoStickers != nil && (videoStickers?.count ?? 0) > 0 || originMusicDuration != 0) {
  289. FilterLog(message: "有参加混音的数据。")
  290. (audioMix, composition) = PQPlayerViewModel.setupAudioMix(originAsset: asset, bgmData: audioMixModel, videoStickers: videoStickers,originMusicDuration:originMusicDuration,clipAudioRange: clipAudioRange)
  291. } else {
  292. audioMix = nil
  293. }
  294. isReadyToPlay = false
  295. asset.loadValuesAsynchronously(forKeys: ["tracks", "duration", "commonMetadata"]) { [weak self] in
  296. guard let strongSelf = self else { return }
  297. let tracksStatus = strongSelf.asset?.statusOfValue(forKey: AVAssetKey.tracks, error: nil) ?? .unknown
  298. let durationStatus = strongSelf.asset?.statusOfValue(forKey: AVAssetKey.duration, error: nil) ?? .unknown
  299. strongSelf.isReadyToPlay = tracksStatus == .loaded && durationStatus == .loaded
  300. }
  301. var audioSettings: [String: Any] = [
  302. AVFormatIDKey: kAudioFormatLinearPCM,
  303. ]
  304. if #available(iOS 14.0, *) {
  305. audioSettings[AVLinearPCMIsFloatKey] = false
  306. audioSettings[AVLinearPCMBitDepthKey] = 16
  307. }
  308. do {
  309. if composition != nil {
  310. FilterLog(message: "composition 方式初始化")
  311. movie = try PQMovieInput(asset: composition!, videoComposition: videoComposition, audioMix: audioMix, playAtActualSpeed: true, loop: isLoop, audioSettings: audioSettings)
  312. } else {
  313. movie = try PQMovieInput(url: url, playAtActualSpeed: true, loop: isLoop, audioSettings: audioSettings)
  314. /* 测试代码
  315. let audioDecodeSettings = [AVFormatIDKey:kAudioFormatLinearPCM]
  316. let bundleURL = Bundle.main.resourceURL!
  317. let movieURL = URL(string:"11111.mp4", relativeTo:bundleURL)!
  318. movie = try MovieInput(url:movieURL, playAtActualSpeed:true, loop:true, audioSettings:audioDecodeSettings)
  319. */
  320. }
  321. movie!.runBenchmark = false
  322. movie!.synchronizedEncodingDebug = false
  323. } catch {
  324. status = .error
  325. if enableDebug {
  326. debugPrint(error)
  327. }
  328. }
  329. guard let movie = movie else { return }
  330. movie.progress = { [weak self, movie] currTime, duration, prgressValue in
  331. guard let strongSelf = self else { return }
  332. FilterLog(message: " movie.currentTime.seconds 进度\(movie.currentTime.seconds)")
  333. self?.changeFilter(currTime: movie.currentTime.seconds)
  334. self?.progress?(currTime, duration, prgressValue)
  335. DispatchQueue.main.async {
  336. strongSelf.playbackTime = movie.currentTime.seconds
  337. // Non-main thread change this property is not valid
  338. strongSelf.animationLayer?.timeOffset = strongSelf.playbackTime
  339. if strongSelf.showProgressLab {
  340. if(strongSelf.showProgressStartTime == 0 ){
  341. strongSelf.showProgressStartTime = Float(CMTimeGetSeconds(movie.startTime ?? .zero))
  342. }
  343. if duration < 1 {
  344. strongSelf.progressLab.text = "\((currTime - Double(CMTimeGetSeconds(movie.startTime ?? .zero))).formatDurationToHMS()) / 00:01"
  345. } else {
  346. strongSelf.progressLab.text = "\((currTime - Double(strongSelf.showProgressStartTime)).formatDurationToHMS()) / \( (duration - Double(strongSelf.showProgressStartTime)).formatDurationToHMS())"
  347. }
  348. }
  349. }
  350. }
  351. movie.completion = { [weak self] in
  352. guard let strongSelf = self else { return }
  353. //缓存已经用完,重新初始化缓存
  354. if(strongSelf.filters.count == 0){
  355. strongSelf.configCache(beginTime: strongSelf.mStickers?.first?.timelineIn ?? 0)
  356. }
  357. DispatchQueue.main.async {
  358. strongSelf.status = .stop
  359. strongSelf.finishedClosure?()
  360. strongSelf.showPlayBtn(isHidden: false)
  361. }
  362. }
  363. speaker = SpeakerOutput()
  364. movie.audioEncodingTarget = speaker
  365. applyFilters()
  366. }
  367. /// 初始化缓存,默认选创建 cacheFiltersMaxCount 个缓存 filterrs
  368. /// - Parameter beginTime: 开始缓存的开始时间,用在 seek操作时 老的缓存已经无效不能在使用了
  369. func configCache(beginTime: Float64 ) {
  370. cacheFilters.removeAll()
  371. FilterLog(message: "原素材 总数:\(mStickers?.count ?? 0) ")
  372. if mStickers?.count ?? 0 > 0 {
  373. for (index , sticker) in mStickers!.enumerated() {
  374. print( "mStickers timelinein:\(sticker.timelineIn) timelineout: \(sticker.timelineOut) index : \(index)")
  375. }
  376. for (index, currentSticker) in mStickers!.enumerated() {
  377. //到达最大缓存数退出
  378. if cacheFilters.count == cacheFiltersMaxCount {
  379. break
  380. }
  381. //小于缓存的开始时间继续查找
  382. if(currentSticker.timelineOut < beginTime){
  383. continue
  384. }
  385. var showFitler: PQBaseFilter?
  386. if currentSticker.type == StickerType.VIDEO.rawValue {
  387. showFitler = PQMovieFilter(movieSticker: currentSticker)
  388. } else if currentSticker.type == StickerType.IMAGE.rawValue {
  389. showFitler = PQImageFilter(sticker: currentSticker)
  390. }
  391. if showFitler != nil {
  392. print( " 加入到缓存 的 filter timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) in :\(currentSticker.model_in) out: \(currentSticker.out) index : \(index)")
  393. cacheFilters.append(showFitler!)
  394. }
  395. }
  396. for (index, filter) in cacheFilters.enumerated() {
  397. FilterLog(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)")
  398. }
  399. if(cacheFilters.first != nil){
  400. movie?.removeAllTargets()
  401. let showFilter: PQBaseFilter = cacheFilters.first!
  402. movie?.addTarget(showFilter, atTargetIndex: 0)
  403. showFilter.addTarget(renderView, atTargetIndex: 0)
  404. }
  405. }
  406. }
  407. //创建下一个filter 数据
  408. func createNextFilter() {
  409. FilterLog(message: "加入前 当前的缓存个数为: \(cacheFilters.count) maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
  410. if cacheFilters.count <= cacheFiltersMaxCount {
  411. let showIndex = mStickers?.firstIndex(where: { (sticker) -> Bool in
  412. (cacheFilters.last?.stickerInfo == sticker)
  413. })
  414. FilterLog(message: "当前显示的showIndex: \(String(describing: showIndex))")
  415. if ((showIndex ?? 0) + 1) < (mStickers?.count ?? 0) {
  416. let currentSticker = mStickers?[(showIndex ?? 0) + 1]
  417. if currentSticker != nil {
  418. var showFitler: PQBaseFilter?
  419. if currentSticker!.type == StickerType.VIDEO.rawValue {
  420. showFitler = PQMovieFilter(movieSticker: currentSticker!)
  421. } else if currentSticker!.type == StickerType.IMAGE.rawValue {
  422. showFitler = PQImageFilter(sticker: currentSticker!)
  423. }
  424. if showFitler != nil {
  425. cacheFilters.append(showFitler!)
  426. }
  427. }else{
  428. FilterLog(message: "缓存数据加入不成功!!!!!")
  429. }
  430. }
  431. FilterLog(message: "加入后 当前的缓存个数为: \(cacheFilters.count) maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
  432. }
  433. }
  434. /// 按时间从缓存中取出要显示的filter
  435. /// - Parameter currTime: 当前播放时间
  436. func changeFilter(currTime: Float64) {
  437. let starts:CFTimeInterval = CFAbsoluteTimeGetCurrent()
  438. FilterLog(message: " 要查找的 currTime is \(currTime)")
  439. //1,删除已经显示过的 filter
  440. self.cacheFilters.removeAll(where: {(filter) -> Bool in
  441. (currTime > (filter.stickerInfo?.timelineOut ?? 0.0))
  442. })
  443. // 2,找出一个要显示的 fitler
  444. let showIndex = cacheFilters.firstIndex(where: { (filter) -> Bool in
  445. (currTime >= (filter.stickerInfo?.timelineIn ?? 0.0) && currTime <= (filter.stickerInfo?.timelineOut ?? 0.0))
  446. })
  447. if(showIndex == nil){
  448. FilterLog(message: "缓存没有查找到?出现数据错误!!!!")
  449. for (index,bsFilter )in cacheFilters.enumerated() {
  450. print( "22222缓存操作 没要查找到要查找的显示是为:\(currTime) 缓存数据timeline in :\(bsFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(bsFilter.stickerInfo?.timelineOut ?? 0.0) 缓存数 \(cacheFilters.count) index: \(index)")
  451. }
  452. return
  453. }
  454. let showFilter: PQBaseFilter = cacheFilters[showIndex ?? 0]
  455. FilterLog(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))")
  456. if(!(showFilter.isShow)){
  457. FilterLog(message: "showIndex当前时间为 \(currTime) showIndex is \(String(describing: showIndex)) 显示 filter timelineIn is: \(String(describing: showFilter.stickerInfo?.timelineIn)) timelineOut is: \(String(describing: showFilter.stickerInfo?.timelineOut))")
  458. showFilter.isShow = true
  459. movie!.removeAllTargets()
  460. if(showFilter.stickerInfo?.type == StickerType.IMAGE.rawValue && showGaussianBlur){
  461. self.createFiltersQueue.async {
  462. //高斯层
  463. let json = showFilter.stickerInfo?.toJSONString(prettyPrint: false)
  464. if json == nil {
  465. FilterLog(message: "数据转换有问题 跳转")
  466. return
  467. }
  468. let blurStickerModel: PQEditVisionTrackMaterialsModel? = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)
  469. blurStickerModel?.canvasFillType = stickerContentMode.aspectFillStr.rawValue
  470. let showGaussianFitler:PQBaseFilter = PQImageFilter(sticker: blurStickerModel!)
  471. let iosb:GaussianBlur = GaussianBlur.init()
  472. iosb.blurRadiusInPixels = 20
  473. showGaussianFitler.addTarget(iosb)
  474. sharedImageProcessingContext.runOperationAsynchronously{ [self] in
  475. self.movie?.addTarget(showGaussianFitler, atTargetIndex: 0)
  476. iosb.addTarget(showFilter)
  477. showFilter.addTarget(self.renderView as ImageConsumer, atTargetIndex: 0)
  478. }
  479. }
  480. }else{
  481. movie?.addTarget(showFilter, atTargetIndex: 0)
  482. showFilter.addTarget(renderView, atTargetIndex: 0)
  483. }
  484. self.createFiltersQueue.async {
  485. self.createNextFilter()
  486. }
  487. }else{
  488. FilterLog(message: " 添加过了 currTime is \(currTime) timelineIn:\(showFilter.stickerInfo?.timelineIn ?? 0.0)")
  489. }
  490. }
  491. /// 设置 filter 是否为 seek 状态
  492. func setEnableSeek(isSeek: Bool) {
  493. for filter in filters {
  494. (filter as? PQBaseFilter)?.enableSeek = isSeek
  495. }
  496. }
  497. private func applyFilters() {
  498. guard let movie = movie else { return }
  499. movie.removeAllTargets()
  500. var currentTarget: ImageSource = movie
  501. filters.forEach {
  502. let f = $0
  503. currentTarget.addTarget(f, atTargetIndex: 0)
  504. currentTarget = f
  505. }
  506. currentTarget.addTarget(renderView, atTargetIndex: 0)
  507. }
  508. }
  509. // MARK: Player control
  510. public extension PQGPUImagePlayerView {
  511. /// 开始播放
  512. /// - Parameter pauseFirstFrame: 是否暂停到第一帧
  513. func play(pauseFirstFrame: Bool = false, playeTimeRange: CMTimeRange = CMTimeRange()) {
  514. DispatchQueue.main.async {
  515. self.playerEmptyView.isHidden = true
  516. self.playView.isHidden = !pauseFirstFrame
  517. self.playMaskView.isHidden = !pauseFirstFrame
  518. self.renderView.isHidden = false
  519. self.progressLab.isHidden = false
  520. }
  521. // guard status != .playing else {
  522. // FilterLog(message: "已经是播放状态")
  523. // return
  524. // }
  525. // 如果没有设置开始结束时长 使用默认音频总时长(创作工具就不会传值)
  526. if CMTIMERANGE_IS_INVALID(playeTimeRange) {
  527. let endTime = CMTime(value: CMTimeValue(CMTimeGetSeconds(asset?.duration ?? .zero) * 600), timescale: 600)
  528. mPlayeTimeRange = CMTimeRange(start: .zero, end: endTime)
  529. } else {
  530. mPlayeTimeRange = playeTimeRange
  531. }
  532. // 清空音频缓存
  533. speaker?.clearBuffer()
  534. movie?.start(timeRange: mPlayeTimeRange ?? CMTimeRange())
  535. speaker?.start()
  536. status = pauseFirstFrame ? .pause : .playing
  537. }
  538. // 快进
  539. func seek(to time: CMTime) {
  540. mPlayeTimeRange?.start = time
  541. play(pauseFirstFrame: false, playeTimeRange: mPlayeTimeRange ?? .zero)
  542. }
  543. // 暂停
  544. func pause() {
  545. guard status != .pause else {
  546. return
  547. }
  548. movie?.pause()
  549. speaker?.pause()
  550. status = .pause
  551. showPlayBtn(isHidden: false)
  552. }
  553. // 停止f解码状态
  554. func stop() {
  555. // guard status != .stop else {
  556. // return
  557. // }
  558. movie?.cancel()
  559. speaker?.cancel()
  560. status = .stop
  561. }
  562. // 清空播放器状态,到空状态
  563. func clearPlayerView() {
  564. playerEmptyView.isHidden = false
  565. renderView.isHidden = true
  566. progressLab.isHidden = true
  567. }
  568. // 显示提示文字
  569. func showTip(show: Bool) {
  570. FilterLog(message: "showTip \(show)")
  571. tipLab.isHidden = !show
  572. if show {
  573. playerEmptyView.isHidden = true
  574. renderView.isHidden = true
  575. progressLab.isHidden = true
  576. }
  577. }
  578. }
  579. // MARK: Filter 操作
  580. public extension PQGPUImagePlayerView {
  581. // 添加 filter
  582. func appendFilter(_ filter: ImageProcessingOperation) {
  583. filters.append(filter)
  584. }
  585. // 添加一组filters
  586. func appendFilters(_ newFilters: [ImageProcessingOperation]) {
  587. filters = filters + newFilters
  588. }
  589. // 移除所有filter
  590. func removeAllFilters() {
  591. filters.removeAll()
  592. }
  593. // 重置所有 filer
  594. func appendFiltersClearOldFilter(_ newFilters: [ImageProcessingOperation]) {
  595. filters.removeAll()
  596. filters = newFilters
  597. }
  598. }
  599. // MARK: - RenderViewDelegate
  600. extension PQGPUImagePlayerView: RenderViewDelegate{
  601. public func willDisplayFramebuffer(renderView _: RenderView, framebuffer _: Framebuffer) {
  602. FilterLog(message: "willDisplayFramebuffer")
  603. }
  604. public func didDisplayFramebuffer(renderView _: RenderView, framebuffer: Framebuffer) {
  605. FilterLog(message: "didDisplayFramebuffer")
  606. }
  607. public func shouldDisplayNextFramebufferAfterMainThreadLoop() -> Bool {
  608. FilterLog(message: "didDisplayFramebuffer")
  609. return false
  610. }
  611. }