利用Qt + OpenGL 渲染 YUV数据,播放视频 mac版

来源:互联网 发布:淘宝的等级怎么提升 编辑:程序博客网 时间:2024/05/16 13:38

最近利用Qt渲染YUV数据,折腾了很久,最开始使用FFmpeg将YUV数据转换成RGB数据后在用qt绘制,很快得到了成功,但是cpu占用率太大,最后放弃了。

在这先感谢来自文章http://blog.csdn.net/su_vast/article/details/52214642的作者,使用他的代码我实现了Windows上的YUV数据渲染。但是移植到mac上渲染不出来,经过折腾及对OpenGL的了解,发现问题出在OpenGL版本问题上,不同版本OpenGL的shader编写使用有些不同,资料来源于http://blog.csdn.net/ym19860303/article/details/44115135。


下面是我写的代码,有什么不完善的地方请读者反馈,相互学习。

renderview.h

#ifndef RENDERVIEW_H#define RENDERVIEW_H#include <QWidget>#include <QOpenGLWidget>#include <QGLContext>#include <QGLWidget>#include <QOpenGLTexture>#include "global.h"class RenderView : public QOpenGLWidget{    Q_OBJECTpublic:    RenderView(QWidget* parent = 0);    ~RenderView();    void Render(unsigned char* buffer,int w, int h);protected:    //virtual void paintEvent(QPaintEvent *event);    virtual void initializeGL();    virtual void resizeGL( int w, int h );    virtual void paintGL();        private:    GLuint prepareShaderProgram();    private:    GLuint m_shader;    GLuint m_vertexBuffer;    GLuint textureUniformY;    GLuint textureUniformU;    GLuint textureUniformV;    GLuint vertexBuffer;    GLuint vertextAttribute;    GLuint textureAttribute;        GLuint id_y;    GLuint id_u;    GLuint id_v;        int m_nVideoW;    int m_nVideoH;    int m_nViewW;    int m_nViewH;    unsigned char* m_pBufYuv420p;    unsigned char* m_pBuffer;    bool m_bStartPlay;};#endif // RENDERVIEW_H


renderview.cpp


