代码之家  ›  专栏  ›  技术社区  ›  PPP

qt qquickframebufferobject opengl渲染侵入其他对象的场景,为红色

  •  0
  • PPP  · 技术社区  · 7 年前

    我知道通常需要一个最小的完整和可验证的例子,但是这个例子不能分成一个较小的例子,因为有太多的库需要从我的安全摄像头获取和解码视频。我希望有人能帮我指出使用qquickframebufferobject进行渲染时可能出现的简单错误。

    enter image description here

    我遇到的两个问题是图像是红色的,一个物体的图像以一种非常难以解释的方式侵入另一个物体的空间。 在上面的图片中,您可以看到应该是通过qml实例化的4个不同的摄像头源。

    这是呈现所有内容的类。YUv420P数据使用 update() 功能。您可以看到将yuv420p解码为rgb的简单明暗器。每个QML对象(摄像机流)都是这个类中的一个实例。

    OpenGlBufferQtQuick.cpp :

    #include "OpenGlBufferQtQuick.h"
    #include <QOpenGLFramebufferObjectFormat>
    #include <QRunnable>
    #include <QEventLoop>
    #include <QNetworkReply>
    #include <QNetworkRequest>
    #include <QMutexLocker>
    #include <memory>
    #include <iostream>
    #include <QTimer>
    
    #define GET_STR(x) #x
    #define A_VER 3
    #define T_VER 4
    
    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
    };
    
    //Simple shader. Outpus the same location as input, I guess
    const char *vString3 = GET_STR(
        attribute vec4 vertexIn;
        attribute vec2 textureIn;
        varying vec2 textureOut;
        uniform mat4 u_transform;   
        void main(void)
        {
            gl_Position = u_transform * vertexIn;
            textureOut = textureIn;
        }
    );
    
    
    //The matrix below does YUV420P to RGB conversion https://en.wikipedia.org/wiki/YUV#Y%E2%80%B2UV420p_(and_Y%E2%80%B2V12_or_YV12)_to_RGB888_conversion
    //This texture shader replaces the color of the pixel with the new color, but in RGB. (I guess)
    const char *tString3 = GET_STR(
        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);
        }
    
    );
    
    
    OpenGlBufferItemRenderer::OpenGlBufferItemRenderer(string uri){
        this->uri = uri;
    }
    
    
    void OpenGlBufferItemRenderer::render() {
        QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
        if (firstFrameReceived) {
            if (this->firstRender) {
                std::cout << "Creating QOpenGLShaderProgram " << std::endl;
                program = new QOpenGLShaderProgram();
                f->initializeOpenGLFunctions();
                //this->m_F  = QOpenGLContext::currentContext()->functions();
                std::cout << "frameWidth: " << frameWidth << + " frameHeight: " << frameHeight << std::endl;
    
                std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString3) << std::endl;
                std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString3) << std::endl;
    
                program->bindAttributeLocation("vertexIn",A_VER);
                program->bindAttributeLocation("textureIn",T_VER);
                std::cout << "program->link() = " << program->link() << std::endl;
    
                f->glGenTextures(3, texs);//TODO: ERASE THIS WITH glDeleteTextures
                this->firstRender = false;
            }
    
            // Not strictly needed for this example, but generally useful for when
            // mixing with raw OpenGL.
            //m_window->resetOpenGLState();//COMMENT OR NOT?
    
            program->bind();
    
            QMatrix4x4 transform;
            transform.setToIdentity();
            program->setUniformValue("u_transform", transform);
    
            f->glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);
            f->glEnableVertexAttribArray(A_VER);
    
            f->glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);
            f->glEnableVertexAttribArray(T_VER);
    
            unis[0] = program->uniformLocation("tex_y");
            unis[1] = program->uniformLocation("tex_u");
            unis[2] = program->uniformLocation("tex_v");
    
            //Y
            f->glBindTexture(GL_TEXTURE_2D, texs[0]);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth, frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    
            //U
            f->glBindTexture(GL_TEXTURE_2D, texs[1]);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth/2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    
            //V
            f->glBindTexture(GL_TEXTURE_2D, texs[2]);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
            f->glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            f->glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, frameWidth / 2, frameHeight / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);
    
            f->glActiveTexture(GL_TEXTURE0);
            f->glBindTexture(GL_TEXTURE_2D, texs[0]);
            f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth, frameHeight, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
            f->glUniform1i(unis[0], 0);
    
    
            f->glActiveTexture(GL_TEXTURE0+1);
            f->glBindTexture(GL_TEXTURE_2D, texs[1]); 
            f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth/2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
            f->glUniform1i(unis[1],1);
    
    
            f->glActiveTexture(GL_TEXTURE0+2);
            f->glBindTexture(GL_TEXTURE_2D, texs[2]);
            f->glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth / 2, frameHeight / 2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
            f->glUniform1i(unis[2], 2);
    
            f->glDrawArrays(GL_TRIANGLE_STRIP,0,4);
    
            program->disableAttributeArray(A_VER);
            program->disableAttributeArray(T_VER);
            program->release();
    
        } 
        update();
    }
    
    QOpenGLFramebufferObject *OpenGlBufferItemRenderer::createFramebufferObject(const QSize &size)
    {
        QOpenGLFramebufferObjectFormat format;
        format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
        //format.setSamples(16);
        return new QOpenGLFramebufferObject(size, format);
    }
    //https://blog.qt.io/blog/2015/05/11/integrating-custom-opengl-rendering-with-qt-quick-via-qquickframebufferobject/
    void OpenGlBufferItemRenderer::synchronize(QQuickFramebufferObject *item)
    {
        OpenGlBufferItem *openGlBufferItem = static_cast<OpenGlBufferItem*>(item);
    
        std::cout << "synchronize called " << std::endl;
        std::cout << "starting new renderer for uri " << this-> uri << std::endl;
    
        MediaStream* camera1 = new MediaStream(this->uri);
        camera1->setFrameUpdater((FrameUpdater *) this);
        //TODO: put mutex on std::cout of this thread
        //TODO: make this thread actualy run here instead of on a thread, I guess.
        boost::thread mediaThread(&MediaStream::run, camera1);
    }
    
    OpenGlBufferItem::OpenGlBufferItem(){}
    
    void OpenGlBufferItemRenderer::updateData(unsigned char**data, int frameWidth, int frameHeight)
    {
        this->frameWidth = frameWidth;
        this->frameHeight = frameHeight;
        //Before first render, datas pointer isn't even created yet
        if (!firstFrameReceived) {
            datas[0] = new unsigned char[frameWidth*frameHeight];   //Y
            datas[1] = new unsigned char[frameWidth*frameHeight/4]; //U
            datas[2] = new unsigned char[frameWidth*frameHeight/4]; //V
            firstFrameReceived = true;
        } else {
            memcpy(datas[0], data[0], frameWidth*frameHeight);
            memcpy(datas[1], data[1], frameWidth*frameHeight/4);
            memcpy(datas[2], data[2], frameWidth*frameHeight/4);
        }
    }
    
    QQuickFramebufferObject::Renderer *OpenGlBufferItem::createRenderer() const
    {
        //std::cout << "createRenderer called ------------------------" << std::endl;
        return new OpenGlBufferItemRenderer(this->uri);
    }
    

    这里是 main.qml :

    import QtQuick 2.0
    import OpenGlBufferQtQuick 1.0
    
    Grid {
        columns: 2
        spacing: 2    
        width: 1280
        height: 720
        OpenGlBufferQtQuick {
            width: 640
            height: 360
            uri: "rtsp://admin:123456@192.168.0.103:10554/tcp/av0_0"
        }
        OpenGlBufferQtQuick {
            width: 640
            height: 360
            uri: "rtsp://admin:123456@192.168.0.101:10554/tcp/av0_0"
        }
        OpenGlBufferQtQuick {
            width: 640
            height: 360
            uri: "rtsp://admin:123456@192.168.0.104:10554/tcp/av0_0"
        }
        OpenGlBufferQtQuick {
            width: 640
            height: 360
            uri: "rtsp://admin:123456@192.168.1.43:10554/tcp/av0_0"
        }
    
    }
    

    如您所见,我正在调用4个不同的摄影机流,但来自第一个摄影机的流会侵入其他流的空间,即使每个流都是完全不同的对象。

    另外,图像是红色的。我用几乎相同的代码用类来呈现 OpenGlVideoQtQuickRenderer : public QObject, protected QOpenGLFunctions 它的工作没有任何红屏或OpenGL侵入其他空间。

    0 回复  |  直到 7 年前
        1
  •  0
  •   PPP    7 年前

    我付钱请人帮我,问题是纹理着色没有激活。这些是变化:

    https://github.com/lucaszanella/orwell/commit/b2882768badb16e4334bc2bd0371611221283e97#diff-b089e4d46edc159fb6e7de932e64219b

    基本上:

    GLint originTextureUnit;
            f->glGetIntegerv(GL_ACTIVE_TEXTURE, &originTextureUnit);
    

    和

     f->glActiveTexture(originTextureUnit);
    

    但是我还是不明白为什么纹理没有被激活。