2011-01-28 8 views
5

Necesito obtener un CMSampleBuffer para el marco OpenGL. Estoy usando esto:CMSampleBuffer de OpenGL para salida de video con AVAssestWritter

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); 

me sale EXEC_BAD_ACCESS para CMSampleBufferCreate.

Se agradece cualquier ayuda, gracias.

Respuesta

6

La solución fue utilizar la clase AVAssetWriterInputPixelBufferAdaptor.

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)]; 
1

¿Por qué el tercer parámetro para CMSampleBufferCreate() es verdadero en su código? De acuerdo con la documentation:

Parámetros

asignador

El asignador de usar para asignar memoria para el objeto CMSampleBuffer . Pase kCFAllocatorDefault a use el asignador predeterminado actual.

dataBuffer

Esto puede ser NULL, un CMBlockBuffer sin memoria de respaldo, un CMBlockBuffer con memoria de respaldo pero no hay datos aún, o una CMBlockBuffer que ya contiene los datos de medios. Solo en ese último caso (o si NULL y numSamples es 0) should dataReady true.

DataReady

Indica si dataBuffer ya contiene los medios datos.

Su cm_block_buffer_ref que se pasa como un amortiguador no contiene datos (que debería NULL para la seguridad, no creo que el compilador hace que, por defecto), por lo que debe utilizar false aquí.

Puede haber otras cosas malas con esto, pero ese es el primer elemento que se me ocurre.

+0

Gracias. ¿Cómo obtengo cm_block_buffer_ref para que contenga los datos de OpenGL? –

+0

@Matthew: mirándolo, creo que deberás crear un CVPixelBuffer, luego usar 'CMSampleBufferCreateForImageBuffer()' en lugar de 'CMSampleBufferCreate()'. De hecho, probablemente sea mejor utilizar un AVAssetWriterInputPixelBufferAdaptor: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAssetWriterInputPixelBufferAdaptor_Class/Reference/Reference.html –

+0

Oh, sí, agregué una respuesta de mío. Me las he arreglado para ponerlo en funcionamiento (un poco lento pero se supone glReadPixels). Pero gracias. –

0

¿Por qué el doble malloc y por qué no intercambiar en el lugar mediante un búfer de temperatura?

Algo como esto:

GLubyte * raw = (GLubyte *) wyMalloc(size); 
    LOGD("raw address %p", raw); 
    glReadPixels(x, y, w, h, GL_RGBA, GL_UNSIGNED_BYTE, raw); 
    const size_t end = h/2; 
    const size_t W = 4*w; 
    GLubyte row[4*w]; 
    for (int i=0; i <= end; i++) { 
     void * top = raw + (h - i - 1)*W; 
     void * bottom = raw + i*W; 
     memcpy(row, top, W); 
     memcpy(top, bottom, W); 
     memcpy(bottom, row, W); 
    } 
+0

Ni siquiera malloc el buffer crudo original, sino que lo reciclo.Creé una clase de grupo de búferes. Hago las cosas ligeramente diferente para mis lazos cortos. Guardo cada imagen en el almacenamiento y luego las leo en secuencia en un momento posterior. – user1524957

Cuestiones relacionadas