2011-01-28 11 views
5

Ho bisogno di ottenere un CMSampleBuffer per il frame OpenGL. Sto usando questo:CMSampleBuffer da OpenGL per l'output 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); 

Ottengo EXEC_BAD_ACCESS per CMSampleBufferCreate.

Qualsiasi aiuto è apprezzato, grazie.

risposta

6

La soluzione era utilizzare la classe 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

Perché il terzo parametro è CMSampleBufferCreate() vero nel codice? Secondo il documentation:

Parametri

allocatore

L'allocatore da utilizzare per assegnare memoria per l'oggetto CMSampleBuffer . Passa kCFAllocatorDefault a usa l'attuale allocatore di default.

dataBuffer

Questo può essere NULL, un CMBlockBuffer senza memoria di massa, un CMBlockBuffer con memoria di massa ma nessuna di dati, o un CMBlockBuffer che contiene già i dati multimediali. Solo in quest'ultimo caso (o se NULL e numSamples è 0) dovrebbe dataReady essere true.

dataReady

Indica se dataBuffer contiene già i supporti dati .

tuo cm_block_buffer_ref che viene passato come un buffer non contiene dati (si dovrebbe NULL per la sicurezza, non credo che il compilatore lo fa di default), quindi si dovrebbe usare false qui.

Ci possono essere altre cose sbagliate in questo, ma questo è il primo elemento che mi viene fuori.

+0

Grazie. Come posso ottenere cm_block_buffer_ref per contenere i dati OpenGL? –

+0

@Matthew - A mio parere, dovrai creare un CVPixelBuffer, quindi utilizzare 'CMSampleBufferCreateForImageBuffer()' invece di 'CMSampleBufferCreate()'. In effetti, probabilmente stai meglio usando AVAssetWriterInputPixelBufferAdaptor: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAssetWriterInputPixelBufferAdaptor_Class/Reference/Reference.html –

+0

Oh sì, ho aggiunto una risposta di il mio. Sono riuscito a farlo funzionare (un po 'lento ma dovrebbe essere glReadPixels). Ma grazie. –

0

Perché il doppio malloc e perché non scambiare sul posto tramite un buffer temporaneo?

Qualcosa di simile a questo:

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

Non ho più malloc il buffer raw originale ma lo ricicla.Ho creato una classe del pool di buffer. Faccio le cose in modo leggermente diverso per i miei loop brevi. Salviamo ogni immagine in memoria, quindi li rileggo in sequenza in un secondo momento. – user1524957