截图如下:
```c++
#include "gl_show_widget.h"
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QMouseEvent>
#include <QTimer>
static const uint32_t VideoWidth = 886;
static const uint32_t VideoHeight = 1920;
#define GL_VERSION_this "#version 330 core\n"
#define GET_GLSTR(x) GL_VERSION_this#x
const char *vsrc = GET_GLSTR(
layout (location = 0) in vec2 position; // 顶点坐标
out vec2 texCoord; // 纹理坐标传递给片段着色器
void main()
{
gl_Position = vec4(position, 0.0, 1.0);
texCoord = position * 0.5 + 0.5; // 将顶点坐标转换为纹理坐标范围
}
);
const char *fsrc =GET_GLSTR(
in vec2 texCoord; // 从顶点着色器传递的纹理坐标
uniform sampler2D yTexture; // Y分量纹理
uniform sampler2D uTexture; // U分量纹理
uniform sampler2D vTexture; // V分量纹理
out vec4 fragColor; // 最终的颜色输出
void main()
{
float y = texture(yTexture, texCoord).r;
float u = texture(uTexture, texCoord).r - 0.5;
float v = texture(vTexture, texCoord).r - 0.5;
// YUV到RGB转换
float r = y + 1.13983 * v;
float g = y - 0.39465 * u - 0.5806 * v;
float b = y + 2.03211 * u;
// 输出RGB颜色
fragColor = vec4(r, g, b, 1.0);
}
);
GLShowWidget::GLShowWidget(QWidget *parent) : QOpenGLWidget(parent)
{
qDebug() << "GLShowWidget::GLShowWidget";
vbo_ = QOpenGLBuffer(QOpenGLBuffer::VertexBuffer);
m_sharder_program_ = new QOpenGLShaderProgram();
m_textureYUV_ = std::vector<QOpenGLTexture*>(3, nullptr);
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setStencilBufferSize(8);
format.setVersion(3, 3);
format.setProfile(QSurfaceFormat::CoreProfile);
QSurfaceFormat::setDefaultFormat(format);
setFormat(format);
}
GLShowWidget::~GLShowWidget()
{
qDebug("GLShowWidget::~GLShowWidget");
if (!m_textureYUV_.empty()) {
for (auto texture : m_textureYUV_) {
texture->destroy();
delete texture;
}
m_textureYUV_.clear();
}
if (m_sharder_program_) {
m_sharder_program_->release();
delete m_sharder_program_;
m_sharder_program_ = nullptr;
}
vbo_.destroy();
vao_.destroy();
}
void GLShowWidget::initializeGL() {
qDebug() << "GLShowWidget::initializeGL";
m_file_.setFileName("/Users/chengchao/Desktop/886x1920.yuv");
if(!m_file_.open(QIODevice::ReadOnly))
{
qDebug() << "打开失败!";
return;
}
// {
// QFile test_file("/Users/chengchao/Desktop/886x1920_first_frame.yuv");
// test_file.open(QIODevice::ReadWrite);
// QByteArray buf = m_file_.read(VideoWidth * VideoHeight * 3 / 2);
// test_file.write(buf);
// test_file.close();
// }
initializeOpenGLFunctions();
glClearColor(1.0f, 1.0f, 1.0f, 1.0f);
for(int i = 0; i < 3; i++)
{
m_textureYUV_[i] = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_textureYUV_[i]->create();
if(i == 0)
{
m_textureYUV_[i]->setSize(VideoWidth, VideoHeight);
}
else
{
m_textureYUV_[i]->setSize(VideoWidth / 2, VideoHeight / 2);
}
m_textureYUV_[i]->setMinMagFilters(QOpenGLTexture::LinearMipMapNearest, QOpenGLTexture::Linear);
m_textureYUV_[i]->setFormat(QOpenGLTexture::R8_UNorm);
m_textureYUV_[i]->setWrapMode(QOpenGLTexture::ClampToEdge);
m_textureYUV_[i]->allocateStorage(); //存储配置(放大缩小过滤、格式、size)
qDebug() << "textureId: " << m_textureYUV_[i]->textureId();
}
vao_.create();
vao_.bind();
vbo_.create();
vbo_.bind();
m_sharder_program_->addShaderFromSourceCode(QOpenGLShader::Vertex, vsrc);
m_sharder_program_->addShaderFromSourceCode(QOpenGLShader::Fragment, fsrc);
m_sharder_program_->link();
m_sharder_program_->bind();
float vertices[] = {
//顶点坐标
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
vbo_.allocate(vertices, sizeof(vertices));
vbo_.setUsagePattern(QOpenGLBuffer::StaticDraw);
m_sharder_program_->setAttributeBuffer(0, GL_FLOAT, 0, 2, 2 * sizeof(float));
m_sharder_program_->enableAttributeArray(0);
m_sharder_program_->setUniformValue("yTexture", 0);
m_sharder_program_->setUniformValue("uTexture", 1);
m_sharder_program_->setUniformValue("vTexture", 2);
vbo_.release();
vao_.release();
//启动定时器
QTimer *ti = new QTimer(this);
connect(ti, SIGNAL(timeout()), this, SLOT(update()));
ti->start(30);
}
void GLShowWidget::paintGL() {
qDebug() << "GLShowWidget::paintGL";
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, VideoWidth, VideoHeight);
vao_.bind();
vbo_.bind();
if (m_file_.atEnd())
{
m_file_.seek(0);
}
QByteArray buf = m_file_.read(VideoWidth * VideoHeight);
m_textureYUV_[0]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
m_textureYUV_[0]->bind(0);
buf = m_file_.read(VideoWidth * VideoHeight / 4);
m_textureYUV_[1]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
m_textureYUV_[1]->bind(1);
buf = m_file_.read(VideoWidth * VideoHeight / 4);
m_textureYUV_[2]->setData(QOpenGLTexture::Red,QOpenGLTexture::UInt8,buf.data());
m_textureYUV_[2]->bind(2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
m_textureYUV_[0]->release();
m_textureYUV_[1]->release();
m_textureYUV_[2]->release();
vbo_.release();
vao_.release();
}
void GLShowWidget::resizeGL(int w, int h) {
qDebug() << "resizeGL "<<w<<":"<<h;
}
```