2016-04-20 51 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有一个AVPixFmtDescriptor描述其在AVFrame->data[]包装。要得到您的,请使用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

天啊,太感谢你了。我不知道我可以从他们的资料中找到。我的意思是,显然,描述必须在某处,但我不知道在哪里看。这真是太好了,我甚至无法形容我有多兴奋。现在我可以尝试在任何像素格式之间进行压缩,并找出哪一个最佳/最快。我不明白的一件事是'AVComponentDescriptor-> step',其他的一切都是自我解释的。例如,YUV420P的step设置为1,这是否意味着在2个水平连续的像素之间有1个色度元素? –

+0

另外,我怎么能推断有多少字节我需要从'AVFrame->数据[0]'每行复制? –

+0

该步骤意味着“需要多少个元素才能增加指针以获取此类型的下一个元素”。例如:UYVY布局正是:U1Y1V1Y2U2Y3V2Y4 [etc]。所以,如果我的uint8_t * ptr设置为U1,我需要增加多少个元素(uint8_t)才能到达U2? 4!而对于Y1到Y2? 2!对于大多数平面像素格式,该值始终为1.对于非平面像素格式(或混合格式,如NV12中的色度平面),该值仅> 1。 –