2

我有两个解决方案转换CVPixelBufferUIImage.

  1. 使用 CIImage 及其上下文

第一个解决方案是使用CIImageand 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()
                }
            }
        }
    }
}
  1. 使用 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)
        }
    }

从视频中提取图像的整个过程如下。

全过程

  1. 串行提取所有帧。
  2. 使用 .将每个图像同时缓存在磁盘中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)
}
4

0 回答 0