2010-10-02 4 views
7

Sto impazzendo con questo - ho cercato ovunque e provato qualsiasi cosa e tutto quello che posso pensare.AVCapture appendSampleBuffer

Sto creando un'app per iPhone che utilizza AVFoundation, in particolare AVCapture per acquisire video utilizzando la fotocamera dell'iPhone.

È necessario disporre di un'immagine personalizzata sovrascritta sul feed video incluso nella registrazione.

Finora ho impostato la sessione di AVCapture, posso visualizzare il feed, accedere al frame, salvarlo come UIImage e spostare l'immagine di overlay su di esso. Quindi converti questo nuovo UIImage in un CVPixelBufferRef. annnd per ricontrollare che il bufferRef stia funzionando, l'ho riconvertito in una UIImage e visualizza l'immagine bene immobile.

Il problema si verifica quando si tenta di convertire CVPixelBufferRef in CMSampleBufferRef per aggiungere a assetWriterInput di AVCaptureSession. Il CMSampleBufferRef restituisce sempre NULL quando provo a crearlo.

Ecco la - Funzione (void) captureOutput

- (void)captureOutput:(AVCaptureOutput *)captureOutput 
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer 
    fromConnection:(AVCaptureConnection *)connection 
{ 

UIImage *botImage = [self imageFromSampleBuffer:sampleBuffer]; 
UIImage *wheel = [self imageFromView:wheelView]; 

UIImage *finalImage = [self overlaidImage:botImage :wheel]; 
//[previewImage setImage:finalImage]; <- works -- the image is being merged into one UIImage 

CVPixelBufferRef pixelBuffer = NULL; 
CGImageRef cgImage = CGImageCreateCopy(finalImage.CGImage); 
CFDataRef image = CGDataProviderCopyData(CGImageGetDataProvider(cgImage)); 
int status = CVPixelBufferCreateWithBytes(NULL, 
      self.view.bounds.size.width, 
      self.view.bounds.size.height, 
      kCVPixelFormatType_32BGRA, 
      (void*)CFDataGetBytePtr(image), 
      CGImageGetBytesPerRow(cgImage), 
      NULL, 
      0, 
      NULL, 
      &pixelBuffer); 
if(status == 0){ 
    OSStatus result = 0; 

    CMVideoFormatDescriptionRef videoInfo = NULL; 
    result = CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixelBuffer, &videoInfo); 
    NSParameterAssert(result == 0 && videoInfo != NULL); 

    CMSampleBufferRef myBuffer = NULL; 
    result = CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, 
      pixelBuffer, true, NULL, NULL, videoInfo, NULL, &myBuffer); 
    NSParameterAssert(result == 0 && myBuffer != NULL);//always null :S 

    NSLog(@"Trying to append"); 

    if (!CMSampleBufferDataIsReady(myBuffer)){ 
    NSLog(@"sampleBuffer data is not ready"); 
    return; 
    } 

    if (![assetWriterInput isReadyForMoreMediaData]){ 
    NSLog(@"Not ready for data :("); 
    return; 
    } 

    if (![assetWriterInput appendSampleBuffer:myBuffer]){ 
    NSLog(@"Failed to append pixel buffer"); 
    } 



} 

} 

Un'altra soluzione Ho sentito parlare utilizza un AVAssetWriterInputPixelBufferAdaptor che elimina la necessità di fare la disordinata involucro CMSampleBufferRef. Tuttavia, ho setacciato forum e documenti per sviluppatori in pila e Apple e non riesco a trovare una descrizione chiara o un esempio su come impostarlo o su come usarlo. Se qualcuno ne ha un esempio funzionante potresti per favore mostrarmelo o aiutarmi a risolvere il problema di cui sopra: ho lavorato su questo non-stop per una settimana e sono a fine ingegno.

Fatemi sapere se avete bisogno di altre informazioni

Grazie in anticipo,

Michael

+0

Ci scusiamo per la mancanza di formattazione del codice - è apparso bene nell'anteprima: S –

risposta

6

È necessario AVAssetWriterInputPixelBufferAdaptor, ecco il codice per crearlo:

// Create dictionary for pixel buffer adaptor 
NSDictionary *bufferAttributes = [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32BGRA], kCVPixelBufferPixelFormatTypeKey, nil]; 

// Create pixel buffer adaptor 
m_pixelsBufferAdaptor = [[AVAssetWriterInputPixelBufferAdaptor alloc] initWithAssetWriterInput:assetWriterInput sourcePixelBufferAttributes:bufferAttributes]; 

E il codice per utilizzarlo:

// If ready to have more media data 
if (m_pixelsBufferAdaptor.assetWriterInput.readyForMoreMediaData) { 
    // Create a pixel buffer 
    CVPixelBufferRef pixelsBuffer = NULL; 
    CVPixelBufferPoolCreatePixelBuffer(NULL, m_pixelsBufferAdaptor.pixelBufferPool, &pixelsBuffer); 

    // Lock pixel buffer address 
    CVPixelBufferLockBaseAddress(pixelsBuffer, 0); 

    // Create your function to set your pixels data in the buffer (in your case, fill with your finalImage data) 
    [self yourFunctionToPutDataInPixelBuffer:CVPixelBufferGetBaseAddress(pixelsBuffer)]; 

    // Unlock pixel buffer address 
    CVPixelBufferUnlockBaseAddress(pixelsBuffer, 0); 

    // Append pixel buffer (calculate currentFrameTime with your needing, the most simplest way is to have a frame time starting at 0 and increment each time you write a frame with the time of a frame (inverse of your framerate)) 
    [m_pixelsBufferAdaptor appendPixelBuffer:pixelsBuffer withPresentationTime:currentFrameTime]; 

    // Release pixel buffer 
    CVPixelBufferRelease(pixelsBuffer); 
} 

E non dimenticare di rilasciare i pixelBufferAdaptor.

+0

Funziona davvero? Ho provato a mano a creare il buffer dei pixel come l'OP, e ho provato con un buffer pool di pixel. Quando provo con un pool di buffer di pixel come sopra definito, funziona nel simulatore ma non ha mai assegnato il pool di buffer di pixel quando è in esecuzione sul dispositivo. –

1

Lo faccio utilizzando CMSampleBufferCreateForImageBuffer().

OSStatus ret = 0; 
CMSampleBufferRef sample = NULL; 
CMVideoFormatDescriptionRef videoInfo = NULL; 
CMSampleTimingInfo timingInfo = kCMTimingInfoInvalid; 
timingInfo.presentationTimeStamp = pts; 
timingInfo.duration = duration; 

ret = CMVideoFormatDescriptionCreateForImageBuffer(NULL, pixel, &videoInfo); 
if (ret != 0) { 
    NSLog(@"CMVideoFormatDescriptionCreateForImageBuffer failed! %d", (int)ret); 
    goto done; 
} 
ret = CMSampleBufferCreateForImageBuffer(kCFAllocatorDefault, pixel, true, NULL, NULL, 
             videoInfo, &timingInfo, &sample); 
if (ret != 0) { 
    NSLog(@"CMSampleBufferCreateForImageBuffer failed! %d", (int)ret); 
    goto done; 
} 
+0

Puoi specificare come imposti il ​​timingInfo? Vedo "pts" e "duration" sono quei valori costanti? o cosa sono quelli .. come li imposti? – omarojo

+0

Nel mio caso non funziona ... tuttavia Error è nullo..ma quando ottengo CMVideoFormatDescriptionRef .... il suo ritorno nil. –