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<uint8_t> 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<uint8_t> 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<uint8_t> 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()<data(); } else { return; } int w = m_width; int h = m_height; const uint8_t *y = m_cur_data.get() ; 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 viewWidth=2.0f; float viewHeight=2.0f; mWorld.setToIdentity(); mView.setToIdentity(); mView.lookAt(QVector3D(0.0f,0.0f,1.0f),QVector3D(0.f,0.f,0.f),QVector3D(0.f,1.f,0.f)); mProj.setToIdentity(); if(m_cur_data) /// 在这里计算宽高比 { float aspectRatio = 1.0*m_width/m_height; //aspectRatio = float(4) / 3; // 强制长宽比 if(float(float(w)/h > aspectRatio)) { viewHeight = 2.0f; viewWidth = w*viewHeight / (aspectRatio * h); } else { viewWidth = 2.0f; viewHeight = h*viewWidth / (1/aspectRatio * w); } } mProj.ortho(-viewWidth/2,viewWidth/2,-viewHeight/2,viewHeight/2,-1.f,1.0f); } void PlayerWidget::InitShaders() { GLint vertCompiled, fragCompiled, linked; GLint v, f; //Shader: step1 v = glCreateShader(GL_VERTEX_SHADER); f = glCreateShader(GL_FRAGMENT_SHADER); //Shader: step2 glShaderSource(v, 1, &vertexShader,NULL); glShaderSource(f, 1, &fragmentShader,NULL); //Shader: step3 glCompileShader(v); glGetShaderiv(v, GL_COMPILE_STATUS, &vertCompiled); //Debug glCompileShader(f); glGetShaderiv(f, GL_COMPILE_STATUS, &fragCompiled); //Debug //Program: Step1 program = glCreateProgram(); //Program: Step2 glAttachShader(program,v); glAttachShader(program,f); glBindAttribLocation(program, ATTRIB_VERTEX, "vertexIn"); 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"); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术