windows下用OPENGL播放视频 -采用纹理显示



采用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;
  }
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值