QT开发中文网

c++使用opengl将yuv渲染到widget窗口中完整程序示例

这里提供一个c++使用opengl将yuv渲染到widget窗口中的完整程序示例:

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLTexture>
#include <QFile>

class YUVRenderer : public QOpenGLWidget, protected QOpenGLFunctions {
public:
    YUVRenderer(QWidget *parent = nullptr) : QOpenGLWidget(parent), m_program(nullptr),
        m_yTexture(nullptr), m_uTexture(nullptr), m_vTexture(nullptr) {}
    virtual ~YUVRenderer() {}

    void initializeGL() override {
        initializeOpenGLFunctions();

        // 创建着色器程序
        m_program = new QOpenGLShaderProgram();
        m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/yuv.vert");
        m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/yuv.frag");
        m_program->link();

        // 获取着色器中的变量位置
        m_positionAttr = m_program->attributeLocation("aPosition");
        m_texCoordAttr = m_program->attributeLocation("aTexCoord");
        m_yTextureUniform = m_program->uniformLocation("uYTexture");
        m_uTextureUniform = m_program->uniformLocation("uUTexture");
        m_vTextureUniform = m_program->uniformLocation("uVTexture");

        // 创建纹理对象并设置参数
        m_yTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_uTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_vTexture = new QOpenGLTexture(QOpenGLTexture::Target2D);
        m_yTexture->setMinificationFilter(QOpenGLTexture::Nearest);
        m_yTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
        m_uTexture->setMinificationFilter(QOpenGLTexture::Nearest);
        m_uTexture->setMagnificationFilter(QOpenGLTexture::Nearest);
        m_vTexture->setMinificationFilter(QOpenGLTexture::Nearest);
        m_vTexture->setMagnificationFilter(QOpenGLTexture::Nearest);

        // 加载测试yuv数据
        loadYUV(":/test.yuv", 1920, 1080);
    }

    void paintGL() override {
        glClearColor(0.1f, 0.2f, 0.3f, 1.f);
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        m_program->bind();

        glEnableVertexAttribArray(m_positionAttr);
        glVertexAttribPointer(m_positionAttr, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, m_vertices);

        glEnableVertexAttribArray(m_texCoordAttr);
        glVertexAttribPointer(m_texCoordAttr, 2, GL_FLOAT, GL_FALSE, sizeof(float) * 4, m_vertices + 2);

        // 绑定纹理并设置采样器参数
        m_yTexture->bind(0);
        m_yTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
        m_yTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
        m_program->setUniformValue(m_yTextureUniform, 0);

        m_uTexture->bind(1);
        m_uTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
        m_uTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
        m_program->setUniformValue(m_uTextureUniform, 1);

        m_vTexture->bind(2);
        m_vTexture->setWrapMode(QOpenGLTexture::DirectionS, QOpenGLTexture::ClampToEdge);
        m_vTexture->setWrapMode(QOpenGLTexture::DirectionT, QOpenGLTexture::ClampToEdge);
        m_program->setUniformValue(m_vTextureUniform, 2);

        // 绘制
        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glDisableVertexAttribArray(m_positionAttr);
        glDisableVertexAttribArray(m_texCoordAttr);

        m_program->release();
    }

private:
    void loadYUV(const QString &path, int width, int height) {
        QFile file(path);
        if (!file.open(QFile::ReadOnly)) {
            qWarning("Failed to open YUV file.");
            return;
        }

        QByteArray data = file.readAll();
        if (data.size() != width * height * 3 / 2) {
            qWarning("Invalid YUV data size.");
            return;
        }

        const uchar *yData = reinterpret_cast<const uchar *>(data.constData());
        const uchar *uData = yData + width * height;
        const uchar *vData = uData + width * height / 4;

        m_yTexture->setSize(width, height);
        m_uTexture->setSize(width / 2, height / 2);
        m_vTexture->setSize(width / 2, height / 2);

        m_yTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, yData);
        m_uTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, uData);
        m_vTexture->setData(QOpenGLTexture::Red, QOpenGLTexture::UInt8, vData);

        // 设置顶点数据
        m_vertices[0] = -1.f;
        m_vertices[1] = 1.f;
        m_vertices[2] = 0.f;
        m_vertices[3] = 1.f;

        m_vertices[4] = -1.f;
        m_vertices[5] = -1.f;
        m_vertices[6] = 0.f;
        m_vertices[7] = 0.f;

        m_vertices[8] = 1.f;
        m_vertices[9] = 1.f;
        m_vertices[10] = 1.f;
        m_vertices[11] = 1.f;

        m_vertices[12] = 1.f;
        m_vertices[13] = -1.f;
        m_vertices[14] = 1.f;
        m_vertices[15] = 0.f;
    }

    QOpenGLShaderProgram *m_program;
    int m_positionAttr;
    int m_texCoordAttr;
    int m_yTextureUniform;
    int m_uTextureUniform;
    int m_vTextureUniform;
    QOpenGLTexture *m_yTexture;
    QOpenGLTexture *m_uTexture;
    QOpenGLTexture *m_vTexture;
    float m_vertices[16];
};

