OpenGL PBO渲染视频数据 [转]
目录
PBO
#pragma once #include <assert.h> class ShaderId { public: ShaderId() { _shaderId = -1; } int _shaderId; }; /** * 程序 */ class ProgramId { public: int _programId; ShaderId _vertex; ShaderId _fragment; public: ProgramId() { _programId = -1; } public: /** * 加载函数 */ bool createProgram( const char* vertex,const char* fragment ) { bool error = false; do { if (vertex) { _vertex._shaderId = glCreateShader( GL_VERTEX_SHADER ); glShaderSource( _vertex._shaderId, 1, &vertex, 0 ); glCompileShader( _vertex._shaderId ); GLint compileStatus; glGetShaderiv( _vertex._shaderId, GL_COMPILE_STATUS, &compileStatus ); error = compileStatus == GL_FALSE; if( error ) { GLchar messages[256]; glGetShaderInfoLog( _vertex._shaderId, sizeof(messages), 0,messages); assert( messages && 0 != 0); break; } } if (fragment) { _fragment._shaderId = glCreateShader( GL_FRAGMENT_SHADER ); glShaderSource( _fragment._shaderId, 1, &fragment, 0 ); glCompileShader( _fragment._shaderId ); GLint compileStatus; glGetShaderiv( _fragment._shaderId, GL_COMPILE_STATUS, &compileStatus ); error = compileStatus == GL_FALSE; if( error ) { GLchar messages[256]; glGetShaderInfoLog( _fragment._shaderId, sizeof(messages), 0,messages); assert( messages && 0 != 0); break; } } _programId = glCreateProgram( ); if (_vertex._shaderId) { glAttachShader( _programId, _vertex._shaderId); } if (_fragment._shaderId) { glAttachShader( _programId, _fragment._shaderId); } glLinkProgram( _programId ); GLint linkStatus; glGetProgramiv( _programId, GL_LINK_STATUS, &linkStatus ); if (linkStatus == GL_FALSE) { GLchar messages[256]; glGetProgramInfoLog( _programId, sizeof(messages), 0, messages); break; } glUseProgram(_programId); } while(false); if (error) { if (_fragment._shaderId) { glDeleteShader(_fragment._shaderId); _fragment._shaderId = 0; } if (_vertex._shaderId) { glDeleteShader(_vertex._shaderId); _vertex._shaderId = 0; } if (_programId) { glDeleteProgram(_programId); _programId = 0; } } return true; } /** * 使用程序 */ virtual void begin() { glUseProgram(_programId); } /** * 使用完成 */ virtual void end() { glUseProgram(0); } }; class PROGRAM_YUV1 :public ProgramId { public: typedef int attribute; typedef int uniform; public: attribute _position; attribute _uvY; attribute _uvU; attribute _uvV; uniform _MVP; uniform _textureYUV; public: PROGRAM_YUV1() { _position = -1; _uvY = -1; _uvU = -1; _uvV = -1; _MVP = -1; _textureYUV = -1; } ~PROGRAM_YUV1() { } /// 初始化函数 virtual bool initialize() { const char* vs = { "precision lowp float; " "uniform mat4 _MVP;" "attribute vec2 _position;" "attribute vec2 _uvY;" "attribute vec2 _uvU;" "attribute vec2 _uvV;" "varying vec2 _outUVY;" "varying vec2 _outUVU;" "varying vec2 _outUVV;" "void main()" "{" " _outUVY = _uvY;" " _outUVU = _uvU;" " _outUVV = _uvV;" " vec4 pos = vec4(_position,0,1);" " gl_Position = _MVP * pos;" "}" }; const char* ps = { "precision lowp float; " "uniform sampler2D _textureYUV;" "varying vec2 _outUVY;" "varying vec2 _outUVU;" "varying vec2 _outUVV;" "void main()" "{" " vec3 yuv;" " vec3 rgb; " " yuv.x = texture2D(_textureYUV, _outUVY).a;" " yuv.y = texture2D(_textureYUV, _outUVU).a - 0.5;" " yuv.z = texture2D(_textureYUV, _outUVV).a - 0.5;" " rgb = mat3( 1, 1, 1," " 0, -0.39465, 2.03210," " 1.13983, -0.58060, 0) * yuv;" " gl_FragColor = vec4(rgb, 1);" "}" }; bool res = createProgram(vs,ps); if(res) { _position = glGetAttribLocation(_programId,"_position"); _uvY = glGetAttribLocation(_programId,"_uvY"); _uvU = glGetAttribLocation(_programId,"_uvU"); _uvV = glGetAttribLocation(_programId,"_uvV"); _textureYUV = glGetUniformLocation(_programId,"_textureYUV"); _MVP = glGetUniformLocation(_programId,"_MVP"); } return res; } /** * 使用程序 */ virtual void begin() { glUseProgram(_programId); glEnableVertexAttribArray(_position); glEnableVertexAttribArray(_uvY); glEnableVertexAttribArray(_uvU); glEnableVertexAttribArray(_uvV); } /** * 使用完成 */ virtual void end() { glDisableVertexAttribArray(_position); glDisableVertexAttribArray(_uvY); glDisableVertexAttribArray(_uvU); glDisableVertexAttribArray(_uvV); glUseProgram(0); } };
#include <windows.h> #include <tchar.h> #include "glew/glew.h" #include "FFVideoReader.hpp" #include "Thread.hpp" #include "Timestamp.hpp" #include "GLContext.h" #include "CELLShader.hpp" #include "CELLMath.hpp" #define WM_UPDATE_VIDEO WM_USER + 100 void getResourcePath(HINSTANCE hInstance,char pPath[1024]) { char szPathName[1024]; char szDriver[64]; char szPath[1024]; GetModuleFileNameA(hInstance,szPathName,sizeof(szPathName)); _splitpath( szPathName, szDriver, szPath, 0, 0 ); sprintf(pPath,"%s%s",szDriver,szPath); } class DecodeThread :public Thread { public: FFVideoReader _ffReader; HWND _hWnd; bool _exitFlag; Timestamp _timestamp; GLContext _glContext; unsigned _textureYUV; PROGRAM_YUV1 _shaderTex; unsigned _pbo; public: DecodeThread() { _exitFlag = false; _hWnd = 0; _pbo = 0; } virtual void setup(HWND hwnd,const char* fileName = "11.flv") { _hWnd = hwnd; _ffReader.setup(); _ffReader.load(fileName); _glContext.setup(hwnd,GetDC(hwnd)); glewInit(); glEnable(GL_TEXTURE_2D); _textureYUV = createTexture(_ffReader._screenW,_ffReader._screenH + _ffReader._screenH/2); _shaderTex.initialize(); /** * 创建PBuffer */ _pbo = createPBuffer(_ffReader._screenW,_ffReader._screenH + _ffReader._screenH/2); } /** * 加载文件 */ virtual void load(const char* fileName) { _ffReader.load(fileName); } virtual void shutdown() { _exitFlag = true; Thread::join(); _glContext.shutdown(); } /** * 线程执行函数 */ virtual bool run() { _timestamp.update(); while(!_exitFlag) { FrameInfor* infor = new FrameInfor(); if (!_ffReader.readFrame(*infor)) { break; } double tims = infor->_pts * infor->_timeBase * 1000; //! 这里需要通知窗口进行重绘制更新,显示更新数据 PostMessage(_hWnd,WM_UPDATE_VIDEO,(WPARAM)infor,0); double elsped = _timestamp.getElapsedTimeInMilliSec(); double sleeps = (tims - elsped); if (sleeps > 1) { Sleep((DWORD)sleeps); } } return true; } void updateImage(GLubyte* dst,int x,int y,int w,int h,void* data) { int pitch = _ffReader._screenW; GLubyte* dst1 = dst + y * pitch + x; GLubyte* src = (GLubyte*)(data); int size = w; for (int i = 0 ; i < h ; ++ i) { memcpy(dst1,src,w); dst1 += pitch; src += w; } } void updateTexture(FrameInfor* infor) { int w = _ffReader._screenW; int h = _ffReader._screenH + _ffReader._screenH/2; glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pbo); GLubyte* dst = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); if( dst != 0) { memcpy(dst,infor->_data->data[0],_ffReader._screenW * _ffReader._screenH); updateImage(dst,0, _ffReader._screenH,_ffReader._screenW/2,_ffReader._screenH/2,infor->_data->data[1]); updateImage(dst,_ffReader._screenW/2, _ffReader._screenH,_ffReader._screenW/2,_ffReader._screenH/2,infor->_data->data[2]); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); } glBindTexture(GL_TEXTURE_2D,_textureYUV); glTexSubImage2D(GL_TEXTURE_2D,0,0,0,w,h,GL_ALPHA,GL_UNSIGNED_BYTE,0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); } void render() { struct Vertex { CELL::float2 pos; CELL::float2 uvY; CELL::float2 uvU; CELL::float2 uvV; }; RECT rt; GetClientRect(_hWnd,&rt); int w = rt.right - rt.left; int h = rt.bottom - rt.top; glClear(GL_COLOR_BUFFER_BIT); glClearColor(1,0,0,1); glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,w,h,0,-100,100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D,_textureYUV); float yv = (float)_ffReader._screenH/(float)(_ffReader._screenH + _ffReader._screenH/2); float fw = _ffReader._screenW; float fh = _ffReader._screenH; float x = 0; float y = 0; float Yv = (float)fh/(float)(fh + fh/2); float Uu0 = 0; float Uv0 = Yv; float Uu1 = 0.5f; float Uv1 = 1.0f; float Vu0 = 0.5f; float Vv0 = Yv; float Vu1 = 1.0f; float Vv1 = 1.0f; Vertex vertex[] = { CELL::float2(x,y), CELL::float2(0,0), CELL::float2(Uu0,Uv0), CELL::float2(Vu0,Vv0), CELL::float2(x + w,y), CELL::float2(1,0), CELL::float2(Uu1,Uv0), CELL::float2(Vu1,Vv0), CELL::float2(x,y + h), CELL::float2(0,Yv), CELL::float2(Uu0,Uv1), CELL::float2(Vu0,Vv1), CELL::float2(x + w, y + h), CELL::float2(1,Yv), CELL::float2(Uu1,Uv1), CELL::float2(Vu1,Vv1), }; _shaderTex.begin(); CELL::matrix4 matMVP = CELL::ortho<float>(0,w,h,0,-100,100); glUniformMatrix4fv(_shaderTex._MVP, 1, false, matMVP.data()); glUniform1i(_shaderTex._textureYUV, 0); glVertexAttribPointer(_shaderTex._position,2,GL_FLOAT, false, sizeof(Vertex),vertex); glVertexAttribPointer(_shaderTex._uvY, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvY); glVertexAttribPointer(_shaderTex._uvU, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvU); glVertexAttribPointer(_shaderTex._uvV, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvV); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shaderTex.end(); _glContext.swapBuffer(); } protected: unsigned createTexture(int w,int h) { unsigned texId; glGenTextures(1,&texId); glBindTexture(GL_TEXTURE_2D,texId); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D,0,GL_ALPHA,w,h,0,GL_ALPHA,GL_UNSIGNED_BYTE,0); return texId; } unsigned createPBuffer(int w,int h) { unsigned pbuffer = 0; glGenBuffers(1, &pbuffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbuffer); glBufferData(GL_PIXEL_UNPACK_BUFFER, w* h, 0, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); return pbuffer; } }; DecodeThread g_decode; LRESULT CALLBACK windowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_UPDATE_VIDEO: { FrameInfor* infor = (FrameInfor*)wParam; g_decode.updateTexture(infor); delete infor; g_decode.render(); } break; case WM_SIZE: break; case WM_CLOSE: case WM_DESTROY: g_decode.shutdown(); PostQuitMessage(0); break; default: break; } return DefWindowProc( hWnd, msg, wParam, lParam ); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) { // 1 注册窗口类 ::WNDCLASSEXA winClass; winClass.lpszClassName = "FFVideoPlayer"; winClass.cbSize = sizeof(::WNDCLASSEX); winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; winClass.lpfnWndProc = windowProc; winClass.hInstance = hInstance; winClass.hIcon = 0; winClass.hIconSm = 0; winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = (HBRUSH)(BLACK_BRUSH); winClass.lpszMenuName = NULL; winClass.cbClsExtra = 0; winClass.cbWndExtra = 0; RegisterClassExA(&winClass); // 2 创建窗口 HWND hWnd = CreateWindowExA( NULL, "FFVideoPlayer", "FFVideoPlayer", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 480, 320, 0, 0, hInstance, 0 ); UpdateWindow( hWnd ); ShowWindow(hWnd,SW_SHOW); char szPath[1024]; char szPathName[1024]; getResourcePath(hInstance,szPath); sprintf(szPathName,"%sdata/11.flv",szPath); g_decode.setup(hWnd,szPathName); g_decode.start(); MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } g_decode.shutdown(); return 0; }
双PBO
#pragma once #include <assert.h> class ShaderId { public: ShaderId() { _shaderId = -1; } int _shaderId; }; /** * 程序 */ class ProgramId { public: int _programId; ShaderId _vertex; ShaderId _fragment; public: ProgramId() { _programId = -1; } public: /** * 加载函数 */ bool createProgram(const char* vertex, const char* fragment) { bool error = false; do { if (vertex) { _vertex._shaderId = glCreateShader(GL_VERTEX_SHADER); glShaderSource(_vertex._shaderId, 1, &vertex, 0); glCompileShader(_vertex._shaderId); GLint compileStatus; glGetShaderiv(_vertex._shaderId, GL_COMPILE_STATUS, &compileStatus); error = compileStatus == GL_FALSE; if (error) { GLchar messages[256]; glGetShaderInfoLog(_vertex._shaderId, sizeof(messages), 0, messages); assert(messages && 0 != 0); break; } } if (fragment) { _fragment._shaderId = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(_fragment._shaderId, 1, &fragment, 0); glCompileShader(_fragment._shaderId); GLint compileStatus; glGetShaderiv(_fragment._shaderId, GL_COMPILE_STATUS, &compileStatus); error = compileStatus == GL_FALSE; if (error) { GLchar messages[256]; glGetShaderInfoLog(_fragment._shaderId, sizeof(messages), 0, messages); assert(messages && 0 != 0); break; } } _programId = glCreateProgram(); if (_vertex._shaderId) { glAttachShader(_programId, _vertex._shaderId); } if (_fragment._shaderId) { glAttachShader(_programId, _fragment._shaderId); } glLinkProgram(_programId); GLint linkStatus; glGetProgramiv(_programId, GL_LINK_STATUS, &linkStatus); if (linkStatus == GL_FALSE) { GLchar messages[256]; glGetProgramInfoLog(_programId, sizeof(messages), 0, messages); break; } glUseProgram(_programId); } while (false); if (error) { if (_fragment._shaderId) { glDeleteShader(_fragment._shaderId); _fragment._shaderId = 0; } if (_vertex._shaderId) { glDeleteShader(_vertex._shaderId); _vertex._shaderId = 0; } if (_programId) { glDeleteProgram(_programId); _programId = 0; } } return true; } /** * 使用程序 */ virtual void begin() { glUseProgram(_programId); } /** * 使用完成 */ virtual void end() { glUseProgram(0); } }; class PROGRAM_YUV1 :public ProgramId { public: typedef int attribute; typedef int uniform; public: attribute _position; attribute _uvY; attribute _uvU; attribute _uvV; uniform _MVP; uniform _textureYUV; public: PROGRAM_YUV1() { _position = -1; _uvY = -1; _uvU = -1; _uvV = -1; _MVP = -1; _textureYUV = -1; } ~PROGRAM_YUV1() { } /// 初始化函数 virtual bool initialize() { const char* vs = { "precision lowp float; " "uniform mat4 _MVP;" "attribute vec2 _position;" "attribute vec2 _uvY;" "attribute vec2 _uvU;" "attribute vec2 _uvV;" "varying vec2 _outUVY;" "varying vec2 _outUVU;" "varying vec2 _outUVV;" "void main()" "{" " _outUVY = _uvY;" " _outUVU = _uvU;" " _outUVV = _uvV;" " vec4 pos = vec4(_position,0,1);" " gl_Position = _MVP * pos;" "}" }; const char* ps = { "precision lowp float; " "uniform sampler2D _textureYUV;" "varying vec2 _outUVY;" "varying vec2 _outUVU;" "varying vec2 _outUVV;" "void main()" "{" " vec3 yuv;" " vec3 rgb; " " yuv.x = texture2D(_textureYUV, _outUVY).a;" " yuv.y = texture2D(_textureYUV, _outUVU).a - 0.5;" " yuv.z = texture2D(_textureYUV, _outUVV).a - 0.5;" " rgb = mat3( 1, 1, 1," " 0, -0.39465, 2.03210," " 1.13983, -0.58060, 0) * yuv;" " gl_FragColor = vec4(rgb, 1);" "}" }; bool res = createProgram(vs, ps); if (res) { _position = glGetAttribLocation(_programId, "_position"); _uvY = glGetAttribLocation(_programId, "_uvY"); _uvU = glGetAttribLocation(_programId, "_uvU"); _uvV = glGetAttribLocation(_programId, "_uvV"); _textureYUV = glGetUniformLocation(_programId, "_textureYUV"); _MVP = glGetUniformLocation(_programId, "_MVP"); } return res; } /** * 使用程序 */ virtual void begin() { glUseProgram(_programId); glEnableVertexAttribArray(_position); glEnableVertexAttribArray(_uvY); glEnableVertexAttribArray(_uvU); glEnableVertexAttribArray(_uvV); } /** * 使用完成 */ virtual void end() { glDisableVertexAttribArray(_position); glDisableVertexAttribArray(_uvY); glDisableVertexAttribArray(_uvU); glDisableVertexAttribArray(_uvV); glUseProgram(0); } };
#include <windows.h> #include <tchar.h> #include "glew/glew.h" #include "FFVideoReader.hpp" #include "Thread.hpp" #include "Timestamp.hpp" #include "GLContext.h" #include "CELLShader.hpp" #include "CELLMath.hpp" #define WM_UPDATE_VIDEO WM_USER + 100 void getResourcePath(HINSTANCE hInstance,char pPath[1024]) { char szPathName[1024]; char szDriver[64]; char szPath[1024]; GetModuleFileNameA(hInstance,szPathName,sizeof(szPathName)); _splitpath( szPathName, szDriver, szPath, 0, 0 ); sprintf(pPath,"%s%s",szDriver,szPath); } class DecodeThread :public Thread { public: FFVideoReader _ffReader; HWND _hWnd; bool _exitFlag; Timestamp _timestamp; GLContext _glContext; unsigned _textureYUV; PROGRAM_YUV1 _shaderTex; unsigned _pbo[2]; int _DMA; int _WRITE; void* _dmaPtr; public: DecodeThread() { _exitFlag = false; _hWnd = 0; _DMA = 0; _WRITE = 1; _dmaPtr = 0; } virtual void setup(HWND hwnd,const char* fileName = "11.flv") { _hWnd = hwnd; _ffReader.setup(); _ffReader.load(fileName); _glContext.setup(hwnd,GetDC(hwnd)); glewInit(); glEnable(GL_TEXTURE_2D); _textureYUV = createTexture(_ffReader._screenW,_ffReader._screenH + _ffReader._screenH/2); _shaderTex.initialize(); /** * 创建PBuffer */ _pbo[0] = createPBuffer(_ffReader._screenW,_ffReader._screenH + _ffReader._screenH/2); _pbo[1] = createPBuffer(_ffReader._screenW,_ffReader._screenH + _ffReader._screenH/2); } /** * 加载文件 */ virtual void load(const char* fileName) { _ffReader.load(fileName); } virtual void shutdown() { _exitFlag = true; Thread::join(); _glContext.shutdown(); } /** * 线程执行函数 */ virtual bool run() { _timestamp.update(); while(!_exitFlag) { FrameInfor* infor = new FrameInfor(); if (!_ffReader.readFrame(*infor)) { break; } double tims = infor->_pts * infor->_timeBase * 1000; //! 这里需要通知窗口进行重绘制更新,显示更新数据 if ( infor->_data->data[0] == 0 || infor->_data->data[1] == 0 || infor->_data->data[2] == 0 ) { continue; } PostMessage(_hWnd,WM_UPDATE_VIDEO,(WPARAM)infor,0); double elsped = _timestamp.getElapsedTimeInMilliSec(); double sleeps = (tims - elsped); if (sleeps > 1) { Sleep((DWORD)sleeps); } } return true; } void updateImage(GLubyte* dst,int x,int y,int w,int h,void* data) { int pitch = _ffReader._screenW; GLubyte* dst1 = dst + y * pitch + x; GLubyte* src = (GLubyte*)(data); int size = w; for (int i = 0 ; i < h ; ++ i) { memcpy(dst1,src,w); dst1 += pitch; src += w; } } void updateTexture(FrameInfor* infor) { int w = _ffReader._screenW; int h = _ffReader._screenH + _ffReader._screenH/2; glBindBuffer(GL_PIXEL_UNPACK_BUFFER, _pbo[_WRITE]); GLubyte* dst = (GLubyte*)glMapBuffer(GL_PIXEL_UNPACK_BUFFER, GL_WRITE_ONLY); if( dst != 0) { memcpy(dst,infor->_data->data[0],_ffReader._screenW * _ffReader._screenH); updateImage(dst,0, _ffReader._screenH,_ffReader._screenW/2,_ffReader._screenH/2,infor->_data->data[1]); updateImage(dst,_ffReader._screenW/2, _ffReader._screenH,_ffReader._screenW/2,_ffReader._screenH/2,infor->_data->data[2]); glUnmapBuffer(GL_PIXEL_UNPACK_BUFFER); } glBindBuffer(GL_PIXEL_UNPACK_BUFFER,_pbo[_DMA]); glBindTexture(GL_TEXTURE_2D,_textureYUV); glTexSubImage2D(GL_TEXTURE_2D,0,0,0,w,h,GL_ALPHA,GL_UNSIGNED_BYTE,0); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); std::swap(_DMA,_WRITE); } void render() { struct Vertex { CELL::float2 pos; CELL::float2 uvY; CELL::float2 uvU; CELL::float2 uvV; }; RECT rt; GetClientRect(_hWnd,&rt); int w = rt.right - rt.left; int h = rt.bottom - rt.top; glClear(GL_COLOR_BUFFER_BIT); glClearColor(1,0,0,1); glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(0,w,h,0,-100,100); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glBindTexture(GL_TEXTURE_2D,_textureYUV); float yv = (float)_ffReader._screenH/(float)(_ffReader._screenH + _ffReader._screenH/2); float fw = _ffReader._screenW; float fh = _ffReader._screenH; float x = 0; float y = 0; float Yv = (float)fh/(float)(fh + fh/2); float Uu0 = 0; float Uv0 = Yv; float Uu1 = 0.5f; float Uv1 = 1.0f; float Vu0 = 0.5f; float Vv0 = Yv; float Vu1 = 1.0f; float Vv1 = 1.0f; Vertex vertex[] = { CELL::float2(x,y), CELL::float2(0,0), CELL::float2(Uu0,Uv0), CELL::float2(Vu0,Vv0), CELL::float2(x + w,y), CELL::float2(1,0), CELL::float2(Uu1,Uv0), CELL::float2(Vu1,Vv0), CELL::float2(x,y + h), CELL::float2(0,Yv), CELL::float2(Uu0,Uv1), CELL::float2(Vu0,Vv1), CELL::float2(x + w, y + h), CELL::float2(1,Yv), CELL::float2(Uu1,Uv1), CELL::float2(Vu1,Vv1), }; _shaderTex.begin(); CELL::matrix4 matMVP = CELL::ortho<float>(0,w,h,0,-100,100); glUniformMatrix4fv(_shaderTex._MVP, 1, false, matMVP.data()); glUniform1i(_shaderTex._textureYUV, 0); glVertexAttribPointer(_shaderTex._position,2,GL_FLOAT, false, sizeof(Vertex),vertex); glVertexAttribPointer(_shaderTex._uvY, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvY); glVertexAttribPointer(_shaderTex._uvU, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvU); glVertexAttribPointer(_shaderTex._uvV, 2,GL_FLOAT, false, sizeof(Vertex),&vertex[0].uvV); glDrawArrays(GL_TRIANGLE_STRIP,0,4); _shaderTex.end(); _glContext.swapBuffer(); } protected: unsigned createTexture(int w,int h) { unsigned texId; glGenTextures(1,&texId); glBindTexture(GL_TEXTURE_2D,texId); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); glTexImage2D(GL_TEXTURE_2D,0,GL_ALPHA,w,h,0,GL_ALPHA,GL_UNSIGNED_BYTE,0); return texId; } unsigned createPBuffer(int w,int h) { unsigned pbuffer = 0; glGenBuffers(1, &pbuffer); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, pbuffer); glBufferData(GL_PIXEL_UNPACK_BUFFER, w* h, 0, GL_STREAM_DRAW); glBindBuffer(GL_PIXEL_UNPACK_BUFFER, 0); return pbuffer; } }; DecodeThread g_decode; LRESULT CALLBACK windowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch(msg) { case WM_UPDATE_VIDEO: { FrameInfor* infor = (FrameInfor*)wParam; g_decode.updateTexture(infor); delete infor; g_decode.render(); } break; case WM_SIZE: break; case WM_CLOSE: case WM_DESTROY: g_decode.shutdown(); PostQuitMessage(0); break; default: break; } return DefWindowProc( hWnd, msg, wParam, lParam ); } int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd ) { // 1 注册窗口类 ::WNDCLASSEXA winClass; winClass.lpszClassName = "FFVideoPlayer"; winClass.cbSize = sizeof(::WNDCLASSEX); winClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; winClass.lpfnWndProc = windowProc; winClass.hInstance = hInstance; winClass.hIcon = 0; winClass.hIconSm = 0; winClass.hCursor = LoadCursor(NULL, IDC_ARROW); winClass.hbrBackground = (HBRUSH)(BLACK_BRUSH); winClass.lpszMenuName = NULL; winClass.cbClsExtra = 0; winClass.cbWndExtra = 0; RegisterClassExA(&winClass); // 2 创建窗口 HWND hWnd = CreateWindowExA( NULL, "FFVideoPlayer", "FFVideoPlayer", WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS, 0, 0, 480, 320, 0, 0, hInstance, 0 ); UpdateWindow( hWnd ); ShowWindow(hWnd,SW_SHOW); char szPath[1024]; char szPathName[1024]; getResourcePath(hInstance,szPath); sprintf(szPathName,"%sdata/11.flv",szPath); g_decode.setup(hWnd,szPathName); g_decode.start(); MSG msg = {0}; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } g_decode.shutdown(); return 0; }