Question

Je suis l'esprit assigné la tâche d'écrire un programme qui prend un fichier vidéo YUV échantillon et l'afficher dans un programme OpenGL Cocoa.

Je suis un stagiaire à mon travail et j'ai peu ou pas la moindre idée comment commencer. Je lis wikipedia et articles sur YUV, mais je ne pouvais pas trouver un bon code source sur la façon d'ouvrir un fichier vidéo YUV, extraire les données et le convertir en RGB et l'afficher dans la fenêtre d'affichage.

Pour l'essentiel, je besoin d'aide pour les aspects suivants de la tâche -faire pour extraire les données YUV de l'exemple de fichier YUV -faire pour convertir les données YUV dans l'espace couleur RVB -faire pour afficher l'espace de couleurs RVB en OpenGL. (Ce que je pense que je peux comprendre avec le temps, mais je vraiment besoin d'aide avec les deux premiers points)

S'il vous plaît dites-moi, soit les classes à utiliser, ou me pointer vers des endroits où je peux apprendre sur l'affichage graphique YUV / vidéo

Était-ce utile?

La solution

Cette réponse est inexact, voir les autres réponses et commentaires. Réponse originale gauche ci-dessous pour la postérité.


Vous ne pouvez pas afficher directement. Vous aurez besoin de le convertir en une texture RGB. Comme vous avez pu le constater à partir de Wikipedia , il y a un tas de variations sur l'espace colorimétrique YUV. Assurez-vous que vous utilisez la bonne.

Pour chaque pixel, la conversion de YUV à RVB est une transformation linéaire simple. Vous venez de faire la même chose à chaque pixel indépendamment.

Une fois que vous avez converti l'image en RVB, vous pouvez l'afficher en créant une texture. Vous devez appeler glGenTextures() allouer une poignée de texture, glBindTexture() pour lier la texture au contexte rendu, et glTexImage2D() pour télécharger les données de texture au GPU. Pour le rendre, vous appelez à nouveau glBindTexture(), suivi par le rendu d'un quad avec coordonnées de texture correctement mis en place.

// parameters: image:  pointer to raw YUV input data
//             width:  image width (must be a power of 2)
//             height: image height (must be a power of 2)
// returns: a handle to the resulting RGB texture
GLuint makeTextureFromYUV(const float *image, int width, int height)
{
    float *rgbImage = (float *)malloc(width * height * 3 * sizeof(float));  // check for NULL
    float *rgbImagePtr = rgbImage;

    // convert from YUV to RGB (floats used here for simplicity; it's a little
    // trickier with 8-bit ints)
    int y, x;
    for(y = 0; y < height; y++)
    {
        for(x = 0; x < width; x++)
        {
            float Y = *image++;
            float U = *image++;
            float V = *image++;
            *rgbImagePtr++ = Y                + 1.13983f * V;  // R
            *rgbImagePtr++ = Y - 0.39465f * U - 0.58060f * V;  // G
            *rgbImagePtr++ = Y + 2.03211f * U;                 // B
        }
    }

    // create texture
    GLuint texture;
    glGenTextures(1, &texture);

    // bind texture to render context
    glBindTexture(GL_TEXTURE_2D, texture);

    // upload texture data
    glTexImage2D(GL_TEXTURE_2D, 0, 3, width, height, 0, GL_RGB, GL_FLOAT, rgbImage);

    // don't use mipmapping (since we're not creating any mipmaps); the default
    // minification filter uses mipmapping.  Use linear filtering for minification
    // and magnification.
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    // free data (it's now been copied onto the GPU) and return texture handle
    free(rgbImage);
    return texture;
}

Pour rendre:

glBindTexture(GL_TEXTURE_2D, texture);

glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f); glVertex3f( 0.0f,  0.0f, 0.0f);
    glTexCoord2f(1.0f, 0.0f); glVertex3f(64.0f,  0.0f, 0.0f);
    glTexCoord2f(1.0f, 1.0f); glVertex3f(64.0f, 64.0f, 0.0f);
    glTexCoord2f(0.0f, 1.0f); glVertex3f( 0.0f, 64.0f, 0.0f);
glEnd();

Et ne pas oublier d'appeler glEnable(GL_TEXTURE_2D) à un moment donné pendant l'initialisation, et appelez glDeleteTextures(1, &texture) lors de l'arrêt.

Autres conseils

Je l'ai fait avec des cadres YUV capturées à partir d'une caméra CCD. Malheureusement, il y a un certain nombre de différents formats YUV. Je crois que celui que Apple utilise le format de texture GL_YCBCR_422_APPLE est techniquement 2VUY422. Pour convertir une image à partir d'un cadre YUV422 généré par une caméra IIDC Firewire à 2VUY422, je l'ai utilisé comme suit:

