播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge

  • Post author:
  • Post category:其他


项目目录:

在这里插入图片描述

一般ffmpeg解码后的数据类型都是I420,即YUV420P,OpenGL没有提供直接渲染yuv的接口,我们可以通过可编程渲染管线,利用多重纹理将Y、U、V纹理分别传入,在片元着色器GL_FRAGMENT_SHADER中将yuv进行矩阵转化成RGB,然后进行渲染。

1.打开testQTOpenGL.ui

在这里插入图片描述

可以看到已经有一个框了,这个框的类为自己输入的xvideo,再加一个框,默认类为QOpenGLwidget,随后将其提升为xvideo类。

在自动生成的xvideo.h中也可以看到xvideo为QOpenGLwidget的公有继承

在这里插入图片描述

2.xvideo.h

#pragma once

#include <QOpenGLWidget>
#include<qopenglfunctions.h>
#include<qglshaderprogram.h>
class xvideo : public QOpenGLWidget,protected QOpenGLFunctions
{
	Q_OBJECT

public:
	xvideo(QWidget *parent);
	~xvideo();
protected:
	void paintGL();  //绘制GL
	void initialGL();//初始化GL
	void resizeGL(int width,int height);//改尺寸
private:
	//通过该成员运行shader程序
	QGLShaderProgram program;
};

QOpenGLFunctions 类提供了跨平台的OpenGl ES2.0 API版本。

OpenGL 2.0 提供了OpenGL中的子类集合,可以提供跨多个平台的桌面系统以及嵌入式OpenGL的实现。

然而,却很难使用子类因为子类需要解决许多平台系统的操作问题。

因此 QOpenGLFunctions提供了这样的API,可以保证在所有的OpenGL系统中使用, 并且也关注不同系统中的OpenGL的版本API的使用。

Qt推荐直接继承的方式来使用 QOpenGLFunctions类,就不用把库引用进来了

在后面代码中将通过program成员加载shader

3.xvideo.cpp

#include "xvideo.h"
#include<qdebug.h>
#define GET_STR(x) #x //自动加双引号

//
const char* Vstring = GET_STR(
	attribute vec4 vertexIn;//顶点输入
	attribute vec2 textureIn;//材质输入
	varying  vec2 textureOut;//顶点与片元shader共享变量
	void main(void)
	{
		gl_Position = vertexIn;
		textureOut = textureIn;
	}
);

//片元shader
const char* Tstring = GET_STR(
	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.0, 1.0, 1.0,
		0, -0.39465, 2.03211,
		1.13983, -0.58060, 0) * yuv;//YUV转换成rgb
	gl_FragColor = vec4(rgb, 1.0);
    }
    );
xvideo::xvideo(QWidget *parent)
	: QOpenGLWidget(parent)
{
	qDebug() << "gouzao" << endl;
}

xvideo::~xvideo()
{
	qDebug() << "xigou" << endl;
}

//初始化opengl


void xvideo::paintGL()  //绘制GL
{
	qDebug() << "paintGL" << endl;
}
void xvideo::initialGL()  //初始化GL
{
	qDebug() << "initialGL" << endl;
	//初始化opengl (QOpenGLFunctions继承)函数 
	initializeOpenGLFunctions();
	qDebug() << program.addShaderFromSourceCode(QGLShader::Fragment, Tstring);
	//顶点shader
	qDebug() << program.addShaderFromSourceCode(QGLShader::Vertex, Vstring);
}
void xvideo::resizeGL(int width, int height) 
{
	qDebug() << "resizeGL" << endl;
}

顶点着色器:

const char* Vstring = GET_STR(

attribute vec4 vertexIn;//顶点输入

attribute vec2 textureIn;//材质输入

varying vec2 textureOut;//顶点与片元shader共享变量

void main(void)

{


gl_Position = vertexIn;

textureOut = textureIn;

}

);//为了设置顶点着色器的输出,我们必须把位置数据赋值给预定义的gl_Position变量,

//它在幕后是vec4类型的。

在这里插入图片描述

传进来的坐标值(vertexIn)只能在顶点shader(Vstring)中获取,获取后转化为位置(GL_POSITION)顶点主要是转发,实际转化(YUV转rgb)还是在片元shader(Tstring)中

在这里插入图片描述

片元着色器:

//片元shader

const char* Tstring = GET_STR(

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.0, 1.0, 1.0,

0, -0.39465, 2.03211,

1.13983, -0.58060, 0) * yuv;//YUV转换成rgb

gl_FragColor = vec4(rgb, 1.0);

}

);

在这里插入图片描述

yuv.x = texture2D(tex_y, textureOut).r;

通过uniform读出来转成yuv

根据坐标textureOut可以取出材质中对应的数值,yuv分开存放,若放在一起则需要遍历取出数值,开销巨大

.r为取第一个数据(rgb中r为第一个)

通过三个材质(tex_y,tex_u,tex_v)拼出yuv数据

可以看到,两个框调用了两次xvideo类的构造函数

在这里插入图片描述



版权声明:本文为qq_42567607原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。