既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!
由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新
需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)
//自动加双引号 定义常量串都可以使用
#define GET\_STR(x) #x
//顶点着色器的shader代码
const char \*vString = GET\_STR(
attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
void main(void)
{
gl_Position = vertexIn;//传入的顶点坐标记录
textureOut = textureIn;//传入的材质坐标保存到textureOut
}
);
//自动加双引号 定义常量串都可以使用
#define GET\_STR(x) #x
//片元着色器的shader代码
const char \*tString = GET\_STR(
varying vec2 textureOut;//刚刚顶点着色器算出来的坐标
uniform sampler2D tex_y;//uniform是外部传入的变量
uniform sampler2D tex_u;
uniform sampler2D tex_v;
void main(void)
{
//420P是平面存储的,最后都是要转换为每个像素都是有yuv再方便转换
//用的是灰度图的形式存储的
//如安装那边硬解码出来的都是yuv420sp,uv是打包存在一起的,则不能使用这套shader代码了,要增加透明度存储方式。
vec3 yuv;
vec3 rgb;
//根据那个坐标把材质坐标计算出来
//传入材质,和坐标 返回材质当中的颜色rgb,但是用灰度图存储的,都是一样的。
//三个材质就可以拼出一个yuv的数据
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, -0.39465, 2.03211,
1.13983, -0.58060, 0.0) \* yuv;
gl_FragColor = vec4(rgb, 1.0);//转换成显示的颜色,再设置一下
}
);
创建材质
shader其实就是绘制某一个材质,那么就要看创建材质了。qt也有创建材质的函数,但是openGL这边要简单一点。
glGenTextures(1,t);创建几个材质,传入二维数组存放创建的材质地址
glBindTexture(GL_TEXTURE_2D \*t)进行绑定 绑定为2d的图像
glTexPatameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR)设置属性 放大的属性
glTexPatameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR)设置属性 缩小的属性
GL_TEXTURE_2D操作的是2D纹理
GL_TEXTURE_MAG_FILTER 放大过滤
GL_TEXTURE_MIN_FILTER 缩小过滤
GL_LINEAR用线性差值的方式进行缩放 使用距离当前渲染像素中心最近的四个纹素加权平均值,则最后的图像变化就比较荣和
写入和绘制材质
glActiveTexture(GL_TEXTURE0);激活材质 序号0
glBindTexture(GL_TEXTURE_2D,id_y);绑定之前创建的材质
在显存当中创建材质
//将openGL里面的创建的材质设置传入到内存当中,就是显存到内存的操作
//GL\_LUMINANCE,pixel\_w,pixel\_h 这个就表示已灰度图的形式存放的,传入宽高
glTexImage2D(GL_TEXTURE_2D,//创建为了
0, //细节显示 0默认 是拉远拉近摄像机相关的显示
GL_LUMINANCE,//gpu显卡内部的格式,就是创建的材质是存放到显卡当中,这是灰度图
pixel_w,pixel_h,
0,
GL_LUMINANCE, 数据格式,内存到显存的格式,但是无法转换因此要一致
GL_UNSIGNED_BYTE,//单个像素的存放格式
plane[0])
//因为创建纹理有很大的开销,因此提供了一个修改纹理的函数
glTexSubImage2D() 修改纹理 存在偏移值的变量就是表示从当前的纹理当中只取一部分
glUniform1i(textureUniformY, 0);材质设完之后与shaeder相关联,通过uniform变量出入到材质0层
glDrawArrays(GL_TRINGLE_STRIP,0,4)//绘制矩形,四个顶点
显示播放整体流程分析
重载QOpenGLWidget的三个函数
//重载那三个函数
//刷新初始化
void paintGL();//具体绘制在这里面实现
//初始化gl
void initializeGL();//初始化
//窗口大小变化
void resizeGL(int width,int height);//当窗口发生变化的时候调用,这个函数
initializeGL 在OPenGL创建的时候就会调用
初始化OpenGL函数
initializeOpenGLFunctions()
调用着色器program添加shader代码
QGLShaderProgram.addShaderFromSourceCode(QGLShader::Fragment,tString);
QGLShaderProgram.addShaderFromSourceCode(QGLShader::Vertex,vString);
//QGLShader::Fragment 纹理材质类型 tString,vString常量串是Shader具体源代码
//这个addShader还可以从文件获取 Fragment是fsh文件,Vertex是vsh文件
//给shader绑定属性 给顶点shader的attribute赋值,A\_VER、T\_VER这个只是标记作用
program.bindAttributeLocation("vertexIn", A_VER);
program.bindAttributeLocation("textureIn",T_VER);
//编译,绑定shader
program.link();
program.bind();
//定义顶点和材质纹理的坐标
static const GLfloat ver[] = {}
static const GLfloat tex[] = {}
//将顶点和材质纹理的坐标设置到shader当中去,A\_VER、T\_VER就是之前赋值属性的时候绑定的flag
glVertexAttribPointer(A_VER,2,GL_FLOAT,0,0,ver);
glEnableVertexAttribArray(A_VER);
glVertexAttribPointer(T_VER,2, GL_FLOAT, 0,0,tex);
glEnableVertexAttribArray(T_VER);
//从shader当中获取uniform sampler2D的位置,之后好传入
unis[0] = program.uniformLocation("tex\_y");
unis[1] = program.uniformLocation("tex\_u");
unis[2] = program.uniformLocation("tex\_v");
//创建材质,并绑定类型,属性及创建空间,对yuv都进行操作,注意uv的大小变化
glGenTextures(3,texs);
//Y
glBindTexture(GL_TEXTURE_2D, texs[0]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width,height,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//width/2 height/2根据yuv420的特性来的 uv是y的四分之一
//U
glBindTexture(GL_TEXTURE_2D, texs[1]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width/2,height/2,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//V
glBindTexture(GL_TEXTURE_2D, texs[2]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width/2,height/2,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//分配材质的内存空间
datas[0] = new unsigned char[width\*height];
datas[1] = new unsigned char[width\*height/4];
datas[2] = new unsigned char[width\*height/4];
//读取文件
fp = fopen("output240X128.yuv", "rb");
if(!fp)
{
qDebug() << "fopen error";
}
//启动定时器,绑定到OPenGL的update()函数调用绘画函数
QTimer \*ti = new QTimer(this);
connect(ti, SIGNAL(timeout()), this, SLOT(update()));//定时器刷新到update()里面取
ti->start(40);
paintGL 绘画时调用
//读取帧数据,存放到分配材质的内存空间
fread(datas[0],1,width\*height, fp);
fread(datas[1], 1, width\*height/4, fp);
fread(datas[2], 1, width\*height/4, fp);
//在显卡中创建材质 并绑定到了0层渲染材质
glActiveTexture(GL_TEXTURE0);//激活第0层
glBindTexture(GL_TEXTURE_2D, texs[0]);//把0层绑定Y材质
//修改材质(复制内存内存)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
//与shader uni变量关联起来
glUniform1i(unis[0], 0);
重复三次
glActiveTexture(GL_TEXTURE0+1);//激活第1层
glBindTexture(GL_TEXTURE_2D, texs[1]);//把1层绑定Y材质
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
glUniform1i(unis[1], 1);
glActiveTexture(GL_TEXTURE0+2);//激活第0层
glBindTexture(GL_TEXTURE_2D, texs[2]);//把0层绑定Y材质
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
glUniform1i(unis[2], 2);
最后绘画 //画三角形 从0开始 四个顶点,
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//画三角形 从0开始 四个顶点,
视频播放实践
拿到output240X128.yuv也可以使用命令制作ffmpeg -i 1.mp4 -t 10 -s 240x128 -pix_fmt yuv420p out240x128.yuv
注意几点
控件这里
qt工程文件.pro文件
需添加
QT += opengl
QT += openglextensions
代码
XVideoWidget.h文件
#ifndef XVIDEOWIDGET\_H
#define XVIDEOWIDGET\_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
#include <QGLShaderProgram>
/\*
\* //引入这个需要在pro文件添加模块
\* QT += opengl
\* QT += openglextensions
\*/
class XVideoWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
//注意Q\_OBJECT这个变量如果没有添加进来则槽函数无法调用
Q_OBJECT
public:
XVideoWidget(QWidget \*parent);
~XVideoWidget();
//从shader的yuv变量地址
GLuint unis[3] = {0};
//opengl的texture地址
GLuint texs[3] = {0};
//材质的内存空间
unsigned char \*datas[3] = {0};
//宽高度
int width = 240;
int height = 128;
protected:
//重载那三个函数
//刷新初始化
void paintGL();//具体绘制在这里面实现
//初始化gl
void initializeGL();//初始化
//窗口大小变化
void resizeGL(int width,int height);//当窗口发生变化的时候调用,这个函数
private:
QGLShaderProgram program;
};
#endif // XVIDEOWIDGET\_H
XVideoWidget.cpp文件
#include "XVideoWidget.h"
#include <QDebug>
#include <QTimer>
FILE \*fp = NULL;
//定义一个宏表示数组
#define A\_VER 3
#define T\_VER 4
//自动加双引号 定义常量串都可以使用
#define GET\_STR(x) #x
//顶点着色器的shader代码
const char \*vString = GET\_STR(
attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;//varying顶点和片元shader共享变量
void main(void)
{
gl_Position = vertexIn;//传入的顶点坐标记录
textureOut = textureIn;//传入的材质坐标保存到textureOut,从而传出去了
}
);
//片元着色器的shader代码
const char \*tString = GET\_STR(
varying vec2 textureOut;//刚刚顶点着色器算出来的坐标 共享的
uniform sampler2D tex_y;//uniform是外部传入的变量
uniform sampler2D tex_u;//sampler2D是一个2d图像
uniform sampler2D tex_v;
void main(void)
{
//420P是平面存储的,最后都是要转换为每个像素都是有yuv再方便转换
//用的是灰度图的形式存储的
//如安装那边硬解码出来的都是yuv420sp,uv是打包存在一起的,则不能使用这套shader代码了,要增加透明度存储方式。
vec3 yuv;
vec3 rgb;
//根据那个坐标把材质坐标计算出来
//传入材质,和坐标 返回材质当中的颜色rgb,但是用灰度图存储的,都是一样的。
//三个材质就可以拼出一个yuv的数据
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, -0.39465, 2.03211,
1.13983, -0.58060, 0.0) \* yuv;
gl_FragColor = vec4(rgb, 1.0);//转换成显示的颜色,再设置一下
}
);
XVideoWidget::XVideoWidget(QWidget \*parent)
:QOpenGLWidget(parent)//初始化列表调用父类构造方法调用paint画出OpenGLWidget
{
int a = 1;
}
XVideoWidget::~XVideoWidget()
{
}
//刷新初始化,每次移动都会调用一次,进行刷新
void XVideoWidget::paintGL()
{
if(feof(fp))
{
fseek(fp, 0, SEEK\_SET);
}
fread(datas[0],1,width\*height, fp);
fread(datas[1], 1, width\*height/4, fp);
fread(datas[2], 1, width\*height/4, fp);
//在显卡中创建材质 并绑定到了0层渲染材质
glActiveTexture(GL_TEXTURE0);//激活第0层
glBindTexture(GL_TEXTURE_2D, texs[0]);//把0层绑定Y材质
//修改材质(复制内存内存)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, datas[0]);
//与shader uni变量关联起来
glUniform1i(unis[0], 0);
glActiveTexture(GL_TEXTURE0+1);//激活第1层
glBindTexture(GL_TEXTURE_2D, texs[1]);//把1层绑定Y材质
//修改材质(复制内存内存)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[1]);
//与shader uni变量关联起来
glUniform1i(unis[1], 1);
glActiveTexture(GL_TEXTURE0+2);//激活第0层
glBindTexture(GL_TEXTURE_2D, texs[2]);//把0层绑定Y材质
//修改材质(复制内存内存)
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width/2, height/2, GL_RED, GL_UNSIGNED_BYTE, datas[2]);
//与shader uni变量关联起来
glUniform1i(unis[2], 2);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);//画三角形 从0开始 四个顶点,
qDebug() << "paintGL";
}
//初始化gl
void XVideoWidget::initializeGL()
{
qDebug() << "initializeGL";
//初始化 opengl(QOpenGLFunctions继承过来的函数)
initializeOpenGLFunctions();
//program(opengl和qt都提供了)加载shader脚本文件 顶点shader 片元shader
// qt 提供的 QGLShaderProgram
qDebug() << "addShaderFromSourceCode :" <<program.addShaderFromSourceCode(QGLShader::Fragment,tString);//在源代码中添加好一些,从文件怕有泄露
qDebug() << "addShaderFromSourceCode :" << program.addShaderFromSourceCode(QGLShader::Vertex,vString);
//设置顶点坐标的变量
program.bindAttributeLocation("vertexIn", A_VER);//这个vertexIn变量对应的本地位置 vertexIn是顶点shader定义的 3的位置
//材质坐标
program.bindAttributeLocation("textureIn",T_VER);//下标四,等下往4的位置存
//编译shader
qDebug() << "program.link():" << program.link();
//绑定shader
qDebug() << "program.link():" << program.bind();
//传递顶点和材质坐标,
//这个坐标是在这个函数中时候,之后draw的时候还要使用的,只传入二维
static const GLfloat ver[] = {
-1.0f,-1.0f,
1.0f,-1.0f,
-1.0f, 1.0f,
1.0f,1.0f
};
static const GLfloat tex[] = {
0.0f, 1.0f,
1.0f, 1.0f,
0.0f, 0.0f,
1.0f, 0.0f
};
//将坐标写入GL当中
glVertexAttribPointer(A_VER,//索引地址
2,//表示一点顶点几个元素,
GL_FLOAT,//存放的类型,浮点数
0,
0,
ver //顶点地址
);
//顶点坐标生效
glEnableVertexAttribArray(A_VER);
//材质 就是shader准备数据
glVertexAttribPointer(T_VER,2, GL_FLOAT, 0,0,tex);
glEnableVertexAttribArray(T_VER);
//从shader当中获取材质
unis[0] = program.uniformLocation("tex\_y");
unis[1] = program.uniformLocation("tex\_u");
unis[2] = program.uniformLocation("tex\_v");
//创建材质
glGenTextures(3,texs);//创建三个对象
//分别对每个材质进行设置
//Y
glBindTexture(GL_TEXTURE_2D, texs[0]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width,height,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//width/2 height/2根据yuv420的特性来的 uv是y的四分之一
//U
glBindTexture(GL_TEXTURE_2D, texs[1]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width/2,height/2,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//V
glBindTexture(GL_TEXTURE_2D, texs[2]);//绑定2D
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);//设置属性 放大 线性差值的属性
glTexImage2D(GL_TEXTURE_2D,0,GL_RED,width/2,height/2,0,GL_RED,GL_UNSIGNED_BYTE,0);//创建材质显卡的空间 ,与内存的空间是不一样的
//分配材质的内存空间
datas[0] = new unsigned char[width\*height];
datas[1] = new unsigned char[width\*height/4];
![img](https://img-blog.csdnimg.cn/img_convert/1b6d695b2464fd6280868964bef8dc91.png)
![img](https://img-blog.csdnimg.cn/img_convert/5911e245a27c02beacc68d2b84d745e9.png)
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**
;//创建材质显卡的空间 ,与内存的空间是不一样的
//分配材质的内存空间
datas[0] = new unsigned char[width\*height];
datas[1] = new unsigned char[width\*height/4];
[外链图片转存中...(img-miSUiS2O-1715872326565)]
[外链图片转存中...(img-vJypu8te-1715872326565)]
**既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,涵盖了95%以上物联网嵌入式知识点,真正体系化!**
**由于文件比较多,这里只是将部分目录截图出来,全套包含大厂面经、学习笔记、源码讲义、实战项目、大纲路线、电子书籍、讲解视频,并且后续会持续更新**
**需要这些体系化资料的朋友,可以加我V获取:vip1024c (备注嵌入式)**
**[如果你需要这些资料,可以戳这里获取](https://bbs.csdn.net/topics/618679757)**