Qt在视频画面上绘制动态矩形
说明
Qt可以通过QOpenGLWidget使用OpenGL渲染显示视频,在渲染的视频画面上,有可能需要绘制一些几何图案。目前试了3种不同的方式在画面上绘制矩形,记录下过程。
通过QPainter绘制
Qt的绘制函数paintEvent(QPaintEvent *event)
在QOpenGLWidget中可以绘制,并且和OpenGL的内容叠在一起,只需要在绘制之前先调用下基类的paintEvent(QPaintEvent *event)
即可,可以理解为先在画布上画好视频,再在画布上画个矩形。这种方式灵活性最好。
void RenderWidget::paintEvent(QPaintEvent *event) { QOpenGLWidget::paintEvent(event); qreal offset = sin(m_nCount * 0.1); //m_nCount是渲染的帧数 QPainter painter(this); painter.setRenderHints(QPainter::SmoothPixmapTransform); painter.save(); painter.setPen(QPen(QColor("#4FE3C1"), 1, Qt::SolidLine, Qt::RoundCap, Qt::RoundJoin)); painter.drawRect(QRectF(width() * offset, height() * 0.7, width() * 0.25, height() * 0.25)); painter.restore(); }
通过OpenGL绘制
通过不同的QOpenGLShaderProgram,可以指定不同的着色器程序来实现矩形的绘制。这种方式绘制的时候,偏移量这些变化参数要通过Uniform传递给OpenGL的顶点着色器,如果图形复杂或者带3D可以考虑。
void RenderWidget::initializeGL() { initializeOpenGLFunctions(); const char *vsrc = "attribute vec4 vertexIn; \ attribute vec4 textureIn; \ varying vec4 textureOut; \ void main(void) \ { \ gl_Position = vertexIn; \ textureOut = textureIn; \ }"; const char *fsrc = "varying mediump vec4 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.st).r; \ yuv.y = texture2D(tex_u, textureOut.st).r - 0.5; \ yuv.z = texture2D(tex_v, textureOut.st).r - 0.5; \ rgb = mat3( 1, 1, 1, \ 0, -0.39465, 2.03211, \ 1.13983, -0.58060, 0) * yuv; \ gl_FragColor = vec4(rgb, 1); \ }"; const char *rcvsrc = "#version 330 core\n \ layout(location = 0) in vec3 aPos;\n \ uniform vec2 offsetP; \ void main(){\n \ gl_Position = vec4(aPos.x + offsetP.x, aPos.y + offsetP.y, aPos.z, 1.0f);\n \ }\n "; const char *rcfsrc = "#version 330 core\n \ out vec4 FragColor;\n \ void main(){\n \ FragColor = vec4(1.0f, 0.0f, 0.0f, 1.0f);\n \ }\n "; videoProgram.addCacheableShaderFromSourceCode(QOpenGLShader::Vertex,vsrc); videoProgram.addCacheableShaderFromSourceCode(QOpenGLShader::Fragment,fsrc); videoProgram.link(); rcProgram.addShaderFromSourceCode(QOpenGLShader::Vertex,rcvsrc); rcProgram.addShaderFromSourceCode(QOpenGLShader::Fragment,rcfsrc); rcProgram.link(); { QOpenGLVertexArrayObject::Binder vaoBind(&rcvao); GLfloat rcPoints[]{ 0.25f, 0.25f, 0.0f, // top right 0.25f, -0.25f, 0.0f, // bottom right -0.25f, -0.25f, 0.0f, // bottom left -0.25f, 0.25f, 0.0f, // top left }; rcvbo.create(); rcvbo.bind(); rcvbo.allocate(rcPoints, sizeof(rcPoints)); int attr = -1; attr = rcProgram.attributeLocation("aPos"); rcProgram.setAttributeBuffer(attr, GL_FLOAT, 0, 3, sizeof(GLfloat) * 3); rcProgram.enableAttributeArray(attr); rcvbo.release(); } { QOpenGLVertexArrayObject::Binder vaoBind(&vao); GLfloat points[]{ -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -1.0f, -1.0f, -1.0f, 0.0f,0.0f, 1.0f,0.0f, 1.0f,1.0f, 0.0f,1.0f }; vbo.create(); vbo.bind(); vbo.allocate(points,sizeof(points)); m_pTextureY = std::make_unique<QOpenGLTexture>(QOpenGLTexture::Target2D