2013-03-06 6 views
6

YUVJ420PにFFMPEG AVFrameがあり、CVPixelBufferRefCVPixelBufferCreateWithBytesと変換したいと思います。私がこれをしたい理由は、AVFoundationを使ってフレームを表示/エンコードすることです。YUVJ420PのFFMPEG AVFrameをAVFoundation cVPixelBufferRefに変換するにはどうすればいいですか?

Iは、kCVPixelFormatType_420YpCbCr8BiPlanarVideoRangeを選択しAVFrameは、3つの平面 Cb240Y480Cr240のデータを有しているので、それを変換しようとしました。私が調査したところによると、これは選択したkCVPixelFormatTypeと一致します。双平面にすることで、私はそれをY480CbCr480のインターリーブを含むバッファに変換する必要があります。

Iは、2面のバッファを作成しようとした:第1の平面上

  • frame->data[0]
  • frame->data[1]及び第二面上にインターリーブframe->data[2]を。

しかし、私はCVPixelBufferCreateWithBytesからリターンエラー-6661 (invalid a)を取得しています:

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

私は私が右に始めることができますドキュメントへのポインタので、全ての画像処理の専門知識を持っていませんこの問題へのアプローチは高く評価されています。私のCスキルはラインの上にないので、多分私はここで基本的な間違いをしています。

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) 

フレームはFFMPEG復号から生データとAVFrameです。

+0

'cvPixelBufferSample'はCVPixelBufferRefですか?その場合、新しいピクセルバッファへのポインタが参照によって返されるようにする代わりに、 'CVPixelBufferCreateWithBytes()'の最後のパラメータは '&cvPixelBufferSample'である必要があります。 –

答えて

6

私のCスキルは、どちらかと言えば、基本的なミスをしている可能性があります。

あなたは、いくつか作っている:あなたはCVPixelBufferCreateWithPlanarBytes()を使用する必要があります

  • 。平面ビデオフレームの作成にCVPixelBufferCreateWithBytes()を使用できるかどうかわかりません。もしそうなら、 "平面記述子ブロック"へのポインタが必要になります(私はドキュメント内の構造体を見つけることができません)。
  • frame->linesize[0]は、画像全体のサイズではなく、ローので、バイトです。ドキュメントは不明ですが、usageはかなり明確です。
  • frame->linesize[0]は、Y平面を指す。あなたはUV面を気にします。
  • sizeof(int)はどこですか?
  • あなたはcvPixelBufferSampleを渡しています。 &cvPixelBufferSampleを意味する可能性があります。
  • リリースコールバックを渡すことはありません。ドキュメントにはNULLを渡すことができるとは言えません。

このような何か試してみてください:

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

メモリ管理を読者への課題として残されているが、テストコードのためにあなたの代わりにリリースコールバックのNULLに渡して逃げるかもしれません。

+0

魅力的な作品です! – cahn

関連する問題