qt实现opengl播放yuv视频

16 篇文章 75 订阅

qt使用opengl播放yuv视频

更多精彩内容
👉个人内容分类汇总 👈

1、实现效果

在这里插入图片描述

2、pro文件

  • 添加Qt += widgets opengl

3、xvideowidget.h

#ifndef XVIDEOWIDGET_H
#define XVIDEOWIDGET_H

#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>
#include <QFile>
#include <QTimer>

class XVideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
    Q_OBJECT
public:
    explicit XVideoWidget(QWidget* parent = nullptr);

signals:

protected:
    void initializeGL() override;               // 初始化gl
    void resizeGL(int w, int h) override;       // 窗口尺寸变化
    void paintGL() override;                    // 刷新显示

private:
    QGLShaderProgram program;    // shader程序

    GLuint unis[3] = {0};   // shader中的yuv变量地址
    GLuint texs[3] = {0};   // opengl的texture地址

    int width = 1920;
    int height = 1080;

    QFile m_file;
    QByteArray m_buf;  // 视频数据

    QTimer m_timer;
};

#endif // XVIDEOWIDGET_H

4、xvideowidget.cpp

#include "xvideowidget.h"

#include <QDebug>

#pragma execution_character_set("utf-8")
// 准备yuv数据
// ffmpeg -i ffmpeg.mp4 -t 10 -s 240x128 -pix_fmt yuv420p out240X128.yuv

// 自动加双引号
#define GET_STR(x) #x
#define A_VER 3
#define T_VER 4
// 顶点shader
const char* vString = GET_STR(
    attribute vec4 vertexIn;
    attribute vec2 textureIn;
    varying vec2 textureOut;

    void main(void)
    {
        gl_Position = vertexIn;
        textureOut = textureIn;
    }
);

// 片元shader
const char* tString = 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);
    }
);

XVideoWidget::XVideoWidget(QWidget *parent) : QOpenGLWidget(parent)
{
    connect(&m_timer, &QTimer::timeout, this,
            [&]()
    {
        this->update();
    });

    m_timer.start(1);
}

void XVideoWidget::initializeGL()
{
    qDebug() << "初始化";
    initializeOpenGLFunctions();    // 初始化opengl

    // program加载shader脚本(顶点和片元)
    qDebug() << "加载片元脚本:" <<program.addShaderFromSourceCode(QGLShader::Fragment, tString);  // 片元
    qDebug() << "加载顶点脚本:" <<program.addShaderFromSourceCode(QGLShader::Vertex, vString);    // 顶点

    // 设置顶点坐标的变量
    program.bindAttributeLocation("vertexIn", A_VER);
    // 设置材质坐标
    program.bindAttributeLocation("textureIn", T_VER);
    qDebug() << "编译shader:" << program.link();
    qDebug() << "绑定shader:" << program.bind();

    // 传递顶点和材质坐标
    // 顶点
    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
    };

    glVertexAttribPointer(A_VER, 2, GL_FLOAT, 0, 0, ver);  // 顶点
    glEnableVertexAttribArray(A_VER); // 启用顶点数组
    glVertexAttribPointer(T_VER, 2, GL_FLOAT, 0, 0, tex);  // 材质
    glEnableVertexAttribArray(T_VER); // 生效

    // 从shader获取材质
    unis[0] = program.uniformLocation("tex_y");
    unis[1] = program.uniformLocation("tex_u");
    unis[2] = program.uniformLocation("tex_v");

    // 创建材质
    glGenTextures(3, texs);
    // Y
    glBindTexture(GL_TEXTURE_2D, texs[0]);   // 绑定材质
    glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);  // 设置纹理参数,放大过滤,线性插值 GL_NEAREST(效率高,效果差)
    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);   // 创建材质显卡空间

    m_file.setFileName("./out.yuv");
    if(!m_file.open(QIODevice::ReadOnly))
    {
        qDebug() << "打开失败!";
        return;
    }
}

void XVideoWidget::resizeGL(int w, int h)
{
    qDebug() << w <<" " << h;
}

void XVideoWidget::paintGL()
{
    qDebug() << "绘制";
    if(m_file.atEnd())
    {
        m_file.seek(0);
    }
    QByteArray buf = m_file.read(width * height);

    glActiveTexture(GL_TEXTURE0);   // 激活第0层
    glBindTexture(GL_TEXTURE_2D, texs[0]);  // 0层绑定到y材质中
    // 修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, buf.data());
    glUniform1i(unis[0], 0);   // 与shader的uni变量关联

    buf = m_file.read(width * height / 4);
    glActiveTexture(GL_TEXTURE0 + 1);   // 激活第1层
    glBindTexture(GL_TEXTURE_2D, texs[1]);  // 1层绑定到U材质中
    // 修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, buf.data());
    glUniform1i(unis[1], 1);   // 与shader的uni变量关联

    buf = m_file.read(width * height / 4);
    glActiveTexture(GL_TEXTURE0 + 2);   // 激活第2层  V
    glBindTexture(GL_TEXTURE_2D, texs[2]);  // 2层绑定到v材质中
    // 修改材质内容(复制内存内容)
    glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width / 2, height / 2, GL_RED, GL_UNSIGNED_BYTE, buf.data());
    glUniform1i(unis[2], 2);   // 与shader的uni变量关联

    glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);  // 开始绘制
}
  • 2
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
要在Qt中使用OpenGL显示YUV图像,你需要将YUV数据转换为RGB格式,并将其作为纹理上传到OpenGL中。以下是一个简单的实现步骤: 1. 加载YUV数据并将其转换为RGB格式。 可以使用libyuv等库来完成YUV到RGB的转换。具体实现可以参考以下代码: ```c++ #include "libyuv.h" void yuv2rgb(unsigned char* src_y, unsigned char* src_u, unsigned char* src_v, unsigned char* dst_rgb, int width, int height) { int u_offset = width * height; int v_offset = u_offset + u_offset / 4; libyuv::I420ToRGB24(src_y, width, src_u, width / 2, src_v, width / 2, dst_rgb, width * 3, width, height); } ``` 2. 创建OpenGL纹理并上传RGB数据。 在Qt中,你可以使用QOpenGLTexture类来创建和绑定纹理。以下是一个简单的实现步骤: ```c++ QOpenGLTexture* texture = new QOpenGLTexture(QOpenGLTexture::Target2D); texture->setSize(width, height); texture->setFormat(QOpenGLTexture::RGBFormat); texture->allocateStorage(); texture->setData(QOpenGLTexture::RGB, QOpenGLTexture::UInt8, rgb_data); ``` 3. 在OpenGL中绘制纹理。 在OpenGL中,你可以使用glTexCoord2f和glVertex2f函数将纹理映射到一个四边形上。以下是一个简单的实现步骤: ```c++ glEnable(GL_TEXTURE_2D); texture->bind(); glBegin(GL_QUADS); glTexCoord2f(0.0, 0.0); glVertex2f(-1.0, -1.0); glTexCoord2f(1.0, 0.0); glVertex2f(1.0, -1.0); glTexCoord2f(1.0, 1.0); glVertex2f(1.0, 1.0); glTexCoord2f(0.0, 1.0); glVertex2f(-1.0, 1.0); glEnd(); texture->release(); glDisable(GL_TEXTURE_2D); ``` 以上是一个简单的实现步骤。当然,实际的实现可能更加复杂,需要根据你的具体需求进行修改和优化。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

mahuifa

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值