Sfoglia il codice sorgente

视频快慢速功能

jsonwang 3 anni fa
parent
commit
52969081ea
1 ha cambiato i file con 52 aggiunte e 48 eliminazioni
  1. 52 48
      BFFramework/Classes/PQGPUImage/akfilters/PQMovieFilter.swift

+ 52 - 48
BFFramework/Classes/PQGPUImage/akfilters/PQMovieFilter.swift

@@ -38,15 +38,14 @@
  output中可以设置supportsRandomAccess,当为true时,可以重置读取范围,但需要调用方调用copyNextSampleBuffer,直到该方法返回NULL。
  或者重新初始化一个AVAssetReader来设置读取时间。
  如果尝试第一种方案,需要使用seek,可以尝试每次设置一个不太长的区间,以保证读取完整个区间不会耗时太多,且时间间隔最好以关键帧划分。
- 
+
  fps
- 
+
  25.0 fps :   0.0000  0.0400  0.0800  0.1200  0.1600  0.2000  0.2400  0.2800  0.3200  0.3600  0.4000  0.4400  0.4800  0.5200  0.5600  0.6000  0.6400  0.6800  0.7200  0.7600  0.8000  0.8400  0.8800  0.9200  0.9600  1.0000  1.0400  1.0800  1.1200  1.1600  1.2000
  30.0 fps :   0.0000  0.0333  0.0667  0.1000  0.1333  0.1667  0.2000  0.2333  0.2667  0.3000  0.3333  0.3667  0.4000  0.4333  0.4667  0.5000  0.5333  0.5667  0.6000  0.6333  0.6667  0.7000  0.7333  0.7667  0.8000  0.8333  0.8667  0.9000  0.9333  0.9667  1.0000
  60.0 fps :   0.0000  0.0167  0.0333  0.0500  0.0667  0.0833  0.1000  0.1167  0.1333  0.1500  0.1667  0.1833  0.2000  0.2167  0.2333  0.2500  0.2667  0.2833  0.3000  0.3167  0.3333  0.3500  0.3667  0.3833  0.4000  0.4167  0.4333  0.4500  0.4667  0.4833  0.5000
  80.0 fps :   0.0000  0.0125  0.0250  0.0375  0.0500  0.0625  0.0750  0.0875  0.1000  0.1125  0.1250  0.1375  0.1500  0.1625  0.1750  0.1875  0.2000  0.2125  0.2250  0.2375  0.2500  0.2625  0.2750  0.2875  0.3000  0.3125  0.3250  0.3375  0.3500  0.3625  0.3750
-120.0 fps :   0.0000  0.0083  0.0167  0.0250  0.0333  0.0417  0.0500  0.0583  0.0667  0.0750  0.0833  0.0917  0.1000  0.1083  0.1167  0.1250  0.1333  0.1417  0.1500  0.1583  0.1667  0.1750  0.1833  0.1917  0.2000  0.2083  0.2167  0.2250  0.2333  0.2417  0.2500
-
+ 120.0 fps :   0.0000  0.0083  0.0167  0.0250  0.0333  0.0417  0.0500  0.0583  0.0667  0.0750  0.0833  0.0917  0.1000  0.1083  0.1167  0.1250  0.1333  0.1417  0.1500  0.1583  0.1667  0.1750  0.1833  0.1917  0.2000  0.2083  0.2167  0.2250  0.2333  0.2417  0.2500
 
  */
 
