2016-04-20 21 views
1

フレームデータをAVFrame構造体からバッファにコピーしようとしています。私はYUV420P形式でそれを行う方法を知っています.YデータはAVFrame frame->data[0]に格納されているので、UデータはAVFrame frame->data[1]に格納され、VデータはAVFrame frame->data[2]に格納されていますので、memcpy() Y、UおよびVデータは別々に+簡単にそれを行うことができました:FFMPEG/libav:UYVY422はAVFrame構造内にどのように書き込まれますか?

for (y = 0; y < height; y++) 
    { 
     memcpy(buffer + y*frame->linesize[0], frame->data[0] + y*frame->linesize[0], width); 
    } 

    buffer += ySize; 

    for (y = 0; y < height/2; y++) 
    { 
     memcpy(buffer + y*frame->linesize[1], frame->data[1] + y*frame->linesize[1], width/2); 
    } 

    buffer += uSize; 

    for (y = 0; y < height/2; y++) 
    { 
     memcpy(buffer + y*frame->linesize[2], frame->data[2] + y*frame->linesize[2], width/2); 
    } 

をしかし、それはUYVY422に来るとき、私は、データが構造内に格納されているか分かりません。私はUYVY422形式に関する一般的な知識を持っていて、名前のようにUYVYUYVYUYVY ...と書かれています。しかし、私の質問はどのくらいのデータがAVFrame frame->data[0]AVFrame frame->data[1]AVFrame frame->data[2]フィールドに格納されているので、私はmemcpy()バッファに正確な量を格納することができます知っていますか?

答えて

2

はUYVYのために、データはフレーム - に独占的に保存されている>データ[0]、およびラインごとに、あなたは幅* 2つのバイトをコピーしてください:

for (y = 0; y < height; y++) 
{ 
    memcpy(output_buffer + y*frame->linesize[0], 
      frame->data[0] + y*frame->linesize[0], width * 2); 
} 

はプログラムでこれを導出する方法はあり、場合にあなた興味がある。各AVPixelFormatには、その包装をAVFrame->data[]に記載しているAVPixFmtDescriptorがあります。あなたを得るには、av_pix_fmt_desc_get(AV_PIX_FMT_UYVY)を使用してください。返される項目はthisです(ここではAVComponentDescriptorの構造体参照を参照してください)。 desc->nb_componentsが3、desc->log2_chroma_wが1であることがわかります。これは、U/Vが水平方向に1でサブサンプルされ、desc->comp[0-2].planeが0であることを意味します。つまり、すべてのデータはAVFrame->data[0]です。 offset/step/depthdesc->comp[0-2])は、pix_fmtを完全に動的に読み取る方法が必要な場合に備えて、残りの部分を説明します。私はあなたが個人的にそれを必要としているとは思っていませんが、少なくともそれは誰でもAVFrame->data[]のpix_fmtのパッキングを派生させることができます。

[編集]次のコード例(おそらくバグだらけ)を参照してください:

#include <assert.h> 
#include <stdio.h> 
#include <libavutil/pixdesc.h> 

int main(int argc, char *argv[]) { 
    if (argc < 2) { 
     fprintf(stderr, "Usage: %s [fmt]\n", argv[0]); 
     return 1; 
    } 
    const char *fmtname = argv[1]; 
    enum AVPixelFormat fmt = av_get_pix_fmt(fmtname); 
    if (fmt == AV_PIX_FMT_NONE) { 
     fprintf(stderr, "Unknown pixfmt %s\n", fmtname); 
     return 1; 
    } 
    const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); 
    assert(desc != NULL); 
    printf("N planes: %d, %d bits/element\n", desc->nb_components, desc->comp[0].depth); 

    int n; 
    int epl[4] = { 0, 0, 0, 0 }; 
    int width = 0x100; 
    for (n = 0; n < desc->nb_components; n++) { 
     int is_y = n == 0; 
     int is_a = !(desc->nb_components & 1) && n == desc->nb_components - 1; 
     int h_ss = (is_y || is_a) ? 0 : desc->log2_chroma_w; 

     epl[desc->comp[n].plane] += width >> h_ss; 
    } 

    for (n = 0; n < 4; n++) { 
     int is_y = n == 0; 
     int is_a = !(desc->nb_components & 1) && n == desc->nb_components - 1; 
     int v_ss = (is_y || is_a) ? 0 : desc->log2_chroma_h; 

     if (epl[n] == 0) continue; 
     printf("Plane %d has %lf elements/y_pixel (horizontally) and %lf lines/y_pixel (vertically)\n", 
       n, epl[n]/(double) width, (width >> v_ss)/(double) width); 
    } 

    return 0; 
} 

次のように出力できます:

$ for fmt in yuyv422 uyvy422 yuv420p yuva420p10; do /tmp/test $fmt; done 
N planes: 3, 8 bits/element 
Plane 0 has 2.000000 elements/y_pixel (horizontally) and 1.000000 lines/y_pixel (vertically) 
N planes: 3, 8 bits/element 
Plane 0 has 2.000000 elements/y_pixel (horizontally) and 1.000000 lines/y_pixel (vertically) 
N planes: 3, 8 bits/element 
Plane 0 has 1.000000 elements/y_pixel (horizontally) and 1.000000 lines/y_pixel (vertically) 
Plane 1 has 0.500000 elements/y_pixel (horizontally) and 0.500000 lines/y_pixel (vertically) 
Plane 2 has 0.500000 elements/y_pixel (horizontally) and 0.500000 lines/y_pixel (vertically) 
N planes: 4, 10 bits/element 
Plane 0 has 1.000000 elements/y_pixel (horizontally) and 1.000000 lines/y_pixel (vertically) 
Plane 1 has 0.500000 elements/y_pixel (horizontally) and 0.500000 lines/y_pixel (vertically) 
Plane 2 has 0.500000 elements/y_pixel (horizontally) and 0.500000 lines/y_pixel (vertically) 
Plane 3 has 1.000000 elements/y_pixel (horizontally) and 1.000000 lines/y_pixel (vertically) 
+0

は神ああ、ありがとうございました。私は彼らの出所からそれを見つけることができるとは考えていません。私は明らかに、説明はどこかにある必要がありますが、私はどこを見なければならないのか分かりませんでした。これはとてもうれしく、私はどれほど興奮しているのかを説明することすらできません。今私は任意のピクセル形式の間で圧縮を試してみて、どれが最高/最速に動作するかを調べることができます。私があまり理解していないことの1つは 'AVComponentDescriptor-> step'です。それ以外はすべて自明です。たとえば、YUV420Pのステップが1に設定されている場合、水平方向に連続する2つのピクセルの間に1つのクロマ要素があることを意味しますか? –

+0

また、1行に 'AVFrame-> data [0]'からいくつのバイトをコピーする必要があるのでしょうか? –

+0

ステップは、「このタイプの次の要素に到達するためにポインタをインクリメントするために必要な要素数」を意味します。例:UYVYレイアウトはまさにそれです:U1Y1V1Y2U2Y3V2Y4 [etc]。したがって、私のuint8_t * ptrがU1に設定されている場合、U2に到達するためにいくつの要素(uint8_t)をインクリメントする必要がありますか? 4!そしてY1からY2の間? 2!ほとんどの平面ピクセル形式では、この値は常に1です。この値は、非平面ピクセル形式(またはNV12のクロマ面のような混合形式)の場合に限り1以上です。 –

関連する問題