基于 qt 的 Opengl 渲染 YUV

运行环境:Ubuntu 14.04、Qt 5.6.1

勘误!

由于本人对 opengl 不甚了解,所以,opengl 各版本的差异也不太懂,上次上这个老哥的博客http://blog.csdn.net/su_vast/article/details/52214642,用他的代码一直渲染不了,我感觉我的运气跟狗屎一样臭,试了不知道 多少遍,一直不行,真的跟吃了屎一样难受!直到今天在交叉编译的时候才意识到opengl 从 ver2.1 之后就不再维护 glBegin(), glEnd(),所以ver2.1之后就不能用来绘制图形了!所以又跑回来试了上面那位老哥的程序,哎呀,居然行了!!心中好多只草泥马奔腾而过!!
刚接触 opengl,而且对 qt 不熟悉,又有任务在身,只想以最快的速度完成,但是找了那么多天CSDN博客找到我心力憔悴,找的我连未来都失去了希望,都没找到能让我在机子上跑起来的,真的好能痛苦啊。所以在此,写下这篇博客,希望以后,有这个需求的童鞋能够第一时间跑起来看看运行效果,再去学习就有信心了!在此感谢 github,真的很感谢。废话不多说,上代码!

1、opengl ver2.1 以前版本渲染 NV12 (YUV420sp)

/* gl_widget.h */

#ifndef GL_WIDGET_H
#define GL_WIDGET_H

#include 
#include 
#include 
#include 
#include 

class Gl_widget: public QGLWidget
{
    Q_OBJECT
public:
    Gl_widget(int width, int height, const QString& path, QWidget *parent = 0);
    ~Gl_widget();

protected:
    void paintGL();
    void initializeGL();
    void resizeGL(int width, int height);

protected slots:
    void on_timeout();

private:
    int video_width;
    int video_height;

    GLuint y_texture;
    GLuint uv_texture;

    unsigned char* y_data;
    unsigned char* uv_data;

    QFile file;
    QTimer timer;
    QGLShaderProgram program;
};

#endif
/* gl_widget.cpp */

#include 

#include 
#include 

Gl_widget::Gl_widget(int width, int height, const QString& path, QWidget* parent)
    :QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
    , video_width(width)
    , video_height(height)
    , y_texture(0)
    , uv_texture(0)
    , y_data(0)
    , uv_data(0)
    , file(path)
    , timer(this)
    , program(this)
{
    setFocusPolicy(Qt::StrongFocus);

    y_data = new unsigned char[(width*height*3)>>1];
    uv_data = y_data+(width*height);
    file.open(QIODevice::ReadOnly);
}

Gl_widget::~Gl_widget()
{
    file.close();

    glDeleteTextures(1, &y_texture);
    glDeleteTextures(1, &uv_texture);

    uv_data = 0;
    delete [] y_data;
    y_data = 0;
}
void Gl_widget::initializeGL()
{
    qDebug() << program.addShaderFromSourceCode(QGLShader::Fragment,
     "uniform sampler2D y_texture;\n"
     "uniform sampler2D uv_texture;\n"
     "void main(void)\n"
     "{\n"
     "   float y, u, v, red, green, blue;\n"
     "   y = texture2D(y_texture, gl_TexCoord[0].st).r ;\n"
     "   y =  1.1643 * (y - 0.0625);\n"
     "   u = texture2D(uv_texture, gl_TexCoord[0].st).r - 0.5;\n"
     "   v = texture2D(uv_texture, gl_TexCoord[0].st).a - 0.5;\n"
     "   red = y+1.5958*v;\n"
     "   green = y-0.39173*u-0.81290*v;\n"
     "   blue = y+2.017*u;\n"
     "   gl_FragColor = vec4(red, green, blue, 1.0);\n"
     "}");

    qDebug() << program.link();
    qDebug() << program.bind();

    glGenTextures(1, &y_texture);
    glGenTextures(1, &uv_texture);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, y_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, video_width, video_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_data);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, uv_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA, video_width>>1, video_height>>1, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, uv_data);

    program.setUniformValue("y_texture", 0);
    program.setUniformValue("uv_texture", 1);

    connect(&timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
    timer.setInterval(25);
    timer.start();
}

