Je l'ai fait avec des trames YUV capturées à partir d'une caméra CCD. Malheureusement, il existe plusieurs formats YUV différents. Je crois que celui qu'Apple utilise pour 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é les éléments suivants:
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 pouvez utiliser Apple's client storage extension, que vous pouvez mettre en place 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 ensuite 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();
Merci beaucoup pour l'information Adam, je l'apprécie vraiment. Maintenant pouvez-vous me dire comment extraire le fichier de données brutes à partir du disque dur? Je suis familier avec NSOpenPanel, je peux l'utiliser pour extraire le chemin du fichier de données, cependant, comment puis-je utiliser un chemin de fichier et charger le fichier YUV dans l'application? – ReachConnection
En supposant que le fichier ne contient que des pixels, vous devez simplement utiliser NSData ou NSFileHandle et tout lire. Si le fichier contient des métadonnées telles que des informations de taille, vous devrez interpréter cela en utilisant les opérateurs de pointeur et/ou de structure C standard. –
Cette réponse est incorrecte. Depuis MacOS 10.2 et versions ultérieures, chaque système Apple prend en charge les extensions OpenGL, qui peuvent charger et afficher directement les données YUV. Recherchez "GL_YCBCR_422_APPLE" pour plus de détails. Que les données soient converties quelque part (par le pilote dans le logiciel, sur le GPU dans le matériel, etc.) ne vous concerne pas lorsque vous utilisez cette extension (et quand le GPU la convertit, croyez-moi, il peut battre votre code ci-dessus d'au moins 1000%) – Mecki