iOS CVPixelBufferCreate在swift 2

时间:2015-11-16 23:32:10

标签: swift2 avfoundation avassetwriter cvpixelbuffer

我正在尝试将图像转换为视频,正确的方法似乎是使用带有AVAssetWriterInputPixelBufferAdaptor的AVAssetWriter,它运行良好,但它会泄漏内存。

当我将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,但无济于事。

每次调用它都会增加内存使用量,如果调用足够的话会使设备崩溃 memory profile

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

2 个答案:

答案 0 :(得分: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!

您还应该处理#include "basicFeedBack.hpp" #include "stdio.h" #include <SFML/Window.hpp> #include <OpenGL/gl3.h> #include <OpenGL/glu.h> #include <GLUT/glut.h> // Shader macro #define GLSL(src) "#version 150 core\n" #src // Vertex shader const GLchar* vertexShaderSrc = GLSL( in float inValue; out float outValue; void main() { outValue = sqrt(inValue); } ); int main() { // Window sf::ContextSettings settings; settings.depthBits = 24; settings.stencilBits = 8; sf::Window window(sf::VideoMode(800, 600), "Transform Feedback", sf::Style::Titlebar | sf::Style::Close, settings); // Compile shader GLuint shader = glCreateShader(GL_VERTEX_SHADER); glShaderSource(shader, 1, &vertexShaderSrc, 0); glCompileShader(shader); // Create program and specify transform feedback variables GLuint program = glCreateProgram(); glAttachShader(program, shader); const GLchar* feedbackVaryings[] = { "outValue" }; glTransformFeedbackVaryings(program, 1, feedbackVaryings, GL_INTERLEAVED_ATTRIBS); glLinkProgram(program); glUseProgram(program); // Create VAO GLuint vao; glGenVertexArrays(1, &vao); glBindVertexArray(vao); // Create input VBO and vertex format GLfloat data[] = { 1.0f, 2.0f, 3.0f, 4.0f, 5.0f }; GLuint vbo; glGenBuffers(1, &vbo); glBindBuffer(GL_ARRAY_BUFFER, vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(data), data, GL_STATIC_DRAW); GLint inputAttrib = glGetAttribLocation(program, "inValue"); glEnableVertexAttribArray(inputAttrib); glVertexAttribPointer(inputAttrib, 1, GL_FLOAT, GL_FALSE, 0, 0); // Create transform feedback buffer GLuint tbo; glGenBuffers(1, &tbo); glBindBuffer(GL_ARRAY_BUFFER, tbo); glBufferData(GL_ARRAY_BUFFER, sizeof(data), nullptr, GL_STATIC_READ); // Perform feedback transform glEnable(GL_RASTERIZER_DISCARD); glBindBufferBase(GL_TRANSFORM_FEEDBACK_BUFFER, 0, tbo); glBeginTransformFeedback(GL_POINTS); glDrawArrays(GL_POINTS, 0, 5); glEndTransformFeedback(); glDisable(GL_RASTERIZER_DISCARD); glFlush(); // Fetch and print results GLfloat feedback[5]; glGetBufferSubData(GL_TRANSFORM_FEEDBACK_BUFFER, 0, sizeof(feedback), feedback); printf("%f %f %f %f %f\n", feedback[0], feedback[1], feedback[2], feedback[3], feedback[4]); return 0; } 并尽快打开可选缓冲区,以避免所有0.000000 0.000000 0.000000 0.000000 0.000000

答案 1 :(得分:0)

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

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