Этот вопрос является перезаписью Красного видео поверх обычного видео в Qt / OpenGL с использованием QQuickItem , но с кодом, разбитым до минимально проверяемого примера.Тем не менее, вы должны увидеть фотографии старого вопроса, потому что они показывают, что происходит, когда настоящее видео отображается на экране
У меня есть класс класса с именем OpenGlVideoQtQuick2
, который я тестирую двумя возможными наследованиями.: от QQuickItem
против QQuickPaintedItem
.Я получаю ожидаемое поведение (гигантский красный экран), когда OpenGlVideoQtQuick2
наследует от QQuickItem
, но не когда он наследует от QQuickPaintedItem
, то есть когда я получаю черный экран размером 640x480, который является размером OpenGlVideoQtQuick2
элемент в main.qml
.
Вот что происходит, когда class OpenGlVideoQtQuick2 : public QQuickPaintedItem
Вот что происходит, когда class OpenGlVideoQtQuick2 : public QQuickItem
Вот код:
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,, где вы можете скомпилировать и протестировать.Я рекомендую компилировать с использованием локально установленных папок cmake
и qt
, как описано в файле Readme.md
в github