MLBDG
MLBDG

Reputation: 1367

iOS OpenGLES Memory Leaks

I'm working on an app that plays a video on an OpenGLES scenario using textures (iOS9 using Xcode 7.1.1. although I don't think this is relevant)

When I start playing the video it goes in a loop and runs out of memory causing the app crash. xCode just says "Lost connection with ------ iPhone" (Thanks Apple, nice help), but after looking in more depth...

From xCode I got this: enter image description here

And from Instruments (running "Leaks") I got: enter image description here

Seems to be clear that the problem comes from the textures but I'm not being able to fix it.

Here is how I declare the vars:

// Points to an unmanaged texture manager object, which can access an OpenGL texture
private var texturePointer = UnsafeMutablePointer<CVOpenGLESTexture?>.alloc(1)


// Cache for managing the video texture pointers
private var videoTextureCachePointer = UnsafeMutablePointer<CVOpenGLESTextureCache?>.alloc(1)

And this is the rest of the code:

// Load an image buffer into OpenGL
private func loadImageTexture(pixelBuffer: CVPixelBuffer!) {

    // If null, return for safety
    if (pixelBuffer == nil) {
        return;
    }

    // Get frame size
    let frameWidth = CVPixelBufferGetWidth(pixelBuffer)
    let frameHeight = CVPixelBufferGetHeight(pixelBuffer)

    // Release previous frame: No longer valid on iOS9! <-I should be removing old frames!
    //texturePointer.release()


    // Periodic texture cache flush every frame
    let videoTextureCache = videoTextureCachePointer.memory!
    CVOpenGLESTextureCacheFlush(videoTextureCache, 0);

    // Copy from CPU to GPU
    glActiveTexture(GLenum(GL_TEXTURE0))
    CVOpenGLESTextureCacheCreateTextureFromImage(
        kCFAllocatorDefault,
        videoTextureCache,
        pixelBuffer,
        nil,
        GLenum(GL_TEXTURE_2D),
        GLint(GL_RGBA),
        GLsizei(frameWidth),
        GLsizei(frameHeight),
        GLenum(GL_BGRA),
        GLenum(GL_UNSIGNED_BYTE),
        0,
        &texturePointer.memory)

    // Extract texture
    let videoTexture = texturePointer[0]!
    let videoTextureId = CVOpenGLESTextureGetName(videoTexture)
    imageTexture = videoTextureId

    // Configure texture
    glBindTexture(CVOpenGLESTextureGetTarget(videoTexture), CVOpenGLESTextureGetName(videoTexture));
    glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GL_LINEAR);
    glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GL_LINEAR);
    glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GL_CLAMP_TO_EDGE);
    glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GL_CLAMP_TO_EDGE);

}

I'm kind of new in OpenGL so I guess I am missing "HOW" and "WHERE" to release the previous frames.

I tried "glDeleteTextures" but not sure if this is the solution.

Upvotes: 2

Views: 1210

Answers (1)

Matic Oblak
Matic Oblak

Reputation: 16794

There is no need to have multiple textures or any kind of cache. I suggest you to create a single texture of fixed (large enough) size for instance 2024x2024 with empty data (pass nil as data parameter). Then when you get the pixel buffer rather use glTexSubImage to transfer the data at (0, 0 , videoWidth, videoHeight). Now your texture is filled, rewritten by pixel buffer data and is ready to be drawn. The texture coordinates need to be computed which are then (0, 0, videoWidth/textureWidth, videoHeight/textureHeight). That is pretty much it. If the leak persists it has nothing to do with the openGL. The texture should be deleted when you don't need it any more (when the video is done playing or never if you want to reuse it for other videos).

Upvotes: 1

Related Questions