使用QT的QOpenGLWidget显示yuv视频数据

QT5的QOpenGLWidget和QGLWidget有不同,将原有的继承自QGLWidget的改为QOpenGLWidget主要区别就是一些函数不能使用,要想使用opengl的一些函数需要继承QOpenGLFunctions,具体修改如下:

头文件:

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLTexture>
#include <QOpenGLShaderProgram>


typedef struct GLTexture_s {
    GLuint id;  // for glGenTextures
    HFrame frame;
} GLTexture;
//qt opengl的封装类

//这个类主要做的是界面显示的操作,不要将业务相关(开始播放,暂停,停止等)的添加进来
//具体做法是再写一个纯业务类来处理,要处理业务时调用这个业务类的方法即可
class HGLWidget :public QOpenGLWidget,protected QOpenGLFunctions
{
  Q_OBJECT
public:
     HGLWidget(QWidget* parent = NULL);

     void setVertices(double ratio);
     void setVertices(QRect rc);

     //画帧
     void drawFrame(HFrame *pFrame);
     //画纹理
     void drawTexture(HRect rc, GLTexture *tex);
     //画框
     void drawRect(HRect rc, HColor clr, int line_width = 1, bool bFill = false);
     //画文本
     void drawText(QPoint lb, const char* text, int fontsize, QColor clr);

protected:
    virtual void initializeGL();
    virtual void resizeGL(int w, int h);
    virtual void paintGL();


    static void loadYUVShader();
    //VAO(Vertex Array Object)顶点数组对象
    void initVAO();
    void initYUV();

    //画yuv数据
    void drawYUV(HFrame* pFrame);

protected:
    static std::atomic_flag s_init_flag;
    //无符号四字节整型,
    static GLuint prog_yuv;  // GLuint
    static GLuint texUniformY;// GLuint
    static GLuint texUniformU;//GLuint
    static GLuint texUniformV;//GLuint

static QOpenGLShaderProgram m_ShaderProgram;
    //编号,对应Y U V
    GLuint  tex_yuv[3];//GLuint

    GLfloat vertices[8];//GLfloat
    GLfloat textures[8];//GLfloat



    // NOTE: QPainter used 3 VertexAttribArray
    enum VER_ATTR{
        VER_ATTR_VER = 3,
        VER_ATTR_TEX,
    };

};

源文件:

std::atomic_flag HGLWidget::s_init_flag = ATOMIC_FLAG_INIT;
GLuint HGLWidget::prog_yuv;
GLuint HGLWidget::texUniformY;
GLuint HGLWidget::texUniformU;
GLuint HGLWidget::texUniformV;
QOpenGLShaderProgram HGLWidget::m_ShaderProgram;

 HGLWidget::HGLWidget(QWidget* parent)
     :QOpenGLWidget(parent)
 {

 }


 void  HGLWidget::setVertices(double ratio)
 {
     double w = 1.0, h = 1.0;
     if (ratio < 1.0) {
         w = ratio;
     }
     else {
         h = 1.0 / ratio;
     }

     GLfloat tmp[] = {
         -w, -h,
          w, -h,
         -w,  h,
          w,  h,
     };

     memcpy(vertices, tmp, sizeof(GLfloat)*8);
 }
 void  HGLWidget::setVertices(QRect rc)
 {
     int wnd_w = width();
     int wnd_h = height();
     if (wnd_w <= 0 || wnd_h <= 0) {
         return;
     }
     GLfloat left = (GLfloat)rc.left() * 2 / wnd_w - 1;
     GLfloat right = (GLfloat)(rc.right()+1) * 2 / wnd_w - 1;
     GLfloat top = 1 - (GLfloat)rc.top() * 2 / wnd_h;
     GLfloat bottom = 1 - (GLfloat)(rc.bottom()+1) * 2 / wnd_h;
     qDebug("l=%d r=%d t=%d b=%d", rc.left(), rc.right(), rc.top(), rc.bottom());
     qDebug("l=%f r=%f t=%f b=%f", left, right, top, bottom);
     GLfloat tmp[] = {
         left,  bottom,
         right, bottom,
         left,  top,
         right, top
     };

     memcpy(vertices, tmp, sizeof(GLfloat)*8);
 }

 //画帧
 void  HGLWidget::drawFrame(HFrame *pFrame)
 {

     if (pFrame->type == GL_I420 || pFrame->type == GL_YV12) {
         drawYUV(pFrame);
     }
     else {
//         glMatrixMode(GL_PROJECTION);
//         glLoadIdentity();
//         glRasterPos3f(-1.0f,1.0f,0);
//         glPixelZoom(width()/(float)pFrame->w, -height()/(float)pFrame->h);
//         glDrawPixels(pFrame->w, pFrame->h, pFrame->type, GL_UNSIGNED_BYTE, pFrame->buf.base);
     }
 }
 //画纹理
 void  HGLWidget::drawTexture(HRect rc, GLTexture *tex)
 {
     glActiveTexture(GL_TEXTURE0);
     glBindTexture(GL_TEXTURE_2D, tex->id);

     glEnable(GL_TEXTURE_2D);
     glEnable(GL_BLEND);
     glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);



     glDisable(GL_TEXTURE_2D);
     glDisable(GL_BLEND);
 }
 //画框
 void  HGLWidget::drawRect(HRect rc, HColor clr, int line_width, bool bFill)
 {

 }
 //画文本
#include <QPainter>
void HGLWidget::drawText(QPoint lb, const char* text, int fontsize, QColor clr) {
    QPainter painter(this);
    QFont font = painter.font();
    font.setPointSize(fontsize);
    painter.setFont(font);
    painter.setPen(clr);
    painter.drawText(lb, text);
}


