我有两个解决方案将CVPixelBuffer
转换为UIImage
。
第一个解决方案是使用CIImage
和CIContext
。
func readAssetAndCache(completion: @escaping () -> Void) {
/** Setup AVAssetReader **/
reader.startReading()
let context = CIContext()
while let sampleBuffer = generator.trackoutput.copyNextSampleBuffer() {
autoreleasepool {
guard let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
let ciImage = CIImage(cvImageBuffer: imageBuffer)
guard let cgImage = context.createCGImage(ciImage, from: ciImage.extent) else { return }
if let image = UIImage(cgImage: cgImage) {
CacheManager.default.cache(image: image, forKey: "CachedImages") {
completion()
}
}
}
}
}
代码看起来像这样。
func readAssetAndCache(completion: @escaping () -> Void) {
/** Setup AVAssetReader **/
reader.startReading()
while let sampleBuffer = generator.trackoutput.copyNextSampleBuffer() {
autoreleasepool {
guard let imageBuffer: CVPixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return }
if let image = UIImage(pixelBuffer: imageBuffer,
scale: 1.0,
orientation: self.imageOrientation) {
CacheManager.default.cache(image: image, forKey: "CachedImages") {
completion()
}
}
}
}
}
}
在此解决方案中,我使用此扩展方法。
import UIKit
import VideoToolbox
extension UIImage {
public convenience init?(pixelBuffer: CVPixelBuffer, scale: CGFloat, orientation: UIImageOrientation) {
var image: CGImage?
VTCreateCGImageFromCVPixelBuffer(pixelBuffer, nil, &image)
guard let cgImage = image else { return nil }
self.init(cgImage: cgImage, scale: scale, orientation: orientation)
}
}
从视频中提取图像的整个过程如下。
OperationQueue
在磁盘上同时缓存每个映像。使用CIContext
及其createCGImage(ciImage:rect:)
同时缓存图像时,会出现问题。在第一种情况下,内存占用量将增加,直到所有缓存过程结束。但是,第二种方式是,当每个workItem完成时,它将释放其内存。
我真的不知道为什么。
这是我与此问题有关的缓存方法。
func cache(image: UIImage, forKey key: String, completion: @escaping () -> Void) {
let operation = BlockOperation(block: { [weak self] in
guard let `self` = self else { return }
self.diskCache(image: image)
})
operation.completionBlock = completion
operationQueue.addOperation(operation)
}
func diskCache(image: UIImage) {
let data = UIImageJPEGRepresentation(image, 1.0)
let key = "\(self.identifierPrefix).jpg"
FileManager.default.createFile(atPath: self.cachePath.appendingPathComponent(key).path,
contents: data, attributes: nil)
}