【问题标题】:iOS CVPixelBufferCreate leaking memory in swift 2iOS CVPixelBuffer在swift 2中创建泄漏内存
【发布时间】:2016-02-18 05:06:26
【问题描述】:

我正在尝试将图像转换为视频,正确的方法似乎是使用 AVAssetWriter 和 AVAssetWriterInputPixelBufferAdaptor,并且效果很好,但是会泄漏内存。

当我将 CGImage 转换为 CVPixelBuffer 时,我调用 CVPixelBufferCreate,它永远不会释放它的内存。

func CGImageToPixelBuffer(image: CGImageRef, frameSize: CGSize) -> CVPixelBuffer {

    // stupid CFDictionary stuff
    let keys: [CFStringRef] = [kCVPixelBufferCGImageCompatibilityKey, kCVPixelBufferCGBitmapContextCompatibilityKey]
    let values: [CFTypeRef] = [kCFBooleanTrue, kCFBooleanTrue]
    let keysPointer = UnsafeMutablePointer<UnsafePointer<Void>>.alloc(1)
    let valuesPointer =  UnsafeMutablePointer<UnsafePointer<Void>>.alloc(1)
    keysPointer.initialize(keys)
    valuesPointer.initialize(values)
    let options = CFDictionaryCreate(kCFAllocatorDefault, keysPointer, valuesPointer, keys.count,
        UnsafePointer<CFDictionaryKeyCallBacks>(), UnsafePointer<CFDictionaryValueCallBacks>())

    let buffer = UnsafeMutablePointer<CVPixelBuffer?>.alloc(1)

    // here's the leak >:[
    let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(frameSize.width), Int(frameSize.height),
        kCVPixelFormatType_32ARGB, options, buffer)

    CVPixelBufferLockBaseAddress(pixelBuffer.memory!, 0);
    let bufferData = CVPixelBufferGetBaseAddress(buffer.memory!);

    let rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    let context = CGBitmapContextCreate(bufferData, Int(frameSize.width),
        Int(frameSize.height), 8, 4*Int(frameSize.width), rgbColorSpace,
        CGImageAlphaInfo.NoneSkipFirst.rawValue);

    CGContextDrawImage(context, CGRectMake(0, 0,
        CGFloat(CGImageGetWidth(image)),
        CGFloat(CGImageGetHeight(image))), image);

    CVPixelBufferUnlockBaseAddress(pixelBuffer.memory!, 0);
    return buffer.memory!
}

这是调用 CGImageToPixelBuffer 的代码

func saveImageAsVideoFile(path: NSURL, image: UIImage, duration: Double) {
    let writer = try! AVAssetWriter(URL: path, fileType: AVFileTypeQuickTimeMovie)

    let videoSettings: NSDictionary = [
        AVVideoCodecKey : AVVideoCodecH264,
        AVVideoWidthKey : NSNumber(integer: Int(image.size.width)),
        AVVideoHeightKey : NSNumber(integer: Int(image.size.height))
    ]
    let input = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: videoSettings as? [String : AnyObject])
    let inputAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: input, sourcePixelBufferAttributes: nil)
    input.expectsMediaDataInRealTime = false
    writer.addInput(input)
    writer.startWriting()
    writer.startSessionAtSourceTime(kCMTimeZero)

    // leak starts here
    let buffer = CGImageToPixelBuffer(image.CGImage!, frameSize: image.size)

    // append 30 frames to AVAssetWriter thing
    for i in 0..<30
        if input.readyForMoreMediaData {
            inputAdaptor.appendPixelBuffer(buffer, withPresentationTime: CMTimeMake(i, 30))
        }
    }

    //CVPixelBufferRelease(buffer) ??

    input.markAsFinished()
    writer.finishWritingWithCompletionHandler({ () -> Void in
        print("yay")
    })
}

CVPixelBufferRelease 在 swift 2 中不可用

CVPixelBufferCreate 在 swift 2 中没有返回非托管指针,所以我不能使用这个 guys code

我尝试在 unsafepointer 上手动调用 destroy 和 dealloc,但无济于事。

每次调用它都会增加内存使用量,如果调用足够多,会导致设备崩溃

任何帮助或建议将不胜感激。

【问题讨论】:

    标签: swift2 avfoundation avassetwriter cvpixelbuffer


    【解决方案1】:

    您的let buffer = UnsafeMutablePointer&lt;CVPixelBuffer?&gt;.alloc(1) 没有被dealloc 平衡,但是添加这似乎并不能解决泄漏问题。 只需使用 CVPixelBuffer? 即可,而且看起来更简单:

    var buffer: CVPixelBuffer?
    
    // TODO: handle status != noErr
    let status = CVPixelBufferCreate(kCFAllocatorDefault, Int(frameSize.width), Int(frameSize.height),
        kCVPixelFormatType_32ARGB, options, &buffer)
    
    CVPixelBufferLockBaseAddress(buffer!, 0);
    let bufferData = CVPixelBufferGetBaseAddress(buffer!);
    
    let rgbColorSpace = CGColorSpaceCreateDeviceRGB();
    let context = CGBitmapContextCreate(bufferData, Int(frameSize.width),
        Int(frameSize.height), 8, 4*Int(frameSize.width), rgbColorSpace,
        CGImageAlphaInfo.NoneSkipFirst.rawValue);
    
    CGContextDrawImage(context, CGRectMake(0, 0,
        CGFloat(CGImageGetWidth(image)),
        CGFloat(CGImageGetHeight(image))), image);
    
    CVPixelBufferUnlockBaseAddress(buffer!, 0);
    

    您还应该处理status != noErr 并尽快打开可选缓冲区,以避免所有这些buffer!s。

    【讨论】:

      【解决方案2】:

      我也有类似的泄漏。我不确定,但我认为可以使用以下内容:

      let bufferPointer = UnsafeMutablePointer<CVPixelBuffer?>.alloc(1)
      ...
      let pixelBuffer = bufferPointer.memory!
      bufferPointer.destroy()
      return pixelBuffer
      

      【讨论】:

        猜你喜欢
        • 2016-12-24
        • 1970-01-01
        • 1970-01-01
        • 2011-12-28
        • 1970-01-01
        • 2020-03-19
        • 2017-08-17
        • 2016-08-17
        • 2016-03-08
        相关资源
        最近更新 更多