2013-03-06 17 views
6

Ho un FFMPEG AVFrame in YUVJ420P e voglio convertirlo in un CVPixelBufferRef con CVPixelBufferCreateWithBytes. La ragione per cui voglio farlo è usare AVFoundation per mostrare/codificare i frame.Come convertire un AVFrame FFMPEG in YUVJ420P in AVFoundation cVPixelBufferRef?

Ho selezionato kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange e provato convertendolo in quanto l'AVFrame ha dati in tre piani Y480Cb240Cr240. E secondo quello che ho cercato questo corrisponde allo kCVPixelFormatType selezionato. Essendo biplanare ho bisogno di convertirlo in un buffer che contiene Y480 e CbCr480 Interlacciato.

ho cercato di creare un buffer di 2 piani:

  • frame->data[0] sul primo piano,
  • frame->data[1] e frame->data[2] interleaved sul secondo piano.

Tuttavia, sto ottenendo l'errore di ritorno -6661 (invalid a) da CVPixelBufferCreateWithBytes:

"Invalid function parameter. For example, out of range or the wrong type." 

Non ho competenze in materia di elaborazione delle immagini a tutti, quindi tutti i puntatori a documentazione che può farmi iniziare a destra l'approccio a questo problema è apprezzato. Anche le mie capacità C non sono al vertice, quindi forse sto facendo un errore di base qui.

uint8_t **buffer = malloc(2*sizeof(int *)); 
    buffer[0] = frame->data[0]; 
    buffer[1] = malloc(frame->linesize[0]*sizeof(int)); 
    for(int i = 0; i<frame->linesize[0]; i++){ 
     if(i%2){ 
      buffer[1][i]=frame->data[1][i/2]; 
     }else{ 
      buffer[1][i]=frame->data[2][i/2]; 
     } 
    } 

    int ret = CVPixelBufferCreateWithBytes(NULL, frame->width, frame->height, kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, buffer, frame->linesize[0], NULL, 0, NULL, cvPixelBufferSample) 

Il telaio è il AVFrame con il rawData da FFMPEG decodifica.

+0

È 'cvPixelBufferSample' a CVPixelBufferRef? In tal caso, l'ultimo parametro in 'CVPixelBufferCreateWithBytes()' dovrebbe essere '& cvPixelBufferSample' per consentire al puntatore del nuovo buffer di pixel di essere restituito per riferimento. –

risposta

6

Le mie capacità di C non sono al top, quindi forse sto facendo un errore di base qui.

Stai facendo diversi:

  • Si deve usare CVPixelBufferCreateWithPlanarBytes(). Non so se CVPixelBufferCreateWithBytes() può essere usato per creare un frame video planare; se è così, richiederà un puntatore a un "blocco descrittore piano" (non riesco a trovare la struttura nei documenti).
  • frame->linesize[0] è il byte per riga, non la dimensione dell'intera immagine. I documenti non sono chiari, ma lo usage è abbastanza chiaro.
  • frame->linesize[0] si riferisce al piano Y; ti preoccupi dei piani UV.
  • Da dove viene il numero sizeof(int)?
  • Stai passando cvPixelBufferSample; potresti voler dire &cvPixelBufferSample.
  • Non stai passando una chiamata di rilascio. La documentazione non dice che è possibile passare NULL.

provare qualcosa di simile:

size_t srcPlaneSize = frame->linesize[1]*frame->height; 
size_t dstPlaneSize = srcPlaneSize *2; 
uint8_t *dstPlane = malloc(dstPlaneSize); 
void *planeBaseAddress[2] = { frame->data[0], dstPlane }; 

// This loop is very naive and assumes that the line sizes are the same. 
// It also copies padding bytes. 
assert(frame->linesize[1] == frame->linesize[2]); 
for(size_t i = 0; i<srcPlaneSize; i++){ 
    // These might be the wrong way round. 
    dstPlane[2*i ]=frame->data[2][i]; 
    dstPlane[2*i+1]=frame->data[1][i]; 
} 

// This assumes the width and height are even (it's 420 after all). 
assert(!frame->width%2 && !frame->height%2); 
size_t planeWidth[2] = {frame->width, frame->width/2}; 
size_t planeHeight[2] = {frame->height, frame->height/2}; 
// I'm not sure where you'd get this. 
size_t planeBytesPerRow[2] = {frame->linesize[0], frame->linesize[1]*2}; 
int ret = CVPixelBufferCreateWithPlanarBytes(
     NULL, 
     frame->width, 
     frame->height, 
     kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange, 
     NULL, 
     0, 
     2, 
     planeBaseAddress, 
     planeWidth, 
     planeHeight, 
     planeBytesPerRow, 
     YOUR_RELEASE_CALLBACK, 
     YOUR_RELEASE_CALLBACK_CONTEXT, 
     NULL, 
     &cvPixelBufferSample); 

La gestione della memoria è lasciata come esercizio per il lettore, ma per il codice di prova si potrebbe farla franca passando NULL invece di un callback rilascio.

+0

Funziona come un fascino! – cahn

Problemi correlati