2011-01-11 31 views
5

Tôi muốn sửa đổi nội dung của CMSampleBuffer và sau đó ghi nó vào một tập tin với AVAssetWriter/AVAssetWriterInput.Cách hiệu quả nhất để sửa đổi nội dung CMSampleBuffer

Cách tôi làm điều này là tạo ra một bối cảnh bitmap đồ họa lõi và sau đó vẽ vào nó, nhưng nó quá chậm. Cụ thể, tôi cần vẽ một hình ảnh vào bộ đệm.

Vì vậy, một người có thể cung cấp một số gợi ý hoặc gợi ý về cách làm điều đó hiệu quả hơn?

Tôi đã nghĩ về việc sử dụng OpenGL để thực hiện điều đó, tức là, trước tiên hãy tạo kết cấu A từ CMSampleBuffer. Sau đó render texture B, được tạo từ ảnh tôi muốn vẽ, vào texture A, sau đó lấy dữ liệu sao lưu texture A từ OpenGL và cuối cùng đưa dữ liệu đó đến AVAssetWriter/AVAssetWriterInput. Nhưng các tài liệu nói rằng chuyển dữ liệu kết cấu từ GPU trở lại CPU là kinda đắt tiền.

Vì vậy, mọi đề xuất về cách tiếp cận điều đó?

Cảm ơn trước

Trả lời

8

OpenGL có lẽ là cách để thực hiện. Tuy nhiên, nó có thể hiệu quả hơn một chút để hiển thị cho một framebuffer ngoài màn hình chứ không phải là kết cấu.

Để trích xuất một kết cấu từ một bộ đệm mẫu:

// 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; 
} 

Để xử lý các kết cấu thông qua OpenGL, sau đó bạn có thể làm một cái gì đó như thế này:

// 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; 
} 
Các vấn đề liên quan