c++ - GTK3 OpenGL 视频渲染大部分为绿色 (YUV420P)

标签 c++ opengl gtk gtk3

我正在尝试在 Linux 上通过 GTK3 中的 OpenGL 渲染视频。这些顶点着色器和片段着色器在 QT 上成功使用。实际上,所有 opengl 函数调用都与 Qt 上的工作示例相同。

谁知道为什么? GLEW 坐标是否可能与 QT OpenGL 中的坐标不同?

视频是YUV420P格式,所以片段着色器做矩阵乘法。有没有可能是我的片段坐标错了?

无论如何,这是视频:

enter image description here

我的顶点着色器:

#version 130

attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
void main(void)
{
    gl_Position = vertexIn;
    textureOut = textureIn;
}

我的片段着色器:

#version 130 

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.0, 1.0, 1.0,
        0.0, -0.39465, 2.03211,
        1.13983, -0.58060, 0.0) * yuv;
    gl_FragColor = vec4(rgb, 1.0);
}

我的渲染代码:

static const GLfloat ver[] = {
    -1.0f,-1.0f,
     1.0f,-1.0f,
    -1.0f, 1.0f,
     1.0f, 1.0f
};


static const GLfloat tex[] = {
    0.0f, 1.0f,
    1.0f, 1.0f,
    0.0f, 0.0f,
    1.0f, 0.0f
};

void OpenGLArea::init()
{
    std::cout << "OpenGLArea init" << std::endl;

    set_size_request(640, 360);
    Singleton::instance()->getStream("cam1").mediaStream->ffmpegDecoder->setVideoReceiver(this);
}

void OpenGLArea::receiveVideo(unsigned char **videoBuffer, int frameWidth, int frameHeight)
{
    this->frameWidth = frameWidth;
    this->frameHeight = frameHeight;
    //Before first render, datas pointer isn't even created yet
    if (!firstFrameReceived)
    {
        buffer[0] = new unsigned char[frameWidth * frameHeight];     //Y
        buffer[1] = new unsigned char[frameWidth * frameHeight / 4]; //U
        buffer[2] = new unsigned char[frameWidth * frameHeight / 4]; //V
        firstFrameReceived = true;
    }
    else
    {
        memcpy(buffer[0], videoBuffer[0], frameWidth * frameHeight);
        memcpy(buffer[1], videoBuffer[1], frameWidth * frameHeight / 4);
        memcpy(buffer[2], videoBuffer[2], frameWidth * frameHeight / 4);
    }
    //glDraw();
}

void OpenGLArea::glInit()
{
    int frameWidth = 640;
    int frameHeight = 360;
    glClearColor(0.0f, 0.0f, 0.4f, 0.0f);

    Shader vertex_shader(ShaderType::Vertex, "vertex.shader");
    Shader fragment_shader(ShaderType::Fragment, "fragment.shader");

    program = new Program();
    program->attach_shader(vertex_shader);
    program->attach_shader(fragment_shader);
    program->link();

    glGenTextures(3, texs);//TODO: delete texture

    //Y
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth, frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //U
    glBindTexture(GL_TEXTURE_2D, texs[1]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
    //V
    glBindTexture(GL_TEXTURE_2D, texs[2]);
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

}

void OpenGLArea::glDraw()
{
    program->use();

    glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
    glEnableVertexAttribArray(A_VER);

    glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
    glEnableVertexAttribArray(T_VER);

    unis[0] = glGetAttribLocation(program->get_id(), "tex_y");
    unis[1] = glGetAttribLocation(program->get_id(), "tex_u");
    unis[2] = glGetAttribLocation(program->get_id(), "tex_v");

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth, frameHeight, GL_RED, GL_UNSIGNED_BYTE, buffer[0]);
    glUniform1i(unis[0], 0);

    glActiveTexture(GL_TEXTURE0 + 1);
    glBindTexture(GL_TEXTURE_2D, texs[1]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, buffer[1]);
    glUniform1i(unis[1], 1);

    glActiveTexture(GL_TEXTURE0 + 2);
    glBindTexture(GL_TEXTURE_2D, texs[2]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, buffer[2]);
    glUniform1i(unis[2], 2);

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);


}

class GLWindow : public Gtk::Window
{
  public:
    GLWindow()
    {

        vbox = new Gtk::VBox;
        drawing_area = new OpenGLArea();

        vbox->pack_start(*drawing_area, true, true);
        add(*vbox);
    }

  private:
    Gtk::Button *button;
    Gtk::VBox *vbox;
    OpenGLArea *drawing_area;
};

此外,我只有在调整屏幕大小或重新聚焦屏幕时才会收到图像更新。更新视频时,我可能忘记调用某些函数。谁知道这是什么函数?

ps: OpenGLAreaGtk::DrawingArea 的子类

更新:

我刚刚注意到在行中

unis[0] = glGetAttribLocation(program->get_id(), "tex_y");
unis[1] = glGetAttribLocation(program->get_id(), "tex_u");
unis[2] = glGetAttribLocation(program->get_id(), "tex_v");

unis[i] 始终具有相同的值:4294967295,因此 glGetAttribLocation 不会返回任何内容

最佳答案

GLEW 是一个用于检索指向 OpenGL 函数的函数指针的库。 OGL 版本 > 1.1 需要它。

因此,不要将 Glew 视为顶点问题的罪魁祸首。如果您需要更改顶点的顺序是由于 Winding order .
顺序也可能是绘制纹理颠倒的原因。


glGetAttribLocation 用于属性。在您的 VS 中,它们是 vertexIntextureIn
对于uniforms(你的tex_XXX)你必须使用glGetUniformLocation


对于大小调整问题,this question可能有用。 简而言之,您必须为“configure-event”连接一个回调并使用glViewport

关于c++ - GTK3 OpenGL 视频渲染大部分为绿色 (YUV420P),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57173060/

相关文章:

OpenGL:VAO 和 VBO 是否适用于大型多边形渲染任务?

c++ - 立即模式纹理奇怪的输出

c++ - GTK 和 CSS : Rounded buttons

c++ - 如何正确指定哪个函数来自哪个文件?

c++ - 是否可以锁定应用程序中常用控件使用的内存?

c - 如何调用函数 glMultiDrawElements::GLenum -> GHC.Ptr.Ptr GLsizei -> GLenum -> GHC.Ptr.Ptr (GHC.Ptr.Ptr a) -> GLsizei -> IO ()

c - 如何将文件路径放入剪贴板,以便将其作为文件粘贴到文件管理器中?

click - Vala 图片点击事件。如何获得点击的协调?

C++整数常量的类型

c++ - std::bind 和/或 std::forward 的语义