FFMPEG / libav:UYVY422是如何写在AVFrame结构中的?

Sir*_*Lot 2 ffmpeg libavcodec libav

我正在尝试将帧数据从AVFrame结构复制到缓冲区。我知道如何使用YUV420P格式来做到这一点,因为 Y 数据存储在内部AVFrame frame->data[0],U 数据存储在内部AVFrame frame->data[1],V 数据存储在内部AVFrame frame->data[2],因此很容易memcpy()单独处理 Y、U 和 V 数据+它是平面格式,所以我能够做到这一点轻松:

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);
    }
Run Code Online (Sandbox Code Playgroud)

但是当涉及到时,UYVY422我不知道数据是如何存储在结构内部的。我对格式有一般了解UYVY422,而且它的写法就像它的名字所暗示的 UYVYUYVYUYVY...等等。AVFrame frame->data[0]但我的问题是我如何知道,AVFrame frame->data[1]和字段中存储了多少数据,AVFrame frame->data[2]以便我可以memcpy()准确地存储到缓冲区?

Ron*_*tje 5

对于 UYVY,数据仅存储在frame->data[0]中,每行您应该复制 width * 2 个字节:

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

如果您感兴趣的话,有一种方法可以以编程方式导出它。每个AVPixelFormat都有一个AVPixFmtDescriptor描述其包装的AVFrame->data[]. 要获得您的,请使用. 返回的项目是这个(请参阅此处的结构参考)。您会看到is 3,is 1,这意味着 U/V 水平二次采样 1,is 0,这意味着所有数据都在 中。如果您想要以完全动态的方式读取任何 pix_fmt,则//会告诉您其余的内容。我不认为你个人需要它,但至少它允许任何人导出.av_pix_fmt_desc_get(AV_PIX_FMT_UYVY)AVComponentDescriptordesc->nb_componentsdesc->log2_chroma_wdesc->comp[0-2].planeAVFrame->data[0]offsetstepdepthdesc->comp[0-2]AVFrame->data[]

[编辑] 请参阅以下示例代码(可能有错误):

#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;
}
Run Code Online (Sandbox Code Playgroud)

给出以下输出:

$ 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)
Run Code Online (Sandbox Code Playgroud)