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

项目目录:
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第1张图片
一般ffmpeg解码后的数据类型都是I420,即YUV420P,OpenGL没有提供直接渲染yuv的接口,我们可以通过可编程渲染管线,利用多重纹理将Y、U、V纹理分别传入,在片元着色器GL_FRAGMENT_SHADER中将yuv进行矩阵转化成RGB,然后进行渲染。
1.打开testQTOpenGL.ui
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第2张图片
可以看到已经有一个框了,这个框的类为自己输入的xvideo,再加一个框,默认类为QOpenGLwidget,随后将其提升为xvideo类。
在自动生成的xvideo.h中也可以看到xvideo为QOpenGLwidget的公有继承
在这里插入图片描述
2.xvideo.h

#pragma once

#include 
#include
#include
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
#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类型的。

播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第3张图片

传进来的坐标值(vertexIn)只能在顶点shader(Vstring)中获取,获取后转化为位置(GL_POSITION)顶点主要是转发,实际转化(YUV转rgb)还是在片元shader(Tstring)中
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第4张图片

片元着色器:

//片元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);
}
);
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第5张图片

yuv.x = texture2D(tex_y, textureOut).r;
通过uniform读出来转成yuv
根据坐标textureOut可以取出材质中对应的数值,yuv分开存放,若放在一起则需要遍历取出数值,开销巨大
.r为取第一个数据(rgb中r为第一个)

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

可以看到,两个框调用了两次xvideo类的构造函数
播放器实战13 创建QtOpengl项目提升窗口控件并重载QOpenGLWidge_第6张图片

你可能感兴趣的:(播放器,音视频)