void Gl_widget::paintGL()
{
    file.read((char*)y_data, (video_width*video_height*3)>>1);

    glActiveTexture(GL_TEXTURE0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width, video_height, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_data);
    glActiveTexture(GL_TEXTURE1);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width>>1, video_height>>1, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, uv_data);


    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.0f);              // Top Left
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f);              // Top Right
        glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 0.0f);              // Bottom Right
        glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f,-1.0f, 0.0f);              // Bottom Left
    glEnd();
    glFlush();
    glDisable(GL_TEXTURE_2D);
}

void Gl_widget::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);
}

void Gl_widget::on_timeout()
{
    updateGL();
}

/* yuv_window.h */

#ifndef _YUV_WINDOW_H
#define _YUV_WINDOW_H

#include 

#include "gl_widget.h"

class Yuv_window: public QWidget
{
    Q_OBJECT

public:
    Yuv_window(int width, int height, const QString& path, QWidget* parent = 0);
    ~Yuv_window();

protected:
    void resizeEvent(QResizeEvent* event);

private:
    Gl_widget gl_widget;
};

#endif
/* yuv_window.cpp */

#include "yuv_window.h"

Yuv_window::Yuv_window(int width, int height, const QString& path, QWidget* parent)
    :QWidget(parent)
    , gl_widget(width, height, path, this)
{
}

Yuv_window::~Yuv_window()
{
}

void Yuv_window::resizeEvent(QResizeEvent* event)
{
    gl_widget.setGeometry(0, 0, width(), height());
}

/* main.cpp */

#include 

#include "yuv_window.h"

int main(int argc, char** argv)
{
    QApplication app(argc, argv);
    Yuv_window window(1920, 1080, "videotestsrc_1920x1080.nv12");//最好是绝对路径
    window.resize(960, 540);
    window.show();
    return app.exec();
}

opengl ver2.1 以前的版本渲染 YV12 (YUV420p)

注意:除了gl_widget.cpp 和 gl_widget.h 跟 NV12 不太一样之外,其他都相同。

/* gl_widget.h */

#ifndef GL_WIDGET_H
#define GL_WIDGET_H

#include 
#include 
#include 
#include 
#include 

class Gl_widget: public QGLWidget
{
    Q_OBJECT
public:
    Gl_widget(int width, int height, const QString& path, QWidget *parent = 0);
    ~Gl_widget();

protected:
    void paintGL();
    void initializeGL();
    void resizeGL(int width, int height);

protected slots:
    void on_timeout();

private:
    int video_width;
    int video_height;

    GLuint y_texture;
    GLuint u_texture;
    GLuint v_texture;

    unsigned char* y_data;
    unsigned char* u_data;
    unsigned char* v_data;

    QFile file;
    QTimer timer;
    //QGLShader shader;
    QGLShaderProgram program;
};

#endif
/* gl_widget.cpp */
#include 

#include 
#include 

Gl_widget::Gl_widget(int width, int height, const QString& path, QWidget* parent)
    :QGLWidget(QGLFormat(QGL::SampleBuffers), parent)
    , video_width(width)
    , video_height(height)
    , y_texture(0)
    , u_texture(0)
    , v_texture(0)
    , y_data(0)
    , u_data(0)
    , v_data(0)
    , file(path)
    , timer(this)
    , program(this)
{
    setFocusPolicy(Qt::StrongFocus);

    y_data = new unsigned char[(width*height*3)>>1];
    u_data = y_data+(width*height);
    v_data = u_data+((width*height)>>2);
    file.open(QIODevice::ReadOnly);
}

Gl_widget::~Gl_widget()
{
    file.close();

    glDeleteTextures(1, &y_texture);
    glDeleteTextures(1, &u_texture);
    glDeleteTextures(1, &v_texture);

    u_data = 0;
    v_data = 0;
    delete [] y_data;
    y_data = 0;
}

