2016-04-20 14 views
1

Ich versuche, Rahmendaten von AVFrame Struktur in einen Puffer zu kopieren. Ich weiß, wie man das mit YUV420P Format, da Y Daten innerhalb AVFrame frame->data[0] gespeichert wird, U Daten innerhalb AVFrame frame->data[1] gespeichert wird und V-Daten innerhalb AVFrame frame->data[2] gespeichert wird, so war es leicht memcpy() Y, U und V Daten getrennt + es ist planaren Format, so dass ich dass mit Leichtigkeit tun konnte:FFMPEG/libav: Wie wird UYVY422 in die AVFrame-Struktur geschrieben?

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); 
    } 

Aber wenn es um UYVY422 kommt habe ich keine Ahnung, wie die Daten innerhalb der Struktur gespeichert ist. Ich habe allgemeines Wissen über UYVY422 Format und dass es geschrieben ist, wie es Name sagt, schlägt UYVYUYVYUYVY ... und so weiter vor. Aber meine Frage ist, woher weiß ich, wie viele Daten in AVFrame frame->data[0], AVFrame frame->data[1] und AVFrame frame->data[2] Feld gespeichert werden, so kann ich memcpy() genaue Menge an den Puffer?

Antwort

2

Für UYVY werden die Daten ausschließlich in Rahmen-> data [0] gespeichert, und pro Zeile sollten Sie Breite * 2 Bytes kopieren:

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

Es gibt einen Weg, dies zu programmatisch ableiten, Sie im Falle bin interessiert. Jede AVPixelFormat hat eine AVPixFmtDescriptor, die ihre Verpackung in AVFrame->data[] beschreibt. Verwenden Sie av_pix_fmt_desc_get(AV_PIX_FMT_UYVY). Das zurückgegebene Element ist this eins (siehe Strukturreferenz für AVComponentDescriptor hier). Sie werden sehen, dass desc->nb_components 3 ist, desc->log2_chroma_w ist 1, was bedeutet, U/V werden von 1 horizontal unterabgetastet, und desc->comp[0-2].plane ist 0, was bedeutet, dass alle Daten in AVFrame->data[0] sind. Die offset/step/depth in desc->comp[0-2] sagen Ihnen den Rest für den Fall, dass Sie eine vollständig dynamische Möglichkeit zum Lesen von Pix_Fmt. Ich glaube nicht, dass Sie es persönlich brauchen, aber zumindest erlaubt es jedem, das Packen eines beliebigen pix_fmt in AVFrame->data[] abzuleiten.

[Bearbeiten] Beispielcode folgende (möglicherweise Buggy):

#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; 
} 

, die die folgende Ausgabe gibt:

$ 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

Oh Gott, ich danke Ihnen so sehr. Ich habe keine Ahnung, dass ich das aus ihrer Quelle herausfinden könnte. Ich meine, offensichtlich muss die Beschreibung irgendwo sein, aber ich hatte keine Ahnung, wo ich hinschauen sollte. Das ist so gut, dass ich nicht einmal beschreiben kann, wie begeistert ich bin. Jetzt kann ich die Komprimierung zwischen jedem beliebigen Pixelformat ausprobieren und herausfinden, welche am besten/am schnellsten funktioniert. Eine Sache, die ich nicht ganz verstehe, ist der 'AVComponentDescriptor-> Schritt ', alles andere ist selbsterklärend. Zum Beispiel wird der Schritt von YUV420P auf 1 gesetzt, heißt das, dass zwischen zwei horizontal aufeinander folgenden Pixeln ein Chroma-Element liegt? –

+0

Wie kann ich auch ableiten, wie viele Bytes ich von 'AVFrame-> Daten [0] pro Zeile kopieren muss? –

+0

Der Schritt bedeutet "wie viele Elemente brauche ich, um meinen Zeiger zu erhöhen, um zum nächsten Element dieses Typs zu gelangen". Beispiel: UYVY Layout ist genau das: U1Y1V1Y2U2Y3V2Y4 [etc]. Also, wenn mein uint8_t * ptr auf U1 gesetzt ist, wie viele Elemente (uint8_t) muss ich inkrementieren, um zu U2 zu gelangen? 4! Und für Y1 bis Y2? 2! Für die meisten planaren Pixelformate ist dieser Wert immer 1. Der Wert ist nur für nicht planare Pixelformate (oder gemischte Formate wie die Chroma-Ebene in NV12)> 1. –