首页 > 代码库 > yuv视频用opengl播放

yuv视频用opengl播放

// openGL_yuv.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include "GL/glew.h"
#include "GL/freeglut.h"

#pragma comment(lib, "glew32.lib")

int g_nQuit=0;

// 视频窗口的宽高
const int WIN_WIDTH = 640;
const int WIN_HEIGHT= 352;
// YUV文件的宽高
const int YUV_WIDTH = 640;
const int YUV_HEIGHT= 352;

FILE    *g_fp=NULL;
GLuint  g_nProgramId=0, g_nFragmentShaderId=0;
GLubyte *g_pYtex=NULL, *g_pUtex=NULL, *g_pVtex=NULL;
GLuint g_nLumaTexture=0;
GLuint g_nChromaUTexture=0;
GLuint g_pChromaVTexture=0;

// fragment shader的GLSL
const GLchar* g_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=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"
};


void Initialize(int, char*[]);
void InitWindow(int, char*[]);
void RenderFunction(void);
void Cleanup(void);
void CreateSurface(void);
void DestroySurface(void);
void CreateShaders(void);
void DestroyShaders(void);

void Initialize(int argc, char* argv[])
{
    GLenum GlewInitResult;
    InitWindow(argc, argv);

    glewExperimental = GL_TRUE;
    GlewInitResult = glewInit();
    if (GLEW_OK != GlewInitResult) {
        fprintf(
            stderr,
            "ERROR: %s\n",
            glewGetErrorString(GlewInitResult)
            );
        exit(EXIT_FAILURE);
    }

    fprintf(
        stdout,
        "INFO: OpenGL Version: %s\n",
        glGetString(GL_VERSION)
        );

    CreateShaders();
    CreateSurface();

    //glMatrixMode(GL_PROJECTION);
    //glLoadIdentity();
    glOrtho(0, WIN_WIDTH, 0, WIN_HEIGHT, -1, 1);
    glViewport(0, 0, WIN_WIDTH,WIN_HEIGHT);
    //glHint(GL_POLYGON_SMOOTH_HINT,GL_NICEST);

    glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
}

// 创建opengl的窗口
void InitWindow(int argc, char* argv[])
{
    glutInit(&argc, argv);

    glutInitContextVersion(2, 0);
    glutInitContextFlags(GLUT_FORWARD_COMPATIBLE);
    glutInitContextProfile(GLUT_CORE_PROFILE);

    glutSetOption(
        GLUT_ACTION_ON_WINDOW_CLOSE,
        GLUT_ACTION_GLUTMAINLOOP_RETURNS
        );

    glutInitWindowSize(WIN_WIDTH, WIN_HEIGHT);
    glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA);

    int WindowHandle = glutCreateWindow("ShowYUV");
    if(WindowHandle < 1) {
        fprintf(
            stderr,
            "ERROR: Could not create a new rendering window.\n"
            );
        exit(EXIT_FAILURE);
    }

    glutDisplayFunc(RenderFunction);
    glutCloseFunc(Cleanup);
}

void Cleanup(void)
{
    DestroyShaders();
    DestroySurface();
}

void RenderFunction(void)
{
    // 读入下一帧视频
    fread(g_pYtex, YUV_WIDTH*YUV_HEIGHT, 1, g_fp);
    fread(g_pUtex, YUV_WIDTH*YUV_HEIGHT/4, 1, g_fp);
    fread(g_pVtex, YUV_WIDTH*YUV_HEIGHT/4, 1, g_fp);

    glActiveTexture(GL_TEXTURE0);
    // 使用glTexSubImage2D来update纹理
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        0, 0,
        YUV_WIDTH, YUV_HEIGHT,
        GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pYtex);

    glActiveTexture(GL_TEXTURE1);
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        0, 0,
        YUV_WIDTH/2, YUV_HEIGHT/2,
        GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pUtex);

    glActiveTexture(GL_TEXTURE2);
    glTexSubImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        0, 0,
        YUV_WIDTH/2, YUV_HEIGHT/2,
        GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pVtex);
    glClear(GL_COLOR_BUFFER_BIT);

    // Draw image
    // 注意opengl中y坐标向上为正,而yuv视频向下为正,需要反转一下
    glBegin(GL_QUADS);
    glTexCoord2i(0, YUV_HEIGHT);
    glVertex2i(0, 0);
    glTexCoord2i(YUV_WIDTH, YUV_HEIGHT);
    glVertex2i(WIN_WIDTH, 0);
    glTexCoord2i(YUV_WIDTH, 0);
    glVertex2i(WIN_WIDTH, WIN_HEIGHT);
    glTexCoord2i(0, 0);
    glVertex2i(0,WIN_HEIGHT);
    glEnd();

    // Flip buffers.
    glutSwapBuffers();
    glutPostRedisplay();

    Sleep(50);
}

