这个问题是对Red video on top of normal video in Qt/OpenGL using QQuickItem的重写,但是代码被破坏为一个最小的可验证示例。但是,您应该看到旧问题的照片,因为它们显示了将真实视频呈现到屏幕中时发生的情况

我有一个名为OpenGlVideoQtQuick2的类,正在测试两种可能的继承:从QQuickItemQQuickPaintedItem的继承。当OpenGlVideoQtQuick2继承自QQuickItem时,我得到预期的行为(红色大屏幕),但是当它继承自QQuickPaintedItem时却没有,这是当我得到黑屏,大小为640x480时,这是OpenGlVideoQtQuick2main.qml项的大小。

这是class OpenGlVideoQtQuick2 : public QQuickPaintedItem发生的情况
c++ - 从QQuickItem与QQuickPaintedItem继承时,QT中的OpenGL行为异常(渲染视频)-LMLPHP

这是class OpenGlVideoQtQuick2 : public QQuickItem发生的情况
c++ - 从QQuickItem与QQuickPaintedItem继承时,QT中的OpenGL行为异常(渲染视频)-LMLPHP

这是代码:

OpenGlVideoQtQuick2.h:

#ifndef OpenGlVideoQtQuick2_H
#define OpenGlVideoQtQuick2_H

#include <QtQuick/QQuickItem>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLFunctions>
#include <QtQuick/qquickwindow.h>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLContext>
#include <QString>
#include <iostream>
#include <QTimer>
#include <QMatrix4x4>
#include <QQmlListProperty>
#include <QQuickPaintedItem>


class OpenGlVideoQtQuick2Renderer2 : public QObject, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    OpenGlVideoQtQuick2Renderer2() {
    }
    ~OpenGlVideoQtQuick2Renderer2();
    void setViewportSize(const QSize &size) { m_viewportSize = size; }
    void setWindow(QQuickWindow *window) { m_window = window; }

    QMatrix4x4 qQuickVideoMatrix;

public slots:
    void render();

private:
    QSize m_viewportSize;
    QOpenGLShaderProgram* program;
    QQuickWindow *m_window;
    GLuint unis[3] = {0};
    GLuint texs[3] = { 0 };
    unsigned char *datas[3] = { 0 };
    bool firstRender = true;
    int width = 0;
    int height = 0;
    int x = 0;
    int y = 0;
};

//class OpenGlVideoQtQuick2 : public QQuickItem
class OpenGlVideoQtQuick2 : public QQuickPaintedItem
{
    Q_OBJECT
protected:
    void paint(QPainter* painter){std::cout << "PAINT BEING USED" << std::endl;};

public:
    OpenGlVideoQtQuick2();
    QMatrix4x4 getModelMatrix();

signals:
    void tChanged();

public slots:
    void sync();
    void cleanup();
    void update();//Updates the window


private slots:
    void handleWindowChanged(QQuickWindow *win);

private:
    OpenGlVideoQtQuick2Renderer2 *openGlVideoQtQuick2Renderer2;

};

#endif // OpenGlVideoQtQuick2_H

OpenGlVideoQtQuick.cpp:
#include "OpenGlVideoQtQuick2.h"

#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4

//Simple shader. Outpus the same location as input, I guess
const char *vString4 = 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;
    }
);


const char *tString4 = GET_STR(
    varying vec2 textureOut;
    void main(void)
    {
        gl_FragColor = vec4(1.0,0,0, 1.0);
    }

);


void OpenGlVideoQtQuick2::update()
{
    if (window())
        window()->update();
}

OpenGlVideoQtQuick2::OpenGlVideoQtQuick2()
    : openGlVideoQtQuick2Renderer2(nullptr)
{
    connect(this, &QQuickItem::windowChanged, this, &OpenGlVideoQtQuick2::handleWindowChanged);
}


void OpenGlVideoQtQuick2::handleWindowChanged(QQuickWindow *win)
{
    if (win) {
        connect(win, &QQuickWindow::beforeSynchronizing, this, &OpenGlVideoQtQuick2::sync, Qt::DirectConnection);
        win->setClearBeforeRendering(false);
    }
}

