2016-04-20 3 views
1

J'essaie de copier les données de trame de AVFrame structure à un tampon. Je sais comment faire cela avec le format YUV420P puisque les données Y sont stockées à l'intérieur AVFrame frame->data[0], les données U sont stockées à l'intérieur AVFrame frame->data[1] et les données V sont stockées à l'intérieur AVFrame frame->data[2], donc il était facile à memcpy() Y, U et V données séparément + son format planaire donc je a pu le faire avec facilité:FFMPEG/libav: Comment est écrit UYVY422 dans la structure d'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); 
    } 

Mais quand il vient à UYVY422 je ne sais pas comment les données sont stockées à l'intérieur de la structure. J'ai des connaissances générales sur le format UYVY422 et qu'il est écrit comme son nom suggère UYVYUYVYUYVY ... et ainsi de suite. Mais ma question est comment puis-je savoir combien de données sont stockées dans AVFrame frame->data[0], AVFrame frame->data[1] et AVFrame frame->data[2] champ afin que je puisse memcpy() quantité exacte à la mémoire tampon?

Répondre

2

Pour UYVY, les données sont stockées exclusivement dans DE CADRE> données [0], et par ligne, vous devez copier la largeur * 2 octets:

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

Il y a une façon de tirer programme ce, au cas où vous êtes intéressé. Chaque AVPixelFormat a un AVPixFmtDescriptor qui décrit son emballage dans AVFrame->data[]. Pour obtenir le vôtre, utilisez av_pix_fmt_desc_get(AV_PIX_FMT_UYVY). L'article renvoyé est this (voir la référence de structure pour AVComponentDescriptor ici). Vous verrez que desc->nb_components est 3, desc->log2_chroma_w est 1, ce qui signifie que U/V sont sous-échantillonnées par 1 horizontalement, et desc->comp[0-2].plane est 0, ce qui signifie que toutes les données sont en AVFrame->data[0]. Le offset/step/depth dans desc->comp[0-2] vous dire le reste au cas où vous voulez une façon entièrement dynamique de lire pix_fmt. Je ne pense pas que vous en ayez besoin personnellement, mais à tout le moins, cela permet à quiconque de dériver l'emballage de n'importe quel pix_fmt dans AVFrame->data[].

[modifier] suivant exemple de code (éventuellement voiturette):

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

Ce qui donne le résultat suivant:

$ 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 mon dieu, je vous remercie beaucoup. Je n'ai aucune idée que je pourrais trouver cela à partir de leur source. Je veux dire, évidemment, la description doit être quelque part mais je n'avais aucune idée de l'endroit où regarder. C'est tellement bon que je ne peux même pas décrire à quel point je suis ravi. Maintenant je peux essayer la compression entre n'importe quel format de pixel et découvrir lequel fonctionne le meilleur/le plus rapide. Une chose que je ne comprends pas bien est l'étape 'AVComponentDescriptor->, tout le reste est explicite. Par exemple, l'étape de YUV420P est définie sur 1, cela signifie-t-il qu'il y a 1 élément de chrominance entre 2 pixels consécutifs horizontaux? –

+0

Aussi, comment puis-je déduire combien d'octets ai-je besoin de copier à partir de 'AVFrame-> data [0]' par ligne? –

+0

L'étape signifie "de combien d'éléments ai-je besoin pour incrémenter mon pointeur pour accéder à l'élément suivant de ce type". Exemple: la disposition UYVY est exactement celle-ci: U1Y1V1Y2U2Y3V2Y4 [etc]. Donc, si mon uint8_t * ptr est mis à U1, combien d'éléments (uint8_t) ai-je besoin de l'incrémenter pour arriver à U2? 4! Et pour Y1 à Y2? 2! Pour la plupart des formats de pixels planaires, cette valeur est toujours 1. La valeur est seulement> 1 pour les formats de pixels non planaires (ou les formats mixtes comme le plan de chrominance dans NV12). –