其中,YUVRenderer类继承自QOpenGLWidget,并实现了initializeGL()paintGL()方法。在initializeGL()方法中,我们创建着色器程序,获取变量位置,并创建纹理对象并设置参数。另外,为了简化示例代码,我们加入了一个loadYUV()方法来加载测试yuv数据,并设置顶点数据。

paintGL()方法中,我们首先清空颜色缓存和深度缓存,然后绑定着色器程序、顶点属性和纹理,并绘制。最后,我们解绑顶点属性和纹理,并释放着色器程序。

需要注意的是,这里使用了一个yuv.vert和一个yuv.frag着色器文件,你需要将这两个文件放到工程资源文件中,并在.pro文件中添加以下语句:

RESOURCES += \
    shaders.qrc

其中,shaders.qrc为资源文件,你可以根据自己的需要进行设置。具体的.qrc文件格式和用法,请参考Qt官方文档。

yuv.vert文件内容如下:

attribute vec2 aPosition;
attribute vec2 aTexCoord;

varying vec2 vTexCoord;

void main() {
    gl_Position = vec4(aPosition, 0.0, 1.0);
    vTexCoord = aTexCoord;
}

yuv.frag文件内容如下:

uniform sampler2D uYTexture;
uniform sampler2D uUTexture;
uniform sampler2D uVTexture;

varying vec2 vTexCoord;

const mat3 yuv2rgb = mat3(
    1.164383561643836, 0,                 1.5960267857142858,
    1.164383561643836, -0.391762290094913, -0.8129676472377709,
    1.164383561643836, 2.0172321428571428,  0
);

void main() {
    float y = texture2D(uYTexture, vTexCoord).r;
    float u = texture2D(uUTexture, vTexCoord / 2.0).r - 0.5;
    float v = texture2D(uVTexture, vTexCoord / 2.0).r - 0.5;

    vec3 yuv = vec3(y, u, v);
    vec3 rgb = yuv2rgb * yuv;

    gl_FragColor = vec4(rgb, 1.0);
}

这两个着色器文件实现了将yuv转换为rgb的功能,具体实现方式可以参考yuv.frag中的代码。

最后,在主函数中创建一个YUVRenderer对象,并将其设置为主窗口的中心组件即可:

int main(int argc, char *argv[]) {
    QApplication app(argc, argv);

    QWidget window;
    YUVRenderer renderer(&window);
    window.setCentralWidget(&renderer);
    window.resize(1920, 1080);
    window.show();

    return app.exec();
}

以上就是一个c++使用opengl将yuv渲染到widget窗口中的完整程序示例。当你运行这个程序时,就会看到一个显示yuv数据的窗口。

本站部分文章来源于网络,版权归原作者所有,如有侵权请联系站长删除。
转载请注明出处:https://qt.0voice.com/?id=625

分享:
扫描分享到社交APP
上一篇
下一篇
发表列表
游客 游客
此处应有掌声~
评论列表

还没有评论,快来说点什么吧~

联系我们

在线咨询: 点击这里给我发消息

微信号:3007537140

上班时间: 10:30-22:30

关注我们
x

注册

已经有帐号?