在之前的文章中,
记录了如何将BMP图像通过opengl显示,并在显示画面上叠加图层。
这一次我们输入一段YUV序列,利用Shader将YUV转换为RGB并显示,同时叠加多个图层上去。代码中调试遇到了一些问题,图像数据总是不能正常的显示,问题的详细解释如code中的注释所示。
// VideoPlayer.cpp : Defines the entry point for the console application.
//
#include <stdio.h>
#include <GLTools.h> // OpenGL toolkit
#include <GLShaderManager.h>
#ifdef __APPLE__
#include <glut/glut.h>
#else
#define FREEGLUT_STATIC
#include <GL/glut.h>
#endif
#include <GL/glew.h>
#include <GL/freeglut.h>
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
//Select one of the Texture mode (Set '1'):
#define TEXTURE_DEFAULT 0
//Rotate the texture
#define TEXTURE_ROTATE 0
//Show half of the Texture
#define TEXTURE_HALF 1
const int screen_w = 640, screen_h = 480;
const int pixel_w = 640, pixel_h = 480;
//YUV 422 file
FILE *infile = NULL;
unsigned char buf[pixel_w*pixel_h * 2];
unsigned char *plane[3];
GLuint p;
GLuint id_y, id_u, id_v; // Texture id
GLuint textureUniformY, textureUniformU, textureUniformV;
GLShaderManager shaderManager;
GLBatch squareBatch;
GLBatch squareBatch_v2;
GLfloat blockSize = 0.2f;
GLfloat vVerts[] = {
-blockSize, -blockSize, 0.0f,
blockSize, -blockSize, 0.0f,
blockSize, blockSize, 0.0f,
-blockSize, blockSize, 0.0f };
GLfloat blockSize_v2 = 0.3f;
GLfloat vVerts_v2[] = {
-blockSize_v2, -blockSize_v2, 0.0f,
blockSize_v2, -blockSize_v2, 0.0f,
blockSize_v2, blockSize_v2, 0.0f,
-blockSize_v2, blockSize_v2, 0.0f };
void add_rect_roi()
{
GLfloat vRed[] = { 0.9f, 0.0f, 0.9f, 0.8f };
//glEnable(GL_DEPTH_TEST);
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_ZERO, GL_ZERO);
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vRed);
squareBatch.Draw();
glDisable(GL_BLEND);
}
void test_line()
{
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glLineWidth(5);
//glBegin(GL_LINES);
glBegin(GL_LINE_STRIP);
//glBegin(GL_LINE_LOOP);
glVertex3f(-0.4, 0.5, 0.0f);
glVertex3f(0.4, 0.5, 0.0f);
glVertex3f(-0.4, -0.5, 0.0f);
glVertex3f(0.4, -0.5, 0.0f);
glEnd();
glLineWidth(10);
glColor3f(0.0, 0.7, 0.0);
glBegin(GL_LINE_STRIP);
//glVertex3f(-0.4, 0.5, 0.0f);
glVertex3f(0.4, 0.5, -0.5f);
glVertex3f(-0.4, -0.5, -0.5f);
glVertex3f(0.2, -0.5, -0.5f);
glEnd();
glDisable(GL_BLEND);
}
void add_rect_roi_v2()
{
GLfloat vColor[] = { 0.0f, 1.0f, 0.9f, 0.5f };
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
shaderManager.UseStockShader(GLT_SHADER_IDENTITY, vColor);
squareBatch_v2.Draw();
glBegin(GL_TRIANGLES);
glVertex3f(-0.5f, 0.0f, 0.0f);
glVertex3f(-0.0f, 0.5f, 0.0f);
glVertex3f(0.5f, 0.0f, 0.0f);
glEnd();
glDisable(GL_BLEND);
}
#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4
void display(void)
{
if (fread(buf, 1, pixel_w*pixel_h * 2, infile) != pixel_w*pixel_h * 2)
{
// Loop
fseek(infile, 0, SEEK_SET);
fread(buf, 1, pixel_w*pixel_h * 2, infile);
}
//add_rect_roi();
//Clear
glClearColor(255, 0, 0, 0.5f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glUseProgram(p); //每一帧都要调用该函数,不然视频数据就不会显示
//Y
//
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id_y);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[0]);
glUniform1i(textureUniformY, 0);
//U
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, id_u);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w / 2, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[1]);
glUniform1i(textureUniformU, 1);
//V
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, id_v);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, pixel_w / 2, pixel_h, 0, GL_RED, GL_UNSIGNED_BYTE, plane[2]);
glUniform1i(textureUniformV, 2);
// Draw
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
// Show
add_rect_roi();
add_rect_roi_v2();
test_line();
//Double
glutSwapBuffers();
//Single
//glFlush();
}
void timeFunc(int value)
{
display();
// Timer: 40ms
glutTimerFunc(40, timeFunc, 0);
}
char *textFileRead(char * filename)
{
char *s = (char *)malloc(8000);
memset(s, 0, 8000);
FILE *infile = fopen(filename, "rb");
int len = fread(s, 1, 8000, infile);
fclose(infile);
s[len] = 0;
return s;
}
//Init Shader
void InitShaders()
{
GLint vertCompiled, fragCompiled, linked;
GLint v, f;
static const char *vs, *fs;
//Shader: step1
v = glCreateShader(GL_VERTEX_SHADER);
f = glCreateShader(GL_FRAGMENT_SHADER);
//Get source code
//vs = textFileRead("Shader.vsh");
//fs = textFileRead("Shader.fsh");
vs =
"attribute vec4 vertexIn;\n"
"attribute vec2 textureIn;\n"
"varying vec2 textureOut;\n"
"void main(void)\n"
"{\n"
"gl_Position = vertexIn;\n"
"textureOut = textureIn;\n"
"}\n";
fs =
"varying vec2 textureOut;\n"
"uniform sampler2D tex_y;\n"
"uniform sampler2D tex_u;\n"
"uniform sampler2D tex_v;\n"
"void main(void)\n"
"{\n"
"vec3 yuv;\n"
"vec3 rgb;\n"
"yuv.x = texture2D(tex_y, textureOut).r;\n"
"yuv.y = texture2D(tex_u, textureOut).r - 0.5;\n"
"yuv.z = texture2D(tex_v, textureOut).r - 0.5;\n"
"rgb = mat3(1, 1, 1, 0, -0.39465, 2.03211, 1.13983, -0.58060, 0) * yuv;\n"
"gl_FragColor = vec4(rgb, 1.0f);\n"
"}\n";
//Shader: step2
glShaderSource(v, 1, &vs, NULL);
glShaderSource(f, 1, &fs, NULL);
//Shader: step3
glCompileShader(v);
//Debug
glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
//Program: Step1
p = glCreateProgram();
//Program: Step2
glAttachShader(p, v);
glAttachShader(p, f);
glBindAttribLocation(p, ATTRIB_VERTEX, "vertexIn");
glBindAttribLocation(p, ATTRIB_TEXTURE, "textureIn");
//Program: Step3
glLinkProgram(p);
//Debug
glGetProgramiv(p, GL_LINK_STATUS, &linked);
//Program: Step4
glUseProgram(p);
//Get Uniform Variables Location
textureUniformY = glGetUniformLocation(p, "tex_y");
textureUniformU = glGetUniformLocation(p, "tex_u");
textureUniformV = glGetUniformLocation(p, "tex_v");
#if TEXTURE_ROTATE
static const GLfloat vertexVertices[] = {
-1.0f, -0.5f,
0.5f, -1.0f,
-0.5f, 1.0f,
1.0f, 0.5f,
};
#else
static const GLfloat vertexVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
#endif
#if TEXTURE_HALF
static const GLfloat textureVertices[] = {
0.0f, 1.0f,
0.5f, 1.0f,
0.0f, 0.0f,
0.5f, 0.0f,
};
#else
static const GLfloat textureVertices[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
#endif
//Set Arrays
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);
//Enable it
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);
glEnableVertexAttribArray(ATTRIB_TEXTURE);
//Init Texture
glGenTextures(1, &id_y);
glBindTexture(GL_TEXTURE_2D, id_y);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &id_u);
glBindTexture(GL_TEXTURE_2D, id_u);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &id_v);
glBindTexture(GL_TEXTURE_2D, id_v);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
shaderManager.InitializeStockShaders();
squareBatch.Begin(GL_LINE_LOOP, 4);
glLineWidth(2.0f);
squareBatch.CopyVertexData3f(vVerts);
squareBatch.End();
squareBatch_v2.Begin(GL_LINE_LOOP, 4);
glLineWidth(3.0f);
squareBatch_v2.CopyVertexData3f(vVerts_v2);
squareBatch_v2.End();
}
int main(int argc, char* argv[])
{
if ((infile = fopen("D:\\y422p.yuv", "rb")) == NULL){
printf("cannot open this file\n");
return -1;
}
//YUV Data
plane[0] = buf;
plane[1] = plane[0] + pixel_w*pixel_h;
plane[2] = plane[0] + pixel_w*pixel_h * 3 / 2;
//Init GLUT
glutInit(&argc, argv);
//GLUT_DOUBLE
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA /*| GLUT_STENCIL | GLUT_DEPTH*/);
glutInitWindowPosition(100, 100);
glutInitWindowSize(screen_w, screen_h);
glutCreateWindow("Video Player By OpenGL (Texture)");
printf("Version: %s\n", glGetString(GL_VERSION));
if (glewInit() != GLEW_OK)
{
printf("Failed to initialize GLEW ... exiting");
exit(EXIT_FAILURE);
}
glutDisplayFunc(&display);
glutTimerFunc(40, timeFunc, 0);
InitShaders();
// Begin!
glutMainLoop();
return 0;
}