void CreateSurface(void)
{
    GLint location;

    // Load the textures.
    g_pYtex = (GLubyte*)malloc(YUV_WIDTH*YUV_HEIGHT);
    g_pUtex = (GLubyte*)malloc(YUV_WIDTH*YUV_HEIGHT/4);
    g_pVtex = (GLubyte*)malloc(YUV_WIDTH*YUV_HEIGHT/4);

    g_fp=fopen("d:\\M640x352_yuv420.yuv","rb");

    // This might not be required, but should not hurt.
    glEnable(GL_TEXTURE_2D);

    glGenTextures(1, &g_nLumaTexture);
    glGenTextures(1, &g_nChromaUTexture);
    glGenTextures(1, &g_pChromaVTexture);

    // Select texture unit 1 as the active unit and bind the U texture.
    glActiveTexture(GL_TEXTURE1);
    location = glGetUniformLocation(g_nProgramId, "Utex");
    glUniform1i(location, 1);  // Bind Utex to texture unit 1
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g_nChromaUTexture);

    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        GL_LUMINANCE,
        YUV_WIDTH/2, YUV_HEIGHT/2,
        0,GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pUtex);

    // Select texture unit 2 as the active unit and bind the V texture.
    glActiveTexture(GL_TEXTURE2);
    location = glGetUniformLocation(g_nProgramId, "Vtex");
    glUniform1i(location, 2);  // Bind Vtext to texture unit 2
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g_pChromaVTexture);

    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        GL_LUMINANCE,
        YUV_WIDTH/2, YUV_HEIGHT/2,
        0,
        GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pVtex);

    // Select texture unit 0 as the active unit and bind the Y texture.
    glActiveTexture(GL_TEXTURE0);
    location = glGetUniformLocation(g_nProgramId, "Ytex");
    glUniform1i(location, 0);  // Bind Ytex to texture unit 0
    glBindTexture(GL_TEXTURE_RECTANGLE_ARB, g_nLumaTexture);

    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_RECTANGLE_ARB, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    glTexImage2D(GL_TEXTURE_RECTANGLE_ARB,
        0,
        GL_LUMINANCE,
        YUV_WIDTH, YUV_HEIGHT,
        0,
        GL_LUMINANCE, GL_UNSIGNED_BYTE,
        g_pYtex);
}

void DestroySurface(void)
{
    free(g_pYtex);
    free(g_pUtex);
    free(g_pVtex);

    glDeleteTextures(1, &g_nLumaTexture);
    glDeleteTextures(1, &g_nChromaUTexture);
    glDeleteTextures(1, &g_pChromaVTexture);
}

void CreateShaders(void)
{
    GLchar messages[256];
    GLenum ErrorCheckValue = glGetError();

    // Compile the shader.
    g_nFragmentShaderId = glCreateShader(GL_FRAGMENT_SHADER);
    glShaderSource(g_nFragmentShaderId, 1, &g_FProgram, NULL);
    glCompileShader(g_nFragmentShaderId);

    // Print the compilation log. 
    glGetShaderInfoLog(g_nFragmentShaderId, sizeof(messages), NULL, messages);
    printf("Compile Log: %s\n", messages);

    // Set up program objects.
    g_nProgramId = glCreateProgram();

    // Create a complete program object.
    glAttachShader(g_nProgramId, g_nFragmentShaderId);
    glLinkProgram(g_nProgramId);

    // And print the link log.
    glGetProgramInfoLog(g_nProgramId, sizeof(messages), NULL, messages);
    printf("Link Log: %s\n", messages);

    // Finally, use the program. 
    glUseProgram(g_nProgramId);
}

void DestroyShaders(void)
{
    GLenum ErrorCheckValue = glGetError();
    glUseProgram(0);
    glDetachShader(g_nProgramId, g_nFragmentShaderId);
    glDeleteShader(g_nFragmentShaderId);
    glDeleteProgram(g_nProgramId);

    ErrorCheckValue = glGetError();
    if (ErrorCheckValue != GL_NO_ERROR)
    {
        fprintf(
            stderr,
            "ERROR: Could not destroy the shaders: %s \n",
            gluErrorString(ErrorCheckValue)
            );

        exit(-1);
    }
}

int main(int argc, char *argv[])
{
    Initialize(argc, argv);
    glutMainLoop();

    return(0);
}

编译脚本:

@echo off

cd %~d0
cd %cd%

@echo on

qmake -project
qmake "QT+=opengl"
nmake

pause