-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcqopengldisplay.cpp
More file actions
234 lines (213 loc) · 7.9 KB
/
cqopengldisplay.cpp
File metadata and controls
234 lines (213 loc) · 7.9 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
#include <QOpenGLTexture>
#include <QOpenGLBuffer>
#include <QMouseEvent>
#include "cqopengldisplay.h"
CQOpenGLDisplay::CQOpenGLDisplay(QWidget *disParent):QOpenGLWidget(disParent)
{
textureUniformY = 0;
textureUniformU = 0;
textureUniformV = 0;
id_y = 0;
id_u = 0;
id_v = 0;
m_pVSHader = NULL;
m_pFSHader = NULL;
m_pShaderProgram = NULL;
m_pTextureY = NULL;
m_pTextureU = NULL;
m_pTextureV = NULL;
m_nVideoH = 0;
m_nVideoW = 0;
paintFlag = false;
}
CQOpenGLDisplay::~CQOpenGLDisplay()
{
if (m_pVSHader)
{
delete(m_pVSHader);
}
if (m_pFSHader)
{
delete(m_pFSHader);
}
if (m_pShaderProgram)
{
delete(m_pShaderProgram);
}
if (m_pTextureY)
{
delete(m_pTextureY);
}
if (m_pTextureU)
{
delete(m_pTextureU);
}
if (m_pTextureV)
{
delete(m_pTextureV);
}
}
void CQOpenGLDisplay::openGLVideoPlayer(uchar * y_data,uchar *u_data, uchar *v_data,int width,int height)
{
m_pBufYuv[0] = y_data;//Y
m_pBufYuv[1] = u_data;//U
m_pBufYuv[2] = v_data;//V
m_nVideoW = width;
m_nVideoH = height;
//刷新界面,触发paintGL接口
update();
}
void CQOpenGLDisplay::initializeGL()
{
initializeOpenGLFunctions();
glEnable(GL_DEPTH_TEST);
//现代opengl渲染管线依赖着色器来处理传入的数据
//着色器:就是使用openGL着色语言(OpenGL Shading Language, GLSL)编写的一个小函数,
// GLSL是构成所有OpenGL着色器的语言,具体的GLSL语言的语法需要读者查找相关资料
//初始化顶点着色器 对象
m_pVSHader = new QOpenGLShader(QOpenGLShader::Vertex, this);
//顶点着色器源码
const char *vsrc = "attribute vec4 vertexIn; \
attribute vec2 textureIn; \
varying vec2 textureOut; \
void main(void) \
{ \
gl_Position = vertexIn; \
textureOut = textureIn; \
}";
//编译顶点着色器程序
bool bCompile = m_pVSHader->compileSourceCode(vsrc);
if(!bCompile)
{
}
//初始化片段着色器 功能gpu中yuv转换成rgb
m_pFSHader = new QOpenGLShader(QOpenGLShader::Fragment, this);
//片段着色器源码
const char *fsrc = "varying highp vec2 textureOut; \
uniform sampler2D tex_y; \
uniform sampler2D tex_u; \
uniform sampler2D tex_v; \
void main(void) \
{ \
highp vec3 yuv; \
highp 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); \
}";
//将glsl源码送入编译器编译着色器程序
bCompile = m_pFSHader->compileSourceCode(fsrc);
if(!bCompile)
{
}
#define PROGRAM_VERTEX_ATTRIBUTE 0
#define PROGRAM_TEXCOORD_ATTRIBUTE 1
//创建着色器程序容器
m_pShaderProgram = new QOpenGLShaderProgram;
//将片段着色器添加到程序容器
m_pShaderProgram->addShader(m_pFSHader);
//将顶点着色器添加到程序容器
m_pShaderProgram->addShader(m_pVSHader);
//绑定属性vertexIn到指定位置ATTRIB_VERTEX,该属性在顶点着色源码其中有声明
m_pShaderProgram->bindAttributeLocation("vertexIn", ATTRIB_VERTEX);
//绑定属性textureIn到指定位置ATTRIB_TEXTURE,该属性在顶点着色源码其中有声明
m_pShaderProgram->bindAttributeLocation("textureIn", ATTRIB_TEXTURE);
//链接所有所有添入到的着色器程序
m_pShaderProgram->link();
//激活所有链接
m_pShaderProgram->bind();
//读取着色器中的数据变量tex_y, tex_u, tex_v的位置,这些变量的声明可以在
//片段着色器源码中可以看到
textureUniformY = m_pShaderProgram->uniformLocation("tex_y");
textureUniformU = m_pShaderProgram->uniformLocation("tex_u");
textureUniformV = m_pShaderProgram->uniformLocation("tex_v");
// 顶点矩阵
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,
};
//设置属性ATTRIB_VERTEX的顶点矩阵值以及格式
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, 0, 0, vertexVertices);
//设置属性ATTRIB_TEXTURE的纹理矩阵值以及格式
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, 0, 0, textureVertices);
//启用ATTRIB_VERTEX属性的数据,默认是关闭的
glEnableVertexAttribArray(ATTRIB_VERTEX);
//启用ATTRIB_TEXTURE属性的数据,默认是关闭的
glEnableVertexAttribArray(ATTRIB_TEXTURE);
//分别创建y,u,v纹理对象
m_pTextureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_pTextureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_pTextureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
m_pTextureY->create();
m_pTextureU->create();
m_pTextureV->create();
//获取返回y分量的纹理索引值
id_y = m_pTextureY->textureId();
//获取返回u分量的纹理索引值
id_u = m_pTextureU->textureId();
//获取返回v分量的纹理索引值
id_v = m_pTextureV->textureId();
m_pTextureY->setMagnificationFilter(QOpenGLTexture::Linear);
m_pTextureY->setMinificationFilter(QOpenGLTexture::Linear);
m_pTextureY->setWrapMode(QOpenGLTexture::ClampToEdge);
m_pTextureU->setMagnificationFilter(QOpenGLTexture::Linear);
m_pTextureU->setMinificationFilter(QOpenGLTexture::Linear);
m_pTextureU->setWrapMode(QOpenGLTexture::ClampToEdge);
m_pTextureV->setMagnificationFilter(QOpenGLTexture::Linear);
m_pTextureV->setMinificationFilter(QOpenGLTexture::Linear);
m_pTextureV->setWrapMode(QOpenGLTexture::ClampToEdge);
//glClearColor(static_cast<GLclampf>(0.15),static_cast<GLclampf>(0.27),static_cast<GLclampf>(0.35),static_cast<GLclampf>(0.5));//设置背景色80264558
//qDebug("addr=%x id_y = %d id_u=%d id_v=%d\n", this, id_y, id_u, id_v);
glClearColor(static_cast<GLclampf>(1.0),static_cast<GLclampf>(1.0),static_cast<GLclampf>(1.0),static_cast<GLclampf>(1.0));
}
void CQOpenGLDisplay::resizeGL(int w, int h)
{
if(h == 0)// 防止被零除
{
h = 1;// 将高设为1
}
//设置视口
glViewport(0,0, w,h);
}
void CQOpenGLDisplay::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//加载y数据纹理
glActiveTexture(GL_TEXTURE0);//激活纹理单元GL_TEXTURE0
//使用来自y数据生成纹理
m_pTextureY->bind();
//使用内存中m_pBufYuv数据创建真正的y数据纹理
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW, m_nVideoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv[0]);
//加载u数据纹理
glActiveTexture(GL_TEXTURE1);//激活纹理单元GL_TEXTURE1
m_pTextureU->bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv[1]);
//加载v数据纹理
glActiveTexture(GL_TEXTURE2);//激活纹理单元GL_TEXTURE2
m_pTextureV->bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv[2]);
//指定y纹理要使用新值 只能用0,1,2等表示纹理单元的索引,这是opengl不人性化的地方
//0对应纹理单元GL_TEXTURE0 1对应纹理单元GL_TEXTURE1 2对应纹理的单元GL_TEXTURE2
glUniform1i(textureUniformY, 0);
//指定u纹理要使用新值
glUniform1i(textureUniformU, 1);
//指定v纹理要使用新值
glUniform1i(textureUniformV, 2);
//使用顶点数组方式绘制图形
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
paintFlag = true;
//return;
}