Search code examples
iphoneobjective-copengl-esavassetwritercore-motion

CMSampleBuffer from OpenGL for video output with AVAssestWritter


I need to get a CMSampleBuffer for the OpenGL frame. I'm using this:

int s = 1;
        UIScreen * screen = [UIScreen mainScreen];
        if ([screen respondsToSelector:@selector(scale)]){
            s = (int)[screen scale];
        }
        const int w = viewController.view.frame.size.width/2;
        const int h = viewController.view.frame.size.height/2;
        const NSInteger my_data_length = 4*w*h*s*s;
        // allocate array and read pixels into it.
        GLubyte * buffer = malloc(my_data_length);
        glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
        // gl renders "upside down" so swap top to bottom into new array.
        GLubyte * buffer2 = malloc(my_data_length);
        for(int y = 0; y < h*s; y++){
            memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s);
        }
        free(buffer);
        CMBlockBufferRef * cm_block_buffer_ref;
        CMBlockBufferAccessDataBytes(cm_block_buffer_ref,0,my_data_length,buffer2,*buffer2);
        CMSampleBufferRef * cm_buffer;
        CMSampleBufferCreate (kCFAllocatorDefault,cm_block_buffer_ref,true,NULL,NULL,NULL,1,1,NULL,0,NULL,cm_buffer);

I get EXEC_BAD_ACCESS for CMSampleBufferCreate.

Any help is appreciated, thank you.


Solution

  • The solution was to use the AVAssetWriterInputPixelBufferAdaptor class.

    int s = 1;
            UIScreen * screen = [UIScreen mainScreen];
            if ([screen respondsToSelector:@selector(scale)]){
                s = (int)[screen scale];
            }
            const int w = viewController.view.frame.size.width/2;
            const int h = viewController.view.frame.size.height/2;
            const NSInteger my_data_length = 4*w*h*s*s;
            // allocate array and read pixels into it.
            GLubyte * buffer = malloc(my_data_length);
            glReadPixels(0, 0, w*s, h*s, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
            // gl renders "upside down" so swap top to bottom into new array.
            GLubyte * buffer2 = malloc(my_data_length);
            for(int y = 0; y < h*s; y++){
                memcpy(buffer2 + (h*s - 1 - y)*4*w*s, buffer + (4*y*w*s), 4*w*s);
            }
            free(buffer);
            CVPixelBufferRef pixel_buffer = NULL;
            CVPixelBufferCreateWithBytes (NULL,w*2,h*2,kCVPixelFormatType_32BGRA,buffer2,4*w*s,NULL,0,NULL,&pixel_buffer);
            [av_adaptor appendPixelBuffer: pixel_buffer withPresentationTime:CMTimeMakeWithSeconds([[NSDate date] timeIntervalSinceDate: start_time],30)];