QT开发中文网

2023/5/13 19:25:02 c++使用QOpengLwidget渲染yuv视频帧的时候设置饱和度、亮度和对比度后并转换为rgb显示完整示例代码

以下是使用QOpenGLWidget渲染YUV视频帧并设置饱和度、亮度和对比度后转换为RGB显示的完整示例代码:

#include <QtWidgets/QApplication>
#include <QtWidgets/QOpenGLWidget>
#include <QtGui/QOpenGLFunctions>
#include <QtGui/QOpenGLShaderProgram>
#include <QtGui/QOpenGLBuffer>
#include <QtGui/QMatrix4x4>
#include <QtCore/QFile>

class VideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
public:
    VideoWidget(QWidget *parent = 0) : QOpenGLWidget(parent)
    {
        m_yuvBuffer.resize(m_width * m_height + m_width / 2 * m_height / 2 * 2);
        // 初始化shader程序
        initializeOpenGLFunctions();
        m_shaderProgram = new QOpenGLShaderProgram(this);
        m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/vertex.glsl");
        m_shaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/fragment.glsl");
        m_shaderProgram->link();
        m_shaderProgram->bind();

        // 初始化顶点缓冲区和纹理坐标缓冲区
        QVector<float> vertices = {
            -1.0f, 1.0f,
            -1.0f, -1.0f,
            1.0f, 1.0f,
            1.0f, -1.0f,
        };
        m_vertexBuffer.create();
        m_vertexBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
        m_vertexBuffer.bind();
        m_vertexBuffer.allocate(vertices.constData(), vertices.size() * sizeof(float));

        QVector<float> texCoords = {
            0.0f, 1.0f,
            0.0f, 0.0f,
            1.0f, 1.0f,
            1.0f, 0.0f,
        };
        m_texCoordBuffer.create();
        m_texCoordBuffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
        m_texCoordBuffer.bind();
        m_texCoordBuffer.allocate(texCoords.constData(), texCoords.size() * sizeof(float));

        // 创建纹理
        glGenTextures(3, m_textures);
        for (int i = 0; i < 3; ++i) {
            glBindTexture(GL_TEXTURE_2D, m_textures[i]);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
            glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
        }
    }

    ~VideoWidget()
    {
        makeCurrent();
        m_vertexBuffer.destroy();
        m_texCoordBuffer.destroy();
        glDeleteTextures(3, m_textures);
        doneCurrent();
    }

    void setYUVData(const QByteArray &data, int width = 1920, int height = 1080)
    {
        if (data.size() != width * height + width / 2 * height / 2 * 2) {
            return;
        }
        m_width = width;
        m_height = height;
        m_yuvBuffer = data;
        update();
    }

    void setBrightness(qreal brightness)
    {
        m_brightness = brightness;
        update();
    }

    void setContrast(qreal contrast)
    {
        m_contrast = contrast;
        update();
    }

    void setSaturation(qreal saturation)
    {
        m_saturation = saturation;
        update();
    }

protected:
    void initializeGL()
    {
        glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
    }

    void resizeGL(int w, int h)
    {
        glViewport(0, 0, w, h);
    }

    void paintGL()
    {
        // 矩阵变换
        QMatrix4x4 modelViewProjection;
        modelViewProjection.setToIdentity();
        modelViewProjection.ortho(-1.0f, 1.0f, -1.0f, 1.0f, -1.0f, 1.0f);

        // 设置shader uniform
        m_shaderProgram->bind();
        m_shaderProgram->setUniformValue("u_modelViewProjection", modelViewProjection);
        m_shaderProgram->setUniformValue("u_textureY", 0);
        m_shaderProgram->setUniformValue("u_textureU", 1);
        m_shaderProgram->setUniformValue("u_textureV", 2);
        m_shaderProgram->setUniformValue("u_brightness", m_brightness);
        m_shaderProgram->setUniformValue("u_contrast", m_contrast);
        m_shaderProgram->setUniformValue("u_saturation", m_saturation);

        // 更新纹理
        glActiveTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, m_textures[0]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_width, m_height, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvBuffer.constData());
        glActiveTexture(GL_TEXTURE1);
        glBindTexture(GL_TEXTURE_2D, m_textures[1]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_width / 2, m_height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvBuffer.constData() + m_width * m_height);
        glActiveTexture(GL_TEXTURE2);
        glBindTexture(GL_TEXTURE_2D, m_textures[2]);
        glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_width / 2, m_height / 2, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvBuffer.constData() + m_width * m_height * 5 / 4);

        // 开始绘制
        glEnableVertexAttribArray(0);
        m_vertexBuffer.bind();
        glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

        glEnableVertexAttribArray(1);
        m_texCoordBuffer.bind();
        glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, nullptr);

        glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);

        glDisableVertexAttribArray(0);
        glDisableVertexAttribArray(1);
        m_shaderProgram->release();
    }

