Question

Je ne parviens pas à afficher un fichier vidéo YUV qu'il est au format NV12.

Je peux afficher une image sélectionnée, cependant, il est encore principalement en noir et blanc avec certaines nuances de rose et vert.

Voici comment ma sortie ressemble text alt

Quoi qu'il en soit, voici comment fonctionne mon programme. (Cela se fait dans le cacao / c-objectif, mais j'ai besoin de vos conseils d'experts sur l'algorithme de programme, et non pas sur la syntaxe.)

Avant l'exécution du programme, le fichier est stocké dans YUV un fichier binaire nommé « test.yuv ». Le fichier est au format NV12, ce qui signifie le plan Y est stocké en premier, puis le plan UV est entrelacée. Mon extraction de fichiers n'a pas de problème parce que je fait beaucoup testings dessus.

Au cours de l'initiation, créer une table de conversion qui convertit binaires / 8 / morsures d'un octet / caractères en Y respecté, U, V les valeurs flottantes

Pour le plan Y ceci est mon code

-(void)createLookupTableY //creates a lookup table for converting a single byte into a float between 0 and 1
{
    NSLog(@"YUVFrame: createLookupTableY");
    lookupTableY = new float [256];

    for (int i = 0; i < 256; i++)
    {
        lookupTableY[i] = (float) i /255;
        //NSLog(@"lookupTableY[%d]: %f",i,lookupTableY[i]);//prints out the value of each float
    }
}

La table de recherche plan U

-(void)createLookupTableU //creates a lookup table for converting a single byte into a float between 0 and 1
{
    NSLog(@"YUVFrame: createLookupTableU");
    lookupTableU = new float [256];

    for (int i = 0; i < 256; i++)
    {
        lookupTableU[i] =  -0.436 + (float) i / 255* (0.436*2);
        NSLog(@"lookupTableU[%d]: %f",i,lookupTableU[i]);//prints out the value of each float
    }
}

Et la table de consultation V

-(void)createLookupTableV //creates a lookup table for converting a single byte into a float between 0 and 1
{
    NSLog(@"YUVFrame: createLookupTableV");
    lookupTableV = new float [256];

    for (int i = 0; i < 256; i++)
    {
        lookupTableV[i] =  -0.615 + (float) i /255 * (0.615*2);
        NSLog(@"lookupTableV[%d]: %f",i,lookupTableV[i]);//prints out the value of each float
    }
}

après ce point, j'extrais le plan Y & UV et de les stocker en deux tampons, yBuffer & uvBuffer

à ce stade, je tente de convertir les données YUV et emmagasinés dans un réseau de tampon RVB appelé « frameImage »

-(void)sortAndConvert//sort the extracted frame data into an array of float
{
    NSLog(@"YUVFrame: sortAndConvert");
    int frameImageCounter = 0;
    int pixelCounter = 0;
    for (int y = 0; y < YUV_HEIGHT; y++)//traverse through the frame's height
    {
        for ( int x = 0; x < YUV_WIDTH; x++)//traverse through the frame's width
        {

            float Y = lookupTableY [yBuffer [y*YUV_WIDTH + x] ];
            float U = lookupTableU [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2  ] ]; 
            float V = lookupTableV [uvBuffer [  ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 + 1] ];

            float RFormula = Y + 1.13983f * V;
            float GFormula = Y - 0.39465f * U - 0.58060f * V;
            float BFormula = Y + 2.03211f * U;

             frameImage [frameImageCounter++] = [self clampValue:RFormula];
             frameImage [frameImageCounter++] = [self clampValue:GFormula];
             frameImage [frameImageCounter++] = [self clampValue:BFormula];

        }
    }

}

alors j'ai essayé de dessiner l'image dans OpenGl