void  HGLWidget::initializeGL()
{
    initializeOpenGLFunctions();
    glEnable(GL_DEPTH_TEST);


    if (!s_init_flag.test_and_set()) {
//        s_init_flag.clear();
        loadYUVShader();
    }

    initVAO();
    initYUV();

}
void  HGLWidget::resizeGL(int w, int h)
{
    //设置视口
    glViewport(0,0,w,h);
}
void  HGLWidget::paintGL()
{
    glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT);
}
void HGLWidget::loadYUVShader() {

    //创建顶点着色器
    QOpenGLShader VSHader(QOpenGLShader::Vertex);//, this

    //顶点着色器源码
    const char *vsrc = "attribute vec4 vertexIn; \
    attribute vec2 textureIn; \
    varying vec2 textureOut;  \
    void main(void)           \
    {                         \
        gl_Position = vertexIn; \
        textureOut = textureIn; \
    }";
    //源码送入顶点着色器程序
    bool bCompile = VSHader.compileSourceCode(vsrc);
    if(!bCompile)
    {
    }

    //创建片元着色器
    QOpenGLShader FSHader(QOpenGLShader::Fragment);//,this

    //片段着色器源码(windows下opengl es 需要加上float这句话)
        const char *fsrc =
    #if defined(WIN32)
        "#ifdef GL_ES\n"
        "precision mediump float;\n"
        "#endif\n"
    #else
    #endif
    "varying vec2 textureOut; \
    uniform sampler2D tex_y; \
    uniform sampler2D tex_u; \
    uniform sampler2D tex_v; \
    void main(void) \
    { \
        vec3 yuv; \
        vec3 rgb; \
        yuv.x = texture2D(tex_y, textureOut).r; \
        yuv.y = texture2D(tex_u, textureOut).r - 0.5; \
        yuv.z = texture2D(tex_v, textureOut).r - 0.5; \
        rgb = mat3( 1,       1,         1, \
                    0,       -0.39465,  2.03211, \
                    1.13983, -0.58060,  0) * yuv; \
        gl_FragColor = vec4(rgb, 1); \
    }";

    //源码送入片元着色器程序
    bCompile = FSHader.compileSourceCode(fsrc);
    if(!bCompile)
    {
    }

    //创建一个新的程序
    //创建着色器程序容器

    //m_ShaderProgram = new QOpenGLShaderProgram;
    //关联着色器
     //将片段着色器添加到程序容器
     m_ShaderProgram.addShader(&FSHader);
     //将顶点着色器添加到程序容器
    m_ShaderProgram.addShader(&VSHader);
    //绑定attribute变量
     //绑定属性vertexIn到指定位置ATTRIB_VERTEX,该属性在顶点着色源码其中有声明
    m_ShaderProgram.bindAttributeLocation("vertexIn", VER_ATTR_VER);
     //绑定属性textureIn到指定位置ATTRIB_TEXTURE,该属性在顶点着色源码其中有声明
     m_ShaderProgram.bindAttributeLocation("textureIn", VER_ATTR_TEX);

    //链接程序
     //链接所有所有添入到的着色器程序
     m_ShaderProgram.link();
     //激活所有链接
    m_ShaderProgram.bind();
    //获取Uniform变量

     //读取着色器中的数据变量tex_y, tex_u, tex_v的位置,这些变量的声明可以在
     //片段着色器源码中可以看到
     texUniformY =m_ShaderProgram.uniformLocation("tex_y");
     texUniformU =m_ShaderProgram.uniformLocation("tex_u");
     texUniformV =m_ShaderProgram.uniformLocation("tex_v");

     qDebug("loadYUVShader ok");

}


//VAO(Vertex Array Object)顶点数组对象
void  HGLWidget::initVAO()
{
    setVertices(1.0);

    GLfloat tmp[] = {
        0.0f, 1.0f,
        1.0f, 1.0f,
        0.0f, 0.0f,
        1.0f, 0.0f,
    };

    // reverse
    /*
    GLfloat tmp[] = {
        0.0f, 0.0f,
        1.0f, 0.0f,
        0.0f, 1.0f,
        1.0f, 1.0f,
    };
    */
    memcpy(textures, tmp, sizeof(GLfloat)*8);

    glVertexAttribPointer(VER_ATTR_VER, 2, GL_FLOAT, GL_FALSE, 0, vertices);
    glEnableVertexAttribArray(VER_ATTR_VER);

    glVertexAttribPointer(VER_ATTR_TEX, 2, GL_FLOAT, GL_FALSE, 0, textures);
    glEnableVertexAttribArray(VER_ATTR_TEX);
}
void  HGLWidget::initYUV()
{
    glGenTextures(3, tex_yuv);
    for (int i = 0; i < 3; ++i) {
        glBindTexture(GL_TEXTURE_2D, tex_yuv[i]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
    }
}


//画yuv数据
void  HGLWidget::drawYUV(HFrame* pFrame)
{
    assert(pFrame->type == GL_I420 || pFrame->type == GL_YV12);

    int w = pFrame->w;
    int h = pFrame->h;
    int y_size = w*h;
    GLubyte* y = (GLubyte*)pFrame->buf.base;
    GLubyte* u = y + y_size;
    GLubyte* v = u + (y_size>>2);
    if (pFrame->type == GL_YV12) {
        GLubyte* tmp = u;
        u = v;
        v = tmp;
    }

    //使用Program
    glUseProgram(prog_yuv);
    m_ShaderProgram.bind();
    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, tex_yuv[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
    glUniform1i(texUniformY, 0);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, tex_yuv[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
    glUniform1i(texUniformU, 1);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, tex_yuv[2]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
    glUniform1i(texUniformV, 2);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

    //使用Program
    glUseProgram(0);
}

 

  • 3
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

gws09876

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值