OpenGL PBO渲染视频数据 [转]

OpenGL PBO渲染视频数据 [转]

目录

OpenGL PBO渲染视频数据 [转]

PBO

双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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值