-(void)drawFrame:(int )x
{

    GLuint texture;

    glGenTextures(1, &texture);
    glBindTexture(GL_TEXTURE_2D, texture);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_FLOAT, frameImage);

    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

    glEnable(GL_TEXTURE_2D);
    glBindTexture(GL_TEXTURE_2D, texture);
    glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );

    glBegin( GL_QUADS );
    glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
    glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
    glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
    glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
    glEnd();

    glFlush();
}

donc en gros ce mon programme dans une coquille de noix. essentiellement j'ai lu les fichiers binaires, YUV stocke toutes les données dans un tampon de tableau de caractères. i puis traduis ces valeurs dans leurs valeurs flottantes respecté YUV.

Ceci est où je pense que l'erreur peut être: dans la table de consultation Y I normaliser le plan Y à [0,1], dans le plan U I normalisé les valeurs comprises entre [-0.435,0.436], et V Je plan standardisé, il bewteen [-0.615,0.615]. Je l'ai fait parce que ce sont les plages de valeurs YUV selon wikipedia.

Et la formule RGB YUV est la même formule de Wikipedia. J'ai aussi essayé diverses autres formules, ce qui est la seule formule qui donne les perspectives rugueux du cadre. Tout le monde peut parierais pour expliquer pourquoi mon programme n'affiche pas correctement les données de trame YUV. Je pense qu'il est quelque chose à voir avec ma technique de normalisation, mais il semble bien pour moi.

Je l'ai fait beaucoup de testings, et je suis certain à 100% que l'erreur est due à regarder par table. Je ne pense pas que mes formules de réglage sont corrects.

  

Une note à tous ceux qui sont en train de lire   cette. Pendant très longtemps, mon cadre   n'a pas été correctement afficher parce que je   n'a pas été en mesure d'extraire les données de trame   correctement.

     

Quand j'ai commencé à programmer, j'étais   l'impression que dans un clip de   dire 30 images, toutes les données planes 30 Y   sont d'abord écrites dans le fichier de données,   suivie ensuite par les caractéristiques planes UV.

     

Ce que j'ai appris par essais et   erreur était que pour un fichier de données YUV,   spécifiquement NV12, le fichier de données est   stockés de la façon suivante

     

Y (1) UV (1) Y (2) UV (2) ... ...

@nschmidt

J'ai changé mon code à ce que vous suggérez

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]

et cela est le résultat que je reçois text alt

ici est la ligne d'impression à partir de la console. je suis imprimer les valeurs Y, U, V et La valeur RGB qui sont en cours de traduction et stocké dans la matrice de frameImage

YUV: [0.658824, -0,022227, -0,045824] RGBFinal: [0.606593,0.694201,0.613655]

YUV: [0.643137, -0,022227, -0,045824] RGBFinal: [0.590906,0.678514,0.597969]

YUV: [0.607843, -0,022227, -0,045824] RGBFinal: [0.555612,0.643220,0.562675]

YUV: [0.592157, -0,022227, -0,045824] RGBFinal: [0.539926,0.627534,0.546988]

YUV: [0.643137,0.025647,0.151941] RGBFinal: [0.816324,0.544799,0.695255]

YUV: [0.662745,0.025647,0.151941] RGBFinal: [0.835932,0.564406,0.714863]

YUV: [0.690196,0.025647,0.151941] RGBFinal: [0.863383,0.591857,0.742314]

mise à jour 13 Juillet, 2009

Le problème a finalement été résolu grâce à la recommandation de nschmidt . Il se trouve que mon fichier YUV était en fait en YUV 4: format 1: 1. Je l'origine dit qu'il était au format YUV NV12. Quoi qu'il en soit, je voudrais partager mes résultats avec vous.

Voici la sortie

text alt