void yuv422_2vuy422(const unsigned char *theYUVFrame, unsigned char *the422Frame, const unsigned int width, const unsigned int height) 
{
    int i =0, j=0;
    unsigned int numPixels = width * height;
    unsigned int totalNumberOfPasses = numPixels * 2;
    register unsigned int y0, y1, y2, y3, u0, u2, v0, v2;

    while (i < (totalNumberOfPasses) )
    {
        u0 = theYUVFrame[i++]-128;
        y0 = theYUVFrame[i++];
        v0 = theYUVFrame[i++]-128;
        y1 = theYUVFrame[i++];
        u2 = theYUVFrame[i++]-128;
        y2 = theYUVFrame[i++];
        v2 = theYUVFrame[i++]-128;
        y3 = theYUVFrame[i++];

        // U0 Y0 V0 Y1 U2 Y2 V2 Y3

        // Remap the values to 2VUY (YUYS?) (Y422) colorspace for OpenGL
        // Y0 U Y1 V Y2 U Y3 V

        // IIDC cameras are full-range y=[0..255], u,v=[-127..+127], where display is "video range" (y=[16..240], u,v=[16..236])

        the422Frame[j++] = ((y0 * 240) / 255 + 16);
        the422Frame[j++] = ((u0 * 236) / 255 + 128);
        the422Frame[j++] = ((y1 * 240) / 255 + 16);
        the422Frame[j++] = ((v0 * 236) / 255 + 128);
        the422Frame[j++] = ((y2 * 240) / 255 + 16);
        the422Frame[j++] = ((u2 * 236) / 255 + 128);
        the422Frame[j++] = ((y3 * 240) / 255 + 16);
        the422Frame[j++] = ((v2 * 236) / 255 + 128);
    }
}

Pour l'affichage efficace d'une source vidéo YUV, vous voudrez peut-être utiliser Extension stockage client d'Apple , que vous pouvez configurer en utilisant quelque chose comme ce qui suit:

glEnable(GL_TEXTURE_RECTANGLE_EXT);
glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1);

glTextureRangeAPPLE(GL_TEXTURE_RECTANGLE_EXT, videoImageWidth * videoImageHeight * 2, videoTexture);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_STORAGE_HINT_APPLE , GL_STORAGE_SHARED_APPLE);
glPixelStorei(GL_UNPACK_CLIENT_STORAGE_APPLE, GL_TRUE);

glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_RECTANGLE_EXT, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);

glTexImage2D(GL_TEXTURE_RECTANGLE_EXT, 0, GL_RGBA, videoImageWidth, videoImageHeight, 0, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture);    

Cela vous permet de modifier rapidement les données stockées dans votre texture vidéo côté client avant chaque image à afficher sur l'écran.

Pour dessiner, vous pouvez alors utiliser le code comme suit:

glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);         
glEnable(GL_TEXTURE_2D);

glViewport(0, 0, [self frame].size.width, [self frame].size.height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();
NSRect bounds = NSRectFromCGRect([self bounds]);
glOrtho( (GLfloat)NSMinX(bounds), (GLfloat)NSMaxX(bounds), (GLfloat)NSMinY(bounds), (GLfloat)NSMaxY(bounds), -1.0, 1.0);

glBindTexture(GL_TEXTURE_RECTANGLE_EXT, 1);
glTexSubImage2D (GL_TEXTURE_RECTANGLE_EXT, 0, 0, 0, videoImageWidth, videoImageHeight, GL_YCBCR_422_APPLE, GL_UNSIGNED_SHORT_8_8_REV_APPLE, videoTexture);

glMatrixMode(GL_TEXTURE);
glLoadIdentity();

glBegin(GL_QUADS);
    glTexCoord2f(0.0f, 0.0f);
    glVertex2f(0.0f, videoImageHeight);

    glTexCoord2f(0.0f, videoImageHeight);
    glVertex2f(0.0f, 0.0f);

    glTexCoord2f(videoImageWidth, videoImageHeight);
    glVertex2f(videoImageWidth, 0.0f);

    glTexCoord2f(videoImageWidth, 0.0f);
    glVertex2f(videoImageWidth, videoImageHeight);      
glEnd();

Le commentaire d'Adam Rosenfield est incorrect. Sur Mac, vous pouvez afficher YCbCr (l'équivalent numérique à YUV) textures en utilisant le format de texture GL_YCBCR_422_APPLE, comme spécifié dans le l'extension APPLE_ycbcr_422.

scroll top