2011-01-28 5 views
5

J'ai besoin d'un CMSampleBuffer pour le cadre OpenGL. J'utilise ceci:CMSampleBuffer d'OpenGL pour la sortie vidéo avec 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); 

je reçois EXEC_BAD_ACCESS pour CMSampleBufferCreate.

Toute aide est appréciée, merci.

Répondre

6

La solution consistait à utiliser 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

Pourquoi le troisième paramètre à CMSampleBufferCreate() est-il vrai dans votre code? Selon le documentation:

Paramètres

allocateur

Le allocateur à utiliser pour allouer de la mémoire pour l'objet CMSampleBuffer . Passez kCFAllocatorDefault à en utilisant l'allocateur par défaut actuel.

DataBuffer

Cela peut être NULL, un CMBlockBuffer sans mémoire de support, un CMBlockBuffer avec mémoire de soutien mais pas encore de données, ou un CMBlockBuffer qui contient déjà les données des médias. Seulement dans ce dernier cas (ou si NULL et numSamples est 0), dataReady doit être true.

dataReady

Indique si DataBuffer contient déjà les médias données.

Votre cm_block_buffer_ref qui est transmis comme un tampon ne contient aucune donnée (vous devez NULL pour la sécurité, je ne crois pas que le compilateur fait que par défaut), vous devez donc utiliser false ici.

Il peut y avoir d'autres choses qui ne vont pas, mais c'est le premier élément qui me saute aux yeux.

+0

Merci. Comment obtenir cm_block_buffer_ref pour contenir les données OpenGL? –

+0

@Matthew - En y regardant, je pense que vous devrez créer un CVPixelBuffer, puis utiliser 'CMSampleBufferCreateForImageBuffer()' au lieu de 'CMSampleBufferCreate()'. En fait, vous êtes probablement mieux d'utiliser un AVAssetWriterInputPixelBufferAdaptor: http://developer.apple.com/library/ios/#documentation/AVFoundation/Reference/AVAssetWriterInputPixelBufferAdaptor_Class/Reference/Reference.html –

+0

Oh oui, j'ai ajouté une réponse de le mien. J'ai réussi à le faire fonctionner (Un peu lent mais glReadPixels est supposé l'être). Mais merci. –

0

Pourquoi la double malloc et pourquoi ne pas échanger en place par un tampon temporaire?

Quelque chose comme ceci:

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

Je ne mets même plus le tampon brut d'origine mais je le recycle.J'ai créé une classe de pool de mémoire tampon. Je fais les choses légèrement différemment pour mes boucles courtes. Je sauvegarde chaque image dans le stockage puis je les relis dans l'ordre à un moment ultérieur. – user1524957

Questions connexes