et mon code pour le décodage est la suivante

        float Y = (float) yBuffer [y*YUV_WIDTH + x] ;
        float U = (float) uvBuffer [ ((y / 2) * (YUV_WIDTH  / 2) + (x/2))   ] ; 
        float V = (float) uvBuffer [  ((y / 2) * (YUV_WIDTH  / 2) + (x/2))  + UOffset] ;

        float RFormula = (1.164*(Y-16) + (1.596* (V - 128) ));
        float GFormula = ((1.164 * (Y - 16)) - (0.813 * ((V) - 128)) - (0.391 * ((U) - 128)));
        float BFormula = ((1.164 * (Y - 16)) + (2.018 * ((U) - 128)));


        frameImage [frameImageCounter] = (unsigned char)( (int)[self clampValue:RFormula]);
        frameImageCounter ++;
        frameImage [frameImageCounter] =  (unsigned char)((int)[self clampValue:GFormula]);
        frameImageCounter++;
        frameImage [frameImageCounter] = (unsigned char)((int) [self clampValue:BFormula]);
        frameImageCounter++;



GLuint texture;

glGenTextures(1, &texture);
glEnable(GL_TEXTURE_2D);

glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, GL_TRUE);

glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, YUV_WIDTH, YUV_HEIGHT, 0, GL_RGB, GL_UNSIGNED_BYTE, frameImage);

//glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE_SGIS);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE_SGIS);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_LINEAR);

glRotatef( 180.0f, 1.0f, 0.0f, 0.0f );

glBegin( GL_QUADS );
glTexCoord2d(0.0,0.0); glVertex2d(-1.0,-1.0);
glTexCoord2d(1.0,0.0); glVertex2d(+1.0,-1.0);
glTexCoord2d(1.0,1.0); glVertex2d(+1.0,+1.0);
glTexCoord2d(0.0,1.0); glVertex2d(-1.0,+1.0);
glEnd();

NSLog(@"YUVFrameView: drawRect complete");
glFlush();

essentiellement, je NSData pour l'extraction de fichier brut. stocké dans une mémoire tampon de tableau de caractères. Pour YUV vers RGB, je la formule ci-dessus, après, je les valeurs serrées [0: 255]. alors j'ai utilisé un 2DTexture en OpenGL pour l'affichage.

Donc, si vous convertissez en RVB YUV à l'avenir, utilisez la formule ci-dessus à partir. Si utilisent le YUV à la formule de conversion RVB du poste antérieur, vous devez afficher la texture dans GL_FLOAT des valeurs RVB sont bridées entre [0: 1]

Était-ce utile?

La solution

Ensuite, essayez :) Je pense que vous êtes un tampon uv n'est pas entrelacée. On dirait que les valeurs U sont d'abord et ensuite le tableau de valeurs V. Modification des lignes à

unsigned int voffset = YUV_HEIGHT * YUV_WIDTH / 2;
float U = lookupTableU [uvBuffer [ y * (YUV_WIDTH / 2) + x/2] ]; 
float V = lookupTableV [uvBuffer [ voffset + y * (YUV_WIDTH / 2) + x/2] ];

peut indiquer si cela est vraiment le cas.

Autres conseils

Je pense que vous vous adressez à des valeurs U et V de manière incorrecte. Plutôt que:

float U = lookupTableU [uvBuffer [ ((y / 2) * (x / 2) + (x/2)) * 2  ] ]; 
float V = lookupTableV [uvBuffer [  ((y / 2) * (x / 2) + (x/2)) * 2 + 1] ];

Il doit être quelque chose le long des lignes de

float U = lookupTableU [uvBuffer [ ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2  ] ]; 
float V = lookupTableV [uvBuffer [  ((y / 2) * (YUV_WIDTH / 2) + (x/2)) * 2 + 1] ];

L'image semble que vous avez le format 4: 1: 1. Vous devez changer vos lignes à

float U = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 ] ]
float V = lookupTableU [uvBuffer [ (y * (YUV_WIDTH / 4) + (x/4)) * 2 + 1] ]

Peut-être que vous pouvez poster le résultat pour voir, ce que les autres ont tort. Je trouve toujours difficile de penser. Il est beaucoup plus facile d'aborder cette itérativement.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top