采用OPENGL纹理显示视频
OPENGL 显示视频2种
1.直接纹理显示 在1.0 就支持
2.基于可编程(着色器)纹理显示 1.5后支持 这个之前的文章介绍过
有一点要记住 在windows上显示视频,窗口DC只支持RGB,所以如果是YUV 一定要转换RGB
在1.5后着色器可编程转换。1.5之前的自己转换
这里介绍直接纹理显示视频
1.设置显示窗口DC参数,创建OPENGL上下文,纹理对象及参数
2.显示视频
a.将YUV 转换 RGB
b.将数据拷贝到纹理glTexSubImage2D
c.通过glBegin glTexCoord2f glVertex2f 绘制纹理数据
d.显示SwapBuffers(hGLDC)
3.释放资源
OPENGL上下文,纹理资源
//代码头文件 OpenGLDisplay5.h
#pragma once
#include "GL/glew.h"
class OpenGLDisplay5
{
public:
OpenGLDisplay5(void);
~OpenGLDisplay5(void){};
public:
int init(HWND hwnd,int w,int h);
void fini();
int display(uint8_t* Y,uint8_t* U,uint8_t* V);
private:
void ConvertYUVtoRGB (unsigned char *src0, unsigned char *src1, unsigned char *src2,
unsigned char *dst_ori,int width,int height);
void init_dither_tab ();
private:
unsigned char *clp;
unsigned char *clp1;
long int crv_tab[256];
long int cbu_tab[256];
long int cgu_tab[256];
long int cgv_tab[256];
long int tab_76309[256];
BYTE* pRGB24Out;
HDC hGLDC;
HGLRC hGLRC;
int m_nWidth;
int m_nHeight;
HWND videoHwnd;
GLuint id_rgb;
};
//代码源文件 OpenGLDisplay5.cpp
#include "StdAfx.h"
#include "OpenGLDisplay5.h"
#pragma comment(lib, "glew32.lib")
static GLint gl_texfmt = GL_RGB;
static GLenum gl_format = GL_RGB;
static GLenum gl_type = GL_UNSIGNED_BYTE;
OpenGLDisplay5::OpenGLDisplay5(void)
{
clp = NULL;
clp1= NULL;
pRGB24Out= NULL;
id_rgb = 0;
};
//初始化OPENGL上下文 纹理对象
int OpenGLDisplay5::init(HWND hwnd,int w,int h)
{
fini();
init_dither_tab();
hGLDC = ::GetDC(hwnd);
videoHwnd = hwnd;
m_nWidth = w;
m_nHeight = h;
/* Set the pixel format for the DC */
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(pfd));
pfd.nSize = sizeof(pfd);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 24;
pfd.cDepthBits = 16;
pfd.iLayerType = PFD_MAIN_PLANE;
SetPixelFormat(hGLDC,
ChoosePixelFormat(hGLDC, &pfd), &pfd);
HGLRC rc_before=wglGetCurrentContext();
HDC hDC_before=wglGetCurrentDC();
/* Create and enable the render context */
hGLRC = wglCreateContext(hGLDC);
wglMakeCurrent(hGLDC, hGLRC);
GLenum err = glewInit();
if (GLEW_OK != err)
{
const char* str = (const char*)glewGetErrorString(err);
int err = 1;
}
const char *version = (const char*)glGetString(GL_VERSION);
const char *extensions = (const char*)glGetString(GL_EXTENSIONS);
static const float matrix[16] = {
2, 0, 0, 0,
0, -2, 0, 0,
0, 0, 0, 0,
-1, 1, 0, 1,
};
glMatrixMode(GL_PROJECTION);
glLoadMatrixf(matrix);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_BLEND);
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
glDisable(GL_CULL_FACE);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &id_rgb);
glBindTexture(GL_TEXTURE_2D, id_rgb);
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);
glTexImage2D(GL_TEXTURE_2D, 0, gl_texfmt, m_nWidth, m_nHeight, 0, gl_format, gl_type,NULL);
pRGB24Out = new BYTE[w*h*3];
return TRUE;
}
//资源释放
void OpenGLDisplay5::fini()
{
if (clp1)
{
free(clp1);
clp1 = NULL;
}
if (hGLDC && hGLRC)
wglMakeCurrent(NULL, NULL);
if (hGLRC)
wglDeleteContext(hGLRC);
if (hGLDC)
::ReleaseDC(videoHwnd, hGLDC);
if (id_rgb>0)
{
glDeleteTextures(1,&id_rgb);
id_rgb = 0;
}
hGLRC = NULL;
hGLDC = NULL;
}
//视频显示到窗口
int OpenGLDisplay5::display(uint8_t* Y,uint8_t* U,uint8_t* V)
{
RECT rc;
::GetWindowRect(videoHwnd,&rc);
int w = rc.right - rc.left;
int h = rc.bottom - rc.top;
glViewport( 0, 0, w, h );
ConvertYUVtoRGB(Y,U,V,pRGB24Out,m_nWidth,m_nHeight);
//yuv2rgb_24(Y,m_nWidth,U,V,m_nWidth/2,pRGB24Out,m_nWidth,m_nHeight,m_nWidth);
//Clear
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
glPixelStorei(GL_UNPACK_ALIGNMENT, 4);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, id_rgb);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, m_nWidth, m_nHeight, gl_format, gl_type, pRGB24Out);
glBegin(GL_QUADS);
/*RGB ok but YUV reverse*/
glTexCoord2f(0, 1);
glVertex2f(0, 0);
glTexCoord2f(0,0);
glVertex2f(0,1);
glTexCoord2f(1,0);
glVertex2f(1,1);
glTexCoord2f(1,1);
glVertex2f(1, 0);
/*YUV ok but rgb reverse
glTexCoord2f(0, 0);
glVertex2f(0, 0);
glTexCoord2f(0,1);
glVertex2f(0,1);
glTexCoord2f(1,1);
glVertex2f(1,1);
glTexCoord2f(1,0);
glVertex2f(1, 0);
*/
glEnd();
SwapBuffers(hGLDC);
return TRUE;
}
//进行YUV->RGB转换的函数
void OpenGLDisplay5::init_dither_tab ()
{
long int crv, cbu, cgu, cgv;
int i;
crv = 104597;
cbu = 132201;
cgu = 25675;
cgv = 53279;
for (i = 0; i < 256; i++)
{
crv_tab[i] = (i - 128) * crv;
cbu_tab[i] = (i - 128) * cbu;
cgu_tab[i] = (i - 128) * cgu;
cgv_tab[i] = (i - 128) * cgv;
tab_76309[i] = 76309 * (i - 16);
}
if (!(clp = (unsigned char *)malloc(sizeof(unsigned char)*1024)))
{
}
clp1 = clp;
clp += 384;
for (i = -384; i < 640; i++)
clp[i] = (i < 0) ? 0 : ((i > 255) ? 255 : i);
}
void OpenGLDisplay5::ConvertYUVtoRGB (unsigned char *src0, unsigned char *src1, unsigned char *src2,
unsigned char *dst_ori,int width,int height)
{
int y11, y21;
int y12, y22;
int y13, y23;
int y14, y24;
int u, v;
int i, j;
int c11, c21, c31, c41;
int c12, c22, c32, c42;
unsigned int DW;
unsigned int *id1, *id2;
unsigned char *py1, *py2, *pu, *pv;
unsigned char *d1, *d2;
d1 = dst_ori;
d1 += width * height * 3 - width * 3;
d2 = d1 - width * 3;
py1 = src0;
pu = src1;
pv = src2;
py2 = py1 + width;
id1 = (unsigned int *) d1;
id2 = (unsigned int *) d2;
for (j = 0; j < height; j += 2)
{
/* line j + 0 */
for (i = 0; i < width; i += 4)
{
u = *pu++;
v = *pv++;
c11 = crv_tab[v];
c21 = cgu_tab[u];
c31 = cgv_tab[v];
c41 = cbu_tab[u];
u = *pu++;
v = *pv++;
c12 = crv_tab[v];
c22 = cgu_tab[u];
c32 = cgv_tab[v];
c42 = cbu_tab[u];
y11 = tab_76309[*py1++]; /* (255/219)*65536 */
y12 = tab_76309[*py1++];
y13 = tab_76309[*py1++]; /* (255/219)*65536 */
y14 = tab_76309[*py1++];
y21 = tab_76309[*py2++];
y22 = tab_76309[*py2++];
y23 = tab_76309[*py2++];
y24 = tab_76309[*py2++];
/* RGBR */
DW = ((clp[(y11 + c41) >> 16])) |
((clp[(y11 - c21 - c31) >> 16]) << 8) |
((clp[(y11 + c11) >> 16]) << 16) |
((clp[(y12 + c41) >> 16]) << 24);
*id1++ = DW;
/* GBRG */
DW = ((clp[(y12 - c21 - c31) >> 16])) |
((clp[(y12 + c11) >> 16]) << 8) |
((clp[(y13 + c42) >> 16]) << 16) |
((clp[(y13 - c22 - c32) >> 16]) << 24);
*id1++ = DW;
/* BRGB */
DW = ((clp[(y13 + c12) >> 16])) |
((clp[(y14 + c42) >> 16]) << 8) |
((clp[(y14 - c22 - c32) >> 16]) << 16) |
((clp[(y14 + c12) >> 16]) << 24);
*id1++ = DW;
/* RGBR */
DW = ((clp[(y21 + c41) >> 16])) |
((clp[(y21 - c21 - c31) >> 16]) << 8) |
((clp[(y21 + c11) >> 16]) << 16) |
((clp[(y22 + c41) >> 16]) << 24);
*id2++ = DW;
/* GBRG */
DW = ((clp[(y22 - c21 - c31) >> 16])) |
((clp[(y22 + c11) >> 16]) << 8) |
((clp[(y23 + c42) >> 16]) << 16) |
((clp[(y23 - c22 - c32) >> 16]) << 24);
*id2++ = DW;
/* BRGB */
DW = ((clp[(y23 + c12) >> 16])) |
((clp[(y24 + c42) >> 16]) << 8) |
((clp[(y24 - c22 - c32) >> 16]) << 16) |
((clp[(y24 + c12) >> 16]) << 24);
*id2++ = DW;
}
id1 -= (9 * width) >> 2;
id2 -= (9 * width) >> 2;
py1 += width;
py2 += width;
}
}