热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

使用QT实现YUV420图像渲染技术

在使用Qt进行YUV420图像渲染时,由于Qt本身不支持直接绘制YUV数据,因此需要借助QOpenGLWidget和OpenGL技术来实现。通过继承QOpenGLWidget类并重写其绘图方法,可以利用GPU的高效渲染能力,实现高质量的YUV420图像显示。此外,这种方法还能显著提高图像处理的性能和流畅性。

Qt不能直接绘制YUV数据,需要使用QOPenGLWidget使用OPENGL来绘制,并且这样显示直接用的显卡绘制

使用QOPenGLWidget绘制YUV数据,我们需要继承QOpenGLWidget和QOpenGLFunctions(可以使用更高版本的QOpenGLFunctions_4_5_Core),QOpenGLFunctions提供了OPENGL的绘制接口。

头文件如下:

#include "QOpenGLWidget"
#include "QMatrix4x4"
#include "qopenglfunctions_4_5_core.h"
class PlayerWidget : public QOpenGLWidget,
public QOpenGLFunctions_4_5_Core
{
Q_OBJECT
public:
PlayerWidget(QWidget *parent = Q_NULLPTR);
/// I420 就是 YUV420P,这个函数设置裸数据,和图片宽高
void setI420Data(std::shared_ptr> d, int width, int height);
// 以下是绘制YUV420P的方法,继承自QOPenGLWidget
protected:
void initializeGL() override;
void paintGL() override;
void resizeGL(int w, int h) override;
private:
void InitShaders();
GLuint program{0};
GLuint tex_y{0};
GLuint tex_u{0};
GLuint tex_v{0};
GLuint sampler_y{0};
GLuint sampler_u{0};
GLuint sampler_v{0};
GLuint matWorld{0};
GLuint matView{0};
GLuint matProj{0};
QMatrix4x4 mProj;
QMatrix4x4 mView;
QMatrix4x4 mWorld;
// 图片宽高,和I420裸数据
int m_width{-1};
int m_height{1};
std::shared_ptr> m_cur_data{nullptr};// 需要绘制的I420数据
};

源文件如下:

#include "playerwidget.h"
#define ATTRIB_VERTEX 3
#define ATTRIB_TEXTURE 4
static const char *vertexShader = "\
attribute vec4 vertexIn;\
attribute vec2 textureIn;\
varying vec2 textureOut;\
uniform mat4 mWorld;\
uniform mat4 mView;\
uniform mat4 mProj;\
void main(void)\
{\
gl_Position =vertexIn * mWorld * mView * mProj ;\
textureOut = textureIn;\
}";
static const char *fragmentShader =
#if defined(WIN32)
"#ifdef GL_ES\n"
"precision mediump float;\n"
"#endif\n"
#else
#endif
"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, 1, 1,\
0, -0.39465, 2.03211,\
1.13983, -0.58060, 0) * yuv;\
gl_FragColor = vec4(rgb, 1);\
}";
static const GLfloat vertexVertices[] = {
-1.0f, -1.0f,
1.0f, -1.0f,
-1.0f, 1.0f,
1.0f, 1.0f,
};
static const GLfloat textureVertices[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f,
};
PlayerWidget::PlayerWidget(QWidget *parent):QOpenGLWidget(parent)
{}
void PlayerWidget::setI420Data(std::shared_ptr > d, int width, int height )
{
m_cur_data = std::move(d);
m_width = width;
m_height = height;
repaint();
}
void PlayerWidget::initializeGL()
{
initializeOpenGLFunctions();
const GLubyte* name = glGetString(GL_VENDOR); //返回负责当前OpenGL实现厂商的名字
const GLubyte* biaoshifu = glGetString(GL_RENDERER); //返回一个渲染器标识符,通常是个硬件平台
const GLubyte* OpenGLVersion =glGetString(GL_VERSION); //返回当前OpenGL实现的版本号
// const GLubyte* OpenGLExensiOns=glGetString(GL_EXTENSIONS); //
/// 打印OpenGL版本,标识,厂商信息
QString str;
str.sprintf("%s | %s | %s",name, biaoshifu, OpenGLVersion);
qDebug() }
else
{
return;
}
int w = m_width;
int h = m_height;
const uint8_t *u = y + w*h ;
const uint8_t *v = u + w*h/4;
// 清除缓冲区
glClearColor(0.0,0.0,0.0,0.0);
glClear(GL_COLOR_BUFFER_BIT);
// Y
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, tex_y);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w, h, 0, GL_RED, GL_UNSIGNED_BYTE, y);
glUniform1i(sampler_y, 0);
// U
glActiveTexture(GL_TEXTURE1);
glBindTexture(GL_TEXTURE_2D, tex_u);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, u);
glUniform1i(sampler_u, 1);
// V
glActiveTexture(GL_TEXTURE2);
glBindTexture(GL_TEXTURE_2D, tex_v);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, w/2, h/2, 0, GL_RED, GL_UNSIGNED_BYTE, v);
glUniform1i(sampler_v, 2);
// QOpenGLShaderProgram::setUniformValue();
glUniformMatrix4fv(matWorld,1, GL_FALSE, mWorld.constData());
glUniformMatrix4fv(matView,1, GL_FALSE, mView.constData());
glUniformMatrix4fv(matProj,1, GL_FALSE, mProj.constData());
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glFlush();
}
void PlayerWidget::resizeGL(int w, int h)
{
float viewvertexIn");
glBindAttribLocation(program, ATTRIB_TEXTURE, "textureIn");
//Program: Step3
glLinkProgram(program);
//Debug
glGetProgramiv(program, GL_LINK_STATUS, &linked);
glUseProgram(program);
//Get Uniform Variables Location
sampler_y = glGetUniformLocation(program, "tex_y");
sampler_u = glGetUniformLocation(program, "tex_u");
sampler_v = glGetUniformLocation(program, "tex_v");
//Init Texture
glGenTextures(1, &tex_y);
glBindTexture(GL_TEXTURE_2D, tex_y);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &tex_u);
glBindTexture(GL_TEXTURE_2D, tex_u);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glGenTextures(1, &tex_v);
glBindTexture(GL_TEXTURE_2D, tex_v);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glVertexAttribPointer(ATTRIB_VERTEX,2,GL_FLOAT,0,0,vertexVertices);
glEnableVertexAttribArray(ATTRIB_VERTEX);
glVertexAttribPointer(ATTRIB_TEXTURE,2,GL_FLOAT,0,0,textureVertices);
glEnableVertexAttribArray(ATTRIB_TEXTURE);
matWorld = glGetUniformLocation(program,"mWorld");
matView = glGetUniformLocation(program,"mView");
matProj = glGetUniformLocation(program,"mProj");
}


推荐阅读
author-avatar
杰杰
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有