我该如何使用OpenGL着色器绘制上述格式的纹理?并且我该如何使用glTexImage2d将数据传递给着色器?
这里 是一个使用SDL的示例,展示了如何将YUV420数据传递到片段着色器中,并将其转换为RGB以写入帧缓冲区:
/*
* Very simple example of how to perform YUV->RGB (YCrCb->RGB)
* conversion with an OpenGL fragmen shader. The data (not included)
* is presumed to be three files with Y, U and V samples for a 720x576
* pixels large image.
*
* Note! The example uses NVidia extensions for rectangular textures
* to make it simpler to read (non-normalised coordinates).
* Rewriting it without the extensions is quite simple, but left as an
* exercise to the reader. (The trick is that the shader must know the
* image dimensions instead)
*
* The program also does not check to see if the shader extensions are
* available - this is after all just a simple example.
*
* This code is released under a BSD style license. Do what you want, but
* do not blame me.
*
* Peter Bengtsson, Dec 2004.
*/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <GL/gl.h>
#include <GL/glext.h>
#include <SDL/SDL.h>
int Quit=0;
static int B_WIDTH=640;
static int B_HEIGHT=480;
int main(int cnt,char *arg[])
{
SDL_Surface *Win=NULL;
GLubyte *Ytex,*Utex,*Vtex;
SDL_Event evt;
int i;
GLhandleARB FSHandle,PHandle;
char *s;
FILE *fp;
char *FProgram=
"uniform sampler2DRect Ytex;\n"
"uniform sampler2DRect Utex,Vtex;\n"
"void main(void) {\n"
" float nx,ny,r,g,b,y,u,v;\n"
" vec4 txl,ux,vx;"
" nx=gl_TexCoord[0].x;\n"
" ny=576.0-gl_TexCoord[0].y;\n"
" y=texture2DRect(Ytex,vec2(nx,ny)).r;\n"
" u=texture2DRect(Utex,vec2(nx/2.0,ny/2.0)).r;\n"
" v=texture2DRect(Vtex,vec2(nx/2.0,ny/2.0)).r;\n"
" y=1.1643*(y-0.0625);\n"
" u=u-0.5;\n"
" v=v-0.5;\n"
" r=y+1.5958*v;\n"
" g=y-0.39173*u-0.81290*v;\n"
" b=y+2.017*u;\n"
" gl_FragColor=vec4(r,g,b,1.0);\n"
"}\n";
if(!SDL_Init(SDL_INIT_VIDEO)) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER,1);
Win=SDL_SetVideoMode(B_WIDTH,B_HEIGHT,32,SDL_HWSURFACE|SDL_ANYFORMAT|SDL_OPENGL);
if(Win) {
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(0,B_WIDTH,0,B_HEIGHT,-1,1);
glViewport(0,0,B_WIDTH,B_HEIGHT);
glClearColor(0,0,0,0);
glColor3f(1.0,0.84,0.0);
glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);
/* Set up program objects. */
PHandle=glCreateProgramObjectARB();
FSHandle=glCreateShaderObjectARB(GL_FRAGMENT_SHADER_ARB);
/* Compile the shader. */
glShaderSourceARB(FSHandle,1,&FProgram,NULL);
glCompileShaderARB(FSHandle);
/* Print the compilation log. */
glGetObjectParameterivARB(FSHandle,GL_OBJECT_COMPILE_STATUS_ARB,&i);
s=malloc(32768);
glGetInfoLogARB(FSHandle,32768,NULL,s);
printf("Compile Log: %s\n", s);
free(s);
/* Create a complete program object. */
glAttachObjectARB(PHandle,FSHandle);
glLinkProgramARB(PHandle);
/* And print the link log. */
s=malloc(32768);
glGetInfoLogARB(PHandle,32768,NULL,s);
printf("Link Log: %s\n", s);
free(s);
/* Finally, use the program. */
glUseProgramObjectARB(PHandle);
/* Load the textures. */
Ytex=malloc(414720);
Utex=malloc(103680);
Vtex=malloc(103680);
fp=fopen("Image.Y","rb");
fread(Ytex,414720,1,fp);
fclose(fp);
fp=fopen("Image.U","rb");
fread(Utex,103680,1,fp);
fclose(fp);
fp=fopen("Image.V","rb");
fread(Vtex,103680,1,fp);
fclose(fp);
/* This might not be required, but should not hurt. */
glEnable(GL_TEXTURE_2D);
/* Select texture unit 1 as the active unit and bind the U texture. */
glActiveTexture(GL_TEXTURE1);
i=glGetUniformLocationARB(PHandle,"Utex");
glUniform1iARB(i,1); /* Bind Utex to texture unit 1 */
glBindTexture(GL_TEXTURE_RECTANGLE_NV,1);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,376,288,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,Utex);
/* Select texture unit 2 as the active unit and bind the V texture. */
glActiveTexture(GL_TEXTURE2);
i=glGetUniformLocationARB(PHandle,"Vtex");
glBindTexture(GL_TEXTURE_RECTANGLE_NV,2);
glUniform1iARB(i,2); /* Bind Vtext to texture unit 2 */
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,376,288,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,Vtex);
/* Select texture unit 0 as the active unit and bind the Y texture. */
glActiveTexture(GL_TEXTURE0);
i=glGetUniformLocationARB(PHandle,"Ytex");
glUniform1iARB(i,0); /* Bind Ytex to texture unit 0 */
glBindTexture(GL_TEXTURE_RECTANGLE_NV,3);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_RECTANGLE_NV,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
glTexImage2D(GL_TEXTURE_RECTANGLE_NV,0,GL_LUMINANCE,752,576,0,GL_LUMINANCE,GL_UNSIGNED_BYTE,Ytex);
/* Simple loop, just draws the image and waits for quit. */
while(!Quit) {
if(SDL_PollEvent(&evt)) {
switch(evt.type) {
case SDL_KEYDOWN:
case SDL_QUIT:
Quit=1;
break;
}
}
glClear(GL_COLOR_BUFFER_BIT);
/* Draw image (again and again). */
glBegin(GL_QUADS);
glTexCoord2i(0,0);
glVertex2i(0,0);
glTexCoord2i(720,0);
glVertex2i(B_WIDTH,0);
glTexCoord2i(720,576);
glVertex2i(B_WIDTH,B_HEIGHT);
glTexCoord2i(0,576);
glVertex2i(0,B_HEIGHT);
glEnd();
/* Flip buffers. */
glFlush();
SDL_GL_SwapBuffers();
sleep(1);
} /* while(!Quit) */
/* Clean up before exit. */
glUseProgramObjectARB(0);
glDeleteObjectARB(sprog);
free(Ytex);
free(Utex);
free(Vtex);
} else {
fprintf(stderr,"Unable to create primary surface. \"%s\".\n",SDL_GetError());
}
SDL_Quit();
} else {
fprintf(stderr,"Initialisation failed. \"%s\".\n",SDL_GetError());
}
return(0);
}
glTexImage2D
或glMapBuffer
)。如何做到这一点取决于视频数据来自何处。