@@ -102,14 +101,13 @@ class PQMovieFilter: PQBaseFilter {
     /// Use serial queue to ensure that the picture is smooth
     var seekQueue: DispatchQueue!
 
-    // * 设置播放速率 范围 0 - 8(理论值) rate 正常速度为1.0;小于为慢速;大于为快速。但不能高于解码速度1-2ms硬解一帧
-    var speedRate: Float = 1
-
     // 原视频素材的 FPS
     var stickerFPS: Float = 0
 
     // 开始时间,创建 filter 显示的时候有
     var startTimeStamp: CMTime?
+    // 最后一次显示帧时间戳
+    var targetTimeStamp: CMTime = .zero
 
     deinit {
         FilterLog(message: "movie filter deinit")
@@ -196,23 +194,23 @@ class PQMovieFilter: PQBaseFilter {
         releaseIncomingFramebuffers()
 
 //        if CMTimeGetSeconds(currentTime) >= moveSticker!.timelineIn, CMTimeGetSeconds(currentTime) <= moveSticker!.timelineOut {
-            FilterLog(message: "开始显示 movefilter 了 开始\(String(describing: moveSticker?.timelineIn)) 结束 :\(String(describing: moveSticker?.timelineOut)) currentTime \(CMTimeGetSeconds(currentTime)) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) ")
+        FilterLog(message: "开始显示 movefilter 了 开始\(String(describing: moveSticker?.timelineIn)) 结束 :\(String(describing: moveSticker?.timelineOut)) currentTime \(CMTimeGetSeconds(currentTime)) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) ")
 
-            if enableSeek {
-                FilterLog(message: "seek 到 \(CMTimeGetSeconds(currentTime))  ")
-                resetRangeTime(startTime: currentTime)
-                enableSeek = false
-            }
+        if enableSeek {
+            FilterLog(message: "seek 到 \(CMTimeGetSeconds(currentTime))  ")
+            resetRangeTime(startTime: currentTime)
+            enableSeek = false
+        }
 
-            if startTimeStamp == nil {
-                startTimeStamp = currentTime
-            }
+        if startTimeStamp == nil {
+            startTimeStamp = currentTime
+        }
 
-            let stickerTime = CMTime(value: Int64(moveSticker?.model_in ?? 0) * Int64(BASE_FILTER_TIMESCALE), timescale: BASE_FILTER_TIMESCALE)
+        let stickerTime = CMTime(value: Int64(moveSticker?.model_in ?? 0) * Int64(BASE_FILTER_TIMESCALE), timescale: BASE_FILTER_TIMESCALE)
 
-            let PTSTime = CMTimeAdd(stickerTime, CMTimeSubtract(currentTime, startTimeStamp ?? .zero))
+        let PTSTime = CMTimeAdd(stickerTime, CMTimeSubtract(currentTime, startTimeStamp ?? .zero))
 
-            readNextVideoFrame(showTimeStamp: CMTime(value: CMTimeValue(Int(Float(PTSTime.value) * speedRate)), timescale: PTSTime.timescale))
+        readNextVideoFrame(showTimeStamp: CMTime(value: CMTimeValue(Int(Float(PTSTime.value) * Float(stickerInfo!.speedRate))), timescale: PTSTime.timescale))
 
 //        } else {
 //            FilterLog(message: "movefilter 了 结束了  timelineIN\(String(describing: moveSticker?.timelineIn)) timelineOut\(String(describing: moveSticker?.timelineOut)) currentTime  \(CMTimeGetSeconds(currentTime)) 裁剪in:\(String(describing: moveSticker?.model_in))  裁剪out:\(String(describing: moveSticker?.out)) ")
@@ -334,10 +332,15 @@ class PQMovieFilter: PQBaseFilter {
 
     // 取出第一帧数据
     func readNextVideoFrame(showTimeStamp: CMTime) {
-        
         // XXXX 有时渲染视频取出来的画面时为黑屏,再渲染一次,数据是没有问题已经保存到沙盒进行验证,这个不是最好的方案!
-        if(lastImageBuffer != nil){
-            self.renderPixelBuffler(movieFrame: lastImageBuffer!, withSampleTime: currentTime)
+        if lastImageBuffer != nil {
+            renderPixelBuffler(movieFrame: lastImageBuffer!, withSampleTime: currentTime)
+        }
+
+        // 最后一帧的PTS > 要显示的目标时间 就不从解码器要数据,直接返回 view 不刷新 只有慢速时会调用
+        if CMTimeGetSeconds(targetTimeStamp) >= CMTimeGetSeconds(showTimeStamp) + (stickerInfo?.model_in ?? 0) && CMTimeGetSeconds(targetTimeStamp) != 0 {
+            FilterLog(message: "目标显示时间 \(String(format: "%.6f", (CMTimeGetSeconds(showTimeStamp)))) 最后显示的时间 \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp) + (stickerInfo?.model_in ?? 0))) 裁剪开始时间:\(String(describing: moveSticker?.model_in)) speedRate is \(stickerInfo!.speedRate)")
+            return
         }
 
         if assetReader == nil {
@@ -365,21 +368,26 @@ class PQMovieFilter: PQBaseFilter {
                 FilterLog(message: " copyNextSampleBuffer is nil error!!!")
                 return
             }
-            let targetTimeStamp = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer!)
+            targetTimeStamp = CMSampleBufferGetOutputPresentationTimeStamp(sampleBuffer!)
 
             // 目标帧 时间
             if sampleBuffer != nil && CMTimeGetSeconds(targetTimeStamp) >= (CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out)) {
-                if sampleBuffer != nil {
-                    let endDecoderTime: TimeInterval = Date().timeIntervalSince1970
-                    FilterLog(message: "查找的帧时间为:\(CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out))  命中时间为: \(CMTimeGetSeconds(targetTimeStamp))  查找时长为\(TimeInterval(endDecoderTime - beginDecoderTime)) 查找次数\(count)  进场时间: \(String(describing: moveSticker?.timelineIn))  裁剪开始时间:\(String(describing: moveSticker?.model_in))")
-                    break
-                }
+                let endDecoderTime: TimeInterval = Date().timeIntervalSince1970
+                FilterLog(message: " speedRate is \(stickerInfo!.speedRate) 当前主线时间为:\(String(format: "%.6f", CMTimeGetSeconds(currentTime))) 查找的帧时间为:\(String(format: "%.6f", CMTimeGetSeconds(showTimeStamp).truncatingRemainder(dividingBy: moveSticker!.out)))  命中时间为: \(String(format: "%.6f", CMTimeGetSeconds(targetTimeStamp)))  查找耗时为:\(String(format: "%.6f", TimeInterval(endDecoderTime - beginDecoderTime))) 查找次数\(count)  进场时间: \(String(describing: moveSticker?.timelineIn))  裁剪开始时间:\(String(describing: moveSticker?.model_in)) 裁剪结束时间:\(String(describing: moveSticker?.out))")
+                break
+
+            } else {
+                FilterLog(message: "不丢帧显示")
+//                usleep(2)
+//                sharedImageProcessingContext.runOperationSynchronously {
+//                    self.renderPixelBuffler(movieFrame: CMSampleBufferGetImageBuffer(sampleBuffer!)!, withSampleTime: currentTime)
+//                }
             }
         }
         // 一,显示命中的帧数据
         if sampleBuffer != nil {
 //            if moveSticker?.materialDurationFit?.fitType == adapterMode.staticFrame.rawValue {
-                lastImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer!)!
+            lastImageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer!)!
 //            }
 
             sharedImageProcessingContext.runOperationSynchronously {
@@ -388,7 +396,6 @@ class PQMovieFilter: PQBaseFilter {
             return
         } else {
             FilterLog(message: "sampleBuffer is  nil data is error self.assetReader?.status is \(String(describing: assetReader?.status))")
-            
         }
         // 二, 已经播放完一次
         if assetReader?.status == .completed {
@@ -418,20 +425,19 @@ class PQMovieFilter: PQBaseFilter {
     ///   - movieFrame:帧数据
     ///   - withSampleTime: 渲染时间戳,不是帧的 PTS 是渲染的时间
     func renderPixelBuffler(movieFrame: CVPixelBuffer, withSampleTime: CMTime) {
-        
-        //NV12 会返回 2,Y分量和UV 分量, 如果buffer 是BGRA 则返回0
+        // NV12 会返回 2,Y分量和UV 分量, 如果buffer 是BGRA 则返回0
         FilterLog(message: "CVPixelBufferGetPlaneCount is \(CVPixelBufferGetPlaneCount(movieFrame))")
-        
+
         let bufferHeight = CVPixelBufferGetHeight(movieFrame)
         let bufferWidth = CVPixelBufferGetWidth(movieFrame)
         CVPixelBufferLockBaseAddress(movieFrame, CVPixelBufferLockFlags(rawValue: CVOptionFlags(0)))
 
         let conversionMatrix = colorConversionMatrix601FullRangeDefault
 
-        //1 Y-plane
+        // 1 Y-plane
         var luminanceGLTexture: CVOpenGLESTexture?
 
-        //激活纹理
+        // 激活纹理
         glActiveTexture(GLenum(GL_TEXTURE0))
 
         let luminanceGLTextureResult = CVOpenGLESTextureCacheCreateTextureFromImage(kCFAllocatorDefault, sharedImageProcessingContext.coreVideoTextureCache, movieFrame, nil, GLenum(GL_TEXTURE_2D), GL_LUMINANCE, GLsizei(bufferWidth), GLsizei(bufferHeight), GLenum(GL_LUMINANCE), GLenum(GL_UNSIGNED_BYTE), 0, &luminanceGLTexture)
@@ -443,7 +449,7 @@ class PQMovieFilter: PQBaseFilter {
 
         let luminanceTexture = CVOpenGLESTextureGetName(luminanceGLTexture!)
 
-        //绑定纹理
+        // 绑定纹理
         glBindTexture(GLenum(GL_TEXTURE_2D), luminanceTexture)
         glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GLfloat(GL_CLAMP_TO_EDGE))
         glTexParameterf(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GLfloat(GL_CLAMP_TO_EDGE))
@@ -457,8 +463,7 @@ class PQMovieFilter: PQBaseFilter {
         }
         luminanceFramebuffer.timingStyle = .videoFrame(timestamp: Timestamp(withSampleTime))
 
-        
-        //2 UV-plane.
+        // 2 UV-plane.
         var chrominanceGLTexture: CVOpenGLESTexture?
 
         glActiveTexture(GLenum(GL_TEXTURE1))
@@ -552,14 +557,13 @@ extension UIImage {
 //
 //        self.init(cgImage: cgImage)
 //    }
-    
-    func saveImage(currentImage: UIImage, persent: CGFloat, imageName: String){
-       
-        if let imageData =  currentImage.jpegData(compressionQuality: persent) {
-               let fullPath = NSHomeDirectory().appending("/Documents/").appending(imageName)
-
-                try? imageData.write(to: URL(fileURLWithPath: fullPath))
-               print("fullPath=\(fullPath)")
-           }
-       }
+
+    func saveImage(currentImage: UIImage, persent: CGFloat, imageName: String) {
+        if let imageData = currentImage.jpegData(compressionQuality: persent) {
+            let fullPath = NSHomeDirectory().appending("/Documents/").appending(imageName)
+
+            try? imageData.write(to: URL(fileURLWithPath: fullPath))
+            print("fullPath=\(fullPath)")
+        }
+    }
 }