private:
    QOpenGLShaderProgram *m_shaderProgram;
    QOpenGLBuffer m_vertexBuffer;
    QOpenGLBuffer m_texCoordBuffer;
    GLuint m_textures[3];
    QByteArray m_yuvBuffer;
    int m_width = 1920;
    int m_height = 1080;
    qreal m_brightness = 0.0;
    qreal m_contrast = 1.0;
    qreal m_saturation = 1.0;
};

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    VideoWidget widget;
    widget.show();

    QFile file(":/test.yuv");
    file.open(QIODevice::ReadOnly);
    widget.setYUVData(file.readAll(), 1920, 1080);

    widget.setBrightness(0.5);
    widget.setContrast(1.5);
    widget.setSaturation(2.0);

    return app.exec();
}

其中,vertex.glsl代码如下:

attribute vec4 a_position;
attribute vec2 a_texCoord;
varying vec2 v_texCoord;

uniform mat4 u_modelViewProjection;

void main()
{
    gl_Position = u_modelViewProjection * a_position;
    v_texCoord = a_texCoord;
}

fragment.glsl代码如下:

precision highp float;

varying vec2 v_texCoord;

uniform sampler2D u_textureY;
uniform sampler2D u_textureU;
uniform sampler2D u_textureV;
uniform float u_brightness;
uniform float u_contrast;
uniform float u_saturation;

vec3 RGB2YUV(vec3 rgb)
{
    return vec3(
        0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b,
        -0.14713 * rgb.r - 0.28886 * rgb.g + 0.436 * rgb.b,
        0.615 * rgb.r - 0.51498 * rgb.g - 0.10001 * rgb.b
    );
}

vec3 YUV2RGB(vec3 yuv)
{
    return vec3(
        yuv.r + 1.13983 * yuv.b,
        yuv.r - 0.39465 * yuv.g - 0.58060 * yuv.b,
        yuv.r + 2.03211 * yuv.g
    );
}

void main()
{
    vec3 yuv;
    yuv.x = texture2D(u_textureY, v_texCoord).r;
    yuv.y = texture2D(u_textureU, v_texCoord / 2.0).r - 0.5;
    yuv.z = texture2D(u_textureV, v_texCoord / 2.0).r - 0.5;

    vec3 rgb = YUV2RGB(yuv);
    rgb = rgb * u_contrast + vec3((u_brightness - 0.5) * 2.0, (u_brightness - 0.5) * 2.0, (u_brightness - 0.5) * 2.0);
    float gray = 0.299 * rgb.r + 0.587 * rgb.g + 0.114 * rgb.b;
    rgb = mix(vec3(gray), rgb, u_saturation);

    gl_FragColor = vec4(rgb, 1.0);
}

其中,RGB2YUV和YUV2RGB函数用于颜色空间的转换。在主函数中,首先从文件中读取了一个YUV视频帧,并设置了亮度、对比度、饱和度三个参数。在paintGL函数中,首先进行矩阵变换和uniform赋值,然后更新纹理,最后开启顶点属性和纹理坐标属性,执行绘制操作。

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

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

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

联系我们

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

微信号:3007537140

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

关注我们
x

注册

已经有帐号?