void OpenGlVideoQtQuick2::cleanup()
{
   if (openGlVideoQtQuick2Renderer2) {
        delete openGlVideoQtQuick2Renderer2;
        openGlVideoQtQuick2Renderer2 = nullptr;
    }
}

OpenGlVideoQtQuick2Renderer2::~OpenGlVideoQtQuick2Renderer2()
{
    delete program;
}

void OpenGlVideoQtQuick2::sync()
{
    //std::cout << "sync called" << std::endl;
    if (!openGlVideoQtQuick2Renderer2) {
        openGlVideoQtQuick2Renderer2 = new OpenGlVideoQtQuick2Renderer2();
        connect(window(), &QQuickWindow::beforeRendering, openGlVideoQtQuick2Renderer2, &OpenGlVideoQtQuick2Renderer2::render, Qt::DirectConnection);
        connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick2::update, Qt::DirectConnection);
    }
}


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
};

//TODO: FIX THIS https://stackoverflow.com/a/54773889/6655884
void OpenGlVideoQtQuick2Renderer2::render()
{
    int frameWidth = 1280;
    int frameHeight = 720;
    if (this->firstRender) {
        std::cout << "Creating QOpenGLShaderProgram " << std::endl;
        program = new QOpenGLShaderProgram();
        initializeOpenGLFunctions();
        //this->m_F  = QOpenGLContext::currentContext()->functions();
        std::cout << "frameWidth: " << frameWidth << + " frameHeight: " << frameHeight << std::endl;
        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

        std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString4) << std::endl;
        std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString4) << std::endl;

        program->bindAttributeLocation("vertexIn",A_VER);
        program->bindAttributeLocation("textureIn",T_VER);
        std::cout << "program->link() = " << program->link() << std::endl;

        glGenTextures(3, texs);//TODO: ERASE THIS WITH glDeleteTextures
        this->firstRender = false;

    }
    program->bind();

    QMatrix4x4 transform;
    transform.setToIdentity();
    program->setUniformValue("u_transform", this->qQuickVideoMatrix);

    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] = program->uniformLocation("tex_y");
    unis[1] = program->uniformLocation("tex_u");
    unis[2] = program->uniformLocation("tex_v");

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

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

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

    glActiveTexture(GL_TEXTURE0);
    glBindTexture(GL_TEXTURE_2D, texs[0]);
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, frameWidth, frameHeight, GL_RED, GL_UNSIGNED_BYTE, datas[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, datas[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, datas[2]);
    glUniform1i(unis[2], 2);

    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

    program->disableAttributeArray(A_VER);
    program->disableAttributeArray(T_VER);
    program->release();
}

main.qml:
import QtQuick 2.0

import OpenGlVideoQtQuick2 1.0


Grid {
    columns: 2
    spacing: 2
    width: 1280
    height: 720
    OpenGlVideoQtQuick2 {
        width: 640
        height: 360
    }

}

因此,我需要使我的类派生自QQuickPaintedItem而不是QQuickItem,并且我需要黑屏不要出现在我的红屏之上,这是实际视频的加载位置。

整个项目可以在这里找到:https://github.com/lucaszanella/QQuickPaintedItemBug/tree/c9c2b23d891689a63fbaf2f014142be1f3c5ff0d,您可以在其中进行编译和测试。我建议使用本地安装的cmakeqt文件夹进行编译,如github中的Readme.md文件中所述

最佳答案

我不希望使用QQuickItemQQuickPaintedItem的结果相同。

使用QQuickPaintedItem时,应该使用paint()函数渲染项目。由于您在render()上调用了beforeRendering()函数,因此在您自己进行渲染之后,QQuickPaintedItem将在其之上渲染您应该在paint()函数中绘制的内容。

通过将QQuickPaintedItem重新实现为空函数,可以防止updatePaintNode()呈现黑色矩形。

关于c++ - 从QQuickItem与QQuickPaintedItem继承时,QT中的OpenGL行为异常(渲染视频),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56658299/

10-11 21:35