7

私は FFMPEG を持っていて、AVFrameそれをwithYUVJ420Pに変換したいと思っています。これを行う理由は、AVFoundation を使用してフレームを表示/エンコードするためです。CVPixelBufferRefCVPixelBufferCreateWithBytes

kCVPixelFormatType_420YpCbCr8BiPlanarVideoRangeAVFrame は 3 つのプレーンにデータがあるので、それ を選択して変換してみましY480 Cb240 Cr240た。そして、私が調査したところによると、これは選択しkCVPixelFormatTypeた . Y480バイプラナーであるため、CbCr480インターリーブを含むバッファーに変換する必要があります。

2つのプレーンでバッファを作成しようとしました:

  • frame->data[0]最初の飛行機で、
  • frame->data[1]frame->data[2]2 番目のプレーンでインターリーブされます。

ただし、次のエラーが返さ-6661 (invalid a)CVPixelBufferCreateWithBytesます。

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

フレームは、AVFrameFFMPEG Decoding からの rawData を使用したものです。

4

1 に答える 1

7

私のCスキルも一流ではないので、ここで基本的な間違いを犯しているのかもしれません。

あなたはいくつかを作っています:

  • を使用する必要がありますCVPixelBufferCreateWithPlanarBytes()CVPixelBufferCreateWithBytes()平面ビデオフレームの作成に使用できるかどうかはわかりません。もしそうなら、それは「平面記述子ブロック」へのポインタを必要とします(私はドキュメントで構造体を見つけることができないようです)。
  • frame->linesize[0]画像全体のサイズではなく、行あたりのバイト数です。ドキュメントは不明確ですが、使用法はかなり明確です。
  • 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は、リリースコールバックの代わりに渡すことで解決できる場合があります。

于 2013-03-07T03:49:47.127 に答える