Управление памятью - CVPixelBuffer для UIImage, разница между использованием CIImage и VTCreateCGImageFromCVPixelBuffer
Я получил два решения преобразования CVPixelBuffer
в UIImage
,
- Использование CIImage и его контекста
Первое решение использует 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()
}
}
}
}
}
- Использование VTCreateCGImageFromCVPixelBuffer
Код выглядит так.
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:)
, Следы памяти увеличиваются до конца всего процесса кэширования в первом сценарии. Но, во-вторых, он освобождает свою память после завершения каждого рабочего элемента.
Я действительно не знаю почему.
Вот мой метод кэширования, связанный с этой проблемой.
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)
}