|
@@ -36,6 +36,14 @@ public class PQCompositionExporter {
|
|
|
|
|
|
//是否显示高斯
|
|
//是否显示高斯
|
|
public var showGaussianBlur:Bool = false
|
|
public var showGaussianBlur:Bool = false
|
|
|
|
+
|
|
|
|
+ // 缓存创建filter 防止 seek 100ms 慢
|
|
|
|
+ @Atomic var cacheFilters: Array<PQBaseFilter> = Array()
|
|
|
|
+ // 缓存个数
|
|
|
|
+ var cacheFiltersMaxCount: Int = 8
|
|
|
|
+
|
|
|
|
+ /// Use serial queue to ensure that the picture is smooth
|
|
|
|
+ var createFiltersQueue: DispatchQueue!
|
|
|
|
|
|
public init(asset: AVAsset, videoComposition: AVVideoComposition? = nil, audioMix: AVAudioMix? = nil, filters: [ImageProcessingOperation]? = nil,stickers:[PQEditVisionTrackMaterialsModel]? = nil, animationTool: AVVideoCompositionCoreAnimationTool? = nil, exportURL: URL) {
|
|
public init(asset: AVAsset, videoComposition: AVVideoComposition? = nil, audioMix: AVAudioMix? = nil, filters: [ImageProcessingOperation]? = nil,stickers:[PQEditVisionTrackMaterialsModel]? = nil, animationTool: AVVideoCompositionCoreAnimationTool? = nil, exportURL: URL) {
|
|
self.asset = asset
|
|
self.asset = asset
|
|
@@ -57,6 +65,17 @@ public class PQCompositionExporter {
|
|
guard !FileManager.default.fileExists(atPath: exportURL.absoluteString) else {
|
|
guard !FileManager.default.fileExists(atPath: exportURL.absoluteString) else {
|
|
return false
|
|
return false
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ if #available(iOS 10.0, *) {
|
|
|
|
+ createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .default, attributes: .initiallyInactive, autoreleaseFrequency: .never, target: nil)
|
|
|
|
+ } else {
|
|
|
|
+ createFiltersQueue = DispatchQueue(label: "PQ.moveFiler.seeking111", qos: .userInteractive, attributes: [], autoreleaseFrequency: .inherit, target: nil)
|
|
|
|
+ }
|
|
|
|
+ if #available(iOS 10.0, *) {
|
|
|
|
+ createFiltersQueue.activate()
|
|
|
|
+ }
|
|
|
|
+
|
|
// guard let videoTrack = asset.tracks(withMediaType:AVMediaType.video).first else { return false }
|
|
// guard let videoTrack = asset.tracks(withMediaType:AVMediaType.video).first else { return false }
|
|
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first
|
|
let audioTrack = asset.tracks(withMediaType: AVMediaType.audio).first
|
|
|
|
|
|
@@ -131,11 +150,16 @@ public class PQCompositionExporter {
|
|
|
|
|
|
currentTarget.addTarget(output!, atTargetIndex: 0)
|
|
currentTarget.addTarget(output!, atTargetIndex: 0)
|
|
|
|
|
|
|
|
+ }else{
|
|
|
|
+
|
|
|
|
+ configCache(beginTime: mStickers?.first?.timelineIn ?? 0)
|
|
|
|
+
|
|
}
|
|
}
|
|
|
|
|
|
return true
|
|
return true
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+
|
|
public func findShowStikcer(currTime:Float64) {
|
|
public func findShowStikcer(currTime:Float64) {
|
|
|
|
|
|
if(mStickers?.count ?? 0 == 0){
|
|
if(mStickers?.count ?? 0 == 0){
|
|
@@ -216,7 +240,7 @@ public class PQCompositionExporter {
|
|
input?.progress = { [weak self] currTime, duration, progress in
|
|
input?.progress = { [weak self] currTime, duration, progress in
|
|
|
|
|
|
if(self?.mStickers?.count ?? 0 > 0){
|
|
if(self?.mStickers?.count ?? 0 > 0){
|
|
- self?.findShowStikcer(currTime: CMTimeGetSeconds(self?.input?.currentTime ?? .zero) )
|
|
|
|
|
|
+ self?.changeFilter(currTime: CMTimeGetSeconds(self?.input?.currentTime ?? .zero) )
|
|
}
|
|
}
|
|
DispatchQueue.main.async {[weak self] in
|
|
DispatchQueue.main.async {[weak self] in
|
|
self?.progressClosure?(Float(currTime), Float(duration), Float(progress))
|
|
self?.progressClosure?(Float(currTime), Float(duration), Float(progress))
|
|
@@ -282,4 +306,171 @@ public class PQCompositionExporter {
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /// 初始化缓存,默认选创建 cacheFiltersMaxCount 个缓存 filterrs
|
|
|
|
+ /// - Parameter beginTime: 开始缓存的开始时间,用在 seek操作时 老的缓存已经无效不能在使用了
|
|
|
|
+ func configCache(beginTime: Float64 ) {
|
|
|
|
+ cacheFilters.removeAll()
|
|
|
|
+ FilterLog(message: "原素材 总数:\(mStickers?.count ?? 0) ")
|
|
|
|
+
|
|
|
|
+ if mStickers?.count ?? 0 > 0 {
|
|
|
|
+
|
|
|
|
+ for (index , sticker) in mStickers!.enumerated() {
|
|
|
|
+ print( "mStickers timelinein:\(sticker.timelineIn) timelineout: \(sticker.timelineOut) index : \(index)")
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ for (index, currentSticker) in mStickers!.enumerated() {
|
|
|
|
+ //到达最大缓存数退出
|
|
|
|
+ if cacheFilters.count == cacheFiltersMaxCount {
|
|
|
|
+ break
|
|
|
|
+ }
|
|
|
|
+ //小于缓存的开始时间继续查找
|
|
|
|
+ if(currentSticker.timelineOut < beginTime){
|
|
|
|
+ continue
|
|
|
|
+ }
|
|
|
|
+ var showFitler: PQBaseFilter?
|
|
|
|
+ if currentSticker.type == StickerType.VIDEO.rawValue {
|
|
|
|
+ showFitler = PQMovieFilter(movieSticker: currentSticker)
|
|
|
|
+
|
|
|
|
+ } else if currentSticker.type == StickerType.IMAGE.rawValue {
|
|
|
|
+ showFitler = PQImageFilter(sticker: currentSticker)
|
|
|
|
+ }
|
|
|
|
+ if showFitler != nil {
|
|
|
|
+ print( " 加入到缓存 的 filter timelinein:\(currentSticker.timelineIn) timelineout: \(currentSticker.timelineOut) in :\(currentSticker.model_in) out: \(currentSticker.out) index : \(index)")
|
|
|
|
+ cacheFilters.append(showFitler!)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ for (index, filter) in cacheFilters.enumerated() {
|
|
|
|
+ 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)")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ if(cacheFilters.first != nil){
|
|
|
|
+ input?.removeAllTargets()
|
|
|
|
+ let showFilter: PQBaseFilter = cacheFilters.first!
|
|
|
|
+ input?.addTarget(showFilter, atTargetIndex: 0)
|
|
|
|
+ showFilter.addTarget(output!, atTargetIndex: 0)
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ //创建下一个filter 数据
|
|
|
|
+ func createNextFilter() {
|
|
|
|
+ FilterLog(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)
|
|
|
|
+ })
|
|
|
|
+ FilterLog(message: "当前显示的showIndex: \(String(describing: showIndex))")
|
|
|
|
+ if ((showIndex ?? 0) + 1) < (mStickers?.count ?? 0) {
|
|
|
|
+ let currentSticker = mStickers?[(showIndex ?? 0) + 1]
|
|
|
|
+ if currentSticker != nil {
|
|
|
|
+ var showFitler: PQBaseFilter?
|
|
|
|
+ if currentSticker!.type == StickerType.VIDEO.rawValue {
|
|
|
|
+ showFitler = PQMovieFilter(movieSticker: currentSticker!)
|
|
|
|
+
|
|
|
|
+ } else if currentSticker!.type == StickerType.IMAGE.rawValue {
|
|
|
|
+ showFitler = PQImageFilter(sticker: currentSticker!)
|
|
|
|
+ }
|
|
|
|
+ if showFitler != nil {
|
|
|
|
+
|
|
|
|
+ cacheFilters.append(showFitler!)
|
|
|
|
+ }
|
|
|
|
+ }else{
|
|
|
|
+ FilterLog(message: "缓存数据加入不成功!!!!!")
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ FilterLog(message: "加入后 当前的缓存个数为: \(cacheFilters.count) maxCount \(cacheFiltersMaxCount) 最后一个显示时间 \(String(describing: cacheFilters.last?.stickerInfo?.timelineIn))")
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ /// 按时间从缓存中取出要显示的filter
|
|
|
|
+ /// - Parameter currTime: 当前播放时间
|
|
|
|
+ func changeFilter(currTime: Float64) {
|
|
|
|
+ FilterLog(message: " 要查找的 currTime is \(currTime)")
|
|
|
|
+ //1,删除已经显示过的 filter
|
|
|
|
+ self.cacheFilters.removeAll(where: {(filter) -> Bool in
|
|
|
|
+
|
|
|
|
+ (currTime > (filter.stickerInfo?.timelineOut ?? 0.0))
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ // 2,找出一个要显示的 fitler
|
|
|
|
+ let showIndex = cacheFilters.firstIndex(where: { (filter) -> Bool in
|
|
|
|
+ (currTime >= (filter.stickerInfo?.timelineIn ?? 0.0) && currTime <= (filter.stickerInfo?.timelineOut ?? 0.0))
|
|
|
|
+ })
|
|
|
|
+
|
|
|
|
+ if(showIndex == nil){
|
|
|
|
+
|
|
|
|
+ for (index,bsFilter )in cacheFilters.enumerated() {
|
|
|
|
+ print( "22222缓存操作 没要查找到要查找的显示是为:\(currTime) 缓存数据timeline in :\(bsFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(bsFilter.stickerInfo?.timelineOut ?? 0.0) 缓存数 \(cacheFilters.count) index: \(index)")
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let showFilter: PQBaseFilter = cacheFilters[showIndex ?? 0]
|
|
|
|
+
|
|
|
|
+ print("缓存操作 查找到命中的显示是为:\(currTime) 缓存数据timeline in :\(showFilter.stickerInfo?.timelineIn ?? 0.0)) timelineOut:\(showFilter.stickerInfo?.timelineOut ?? 0.0) 缓存数 \(cacheFilters.count) index: \(String(describing: showIndex))")
|
|
|
|
+
|
|
|
|
+ if(!(showFilter.isShow)){
|
|
|
|
+ FilterLog(message: "showIndex当前时间为 \(currTime) showIndex is \(String(describing: showIndex)) 显示 filter timein is: \(String(describing: showFilter.stickerInfo?.timelineIn)) timeout is: \(String(describing: showFilter.stickerInfo?.timelineOut))")
|
|
|
|
+
|
|
|
|
+ showFilter.isShow = true
|
|
|
|
+
|
|
|
|
+ input!.removeAllTargets()
|
|
|
|
+
|
|
|
|
+ if(showFilter.stickerInfo?.type == StickerType.IMAGE.rawValue && showGaussianBlur){
|
|
|
|
+
|
|
|
|
+// self.createFiltersQueue.async {
|
|
|
|
+ //高斯层
|
|
|
|
+ let json = showFilter.stickerInfo?.toJSONString(prettyPrint: false)
|
|
|
|
+ if json == nil {
|
|
|
|
+ FilterLog(message: "数据转换有问题 跳转")
|
|
|
|
+ return
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ let blurStickerModel: PQEditVisionTrackMaterialsModel? = Mapper<PQEditVisionTrackMaterialsModel>().map(JSONString: json!)
|
|
|
|
+ blurStickerModel?.canvasFillType = stickerContentMode.aspectFillStr.rawValue
|
|
|
|
+ let showGaussianFitler:PQBaseFilter = PQImageFilter(sticker: blurStickerModel!)
|
|
|
|
+
|
|
|
|
+ let iosb:GaussianBlur = GaussianBlur.init()
|
|
|
|
+ iosb.blurRadiusInPixels = 20
|
|
|
|
+ showGaussianFitler.addTarget(iosb)
|
|
|
|
+
|
|
|
|
+ sharedImageProcessingContext.runOperationAsynchronously{ [self] in
|
|
|
|
+
|
|
|
|
+ self.input?.addTarget(showGaussianFitler, atTargetIndex: 0)
|
|
|
|
+ iosb.addTarget(showFilter)
|
|
|
|
+ showFilter.addTarget(output!, atTargetIndex: 0)
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+
|
|
|
|
+ }else{
|
|
|
|
+ input?.addTarget(showFilter, atTargetIndex: 0)
|
|
|
|
+ showFilter.addTarget(output!, atTargetIndex: 0)
|
|
|
|
+ }
|
|
|
|
+// self.createFiltersQueue.async {
|
|
|
|
+ self.createNextFilter()
|
|
|
|
+// }
|
|
|
|
+
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|