345 lines
15 KiB
C++
345 lines
15 KiB
C++
|
#include "glyuvwidget.h"
|
|||
|
#include <QOpenGLShaderProgram>
|
|||
|
#include <QOpenGLTexture>
|
|||
|
#include <QDebug>
|
|||
|
#include "globaldata.h"
|
|||
|
|
|||
|
#define ATTRIB_VERTEX 0
|
|||
|
#define ATTRIB_TEXTURE 1
|
|||
|
// 顶点矩阵
|
|||
|
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,
|
|||
|
};
|
|||
|
|
|||
|
glyuvwidget::glyuvwidget(QWidget *parent):
|
|||
|
QOpenGLWidget(parent)
|
|||
|
{
|
|||
|
}
|
|||
|
|
|||
|
glyuvwidget::~glyuvwidget()
|
|||
|
{
|
|||
|
makeCurrent();
|
|||
|
//vbo.destroy();
|
|||
|
globalData::getInstance()->g_GLList.append(id_y);//回收纹理
|
|||
|
globalData::getInstance()->g_GLList.append(id_u);
|
|||
|
globalData::getInstance()->g_GLList.append(id_v);
|
|||
|
|
|||
|
m_pShaderProgram->disableAttributeArray(ATTRIB_VERTEX);
|
|||
|
m_pShaderProgram->disableAttributeArray(ATTRIB_TEXTURE);
|
|||
|
m_pShaderProgram->release();
|
|||
|
m_pShaderProgram->removeAllShaders();
|
|||
|
delete m_pShaderProgram;
|
|||
|
m_pShaderProgram=NULL;
|
|||
|
delete [] m_pBufYuv420p;
|
|||
|
m_pBufYuv420p=NULL;
|
|||
|
doneCurrent();
|
|||
|
}
|
|||
|
|
|||
|
void glyuvwidget::slotShowYuv(uchar *ptr, uint width, uint height)
|
|||
|
{
|
|||
|
if(NULL == ptr){
|
|||
|
//qDebug() << "-------PlayOneFrame inBuf==NULL";
|
|||
|
return;
|
|||
|
}
|
|||
|
if(NULL == m_pBufYuv420p){//如果正在运行中改变摄像头的分辨率有可能导致内存不足而奔溃
|
|||
|
// qDebug() << "-------new buf";
|
|||
|
int bufSize = 1920*1080*1.5;
|
|||
|
m_pBufYuv420p = new unsigned char[bufSize];
|
|||
|
}
|
|||
|
|
|||
|
m_nVideoW = width;
|
|||
|
m_nVideoH = height;
|
|||
|
int bufSize = m_nVideoW * m_nVideoH * 1.5;
|
|||
|
memcpy(m_pBufYuv420p,ptr, bufSize);
|
|||
|
//m_pBufYuv420p = ptr;
|
|||
|
update();
|
|||
|
}
|
|||
|
|
|||
|
void glyuvwidget::initializeGL()
|
|||
|
{
|
|||
|
//初始化OpenGL函数
|
|||
|
initializeOpenGLFunctions();
|
|||
|
glEnable(GL_DEPTH_TEST);
|
|||
|
glEnable(GL_TEXTURE_2D);
|
|||
|
//创建着色器程序容器
|
|||
|
m_pShaderProgram = new QOpenGLShaderProgram();
|
|||
|
|
|||
|
//将顶点着色器源码添加到程序容器
|
|||
|
m_pShaderProgram->addShaderFromSourceCode(QOpenGLShader::Vertex,
|
|||
|
"attribute vec4 vertexIn;"
|
|||
|
"attribute vec2 textureIn;"
|
|||
|
"varying vec2 textureOut;"
|
|||
|
"void main(void) {"
|
|||
|
"gl_Position = vertexIn;"
|
|||
|
"textureOut = textureIn;}");
|
|||
|
//将片段着色器添加到程序容器
|
|||
|
m_pShaderProgram->addShaderFromSourceCode(QOpenGLShader::Fragment,
|
|||
|
"varying lowp vec2 textureOut;"
|
|||
|
"uniform sampler2D tex_y;"
|
|||
|
"uniform sampler2D tex_u;"
|
|||
|
"uniform sampler2D tex_v;"
|
|||
|
"void main(void){"
|
|||
|
"mediump vec3 yuv;"
|
|||
|
"lowp 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);}" );
|
|||
|
|
|||
|
//绑定属性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");
|
|||
|
|
|||
|
//设置属性ATTRIB_VERTEX的顶点矩阵值以及格式
|
|||
|
glVertexAttribPointer(ATTRIB_VERTEX, 2, GL_FLOAT, GL_FALSE, 0, vertexVertices);
|
|||
|
glEnableVertexAttribArray(ATTRIB_VERTEX);
|
|||
|
//设置属性ATTRIB_TEXTURE的纹理矩阵值以及格式
|
|||
|
glVertexAttribPointer(ATTRIB_TEXTURE, 2, GL_FLOAT, GL_FALSE, 0, textureVertices);
|
|||
|
glEnableVertexAttribArray(ATTRIB_TEXTURE);
|
|||
|
|
|||
|
if(globalData::getInstance()->g_GLList.size()==0)
|
|||
|
{
|
|||
|
glGenTextures(1,&id_y); //生成纹理
|
|||
|
//qDebug()<< "生成纹理 "<<id_y;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
id_y = globalData::getInstance()->g_GLList.first();
|
|||
|
globalData::getInstance()->g_GLList.removeFirst();
|
|||
|
// glDeleteTextures(1,&id_y);
|
|||
|
|
|||
|
}
|
|||
|
glBindTexture(GL_TEXTURE_2D,id_y);//绑定纹理
|
|||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,(GLfloat)GL_LINEAR);//设置纹理参数
|
|||
|
glTexParameterf(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,(GLfloat)GL_LINEAR);
|
|||
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S,GL_CLAMP_TO_EDGE);
|
|||
|
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T,GL_CLAMP_TO_EDGE);
|
|||
|
|
|||
|
if(globalData::getInstance()->g_GLList.size()==0)
|
|||
|
{
|
|||
|
glGenTextures(1,&id_u); //生成纹理
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
id_u = globalData::getInstance()->g_GLList.first();
|
|||
|
globalData::getInstance()->g_GLList.removeFirst();
|
|||
|
// glDeleteTextures(1,&id_u);
|
|||
|
}
|
|||
|
glBindTexture(GL_TEXTURE_2D, id_u);
|
|||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_LINEAR);
|
|||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_LINEAR);
|
|||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|||
|
|
|||
|
if(globalData::getInstance()->g_GLList.size()==0)
|
|||
|
{
|
|||
|
glGenTextures(1,&id_v); //生成纹理
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
id_v = globalData::getInstance()->g_GLList.first();
|
|||
|
globalData::getInstance()->g_GLList.removeFirst();
|
|||
|
// glDeleteTextures(1,&id_v);
|
|||
|
}
|
|||
|
glBindTexture(GL_TEXTURE_2D, id_v);
|
|||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, (GLfloat)GL_LINEAR);
|
|||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, (GLfloat)GL_LINEAR);
|
|||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|||
|
|
|||
|
glClearColor(0.3f,0.3f,0.3f,0.0);//设置背景色
|
|||
|
}
|
|||
|
|
|||
|
//void glyuvwidget::initializeGL()
|
|||
|
//{
|
|||
|
// initializeOpenGLFunctions();
|
|||
|
// glEnable(GL_DEPTH_TEST);
|
|||
|
|
|||
|
// static const GLfloat vertices[]{
|
|||
|
// //顶点坐标
|
|||
|
// -1.0f,-1.0f,
|
|||
|
// -1.0f,+1.0f,
|
|||
|
// +1.0f,+1.0f,
|
|||
|
// +1.0f,-1.0f,
|
|||
|
// //纹理坐标
|
|||
|
// 0.0f,1.0f,
|
|||
|
// 0.0f,0.0f,
|
|||
|
// 1.0f,0.0f,
|
|||
|
// 1.0f,1.0f,
|
|||
|
// };
|
|||
|
|
|||
|
|
|||
|
// vbo.create();
|
|||
|
// vbo.bind();
|
|||
|
// vbo.allocate(vertices,sizeof(vertices));
|
|||
|
// //顶点着色器
|
|||
|
// QOpenGLShader *vshader = 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; \
|
|||
|
// }";
|
|||
|
// vshader->compileSourceCode(vsrc);
|
|||
|
// //片元着色器
|
|||
|
// QOpenGLShader *fshader = new QOpenGLShader(QOpenGLShader::Fragment,this);
|
|||
|
// const char *fsrc = "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, 1, 1, \
|
|||
|
// 0, -0.39465, 2.03211, \
|
|||
|
// 1.13983, -0.58060, 0) * yuv; \
|
|||
|
// gl_FragColor = vec4(rgb, 1); \
|
|||
|
// }";
|
|||
|
// fshader->compileSourceCode(fsrc);
|
|||
|
|
|||
|
// program = new QOpenGLShaderProgram(this);
|
|||
|
// program->addShader(vshader);
|
|||
|
// program->addShader(fshader);
|
|||
|
// program->bindAttributeLocation("vertexIn",VERTEXIN);
|
|||
|
// program->bindAttributeLocation("textureIn",TEXTUREIN);
|
|||
|
// program->link();
|
|||
|
// program->bind();
|
|||
|
// program->enableAttributeArray(VERTEXIN);
|
|||
|
// program->enableAttributeArray(TEXTUREIN);
|
|||
|
// program->setAttributeBuffer(VERTEXIN,GL_FLOAT,0,2,2*sizeof(GLfloat));
|
|||
|
// program->setAttributeBuffer(TEXTUREIN,GL_FLOAT,8*sizeof(GLfloat),2,2*sizeof(GLfloat));
|
|||
|
// textureUniformY = program->uniformLocation("tex_y");
|
|||
|
// textureUniformU = program->uniformLocation("tex_u");
|
|||
|
// textureUniformV = program->uniformLocation("tex_v");
|
|||
|
// textureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
// textureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
// textureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|||
|
// textureY->create();
|
|||
|
// textureU->create();
|
|||
|
// textureV->create();
|
|||
|
// idY = textureY->textureId();
|
|||
|
// idU = textureU->textureId();
|
|||
|
// idV = textureV->textureId();
|
|||
|
// // glClearColor(0.0,0.0,0.0,0.0);
|
|||
|
// glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
|||
|
// glClear(GL_COLOR_BUFFER_BIT);
|
|||
|
//}
|
|||
|
|
|||
|
void glyuvwidget::resizeGL(int w, int h)
|
|||
|
{
|
|||
|
// 计算窗口横纵比
|
|||
|
qreal aspect = qreal(w) / qreal(h ? h : 1);
|
|||
|
// 设置近平面值 3.0, 远平面值 7.0, 视场45度
|
|||
|
const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
|
|||
|
// 重设投影
|
|||
|
projection.setToIdentity();
|
|||
|
// 设置透视投影
|
|||
|
projection.perspective(fov, static_cast<float>(aspect), zNear, zFar);
|
|||
|
}
|
|||
|
|
|||
|
void glyuvwidget::paintGL()
|
|||
|
{
|
|||
|
if(NULL != m_pBufYuv420p)
|
|||
|
{
|
|||
|
//清理屏幕
|
|||
|
glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
|||
|
//加载y数据纹理
|
|||
|
glActiveTexture(GL_TEXTURE0);//激活纹理单元GL_TEXTURE0
|
|||
|
glBindTexture(GL_TEXTURE_2D, id_y);
|
|||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW, m_nVideoH, 0, GL_RED, GL_UNSIGNED_BYTE, (char*)m_pBufYuv420p);//使用内存中m_pBufYuv420p数据创建真正的y数据纹理
|
|||
|
//只能用0,1,2等表示纹理单元的索引,这是opengl不人性化的地方
|
|||
|
//0对应纹理单元GL_TEXTURE0,1对应纹理单元GL_TEXTURE1,2对应纹理的单元GL_TEXTURE2
|
|||
|
glUniform1i(textureUniformY, 0); //指定y纹理要使用新值
|
|||
|
|
|||
|
//加载u数据纹理
|
|||
|
glActiveTexture(GL_TEXTURE1);//激活纹理单元GL_TEXTURE1
|
|||
|
glBindTexture(GL_TEXTURE_2D, id_u);
|
|||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW/2, m_nVideoH/2, 0, GL_RED, GL_UNSIGNED_BYTE, (char*)m_pBufYuv420p+m_nVideoW*m_nVideoH);
|
|||
|
glUniform1i(textureUniformU, 1);//指定u纹理要使用新值
|
|||
|
|
|||
|
//加载v数据纹理
|
|||
|
glActiveTexture(GL_TEXTURE2);//激活纹理单元GL_TEXTURE2
|
|||
|
glBindTexture(GL_TEXTURE_2D, id_v);
|
|||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW/2, m_nVideoH/2, 0, GL_RED, GL_UNSIGNED_BYTE, (char*)m_pBufYuv420p+m_nVideoW*m_nVideoH*5/4);
|
|||
|
glUniform1i(textureUniformV, 2);//指定v纹理要使用新值
|
|||
|
glDisable(GL_DEPTH_TEST);//should be put before glDrawArrays
|
|||
|
//使用顶点数组方式绘制图形
|
|||
|
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
|||
|
}
|
|||
|
}
|
|||
|
//void glyuvwidget::paintGL()
|
|||
|
//{
|
|||
|
//// QMatrix4x4 m;
|
|||
|
//// m.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f );//透视矩阵随距离的变化,图形跟着变化。屏幕平面中心就是视点(摄像头),需要将图形移向屏幕里面一定距离。
|
|||
|
//// m.ortho(-2,+2,-2,+2,-10,10);//近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near)所以此处为负,表示z轴最大为10;
|
|||
|
// //远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)所以此处为正,表示z轴最小为-10;
|
|||
|
// //此时坐标中心还是在屏幕水平面中间,只是前后左右的距离已限制。
|
|||
|
// //清理屏幕
|
|||
|
// glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
|
|||
|
// glActiveTexture(GL_TEXTURE0); //激活纹理单元GL_TEXTURE0,系统里面的
|
|||
|
// glBindTexture(GL_TEXTURE_2D,idY); //绑定y分量纹理对象id到激活的纹理单元
|
|||
|
// //使用内存中的数据创建真正的y分量纹理数据
|
|||
|
// glTexImage2D(GL_TEXTURE_2D,0,GL_RED,videoW,videoH,0,GL_RED,GL_UNSIGNED_BYTE,yuvPtr);
|
|||
|
// //https://blog.csdn.net/xipiaoyouzi/article/details/53584798 纹理参数解析
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|||
|
|
|||
|
// glActiveTexture(GL_TEXTURE1); //激活纹理单元GL_TEXTURE1
|
|||
|
// glBindTexture(GL_TEXTURE_2D,idU);
|
|||
|
// //使用内存中的数据创建真正的u分量纹理数据
|
|||
|
// glTexImage2D(GL_TEXTURE_2D,0,GL_RED,videoW >> 1, videoH >> 1,0,GL_RED,GL_UNSIGNED_BYTE,yuvPtr + videoW * videoH);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|||
|
|
|||
|
// glActiveTexture(GL_TEXTURE2); //激活纹理单元GL_TEXTURE2
|
|||
|
// glBindTexture(GL_TEXTURE_2D,idV);
|
|||
|
// //使用内存中的数据创建真正的v分量纹理数据
|
|||
|
// glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, videoW >> 1, videoH >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, yuvPtr+videoW*videoH*5/4);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
|||
|
// glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
|||
|
// //指定y纹理要使用新值
|
|||
|
// glUniform1i(textureUniformY, 0);
|
|||
|
// //指定u纹理要使用新值
|
|||
|
// glUniform1i(textureUniformU, 1);
|
|||
|
// //指定v纹理要使用新值
|
|||
|
// glUniform1i(textureUniformV, 2);
|
|||
|
// //使用顶点数组方式绘制图形
|
|||
|
// glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|||
|
//}
|