void Gl_widget::initializeGL()
{
    qDebug() << program.addShaderFromSourceCode(QGLShader::Fragment,
     "uniform sampler2D y_texture;\n"
     "uniform sampler2D u_texture;\n"
     "uniform sampler2D v_texture;\n"
     "void main(void)\n"
     "{\n"
     "   float y, u, v, red, green, blue;\n"
     "   y = texture2D(y_texture, gl_TexCoord[0].st).r;\n"
     "   y =  1.1643 * (y - 0.0625);\n"
     "   u = texture2D(u_texture, gl_TexCoord[0].st).r - 0.5;\n"
     "   v = texture2D(v_texture, gl_TexCoord[0].st).r - 0.5;\n"
     "   red = y+1.5958*v;\n"
     "   green = y-0.39173*u-0.81290*v;\n"
     "   blue = y+2.017*u;\n"
     "   gl_FragColor = vec4(red, green, blue, 1.0);\n"
     "}");

    qDebug() << program.link();
    qDebug() << program.bind();

    glGenTextures(1, &y_texture);
    glGenTextures(1, &u_texture);
    glGenTextures(1, &v_texture);

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, y_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, video_width, video_height, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_data);

    glActiveTexture(GL_TEXTURE1);
    glBindTexture(GL_TEXTURE_2D, u_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, video_width>>1, video_height>>1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, u_data);

    glActiveTexture(GL_TEXTURE2);
    glBindTexture(GL_TEXTURE_2D, v_texture);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
    glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
    glTexEnvf(GL_TEXTURE_ENV,GL_TEXTURE_ENV_MODE,GL_DECAL);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, video_width>>1, video_height>>1, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, v_data);

    program.setUniformValue("y_texture", 0);
    program.setUniformValue("u_texture", 1);
    program.setUniformValue("v_texture", 2);

    connect(&timer, SIGNAL(timeout()), this, SLOT(on_timeout()));
    timer.setInterval(25);
    timer.start();
}

void Gl_widget::paintGL()
{
    file.read((char*)y_data, (video_width*video_height*3)>>1);

    glActiveTexture(GL_TEXTURE0);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width, video_height, GL_LUMINANCE, GL_UNSIGNED_BYTE, y_data);
    glActiveTexture(GL_TEXTURE1);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width>>1, video_height>>1, GL_LUMINANCE, GL_UNSIGNED_BYTE, u_data);
    glActiveTexture(GL_TEXTURE2);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, video_width>>1, video_height>>1, GL_LUMINANCE, GL_UNSIGNED_BYTE, v_data);

    glClear(GL_COLOR_BUFFER_BIT);

    glEnable(GL_TEXTURE_2D);
    glBegin(GL_QUADS);
        glTexCoord2f(0.0f, 0.0f); glVertex3f(-1.0f, 1.0f, 0.0f);              // Top Left
        glTexCoord2f(1.0f, 0.0f); glVertex3f( 1.0f, 1.0f, 0.0f);              // Top Right
        glTexCoord2f(1.0f,1.0f); glVertex3f( 1.0f,-1.0f, 0.0f);              // Bottom Right
        glTexCoord2f(0.0f,1.0f); glVertex3f(-1.0f,-1.0f, 0.0f);              // Bottom Left
    glEnd();
    glFlush();
    glDisable(GL_TEXTURE_2D);
}

void Gl_widget::resizeGL(int width, int height)
{
    glViewport(0, 0, width, height);

    /*glMatrixMode(GL_PROJECTION);
    glLoadIdentity();
    glOrtho(-1.0, 1.0, -1.0, 1.0, -1.0, 1.0);
    glMatrixMode(GL_MODELVIEW);*/
}

void Gl_widget::on_timeout()
{
    updateGL();
}

学习了解更多

这是我自己参考的一些资料:
http://colabug.com/174582.html
http://m.blog.csdn.net/jxw167/article/details/75501637


源代码下载

qt opengl (Before ver2.1)渲染 显示 nv12 下载地址:

http://download.csdn.net/download/sinat_36684217/9994260

qt opengl (Before ver2.1)渲染 显示 yv12 下载地址:(小勘误,记得在构造函数中将v_date = u_date + 1; 改成 v_data = u_data+((width*height)>>2);上面贴的代码是对的)

http://download.csdn.net/download/sinat_36684217/9994316

qt opengl (After ver2.1)渲染 显示 nv12 下载地址:

http://download.csdn.net/download/sinat_36684217/9998124

qt opengl (After ver2.1)渲染 显示 yv12 下载地址:

你可能感兴趣的:(nv12,opengl,qt,nv12,yv12,渲染)