在Qt5上的OpenGL中进行视频渲染

时间:2016-01-28 17:36:16

标签: opengl video ffmpeg qt5 yuv

我试图将解码后的帧从FFMPEG渲染到QOpenGLWindow。 FFMPEG给我NV12 AVFrame或YUV420p或RGB。 我选择最简单的RGB。

我创建了一个继承自QOpenGLWindow和QOpenGLFunctions_3_3的c_gl_video_yuv类。

我想使用着色器绘制矩形并使用视频帧对其进行纹理处理。 (对于YUV,我希望sader将其转换为RGB并应用纹理)

我的c_gl_video_yuv类定义如下:

class c_gl_video_yuv : public QOpenGLWindow,protected QOpenGLFunctions_3_3_Core
{
public:
   c_gl_video_yuv();
   ~c_gl_video_yuv();
---
   void update_texture(AVFrame *frame, int w, int h);

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

   void paintEvent(QPaintEvent *);

private:

   ---
   GLuint textures[2];
   --- 
   // Shader program
   QOpenGLShaderProgram *m_program;

   GLint locVertices;
   GLint locTexcoord;

};

我初始化OpenGL:

   void c_gl_video_yuv::initializeGL()
    {
      // Init shader program
        initializeOpenGLFunctions();
        glGenTextures(2, textures);
        /* Apply some filter on the texture */
        glBindTexture(GL_TEXTURE_2D, textures[0]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);

        glBindTexture(GL_TEXTURE_2D, textures[1]);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
        glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_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);

        qDebug() << "c_gl_video_yuv::initializeGL() initialise shader"<< endl;
        m_program = new QOpenGLShaderProgram(this);
        m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shader/Ressources/vertex_yuv.glsl");
        m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shader/Ressources/rgb_to_rgb_shader .glsl");
        m_program->link();

    //    /* Grab location of shader attributes. */
        locVertices = m_program->attributeLocation("position");
        locTexcoord = m_program->attributeLocation("texpos");

        /* Enable vertex arrays to push the data. */
        glEnableVertexAttribArray(locVertices);
        glEnableVertexAttribArray(locTexcoord);

        /* set data in the arrays. */
            glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0,
                          &vertices[0][0]);
            glVertexAttribPointer(locTexcoord, 2, GL_FLOAT, GL_FALSE, 0,
                          &texcoords[0][0]);

        // GL options
        glEnable(GL_DEPTH_TEST);    
    }

我渲染

void c_gl_video_yuv::paintGL()
    {

        qDebug() <<  "paintGL()   set viewport "<<endl;
        glViewport(0, 0, width(), height());
        /* Clear background. */
        glClearColor(0.5f,0.5f,0.5f,1.0f);
        glClear(GL_COLOR_BUFFER_BIT);

        if(first_frame)
        {
            qDebug() <<  "paintGL() Bind shader" <<  endl;
            m_program->bind();

            /* Get Ytex attribute to associate to TEXTURE0 */
                m_program->bindAttributeLocation("Ytex",0);
                m_program->bindAttributeLocation("UVtex",1);

                qDebug() <<  "paintGL() Bind texture" <<  endl;
            if(!is_init)
            {
                glActiveTexture(GL_TEXTURE0);
                glBindTexture(GL_TEXTURE_2D, textures[0]);
                glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, frame_width, frame_height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0] );

                glActiveTexture(GL_TEXTURE1);
                glBindTexture(GL_TEXTURE_2D, textures[1]);
                glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, frame_width, frame_height, 0, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0] );
                is_init = true;
            }
            else
            {
                glActiveTexture(GL_TEXTURE0);
                glBindTexture(GL_TEXTURE_2D, textures[0]);
               glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0]);

               glActiveTexture(GL_TEXTURE1);
               glBindTexture(GL_TEXTURE_2D, textures[1]);
               glTexSubImage2D(GL_TEXTURE_2D, 0, 0,0, frame_width, frame_height, GL_RGB, GL_UNSIGNED_BYTE, frame_yuv->data[0]);
            }



            glVertexAttribPointer(locVertices, 2, GL_FLOAT, GL_FALSE, 0, vertices);
            glVertexAttribPointer(locTexcoord, 2, GL_FLOAT, GL_FALSE, 0, texcoords);

            glEnableVertexAttribArray(0);
            glEnableVertexAttribArray(1);

            glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

            glDisableVertexAttribArray(1);
            glDisableVertexAttribArray(0);
            m_program->release();
        }
    }

顶点着色器是:

 #version 330 core
    attribute vec3 position;
    attribute vec2 texpos;
    varying vec2 opos;
    void main(void)
    {
        opos = texpos;
        gl_Position = vec4(position, 1.0);
    }

和Fragment着色器是:

version 330 core
in vec2 TexCoords;
out vec4 color;
uniform sampler2D YImage;
uniform sampler2D UVImage;
const vec3 r_c = vec3(1.164383,  0.000000,  1.596027);
const vec3 g_c = vec3(1.164383, -0.391762, -0.812968);
const vec3 b_c = vec3(1.164383,  2.017232,  0.000000);
const vec3 offset = vec3(-0.0625, -0.5, -0.5);
void main()
{
   float y_val = texture(YImage, TexCoords).r;
   float u_val = texture(UVImage, TexCoords).r;
   float v_val = texture(UVImage, TexCoords).g;
   vec3 yuv = vec3(y_val, u_val, v_val);
   yuv += offset;
   color.r = dot(yuv, r_c);
   color.g = dot(yuv, g_c);
   color.b = dot(yuv, b_c);
   color.a = 1.0;
};

(对于RGB帧a替换thevec3(1.164383,0.000000,1.596027);由vec3(1.0,1.00000000,1.0);

所以在我收到一个框架之前它什么也没渲染,只是一个灰色的窗口 - 没有 收到帧后,纹理会上传,着色器会正常创建播放器。但是没有任何东西看起来甚至没有黑色矩形,只是简单的灰色。

有什么问题? 它不是上传纹理的正确方法,或者我的顶点不是创建的? 当然,我宣布我的vetrtices eand texture coordonate

const GLfloat vertices[][2] = {
    {-1.f, -1.f},
    {1.f, -1.f},
    {-1.f, 1.f},
    {1.f, 1.f}
};
const GLfloat texcoords[][2] = {
    {0.0f, 1.0f},
    {1.0f, 1.0f},
    {0.0f, 0.0f},
    {1.0f, 0.0f}
};

我对OpenGL很陌生,所以它在我脑海中非常模糊,但我认为绘制一个带有流纹理的矩形并不是很难。 也许我应该使用vbo或fbo但我仍然不能理解这一点。

如果有人可以帮助我,我将不胜感激! 感谢

0 个答案:

没有答案