2016-04-20 3 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, данные хранятся исключительно в Frame-> данные [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/depth в desc->comp[0-2] расскажет вам остальное, если вы хотите полностью динамический способ чтения любого pix_fmt. Я не думаю, что вам это лично нужно, но, по крайней мере, это позволяет любому получить упаковку любого pix_fmt в 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; 
} 

Который дает следующий вывод:

$ 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->», все остальное самоочевидно. Например, шаг YUV420P установлен в 1, означает ли это, что имеется 1 элемент цветности между двумя горизонтально последовательными пикселями? –

+0

Также, как я могу определить, сколько байтов мне нужно скопировать из 'AVFrame-> данных [0]' за строку? –

+0

Этот шаг означает «сколько элементов мне нужно, чтобы увеличить мой указатель, чтобы перейти к следующему элементу этого типа». Пример: UYVY-макет точно такой: U1Y1V1Y2U2Y3V2Y4 [и т. Д.]. Итак, если my uint8_t * ptr установлен в U1, сколько элементов (uint8_t) нужно увеличить, чтобы получить U2? 4! А для Y1 - Y2? 2! Для большинства плоскостных форматов пикселей это значение всегда равно 1. Это значение равно> 1 для непланарных пиксельных форматов (или смешанных форматов, таких как цветная плоскость в NV12). –

Смежные вопросы