PQGPUImagePlayerView.swift 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741
  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 - 52) / 2, y: (self.frame.size.height - 52) / 2, width: 52, height: 52))
  128. view.image = UIImage().BF_Image(named: "gpuplayBtn")
  129. view.isHidden = true
  130. return view
  131. }()
  132. // 播放进度/总时长
  133. lazy var progressLab: UILabel = {
  134. let titleLab = UILabel(frame: CGRect(x: (self.frame.size.width - 140) / 2, y: 10, width: 140, height: 14))
  135. titleLab.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  136. titleLab.textColor = UIColor.white
  137. titleLab.textAlignment = .center
  138. titleLab.text = ""
  139. titleLab.layer.shadowColor = UIColor.black.cgColor
  140. titleLab.layer.shadowOpacity = 0.3
  141. titleLab.layer.shadowOffset = .zero
  142. titleLab.layer.shadowRadius = 1
  143. return titleLab
  144. }()
  145. lazy var tipLab: UILabel = {
  146. let tipLab = UILabel(frame: CGRect(x: (self.frame.size.width - 100) / 2, y: (self.frame.size.height - 14) / 2, width: 100, height: 14))
  147. tipLab.font = UIFont.systemFont(ofSize: 14, weight: .medium)
  148. tipLab.textColor = UIColor.white
  149. tipLab.textAlignment = .center
  150. tipLab.text = "资源加载中..."
  151. tipLab.layer.shadowColor = UIColor.white.cgColor
  152. tipLab.layer.shadowOpacity = 0.5
  153. tipLab.layer.shadowOffset = .zero
  154. tipLab.layer.shadowRadius = 1
  155. tipLab.isHidden = true
  156. return tipLab
  157. }()
  158. required public init?(coder _: NSCoder) {
  159. fatalError("init(coder:) has not been implemented")
  160. }
  161. override public init(frame: CGRect) {
  162. super.init(frame: frame)
  163. addSubview(renderView)
  164. addSubview(playView)
  165. addSubview(progressLab)
  166. backgroundColor = PQBFConfig.shared.styleBackGroundColor
  167. playerEmptyView = UIImageView(frame: bounds)
  168. playerEmptyView.backgroundColor = .black
  169. playerEmptyView.image = UIImage().BF_Image(named: "playEmpty")
  170. playerEmptyView.contentMode = .center
  171. addSubview(playerEmptyView)
  172. addSubview(tipLab)
  173. if #available(iOS 10.0, *) {
  174. createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .default, attributes: .initiallyInactive, autoreleaseFrequency: .never, target: nil)
  175. } else {
  176. createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .userInteractive, attributes: [], autoreleaseFrequency: .inherit, target: nil)
  177. }
  178. if #available(iOS 10.0, *) {
  179. createFiltersQueue.activate()
  180. }
  181. }
  182. func showBorderLayer() {
  183. if borderLayer != nil {
  184. borderLayer?.removeFromSuperlayer()
  185. }
  186. // 线条颜色
  187. borderLayer = CAShapeLayer()
  188. borderLayer?.strokeColor = UIColor.hexColor(hexadecimal: "#FFFFFF").cgColor
  189. borderLayer?.fillColor = nil
  190. borderLayer?.path = UIBezierPath(rect: CGRect(x: 1, y: 1, width: bounds.width - 2, height: bounds.height - 2)).cgPath
  191. borderLayer?.frame = bounds
  192. borderLayer?.lineWidth = 2.0
  193. borderLayer?.lineCap = .round
  194. // 第一位是 线条长度 第二位是间距 nil时为实线
  195. if borderLayer != nil {
  196. renderView.layer.addSublayer(borderLayer!)
  197. }
  198. if isAutoHiden {
  199. borderLayer?.opacity = 0
  200. let groupAnimation = CAAnimationGroup()
  201. groupAnimation.beginTime = CACurrentMediaTime()
  202. groupAnimation.duration = 1
  203. groupAnimation.fillMode = .forwards
  204. groupAnimation.isRemovedOnCompletion = true
  205. groupAnimation.repeatCount = 3
  206. let opacity = CABasicAnimation(keyPath: "opacity")
  207. opacity.fromValue = 0
  208. opacity.toValue = 1
  209. opacity.isRemovedOnCompletion = true
  210. let opacity2 = CABasicAnimation(keyPath: "opacity")
  211. opacity2.fromValue = 1
  212. opacity2.toValue = 0
  213. opacity2.isRemovedOnCompletion = false
  214. groupAnimation.animations = [opacity, opacity2]
  215. borderLayer?.add(groupAnimation, forKey: nil)
  216. }
  217. }
  218. // 设置画布比例
  219. public func resetCanvasFrame(frame: CGRect) {
  220. if self.frame.equalTo(frame) {
  221. FilterLog(message: "新老值一样,不重置")
  222. return
  223. }
  224. self.frame = frame
  225. if isShowLine {
  226. showBorderLayer()
  227. }
  228. FilterLog(message: "new frame is \(frame)")
  229. renderView.isHidden = true
  230. renderView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
  231. renderView.resatSize()
  232. playerEmptyView.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height)
  233. tipLab.frame = CGRect(x: (self.frame.size.width - 100) / 2, y: (self.frame.size.height - 14) / 2, width: 100, height: 14)
  234. progressLab.frame = CGRect(x: (self.frame.size.width - 140) / 2, y: 10, width: 140, height: 14)
  235. playView.frame = CGRect(x: (self.frame.size.width - 52) / 2, y: (self.frame.size.height - 52) / 2, width: 52, height: 52)
  236. }
  237. override public func layoutSubviews() {
  238. super.layoutSubviews()
  239. }
  240. @objc func RenderViewOnclick() {
  241. if status == .playing {
  242. playView.isHidden = false
  243. pause()
  244. } else if status == .stop || status == .pause {
  245. playView.isHidden = true
  246. movie?.resume()
  247. speaker?.start()
  248. status = .playing
  249. }
  250. if renderViewOnClickHandle != nil {
  251. renderViewOnClickHandle!()
  252. }
  253. }
  254. func showPlayBtn(isHidden: Bool) {
  255. playView.isHidden = isHidden
  256. }
  257. deinit {
  258. stop()
  259. movie = nil
  260. speaker = nil
  261. }
  262. /// XXXX 这里的 URL 使用的是全路径 ,如果不是全的会 crash ,方便复用 (不用处理业务的文件放在哪里)
  263. public func updateAsset(_ url: URL, videoComposition: AVVideoComposition? = nil, audioMixModel: PQVoiceModel? = nil, videoStickers: [PQEditVisionTrackMaterialsModel]? = nil) {
  264. // 每次初始化的时候设置初始值 为 nIl
  265. var audioMix: AVMutableAudioMix?
  266. var composition: AVMutableComposition?
  267. let asset = AVURLAsset(url: url, options: nil)
  268. FilterLog(message: "播放器初始化的音频时长\(asset.duration.seconds) url is \(url)")
  269. self.asset = asset
  270. if (audioMixModel != nil && audioMixModel?.localPath != nil) || (videoStickers != nil && (videoStickers?.count ?? 0) > 0) {
  271. FilterLog(message: "有参加混音的数据。")
  272. (audioMix, composition) = PQPlayerViewModel.setupAudioMix(originAsset: asset, bgmData: audioMixModel, videoStickers: videoStickers)
  273. } else {
  274. audioMix = nil
  275. }
  276. isReadyToPlay = false
  277. asset.loadValuesAsynchronously(forKeys: ["tracks", "duration", "commonMetadata"]) { [weak self] in
  278. guard let strongSelf = self else { return }
  279. let tracksStatus = strongSelf.asset?.statusOfValue(forKey: AVAssetKey.tracks, error: nil) ?? .unknown
  280. let durationStatus = strongSelf.asset?.statusOfValue(forKey: AVAssetKey.duration, error: nil) ?? .unknown
  281. strongSelf.isReadyToPlay = tracksStatus == .loaded && durationStatus == .loaded
  282. }
  283. var audioSettings: [String: Any] = [
  284. AVFormatIDKey: kAudioFormatLinearPCM,
  285. ]
  286. if #available(iOS 14.0, *) {
  287. audioSettings[AVLinearPCMIsFloatKey] = false
  288. audioSettings[AVLinearPCMBitDepthKey] = 16
  289. }
  290. do {
  291. if composition != nil {
  292. FilterLog(message: "composition 方式初始化")
  293. movie = try PQMovieInput(asset: composition!, videoComposition: videoComposition, audioMix: audioMix, playAtActualSpeed: true, loop: isLoop, audioSettings: audioSettings)
  294. } else {
  295. movie = try PQMovieInput(url: url, playAtActualSpeed: true, loop: isLoop, audioSettings: audioSettings)
  296. /* 测试代码
  297. let audioDecodeSettings = [AVFormatIDKey:kAudioFormatLinearPCM]
  298. let bundleURL = Bundle.main.resourceURL!
  299. let movieURL = URL(string:"11111.mp4", relativeTo:bundleURL)!
  300. movie = try MovieInput(url:movieURL, playAtActualSpeed:true, loop:true, audioSettings:audioDecodeSettings)
  301. */
  302. }
  303. movie!.runBenchmark = false
  304. movie!.synchronizedEncodingDebug = false
  305. } catch {
  306. status = .error
  307. if enableDebug {
  308. debugPrint(error)
  309. }
  310. }
  311. guard let movie = movie else { return }
  312. movie.progress = { [weak self, movie] currTime, duration, prgressValue in
  313. guard let strongSelf = self else { return }
  314. FilterLog(message: " movie.currentTime.seconds 进度\(movie.currentTime.seconds)")
  315. self?.changeFilter(currTime: movie.currentTime.seconds)
  316. self?.progress?(currTime, duration, prgressValue)
  317. DispatchQueue.main.async {
  318. strongSelf.playbackTime = movie.currentTime.seconds
  319. // Non-main thread change this property is not valid
  320. strongSelf.animationLayer?.timeOffset = strongSelf.playbackTime
  321. if strongSelf.showProgressLab {
  322. if duration < 1 {
  323. strongSelf.progressLab.text = "\(currTime.formatDurationToHMS()) / 00:01"
  324. } else {
  325. strongSelf.progressLab.text = "\(currTime.formatDurationToHMS()) / \(duration.formatDurationToHMS())"
  326. }
  327. }
  328. }
  329. }
  330. movie.completion = { [weak self] in
  331. guard let strongSelf = self else { return }
  332. //缓存已经用完,重新初始化缓存
  333. if(strongSelf.filters.count == 0){
  334. strongSelf.configCache(beginTime: strongSelf.mStickers?.first?.timelineIn ?? 0)
  335. }
  336. DispatchQueue.main.async {
  337. strongSelf.status = .stop
  338. strongSelf.finishedClosure?()
  339. strongSelf.showPlayBtn(isHidden: false)
  340. }
  341. }
  342. speaker = SpeakerOutput()
  343. movie.audioEncodingTarget = speaker
  344. applyFilters()
  345. }
  346. /// 初始化缓存,默认选创建 cacheFiltersMaxCount 个缓存 filterrs
  347. /// - Parameter beginTime: 开始缓存的开始时间,用在 seek操作时 老的缓存已经无效不能在使用了
  348. func configCache(beginTime: Float64 ) {
  349. cacheFilters.removeAll()
  350. FilterLog(message: "原素材 总数:\(mStickers?.count ?? 0) ")
  351. if mStickers?.count ?? 0 > 0 {
  352. for (index , sticker) in mStickers!.enumerated() {
  353. print( "mStickers timelinein:\(sticker.timelineIn) timelineout: \(sticker.timelineOut) index : \(index)")
  354. }
  355. for (index, currentSticker) in mStickers!.enumerated() {
  356. //到达最大缓存数退出
  357. if cacheFilters.count == cacheFiltersMaxCount {
  358. break
  359. }
  360. //小于缓存的开始时间继续查找
  361. if(currentSticker.timelineOut < beginTime){
  362. continue
  363. }
  364. var showFitler: PQBaseFilter?
  365. if currentSticker.type == StickerType.VIDEO.rawValue {
  366. showFitler = PQMovieFilter(movieSticker: currentSticker)
  367. } else if currentSticker.type == StickerType.IMAGE.rawValue {
  368. showFitler = PQImageFilter(sticker: currentSticker)
  369. }
  370. if showFitler != nil {
  371. print( " 加入到缓存 的 filter timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) in :\(currentSticker.model_in) out: \(currentSticker.out) index : \(index)")
  372. cacheFilters.append(showFitler!)
  373. }
  374. }
  375. for (index, filter) in cacheFilters.enumerated() {
  376. 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)")
  377. }
  378. if(cacheFilters.first != nil){
  379. movie?.removeAllTargets()
  380. let showFilter: PQBaseFilter = cacheFilters.first!
  381. movie?.addTarget(showFilter, atTargetIndex: 0)
  382. showFilter.addTarget(renderView, atTargetIndex: 0)
  383. }
  384. }
  385. }
  386. //创建下一个filter 数据
  387. func createNextFilter() {
  388. FilterLog(message: "加入前 当前的缓存个数为: \(cacheFilters.count) maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
  389. if cacheFilters.count <= cacheFiltersMaxCount {
  390. let showIndex = mStickers?.firstIndex(where: { (sticker) -> Bool in
  391. (cacheFilters.last?.stickerInfo == sticker)
  392. })
  393. FilterLog(message: "当前显示的showIndex: \(String(describing: showIndex))")
  394. if ((showIndex ?? 0) + 1) < (mStickers?.count ?? 0) {
  395. let currentSticker = mStickers?[(showIndex ?? 0) + 1]
  396. if currentSticker != nil {
  397. var showFitler: PQBaseFilter?
  398. if currentSticker!.type == StickerType.VIDEO.rawValue {
  399. showFitler = PQMovieFilter(movieSticker: currentSticker!)
  400. } else if currentSticker!.type == StickerType.IMAGE.rawValue {
  401. showFitler = PQImageFilter(sticker: currentSticker!)
  402. }
  403. if showFitler != nil {
  404. cacheFilters.append(showFitler!)
  405. }
  406. }else{
  407. FilterLog(message: "缓存数据加入不成功!!!!!")
  408. }
  409. }
  410. FilterLog(message: "加入后 当前的缓存个数为: \(cacheFilters.count) maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
  411. }
  412. }
  413. /// 按时间从缓存中取出要显示的filter
  414. /// - Parameter currTime: 当前播放时间
  415. func changeFilter(currTime: Float64) {
  416. let starts:CFTimeInterval = CFAbsoluteTimeGetCurrent()
  417. FilterLog(message: " 要查找的 currTime is \(currTime)")
  418. //1,删除已经显示过的 filter
  419. self.cacheFilters.removeAll(where: {(filter) -> Bool in
  420. (currTime > (filter.stickerInfo?.timelineOut ?? 0.0))
  421. })
  422. // 2,找出一个要显示的 fitler
  423. let showIndex = cacheFilters.firstIndex(where: { (filter) -> Bool in
  424. (currTime >= (filter.stickerInfo?.timelineIn ?? 0.0) && currTime <= (filter.stickerInfo?.timelineOut ?? 0.0))
  425. })
  426. if(showIndex == nil){
  427. FilterLog(message: "缓存没有查找到?出现数据错误!!!!")
  428. for (index,bsFilter )in cacheFilters.enumerated() {
  429. print( "22222缓存操作 没要查找到要查找的显示是为:\(currTime) 缓存数据timeline in :\(bsFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(bsFilter.stickerInfo?.timelineOut ?? 0.0) 缓存数 \(cacheFilters.count) index: \(index)")
  430. }
  431. return
  432. }
  433. let showFilter: PQBaseFilter = cacheFilters[showIndex ?? 0]
  434. 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))")
  435. if(!(showFilter.isShow)){
  436. FilterLog(message: "showIndex当前时间为 \(currTime) showIndex is \(String(describing: showIndex)) 显示 filter timelineIn is: \(String(describing: showFilter.stickerInfo?.timelineIn)) timelineOut is: \(String(describing: showFilter.stickerInfo?.timelineOut))")
  437. showFilter.isShow = true
  438. movie!.removeAllTargets()
  439. if(showFilter.stickerInfo?.type == StickerType.IMAGE.rawValue && showGaussianBlur){
  440. self.createFiltersQueue.async {
  441. //高斯层
  442. let json = showFilter.stickerInfo?.toJSONString(prettyPrint: false)
  443. if json == nil {
  444. FilterLog(message: "数据转换有问题 跳转")
  445. return
  446. }
  447. let blurStickerModel: PQEditVisionTrackMaterialsModel? = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)
  448. blurStickerModel?.canvasFillType = stickerContentMode.aspectFillStr.rawValue
  449. let showGaussianFitler:PQBaseFilter = PQImageFilter(sticker: blurStickerModel!)
  450. let iosb:GaussianBlur = GaussianBlur.init()
  451. iosb.blurRadiusInPixels = 20
  452. showGaussianFitler.addTarget(iosb)
  453. sharedImageProcessingContext.runOperationAsynchronously{ [self] in
  454. self.movie?.addTarget(showGaussianFitler, atTargetIndex: 0)
  455. iosb.addTarget(showFilter)
  456. showFilter.addTarget(self.renderView as ImageConsumer, atTargetIndex: 0)
  457. }
  458. }
  459. }else{
  460. movie?.addTarget(showFilter, atTargetIndex: 0)
  461. showFilter.addTarget(renderView, atTargetIndex: 0)
  462. }
  463. self.createFiltersQueue.async {
  464. self.createNextFilter()
  465. }
  466. }else{
  467. FilterLog(message: " 添加过了 currTime is \(currTime) timelineIn:\(showFilter.stickerInfo?.timelineIn ?? 0.0)")
  468. }
  469. }
  470. /// 设置 filter 是否为 seek 状态
  471. func setEnableSeek(isSeek: Bool) {
  472. for filter in filters {
  473. (filter as? PQBaseFilter)?.enableSeek = isSeek
  474. }
  475. }
  476. private func applyFilters() {
  477. guard let movie = movie else { return }
  478. movie.removeAllTargets()
  479. var currentTarget: ImageSource = movie
  480. filters.forEach {
  481. let f = $0
  482. currentTarget.addTarget(f, atTargetIndex: 0)
  483. currentTarget = f
  484. }
  485. currentTarget.addTarget(renderView, atTargetIndex: 0)
  486. }
  487. }
  488. // MARK: Player control
  489. public extension PQGPUImagePlayerView {
  490. /// 开始播放
  491. /// - Parameter pauseFirstFrame: 是否暂停到第一帧
  492. func play(pauseFirstFrame: Bool = false, playeTimeRange: CMTimeRange = CMTimeRange()) {
  493. DispatchQueue.main.async {
  494. self.playerEmptyView.isHidden = true
  495. self.playView.isHidden = !pauseFirstFrame
  496. self.renderView.isHidden = false
  497. self.progressLab.isHidden = false
  498. }
  499. // guard status != .playing else {
  500. // FilterLog(message: "已经是播放状态")
  501. // return
  502. // }
  503. // 如果没有设置开始结束时长 使用默认音频总时长(创作工具就不会传值)
  504. if CMTIMERANGE_IS_INVALID(playeTimeRange) {
  505. let endTime = CMTime(value: CMTimeValue(CMTimeGetSeconds(asset?.duration ?? .zero) * 600), timescale: 600)
  506. mPlayeTimeRange = CMTimeRange(start: .zero, end: endTime)
  507. } else {
  508. mPlayeTimeRange = playeTimeRange
  509. }
  510. // 清空音频缓存
  511. speaker?.clearBuffer()
  512. movie?.start(timeRange: mPlayeTimeRange ?? CMTimeRange())
  513. speaker?.start()
  514. status = pauseFirstFrame ? .pause : .playing
  515. }
  516. // 快进
  517. func seek(to time: CMTime) {
  518. mPlayeTimeRange?.start = time
  519. play(pauseFirstFrame: false, playeTimeRange: mPlayeTimeRange ?? .zero)
  520. }
  521. // 暂停
  522. func pause() {
  523. guard status != .pause else {
  524. return
  525. }
  526. movie?.pause()
  527. speaker?.pause()
  528. status = .pause
  529. showPlayBtn(isHidden: false)
  530. }
  531. // 停止f解码状态
  532. func stop() {
  533. // guard status != .stop else {
  534. // return
  535. // }
  536. movie?.cancel()
  537. speaker?.cancel()
  538. status = .stop
  539. }
  540. // 清空播放器状态,到空状态
  541. func clearPlayerView() {
  542. playerEmptyView.isHidden = false
  543. renderView.isHidden = true
  544. progressLab.isHidden = true
  545. }
  546. // 显示提示文字
  547. func showTip(show: Bool) {
  548. FilterLog(message: "showTip \(show)")
  549. tipLab.isHidden = !show
  550. if show {
  551. playerEmptyView.isHidden = true
  552. renderView.isHidden = true
  553. progressLab.isHidden = true
  554. }
  555. }
  556. }
  557. // MARK: Filter 操作
  558. public extension PQGPUImagePlayerView {
  559. // 添加 filter
  560. func appendFilter(_ filter: ImageProcessingOperation) {
  561. filters.append(filter)
  562. }
  563. // 添加一组filters
  564. func appendFilters(_ newFilters: [ImageProcessingOperation]) {
  565. filters = filters + newFilters
  566. }
  567. // 移除所有filter
  568. func removeAllFilters() {
  569. filters.removeAll()
  570. }
  571. // 重置所有 filer
  572. func appendFiltersClearOldFilter(_ newFilters: [ImageProcessingOperation]) {
  573. filters.removeAll()
  574. filters = newFilters
  575. }
  576. }
  577. // MARK: - RenderViewDelegate
  578. extension PQGPUImagePlayerView: RenderViewDelegate{
  579. public func willDisplayFramebuffer(renderView _: RenderView, framebuffer _: Framebuffer) {
  580. FilterLog(message: "willDisplayFramebuffer")
  581. }
  582. public func didDisplayFramebuffer(renderView _: RenderView, framebuffer: Framebuffer) {
  583. FilterLog(message: "didDisplayFramebuffer")
  584. }
  585. public func shouldDisplayNextFramebufferAfterMainThreadLoop() -> Bool {
  586. FilterLog(message: "didDisplayFramebuffer")
  587. return false
  588. }
  589. }