基于上一次的环境,用C++简单地封装了一下OpenGL的播放实现
//YUVReader.h
#pragma once
#include <sys/timeb.h>
#include "glad/glad.h"
#include "GLFW/glfw3.h"
#pragma comment(lib, "glfw3.lib")
// 获取毫秒 时间戳
static int64_t getCurrentTime()
{
struct timeb rawtime;
ftime(&rawtime);
return rawtime.time * 1000 + rawtime.millitm;
}
class CYUVRender
{
public:
CYUVRender(int nFrameW, int nFrameH);
virtual ~ CYUVRender();
int OpenPlayer();
int InputData(unsigned char *pData, int nDataSize);
int ClosePlayer();
int ShouldClose();
private:
int InitShader();
static void error_callback(int error, const char* description);
private:
//yuv w and h
int m_nFrameW = -1;
int m_nFrameH = -1;
GLFWwindow* m_pWindow = NULL;
GLuint m_textureUniformY;
GLuint m_textureUniformUV;
GLuint m_id_y;
GLuint m_id_uv; // Texture id
};
//YUVReader.cpp
#include "YUVRender.h"
CYUVRender:: CYUVRender(int nFrameW, int nFrameH):
m_nFrameW(nFrameW),m_nFrameH(nFrameH)
{
OpenPlayer();
InitShader();
}
CYUVRender::~ CYUVRender()
{
}
int CYUVRender::InputData(unsigned char *pData, int nDataSize)
{
if (nDataSize < m_nFrameW*m_nFrameH * 3 / 2)
{
//error
return -1;
}
//Clear
glClearColor(0.0, 255, 0.0, 0.0);
glClear(GL_COLOR_BUFFER_BIT);
//glClearColor(0.5f, 0.5f, 0.7f, 1.0f);
//glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glDisable(GL_DEPTH_TEST);
//Y
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_id_y);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, pixel_w, pixel_h, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, plane0);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nFrameW, m_nFrameH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pData);
//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);
glUniform1i(m_textureUniformY, 0);
//UV
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_id_uv);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, pixel_w / 2, pixel_h / 2, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, plane1);
//glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, pixel_w >> 1, pixel_h >> 1, 0, GL_RG, GL_UNSIGNED_BYTE, buf + pixel_w * pixel_h);
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, m_nFrameW >> 1, m_nFrameH >> 1, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, pData + m_nFrameW * m_nFrameH);
//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);
glUniform1i(m_textureUniformUV, 1);
// Draw
//glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glfwSwapBuffers(m_pWindow);
glfwPollEvents();
return 0;
}
int CYUVRender::InitShader()
{
GLuint prog;
GLint vertCompiled, fragCompiled, linked;
const char * vs =
"attribute vec4 vertexIn; \
attribute vec2 textureIn; \
varying vec2 textureOut; \
void main(void) \
{ \
gl_Position = vertexIn; \
textureOut = textureIn; \
}";
const char * fs[] = {
"varying vec2 textureOut;\n"
"uniform sampler2D textureY;\n"
"uniform sampler2D textureUV;\n"
"void main(void)\n"
"{\n"
"vec3 yuv; \n"
"vec3 rgb; \n"
"yuv.x = texture2D(textureY, textureOut).r; \n"
"yuv.y = texture2D(textureUV, textureOut).r - 0.5; \n"
"yuv.z = texture2D(textureUV, textureOut).a - 0.5; \n"
"rgb = mat3( 1, 1, 1, \n"
"0, -0.39465, 2.03211, \n"
"1.13983, -0.58060, 0) * yuv; \n"
"gl_FragColor = vec4(rgb, 1); \n"
"}\n"
};
GLuint v = glCreateShader(GL_VERTEX_SHADER);
GLuint f = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(v, 1, &vs, NULL);
glShaderSource(f, 1, fs, NULL);
glCompileShader(v);
glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled);
glCompileShader(f);
glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled);
prog = glCreateProgram();
glAttachShader(prog, v);
glAttachShader(prog, f);
glBindAttribLocation(prog, 4, "vertexIn"); //vertex 4
glBindAttribLocation(prog, 2, "textureIn"); //texture 2
glLinkProgram(prog);
glGetProgramiv(prog, GL_LINK_STATUS, &linked);
glUseProgram(prog);
glDeleteShader(v);
glDeleteShader(f);
m_textureUniformY = glGetUniformLocation(prog, "textureY");
m_textureUniformUV = glGetUniformLocation(prog, "textureUV");
static const GLfloat vertexVertices[] =
{
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
static const GLfloat textureVertices[] =
{
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
glVertexAttribPointer(4, 2, GL_FLOAT, 0, 0, vertexVertices); //vertex 4
glEnableVertexAttribArray(4);
glVertexAttribPointer(2, 2, GL_FLOAT, 0, 0, textureVertices); //texture 2
glEnableVertexAttribArray(2);
//init texture
glGenTextures(1, &m_id_y);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_id_y);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
glUniform1i(m_textureUniformY, 0);
glGenTextures(1, &m_id_uv);
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, m_id_uv);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);
glUniform1i(m_textureUniformUV, 1);
return 0;
}
void CYUVRender::error_callback(int error, const char* description)
{
}
int CYUVRender::OpenPlayer()
{
glfwSetErrorCallback(error_callback);
if (!glfwInit())
{
return -1;
}
m_pWindow = glfwCreateWindow(1280, 720, "OpenGL Player", NULL, NULL);
glfwMakeContextCurrent(m_pWindow);
gladLoadGLLoader((GLADloadproc)glfwGetProcAddress);
glfwSwapInterval(2);
return 0;
}
int CYUVRender::ClosePlayer()
{
if (!m_pWindow)
{
glfwTerminate();
}
return 0;
}
int CYUVRender::ShouldClose()
{
if (!m_pWindow)
{
return 1;
}
return glfwWindowShouldClose(m_pWindow);
}
调用
//YUV_OpenGL_Demo.cpp
#include <iostream>
#include <windows.h>
#include "YUVRender.h"
void print_help()
{
std::cout << "e.g : YUV_OpenGL_Demo frameW frameH filename" << std::endl;
getchar();
}
int main(int argc, char *argv[])
{
std::cout << "Hello OpenGL!\n";
if (argc != 4)
{
print_help();
return 0;
}
int nFrameW = atoi(argv[1]);
int nFrameH = atoi(argv[2]);
char *fileName = argv[3];
std::cout << "nFrameW=" << nFrameW << " nFrameH=" << nFrameW << " filename=" << fileName << std::endl;
CYUVRender yuvRender(nFrameW, nFrameH);
unsigned long nFrameSize = nFrameW * nFrameH * 3 / 2;
FILE *infile;
unsigned char *buf = new unsigned char[nFrameSize];
if (fopen_s(&infile, fileName, "rb") != NULL)
{
printf("cannot open %s\n", fileName);
return false;
}
while (!yuvRender.ShouldClose())
{
if (fread(buf, 1, nFrameSize, infile) != nFrameSize)
{
// Loop
fseek(infile, 0, SEEK_SET);
fread(buf, 1, nFrameSize, infile);
}
int64_t t0 = getCurrentTime();
yuvRender.InputData(buf, nFrameSize);
std::cout << "InputData use time="<< getCurrentTime() - t0<<std::endl;
//Sleep(20);
}
}