热门标签 | 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");
}


推荐阅读
  • 问题描述现在,不管开发一个多大的系统(至少我现在的部门是这样的),都会带一个日志功能;在实际开发过程中 ... [详细]
  • 问题场景用Java进行web开发过程当中,当遇到很多很多个字段的实体时,最苦恼的莫过于编辑字段的查看和修改界面,发现2个页面存在很多重复信息,能不能写一遍?有没有轮子用都不如自己造。解决方式笔者根据自 ... [详细]
  • spring boot使用jetty无法启动 ... [详细]
  • importjava.io.*;importjava.util.*;publicclass五子棋游戏{staticintm1;staticintn1;staticfinalintS ... [详细]
  • 深入理解Java SE 8新特性:Lambda表达式与函数式编程
    本文作为‘Java SE 8新特性概览’系列的一部分,将详细探讨Lambda表达式。通过多种示例,我们将展示Lambda表达式的不同应用场景,并解释编译器如何处理这些表达式。 ... [详细]
  • 本文详细介绍了如何在循环双链表的指定位置插入新元素的方法,包括必要的步骤和代码示例。 ... [详细]
  • 使用QT构建基础串口辅助工具
    本文详细介绍了如何利用QT框架创建一个简易的串口助手应用程序,包括项目的建立、界面设计与编程实现、运行测试以及最终的应用程序打包。 ... [详细]
  • 本文通过C++语言实现了一个递归算法,用于解析并计算数学表达式的值。该算法能够处理加法、减法、乘法和除法操作。 ... [详细]
  • 本问题涉及在给定的无向图中寻找一个至少包含三个节点的环,该环上的节点不重复,并且环上所有边的长度之和最小。目标是找到并输出这个最小环的具体方案。 ... [详细]
  • 洛谷 P4009 汽车加油行驶问题 解析
    探讨了经典算法题目——汽车加油行驶问题,通过网络流和费用流的视角,深入解析了该问题的解决方案。本文将详细阐述如何利用最短路径算法解决这一问题,并提供详细的代码实现。 ... [详细]
  • 入门指南:使用FastRPC技术连接Qualcomm Hexagon DSP
    本文旨在为初学者提供关于如何使用FastRPC技术连接Qualcomm Hexagon DSP的基础知识。FastRPC技术允许开发者在本地客户端实现远程调用,从而简化Hexagon DSP的开发和调试过程。 ... [详细]
  • Web动态服务器Python基本实现
    Web动态服务器Python基本实现 ... [详细]
  • 本文探讨了如何通过Service Locator模式来简化和优化在B/S架构中的服务命名访问,特别是对于需要频繁访问的服务,如JNDI和XMLNS。该模式通过缓存机制减少了重复查找的成本,并提供了对多种服务的统一访问接口。 ... [详细]
  • 本文介绍如何手动实现一个字符串连接函数,该函数不依赖于C语言的标准字符串处理函数,如strcpy或strcat。函数原型为void concatenate(char *dest, char *src),其主要作用是将源字符串src追加到目标字符串dest的末尾。 ... [详细]
  • PHP面试题精选及答案解析
    本文精选了新浪PHP笔试题及最新的PHP面试题,并提供了详细的答案解析,帮助求职者更好地准备PHP相关的面试。 ... [详细]
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社区 版权所有