2011-01-11 9 views
5

CMSampleBufferの内容を変更し、それをAVAssetWriter/AVAssetWriterInputを持つファイルに書きたいとします。CMSampleBufferの内容を変更する最も効率的な方法

私がこれを行う方法は、Core Graphicsビットマップコンテキストを作成して描画することですが、それは遅すぎます。具体的には、イメージをバッファに描画する必要があります。

これをより効率的に行うためのヒントや提案がありますか?

これを達成するためにOpenGLを使用することを考えました。つまり、まずCMSampleBufferからテクスチャAを作成することを考えました。その後、描画したい画像から作成したテクスチャBをテクスチャAにレンダリングし、次にテクスチャAをOpenGLからバックアップして、そのデータをAVAssetWriter/AVAssetWriterInputに渡します。しかし、GPUからCPUにテクスチャデータを転送するのはちょっと高価だと言われています。

それで、どのようにそれにアプローチするかに関する提案はありますか?

ありがとうございます事前にありがとうございました

答えて

8

おそらく行く方法です。しかし、テクスチャではなく、オフスクリーンのフレームバッファにレンダリングするほうが若干効率的かもしれません。

サンプルバッファからテクスチャを抽出するには:

// This function exists to free the malloced data when the CGDataProviderRef is 
// eventually freed. 
void dataProviderFreeData(void *info, const void *data, size_t size){ 
    free((void *)data); 
} 

// Returns an autoreleased CGImageRef. 
- (CGImageRef)processTexture:(GLuint)texture width:(int)width height:(int)height { 
    CGImageRef newImage = NULL; 

    // Set up framebuffer and renderbuffer. 
    GLuint framebuffer; 
    glGenFramebuffers(1, &framebuffer); 
    glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); 

    GLuint colorRenderbuffer; 
    glGenRenderbuffers(1, &colorRenderbuffer); 
    glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer); 
    glRenderbufferStorage(GL_RENDERBUFFER, GL_RGBA8_OES, width, height); 
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, colorRenderbuffer); 

    GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); 
    if (status != GL_FRAMEBUFFER_COMPLETE) { 
     NSLog(@"Failed to create OpenGL frame buffer: %x", status); 
    } else { 
     glViewport(0, 0, width, height); 
     glClearColor(0.0,0.0,0.0,1.0); 
     glClear(GL_COLOR_BUFFER_BIT); 

     // Do whatever is necessary to actually draw the texture to the framebuffer 
     [self renderTextureToCurrentFrameBuffer:texture]; 

     // Read the pixels out of the framebuffer 
     void *data = malloc(width * height * 4); 
     glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); 

     // Convert the data to a CGImageRef. Note that CGDataProviderRef takes 
     // ownership of our malloced data buffer, and the CGImageRef internally 
     // retains the CGDataProviderRef. Hence the callback above, to free the data 
     // buffer when the provider is finally released. 
     CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, data, width * height * 4, dataProviderFreeData); 
     CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB(); 
     newImage = CGImageCreate(width, height, 8, 32, width*4, colorspace, kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast, dataProvider, NULL, true, kCGRenderingIntentDefault); 
     CFRelease(dataProvider); 
     CGColorSpaceRelease(colorspace); 

     // Autorelease the CGImageRef 
     newImage = (CGImageRef)[NSMakeCollectable(newImage) autorelease]; 
    } 

    // Clean up the framebuffer and renderbuffer. 
    glDeleteRenderbuffers(1, &colorRenderbuffer); 
    glDeleteFramebuffers(1, &framebuffer); 

    return newImage; 
} 
:OpenGLの通過質感を処理するには

// Note the caller is responsible for calling glDeleteTextures on the return value. 
- (GLuint)textureFromSampleBuffer:(CMSampleBufferRef)sampleBuffer { 
    GLuint texture = 0; 

    glGenTextures(1, &texture); 
    glBindTexture(GL_TEXTURE_2D, texture); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); 
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); 

    CVImageBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); 
    CVPixelBufferLockBaseAddress(pixelBuffer, 0); 
    int width = CVPixelBufferGetWidth(pixelBuffer); 
    int height = CVPixelBufferGetHeight(pixelBuffer); 
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_BGRA, GL_UNSIGNED_BYTE, CVPixelBufferGetBaseAddress(pixelBuffer)); 
    CVPixelBufferUnlockBaseAddress(pixelBuffer, 0); 

    return texture; 
} 

、あなたは、このような何かを行うことができます

関連する問題