从视频生成UIImage图像非常慢

时间:2017-05-08 20:21:31

标签: ios swift uiimage cmsamplebuffer

我需要从视频的每个帧中提取UIImage,并在UICollectionView中使用这些图像。我的问题是图像生成过程花费的时间太长。如何让这个更快,以便用户看不到图像加载?

这些图像显示在一个视图中,该视图有两个UICollectionViews:一个大的分页视图和一个小的缩略图大小的轮播,所以我为每个集合视图生成两个图像。当使用集合视图进入视图时,我立即开始生成图像,但是每个单元格生成图像时可能需要长达2秒才能生成图像(屏幕上只有1.5个大单元格和5-7个缩略图单元格)。滚动时,我看到空单元格太久(再次长达2秒)。在不同的场景中,我使用来自Photos框架的图像填充这些集合视图,这些图像表现出色。在用户选择使用集合视图进入视图之前,我无法预先加载图像,因为如果用户不选择输入,则可能不需要加载图像。

我以前使用AVAssetImageGenerator来提取图像,但经过一些研究后,我了解到该方法效率不高,并转而使用以下方法。

我确实在集合视图中实现了图像缓存,但这只有在图像已经慢慢生成后才有用。

用于从视频生成图像的集合视图单元调用的代码。

public func image(at index: Int, resizedTo targetSize: CGSize = CGSize(), completed: @escaping (Int, UIImage?, Error?) -> ()) {  

    if sampleBuffers.isEmpty {
        self.loadSampleBuffers()
    }

    DispatchQueue.global().async {
        let pixelBuffer = CMSampleBufferGetImageBuffer(self.sampleBuffers[index])
        let ciImage = CIImage(cvImageBuffer: pixelBuffer!)

         if targetSize == CGSize.zero {
               let context = CIContext()
               let cgImage = context.createCGImage(ciImage, from: ciImage.extent)
               let image = UIImage(cgImage: cgImage!)
               DispatchQueue.main.async {
                   completed(index, image.rotate(), nil)
               }
         } else {

               let image = UIImage(ciImage: ciImage)
               let rect = AVMakeRect(aspectRatio: image.size, insideRect: CGRect(origin: CGPoint(), size: targetSize))
               UIGraphicsBeginImageContextWithOptions(targetSize, false, 1.0)
               image.draw(in:rect)
               let resizedImage = UIGraphicsGetImageFromCurrentImageContext()
               UIGraphicsEndImageContext()
               DispatchQueue.main.async {
                   completed(index, resizedImage, nil)
               }
         }
    }
}

以下是加载样本缓冲区的功能:

public func loadSampleBuffers() {
       var reader: AVAssetReader! = nil
       do {
           reader = try AVAssetReader(asset: self._asset)
      } catch {
           print("could not initialize reader.")
           return
       }

       let readerOutputSettings: [String: Any] = [kCVPixelBufferPixelFormatTypeKey as String : Int(kCVPixelFormatType_420YpCbCr8BiPlanarFullRange)]
       let readerOutput = AVAssetReaderTrackOutput(track: self._track, outputSettings: readerOutputSettings)
       reader.add(readerOutput)
       reader.startReading()

    // read in samples    
      var samples: [CMSampleBuffer] = []
      while let sample = readerOutput.copyNextSampleBuffer() {
           samples.append(sample)
      }

      self.sampleBuffers = samples
      self.frameCount = samples.count    
}

0 个答案:

没有答案