添加一个qt opengl渲染yuv的例子
parent
756f205b05
commit
ab30a63304
|
@ -0,0 +1,223 @@
|
|||
|
||||
#include "CPlayWidget.h"
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLBuffer>
|
||||
#include <QMouseEvent>
|
||||
|
||||
void CPlayWidget::OnUpdateFrame()
|
||||
{
|
||||
this->PlayOneFrame();
|
||||
}
|
||||
|
||||
CPlayWidget::CPlayWidget(QWidget *parent):QOpenGLWidget(parent)
|
||||
{
|
||||
textureUniformY = 0;
|
||||
textureUniformU = 0;
|
||||
textureUniformV = 0;
|
||||
id_y = 0;
|
||||
id_u = 0;
|
||||
id_v = 0;
|
||||
m_pBufYuv420p = NULL;
|
||||
m_pVSHader = NULL;
|
||||
m_pFSHader = NULL;
|
||||
m_pShaderProgram = NULL;
|
||||
m_pTextureY = NULL;
|
||||
m_pTextureU = NULL;
|
||||
m_pTextureV = NULL;
|
||||
m_pYuvFile = NULL;
|
||||
m_nVideoH = 0;
|
||||
m_nVideoW = 0;
|
||||
connect(&this->tm,SIGNAL(timeout()),this,SLOT(OnUpdateFrame()));
|
||||
|
||||
tm.start(1000);
|
||||
}
|
||||
CPlayWidget::~CPlayWidget()
|
||||
{
|
||||
}
|
||||
void CPlayWidget::PlayOneFrame()
|
||||
{//函数功能读取一张yuv图像数据进行显示,每单击一次,就显示一张图片
|
||||
if(NULL == m_pYuvFile)
|
||||
{
|
||||
//打开yuv视频文件 注意修改文件路径
|
||||
// m_pYuvFile = fopen("F://OpenglYuvDemo//1920_1080.yuv", "rb");
|
||||
m_pYuvFile = fopen("F://md_sample_sp420_1080p.yuv", "rb");
|
||||
m_nVideoW = 1920;
|
||||
m_nVideoH = 1080;
|
||||
//根据yuv视频数据的分辨率设置宽高,demo当中是1080p,这个地方要注意跟实际数据分辨率对应上
|
||||
// m_nVideoW = 1920;
|
||||
// m_nVideoH = 1080;
|
||||
}
|
||||
//申请内存存一帧yuv图像数据,其大小为分辨率的1.5倍
|
||||
int nLen = m_nVideoW*m_nVideoH*3/2;
|
||||
if(NULL == m_pBufYuv420p)
|
||||
{
|
||||
m_pBufYuv420p = new unsigned char[nLen];
|
||||
qDebug("CPlayWidget::PlayOneFrame new data memory. Len=%d width=%d height=%d\n",
|
||||
nLen, m_nVideoW, m_nVideoW);
|
||||
}
|
||||
//将一帧yuv图像读到内存中
|
||||
if(NULL == m_pYuvFile)
|
||||
{
|
||||
qFatal("read yuv file err.may be path is wrong!\n");
|
||||
return;
|
||||
}
|
||||
fread(m_pBufYuv420p, 1, nLen, m_pYuvFile);
|
||||
//刷新界面,触发paintGL接口
|
||||
update();
|
||||
return;
|
||||
}
|
||||
void CPlayWidget::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 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); \
|
||||
}";
|
||||
//将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();
|
||||
glClearColor(0.3,0.3,0.3,0.0);//设置背景色
|
||||
//qDebug("addr=%x id_y = %d id_u=%d id_v=%d\n", this, id_y, id_u, id_v);
|
||||
}
|
||||
void CPlayWidget::resizeGL(int w, int h)
|
||||
{
|
||||
if(h == 0)// 防止被零除
|
||||
{
|
||||
h = 1;// 将高设为1
|
||||
}
|
||||
//设置视口
|
||||
glViewport(0,0, w,h);
|
||||
}
|
||||
void CPlayWidget::paintGL()
|
||||
{
|
||||
//加载y数据纹理
|
||||
//激活纹理单元GL_TEXTURE0
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
//使用来自y数据生成纹理
|
||||
glBindTexture(GL_TEXTURE_2D, id_y);
|
||||
//使用内存中m_pBufYuv420p数据创建真正的y数据纹理
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_nVideoW, m_nVideoH, 0, GL_RED, GL_UNSIGNED_BYTE, m_pBufYuv420p);
|
||||
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);
|
||||
//加载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);
|
||||
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);
|
||||
//加载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);
|
||||
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纹理要使用新值 只能用0,1,2等表示纹理单元的索引,这是opengl不人性化的地方
|
||||
//0对应纹理单元GL_TEXTURE0 1对应纹理单元GL_TEXTURE1 2对应纹理的单元
|
||||
glUniform1i(textureUniformY, 0);
|
||||
//指定u纹理要使用新值
|
||||
glUniform1i(textureUniformU, 1);
|
||||
//指定v纹理要使用新值
|
||||
glUniform1i(textureUniformV, 2);
|
||||
//使用顶点数组方式绘制图形
|
||||
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
|
||||
return;
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
#ifndef GLPLAYWIDGET_H
|
||||
#define GLPLAYWIDGET_H
|
||||
#include <QOpenGLWidget>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QOpenGLFunctions>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QFile>
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
#define ATTRIB_VERTEX 3
|
||||
#define ATTRIB_TEXTURE 4
|
||||
class CPlayWidget:public QOpenGLWidget,protected QOpenGLFunctions
|
||||
{
|
||||
Q_OBJECT
|
||||
public slots:
|
||||
void OnUpdateFrame();
|
||||
public:
|
||||
CPlayWidget(QWidget* parent);
|
||||
~CPlayWidget();
|
||||
void PlayOneFrame();
|
||||
protected:
|
||||
QTimer tm;
|
||||
void initializeGL() Q_DECL_OVERRIDE;
|
||||
void resizeGL(int w, int h) Q_DECL_OVERRIDE;
|
||||
void paintGL() Q_DECL_OVERRIDE;
|
||||
private:
|
||||
GLuint textureUniformY; //y纹理数据位置
|
||||
GLuint textureUniformU; //u纹理数据位置
|
||||
GLuint textureUniformV; //v纹理数据位置
|
||||
GLuint id_y; //y纹理对象ID
|
||||
GLuint id_u; //u纹理对象ID
|
||||
GLuint id_v; //v纹理对象ID
|
||||
QOpenGLTexture* m_pTextureY; //y纹理对象
|
||||
QOpenGLTexture* m_pTextureU; //u纹理对象
|
||||
QOpenGLTexture* m_pTextureV; //v纹理对象
|
||||
QOpenGLShader *m_pVSHader; //顶点着色器程序对象
|
||||
QOpenGLShader *m_pFSHader; //片段着色器对象
|
||||
QOpenGLShaderProgram *m_pShaderProgram; //着色器程序容器
|
||||
int m_nVideoW; //视频分辨率宽
|
||||
int m_nVideoH; //视频分辨率高
|
||||
unsigned char* m_pBufYuv420p;
|
||||
FILE* m_pYuvFile;
|
||||
};
|
||||
#endif
|
|
@ -0,0 +1,15 @@
|
|||
#include "mainwindow.h"
|
||||
#include <QApplication>
|
||||
#include "cplaywidget.h"
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
QApplication a(argc, argv);
|
||||
|
||||
CPlayWidget x(nullptr);
|
||||
x.show();
|
||||
x.PlayOneFrame();
|
||||
return a.exec();
|
||||
}
|
|
@ -0,0 +1,14 @@
|
|||
#include "mainwindow.h"
|
||||
#include "ui_mainwindow.h"
|
||||
|
||||
MainWindow::MainWindow(QWidget *parent) :
|
||||
QMainWindow(parent),
|
||||
ui(new Ui::MainWindow)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
}
|
||||
|
||||
MainWindow::~MainWindow()
|
||||
{
|
||||
delete ui;
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
#ifndef MAINWINDOW_H
|
||||
#define MAINWINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
namespace Ui {
|
||||
class MainWindow;
|
||||
}
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit MainWindow(QWidget *parent = nullptr);
|
||||
~MainWindow();
|
||||
|
||||
private:
|
||||
Ui::MainWindow *ui;
|
||||
};
|
||||
|
||||
#endif // MAINWINDOW_H
|
|
@ -0,0 +1,59 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>MainWindow</class>
|
||||
<widget class="QMainWindow" name="MainWindow">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>878</width>
|
||||
<height>732</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>MainWindow</string>
|
||||
</property>
|
||||
<widget class="QWidget" name="centralWidget">
|
||||
<widget class="CPlayWidget" name="widget" native="true">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>19</x>
|
||||
<y>20</y>
|
||||
<width>831</width>
|
||||
<height>630</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
<widget class="QMenuBar" name="menuBar">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>878</width>
|
||||
<height>23</height>
|
||||
</rect>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QToolBar" name="mainToolBar">
|
||||
<attribute name="toolBarArea">
|
||||
<enum>TopToolBarArea</enum>
|
||||
</attribute>
|
||||
<attribute name="toolBarBreak">
|
||||
<bool>false</bool>
|
||||
</attribute>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusBar"/>
|
||||
</widget>
|
||||
<layoutdefault spacing="6" margin="11"/>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>CPlayWidget</class>
|
||||
<extends>QWidget</extends>
|
||||
<header location="global">cplaywidget.h</header>
|
||||
<container>1</container>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -0,0 +1,43 @@
|
|||
#-------------------------------------------------
|
||||
#
|
||||
# Project created by QtCreator 2019-09-23T11:02:49
|
||||
#
|
||||
#-------------------------------------------------
|
||||
|
||||
QT += core gui
|
||||
|
||||
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
|
||||
|
||||
TARGET = yuvgl
|
||||
TEMPLATE = app
|
||||
|
||||
# The following define makes your compiler emit warnings if you use
|
||||
# any feature of Qt which has been marked as deprecated (the exact warnings
|
||||
# depend on your compiler). Please consult the documentation of the
|
||||
# deprecated API in order to know how to port your code away from it.
|
||||
DEFINES += QT_DEPRECATED_WARNINGS
|
||||
|
||||
# You can also make your code fail to compile if you use deprecated APIs.
|
||||
# In order to do so, uncomment the following line.
|
||||
# You can also select to disable deprecated APIs only up to a certain version of Qt.
|
||||
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
|
||||
|
||||
CONFIG += c++11
|
||||
|
||||
SOURCES += \
|
||||
main.cpp \
|
||||
mainwindow.cpp \
|
||||
cplaywidget.cpp
|
||||
|
||||
HEADERS += \
|
||||
mainwindow.h \
|
||||
cplaywidget.h \
|
||||
cplaywidget.h
|
||||
|
||||
FORMS += \
|
||||
mainwindow.ui
|
||||
|
||||
# Default rules for deployment.
|
||||
qnx: target.path = /tmp/$${TARGET}/bin
|
||||
else: unix:!android: target.path = /opt/$${TARGET}/bin
|
||||
!isEmpty(target.path): INSTALLS += target
|
Loading…
Reference in New Issue