Как сделать так, чтобы мое видео OpenGL имело такой же размер и положение, как у моего QQuickItem? - PullRequest
0 голосов
/ 27 февраля 2019

После моего последнего вопроса: Мой OpenGL QQuickItem не будет иметь нужный мне размер , я сейчас пытаюсь, вместо того, чтобы иметь произвольный размер для моего видео OpenGL, чтобы он поместился внутри моего QQuickItem,

Я слышал, что QQuickItem::transform() даст мне список матриц преобразования.Я предполагаю , что этот список содержит все преобразования, необходимые для получения квадрата размера и положения моего QQuickItem.<<<< Это правда?Если да, то из каких координат и размеров области просмотра происходят преобразования? </p>

Учитывая это как истинное, я сделал следующий минимальный проверяемый и компилируемый пример, который пытается привести зеленый экран в соответствие с размером моего QQuickItem.Но в настоящее время он занимает весь экран.

Я использовал функцию getModelMatrix(), которую вы можете найти ниже, чтобы получить все преобразования и сделать из них матрицу.Затем я применяю эти преобразования к своему вершинному шейдеру, выполняя

gl_Position = u_transform * vertexIn;

Как я уже сказал, в результате получается зеленый экран.Тем не менее, он имеет те же размеры моего окна, вместо размеров 640x480 и x, y = 0, как указано в main.qml

. Здесь вы можете найти минимальный скомпилируемый и проверяемый пример: https://github.com/lucaszanella/openglqtquickexample/tree/88fe0092d663dd92c551c72acccd0bf058fe7e5b

OpenGlVideoQtQuick.cpp:

#include "OpenGlVideoQtQuick.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 *vString2 = 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 *tString2 = 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);
    }

);

OpenGlVideoQtQuick::OpenGlVideoQtQuick():
    openGlVideoQtQuickRenderer(nullptr)
{
    connect(this, &QQuickItem::windowChanged, this, &OpenGlVideoQtQuick::handleWindowChanged);

    update();
}

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

QMatrix4x4 OpenGlVideoQtQuick::getModelMatrix() {
    QMatrix4x4 result;

    // Compose model matrix from our transform properties in the QML
    QQmlListProperty<QQuickTransform> transformations = transform();
    const int count = transformations.count(&transformations);
    for (int i=0; i<count; i++) {
        QQuickTransform *transform = transformations.at(&transformations, i);
        transform->applyTo(&result);
    }

    return result;
}


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


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



void OpenGlVideoQtQuick::sync()
{
    if (!openGlVideoQtQuickRenderer) {
        openGlVideoQtQuickRenderer = new OpenGlVideoQtQuickRenderer();
        connect(window(), &QQuickWindow::beforeRendering, openGlVideoQtQuickRenderer, &OpenGlVideoQtQuickRenderer::render, Qt::DirectConnection);
        connect(window(), &QQuickWindow::afterRendering, this, &OpenGlVideoQtQuick::update, Qt::DirectConnection);
    } 
    this->openGlVideoQtQuickRenderer->qQuickVideoMatrix = getModelMatrix();
}

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 OpenGlVideoQtQuickRenderer::render()
{
    if (this->firstRun) {
        std::cout << "Creating QOpenGLShaderProgram " << std::endl;
        this->firstRun = false;
        program = new QOpenGLShaderProgram();
        initializeOpenGLFunctions();

        std::cout << "Fragment Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Fragment, tString2) << std::endl;
        std::cout << "Vertex Shader compilation: " << program->addShaderFromSourceCode(QOpenGLShader::Vertex, vString2) << 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
    }
    program->bind();
    program->setUniformValue("u_transform", this->qQuickVideoMatrix);


    //glViewport(50, 50, 50, 50);

    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, width, height, 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, width/2, height / 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, width / 2, height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, 0);



    glDrawArrays(GL_TRIANGLE_STRIP,0,4);

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

}

OpenGlVideoQtQuick.h :

#ifndef OpenGlVideoQtQuick_H
#define OpenGlVideoQtQuick_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>



class OpenGlVideoQtQuickRenderer : public QObject, protected QOpenGLFunctions
{
    Q_OBJECT

public:
    OpenGlVideoQtQuickRenderer() {        
    }
    ~OpenGlVideoQtQuickRenderer();
    QMatrix4x4 qQuickVideoMatrix;



public slots:
    void render();

private:
    QOpenGLShaderProgram* program;
    GLuint unis[3] = {0};
    GLuint texs[3] = {0};
    unsigned char *datas[3] = { 0 };
    bool firstRun = true;
    //TODO: make this variable according to video data
    int width = 1920;
    int height = 1080;
};

class OpenGlVideoQtQuick : public QQuickItem
{
    Q_OBJECT

public:
    OpenGlVideoQtQuick();
    QMatrix4x4 getModelMatrix();


private slots:
    void handleWindowChanged(QQuickWindow *win);
public slots:
    void sync();
    void update();//Updates the window

private:
    OpenGlVideoQtQuickRenderer *openGlVideoQtQuickRenderer;

};

#endif // OpenGlVideoQtQuick_H

main.qml:

import QtQuick 2.0
import OpenGLComponents 1.0
Item {
    width: 1280
    height: 720
    OpenGlVideoQtQuick {
        width: 640
        height: 480

    }
}

Ответы [ 2 ]

0 голосов
/ 04 марта 2019

Из вашего вопроса и вашего кода немного неясно, что вы «ожидали» увидеть, но я вижу несколько проблем, которые могут вам помочь:

  1. Я не знаюдумаю, ваш цикл рендеринга на самом делеВы должны сделать это в своем конструкторе: setFlag(ItemHasContents);

  2. Убедитесь, что вы передаете некоторые текстурные / видео данные в ваши вызовы glTexImage2D(), иначе вы получите немного мусора (случайный зеленый мусор?)

  3. Возможно, вы захотите взглянуть на QQuickItem::widthChanged и QQuickItem::heightChanged сигналы

  4. Убедитесь, что у вас glViewport() кака также glClear() вызовы при отладке, чтобы избежать путаницы - вы можете удалить их позже, когда они вам больше не нужны

0 голосов
/ 04 марта 2019

Учитывая, что вы выводите координаты нормализованного устройства, вам просто нужно установить glViewPort и scissor test для x (), y (), width (), height () элемента (преобразование не требуется для вершин).Что касается зеленого цвета, который вы видите, это потому, что ни один из ваших текстур YUV не имеет фактических данных.В результате в вашем пиксельном шейдере yuv содержит (0, -0.5, -0.5), который при преобразовании вашей YUV в RGB-матрицу дает rgb (0.0, 0.487625, -1.016055), что соответствует половине интенсивности зеленого цвета.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...