#include "renderview.h"#include <QPainter>#include <QSurfaceFormat>#include <QMutex>#include <QDebug>#include <QSurfaceFormat>#include "DecoderCtrl/MainConcept.h"#define BUFFER_MAX_SIZE 1920*1080+1024const char *vsrc ="#version 410\n""in vec4 vertexIn;\n""in vec2 textureIn;\n""out vec2 textureOut;\n""void main(void)\n""{\n""    gl_Position = vertexIn;\n""    textureOut = textureIn;\n""}";const char *fsrc ="#version 410\n""in vec2 textureOut;\n""out vec4 fragColor;\n""uniform sampler2D tex_y;\n""uniform sampler2D tex_u;\n""uniform sampler2D tex_v;\n""void main(void)\n""{\n""    vec3 yuv;\n""    vec3 rgb;\n""    yuv.x = texture(tex_y, textureOut).r;\n""    yuv.y = texture(tex_u, textureOut).r - 0.5;\n""    yuv.z = texture(tex_v, textureOut).r - 0.5;\n""    rgb = mat3( 1,       1,         1,\n""               0,       -0.21482,  2.12798,\n""               1.28033, -0.38059,  0) * yuv;\n""    fragColor = vec4(rgb, 1);\n""}";void RenderYuv(unsigned char* yuvBuffer,int width, int height,void *pdate){    RenderView *render = (RenderView*)pdate;    if(render)    {        render->Render(yuvBuffer, width, height);    }}RenderView::RenderView(QWidget* parent) :    QOpenGLWidget(parent)    ,m_pBufYuv420p(NULL)    ,m_nVideoW(0)    ,m_nVideoH(0)    ,m_nViewW(0)    ,m_nViewH(0)    ,m_bStartPlay(false){    setAutoFillBackground(false);    MC_Codec_SetRenderNotify(RenderYuv, this);    m_pBufYuv420p = new unsigned char[BUFFER_MAX_SIZE];    memset(m_pBufYuv420p, 0, BUFFER_MAX_SIZE);}RenderView::~RenderView(){    }void RenderView::Render(unsigned char* buffer,int w, int h){    m_nVideoW = w;    m_nVideoH = h;    m_bStartPlay = true;    unsigned long bufLen = w*h*3/2;    m_pBufYuv420p = buffer;    memcpy(m_pBufYuv420p, buffer, bufLen);    update();}GLuint RenderView::prepareShaderProgram(){        GLuint program = glCreateProgram();        //vertex shader    GLuint vertexShader = glCreateShader( GL_VERTEX_SHADER);    glShaderSource( vertexShader, 1, (const GLchar**)&vsrc, NULL );    glCompileShader( vertexShader );    GLint  compiled;    glGetShaderiv( vertexShader, GL_COMPILE_STATUS, &compiled );    if ( !compiled ) {        GLint  logSize;        glGetShaderiv( vertexShader, GL_INFO_LOG_LENGTH, &logSize );        char* logMsg = new char[logSize];        glGetShaderInfoLog( vertexShader, logSize, NULL, logMsg );        qWarning() << logMsg;        delete [] logMsg;        exit( EXIT_FAILURE );    }    glAttachShader( program, vertexShader );        //fragment shader    GLuint fragmentShader = glCreateShader( GL_FRAGMENT_SHADER);    glShaderSource( fragmentShader, 1, (const GLchar**)&fsrc, NULL );    glCompileShader( fragmentShader );    glGetShaderiv( fragmentShader, GL_COMPILE_STATUS, &compiled );    if ( !compiled ) {        GLint  logSize;        glGetShaderiv( vertexShader, GL_INFO_LOG_LENGTH, &logSize );        char* logMsg = new char[logSize];        glGetShaderInfoLog( fragmentShader, logSize, NULL, logMsg );        qWarning() << logMsg;        delete [] logMsg;        exit( EXIT_FAILURE );    }    glAttachShader( program, fragmentShader );        /* Link output */    glBindFragDataLocation(program, 0, "fragColor");        /* link  and error check */    glLinkProgram(program);        GLint  linked;    glGetProgramiv( program, GL_LINK_STATUS, &linked );    if ( !linked ) {        qWarning() << "Shader program failed to link";        GLint  logSize;        glGetProgramiv( program, GL_INFO_LOG_LENGTH, &logSize);        char* logMsg = new char[logSize];        glGetProgramInfoLog( program, logSize, NULL, logMsg );        qWarning() << logMsg ;        delete [] logMsg;                exit( EXIT_FAILURE );    }        /* use program object */    glUseProgram(program);        return program;}void RenderView::initializeGL(){    //glSetup();        // Prepare a complete shader program...    m_shader = prepareShaderProgram();        textureUniformY = glGetUniformLocation(m_shader, "tex_y");    textureUniformU = glGetUniformLocation(m_shader, "tex_u");    textureUniformV = glGetUniformLocation(m_shader, "tex_v");            // Create a interleaved triangle (vec3 position, vec3 color)    float vertexPoints[] ={        -1.0f, -1.0f,0.0f, 1.0f,        1.0f, -1.0f,1.0f, 1.0f,        -1.0f, 1.0f,0.0f, 0.0f,        1.0f, 1.0f,1.0f, 0.0f,    };        glGenVertexArrays(1, &m_vertexBuffer);    glBindVertexArray(m_vertexBuffer);    glGenBuffers(1, &vertexBuffer);    glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);    glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), vertexPoints, GL_STATIC_DRAW);    vertextAttribute = glGetAttribLocation(m_shader, "vertexIn");    textureAttribute = glGetAttribLocation(m_shader, "textureIn");    glEnableVertexAttribArray(vertextAttribute);    glVertexAttribPointer(vertextAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (const GLvoid *)0);    glEnableVertexAttribArray(textureAttribute);    glVertexAttribPointer(textureAttribute, 2, GL_FLOAT, GL_FALSE, sizeof(float)*4, (const GLvoid *)(sizeof(float)*2));            //Init Texture    glGenTextures(1, &id_y);    glBindTexture(GL_TEXTURE_2D, id_y);    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);        glGenTextures(1, &id_u);    glBindTexture(GL_TEXTURE_2D, id_u);    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);        glGenTextures(1, &id_v);    glBindTexture(GL_TEXTURE_2D, id_v);    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);    //glCheckError();}void RenderView::resizeGL( int w, int h ){    // Set the viewport to window dimensions    m_nViewW = w;    m_nViewH = h;    glViewport( 0, 0, w, qMax( h, 1 ) );    //glCheckError();}void RenderView::paintGL(){    // Clear the buffer with the current clearing color    glClearColor(0.0, 0.0, 0.0, 1.0);    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );        if(m_bStartPlay)    {        float x,y;        float wRatio = (float)m_nViewW/m_nVideoW;        float hRatio = (float)m_nViewH/m_nVideoH;        float minRatio = qMin(wRatio, hRatio);        y = m_nVideoH * minRatio/m_nViewH;        x = m_nVideoW * minRatio/m_nViewW;                float vertexPoints[] ={            -x, -y,0.0f, 1.0f,            x, -y,1.0f, 1.0f,            -x, y,0.0f, 0.0f,            x, y,1.0f, 0.0f,        };        glBufferData(GL_ARRAY_BUFFER, 4 * 4 * sizeof(float), vertexPoints, GL_STATIC_DRAW);                glActiveTexture(GL_TEXTURE0);        glBindTexture(GL_TEXTURE_2D, id_y);        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW, m_nVideoH, 0, GL_RED, GL_UNSIGNED_BYTE, m_pBufYuv420p);        glUniform1i(textureUniformY, 0);                glActiveTexture(GL_TEXTURE1);        glBindTexture(GL_TEXTURE_2D, id_u);        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW / 2, m_nVideoH / 2, 0, GL_RED, GL_UNSIGNED_BYTE, (char*)m_pBufYuv420p + m_nVideoW*m_nVideoH);        glUniform1i(textureUniformU, 1);                glActiveTexture(GL_TEXTURE2);        glBindTexture(GL_TEXTURE_2D, id_v);        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW / 2, m_nVideoH / 2, 0, GL_RED, GL_UNSIGNED_BYTE, (char*)m_pBufYuv420p + m_nVideoW*m_nVideoH * 5 / 4);        glUniform1i(textureUniformV, 2);        // Draw stuff        glDrawArrays( GL_TRIANGLE_STRIP, 0, 4 );    }    //∫glCheckError();}

在界面显示前记得添加下面代码


    QSurfaceFormat format;    format.setVersion(4,1);    format.setProfile(QSurfaceFormat::CoreProfile);    QSurfaceFormat::setDefaultFormat(format);



0 0
原创粉丝点击