|
|
|
@ -0,0 +1,187 @@
|
|
|
|
|
|
|
|
#include "glyuvwidget.h"
|
|
|
|
|
|
|
|
#include <QOpenGLShaderProgram>
|
|
|
|
|
|
|
|
#include <QOpenGLTexture>
|
|
|
|
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#include <QFile>
|
|
|
|
|
|
|
|
#define VERTEXIN 0
|
|
|
|
|
|
|
|
#define TEXTUREIN 1
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLYuvWidget::GLYuvWidget(QWidget *parent):
|
|
|
|
|
|
|
|
QOpenGLWidget(parent)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
GLYuvWidget::~GLYuvWidget()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
makeCurrent();
|
|
|
|
|
|
|
|
m_vbo.destroy();
|
|
|
|
|
|
|
|
m_textureY->destroy();
|
|
|
|
|
|
|
|
m_textureU->destroy();
|
|
|
|
|
|
|
|
m_textureV->destroy();
|
|
|
|
|
|
|
|
doneCurrent();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLYuvWidget::slotShowYuv(QByteArray buffer, uint width, uint height)
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
m_videoWidth = width;
|
|
|
|
|
|
|
|
m_videoHeight = height;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
QFile *file = new QFile;
|
|
|
|
|
|
|
|
file->setFileName("android.yuv");
|
|
|
|
|
|
|
|
bool ok = file->open(QIODevice::WriteOnly | QIODevice::Append);
|
|
|
|
|
|
|
|
if(ok) {
|
|
|
|
|
|
|
|
QDataStream out(file);
|
|
|
|
|
|
|
|
//out.setVersion(QDataStream::Qt_5_7);
|
|
|
|
|
|
|
|
out << buffer;
|
|
|
|
|
|
|
|
file->close();
|
|
|
|
|
|
|
|
delete(file);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_buffer.setRawData(buffer, buffer.size());
|
|
|
|
|
|
|
|
m_yuvPtr = m_buffer.data();
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update();
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLYuvWidget::initializeGL()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
initializeOpenGLFunctions();
|
|
|
|
|
|
|
|
glDisable(GL_DEPTH_TEST); // 关闭深度缓冲测试,对于2D图形来说没用
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static const GLfloat vertices[]{
|
|
|
|
|
|
|
|
// 顶点坐标(-1.0,1.0)
|
|
|
|
|
|
|
|
-1.0f,-1.0f,
|
|
|
|
|
|
|
|
-1.0f,+1.0f,
|
|
|
|
|
|
|
|
+1.0f,+1.0f,
|
|
|
|
|
|
|
|
+1.0f,-1.0f,
|
|
|
|
|
|
|
|
// 纹理坐标(0.0,1.0)
|
|
|
|
|
|
|
|
0.0f,1.0f,
|
|
|
|
|
|
|
|
0.0f,0.0f,
|
|
|
|
|
|
|
|
1.0f,0.0f,
|
|
|
|
|
|
|
|
1.0f,1.0f,
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 初始化顶点缓冲
|
|
|
|
|
|
|
|
m_vbo.create();
|
|
|
|
|
|
|
|
m_vbo.bind();
|
|
|
|
|
|
|
|
m_vbo.allocate(vertices,sizeof(vertices));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 顶点着色器
|
|
|
|
|
|
|
|
QOpenGLShader *vShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
|
|
|
|
|
|
|
|
// 顶点着色器源码
|
|
|
|
|
|
|
|
const char *vertexSrc =
|
|
|
|
|
|
|
|
"attribute vec4 vertexIn; \
|
|
|
|
|
|
|
|
attribute vec2 textureIn; \
|
|
|
|
|
|
|
|
varying vec2 textureOut; \
|
|
|
|
|
|
|
|
void main(void) \
|
|
|
|
|
|
|
|
{ \
|
|
|
|
|
|
|
|
gl_Position = vertexIn; \
|
|
|
|
|
|
|
|
textureOut = textureIn; \
|
|
|
|
|
|
|
|
}";
|
|
|
|
|
|
|
|
vShader->compileSourceCode(vertexSrc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 片段着色器
|
|
|
|
|
|
|
|
QOpenGLShader *fShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
|
|
|
|
|
|
|
|
// 片段着色器源码
|
|
|
|
|
|
|
|
const char *fragmentSrc =
|
|
|
|
|
|
|
|
"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(fragmentSrc);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 着色器程序
|
|
|
|
|
|
|
|
m_shaderProgram = new QOpenGLShaderProgram(this);
|
|
|
|
|
|
|
|
// 添加着色器
|
|
|
|
|
|
|
|
m_shaderProgram->addShader(vShader);
|
|
|
|
|
|
|
|
m_shaderProgram->addShader(fShader);
|
|
|
|
|
|
|
|
m_shaderProgram->bindAttributeLocation("vertexIn",VERTEXIN);
|
|
|
|
|
|
|
|
m_shaderProgram->bindAttributeLocation("textureIn",TEXTUREIN);
|
|
|
|
|
|
|
|
// 链接着色器
|
|
|
|
|
|
|
|
m_shaderProgram->link();
|
|
|
|
|
|
|
|
m_shaderProgram->bind();
|
|
|
|
|
|
|
|
m_shaderProgram->enableAttributeArray(VERTEXIN);
|
|
|
|
|
|
|
|
m_shaderProgram->enableAttributeArray(TEXTUREIN);
|
|
|
|
|
|
|
|
m_shaderProgram->setAttributeBuffer(VERTEXIN, GL_FLOAT, 0, 2, 2*sizeof(GLfloat));
|
|
|
|
|
|
|
|
m_shaderProgram->setAttributeBuffer(TEXTUREIN, GL_FLOAT, 8*sizeof(GLfloat), 2, 2*sizeof(GLfloat));
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 着色器程序中取得yuv纹理位置
|
|
|
|
|
|
|
|
m_textureUniformY = m_shaderProgram->uniformLocation("tex_y");
|
|
|
|
|
|
|
|
m_textureUniformU = m_shaderProgram->uniformLocation("tex_u");
|
|
|
|
|
|
|
|
m_textureUniformV = m_shaderProgram->uniformLocation("tex_v");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
m_textureY = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
|
|
|
|
|
|
m_textureU = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
|
|
|
|
|
|
m_textureV = new QOpenGLTexture(QOpenGLTexture::Target2D);
|
|
|
|
|
|
|
|
m_textureY->create();
|
|
|
|
|
|
|
|
m_textureU->create();
|
|
|
|
|
|
|
|
m_textureV->create();
|
|
|
|
|
|
|
|
m_idY = m_textureY->textureId();
|
|
|
|
|
|
|
|
m_idU = m_textureU->textureId();
|
|
|
|
|
|
|
|
m_idV = m_textureV->textureId();
|
|
|
|
|
|
|
|
glClearColor(0.0,0.0,0.0,0.0);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLYuvWidget::inittexture()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
//QMatrix4x4 m;
|
|
|
|
|
|
|
|
//m.perspective(60.0f, 4.0f/3.0f, 0.1f, 100.0f );//透视矩阵随距离的变化,图形跟着变化。屏幕平面中心就是视点(摄像头),需要将图形移向屏幕里面一定距离。
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//近裁剪平面是一个矩形,矩形左下角点三维空间坐标是(left,bottom,-near),右上角点是(right,top,-near)所以此处为负,表示z轴最大为10;
|
|
|
|
|
|
|
|
//远裁剪平面也是一个矩形,左下角点空间坐标是(left,bottom,-far),右上角点是(right,top,-far)所以此处为正,表示z轴最小为-10;
|
|
|
|
|
|
|
|
//此时坐标中心还是在屏幕水平面中间,只是前后左右的距离已限制。
|
|
|
|
|
|
|
|
//m.ortho(-2,+2,-2,+2,-10,10);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
glActiveTexture(GL_TEXTURE0); //激活纹理单元GL_TEXTURE0,系统里面的
|
|
|
|
|
|
|
|
glBindTexture(GL_TEXTURE_2D, m_idY); //绑定y分量纹理对象id到激活的纹理单元
|
|
|
|
|
|
|
|
//使用内存中的数据创建真正的y分量纹理数据
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth, m_videoHeight, 0, GL_RED, GL_UNSIGNED_BYTE, m_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_TEXTURE1, m_idU);
|
|
|
|
|
|
|
|
//使用内存中的数据创建真正的u分量纹理数据
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D,0,GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight);
|
|
|
|
|
|
|
|
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, m_idV);
|
|
|
|
|
|
|
|
//使用内存中的数据创建真正的v分量纹理数据
|
|
|
|
|
|
|
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_videoWidth >> 1, m_videoHeight >> 1, 0, GL_RED, GL_UNSIGNED_BYTE, m_yuvPtr + m_videoWidth * m_videoHeight * 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);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void GLYuvWidget::paintGL()
|
|
|
|
|
|
|
|
{
|
|
|
|
|
|
|
|
inittexture();
|
|
|
|
|
|
|
|
//指定y纹理要使用新值
|
|
|
|
|
|
|
|
glUniform1i(m_textureUniformY, 0);
|
|
|
|
|
|
|
|
//指定u纹理要使用新值
|
|
|
|
|
|
|
|
glUniform1i(m_textureUniformU, 1);
|
|
|
|
|
|
|
|
//指定v纹理要使用新值
|
|
|
|
|
|
|
|
glUniform1i(m_textureUniformV, 2);
|
|
|
|
|
|
|
|
//使用顶点数组方式绘制图形
|
|
|
|
|
|
|
|
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
|
|
|
|
|
|
|
|
}
|