From 4cbaf2dca742bfc9a1b50288e96a574e23230cb0 Mon Sep 17 00:00:00 2001
From: Barry <870709864@qq.com>
Date: Fri, 2 Nov 2018 03:12:39 +0800
Subject: [PATCH] =?UTF-8?q?=E5=AE=8C=E7=BE=8E=E6=94=AF=E6=8C=81opengl,open?=
=?UTF-8?q?gles,=E8=BD=AF=E8=A7=A3?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
src/QtScrcpy.pro | 6 +-
src/dialog.cpp | 21 +++-
src/dialog.h | 2 +
src/dialog.ui | 96 +++++++---------
src/main.cpp | 3 +-
src/qyuvopenglwidget.cpp | 239 +++++++++++++++++++++++++++++++++++++++
src/qyuvopenglwidget.h | 53 +++++++++
7 files changed, 358 insertions(+), 62 deletions(-)
create mode 100644 src/qyuvopenglwidget.cpp
create mode 100644 src/qyuvopenglwidget.h
diff --git a/src/QtScrcpy.pro b/src/QtScrcpy.pro
index 83b4096..938adb1 100644
--- a/src/QtScrcpy.pro
+++ b/src/QtScrcpy.pro
@@ -34,7 +34,8 @@ SOURCES += \
convert.cpp \
frames.cpp \
yuvglwidget.cpp \
- fpscounter.cpp
+ fpscounter.cpp \
+ qyuvopenglwidget.cpp
HEADERS += \
dialog.h \
@@ -44,7 +45,8 @@ HEADERS += \
convert.h \
frames.h \
yuvglwidget.h \
- fpscounter.h
+ fpscounter.h \
+ qyuvopenglwidget.h
FORMS += \
dialog.ui
diff --git a/src/dialog.cpp b/src/dialog.cpp
index fcb583e..5478521 100644
--- a/src/dialog.cpp
+++ b/src/dialog.cpp
@@ -5,6 +5,7 @@
#include "ui_dialog.h"
#include "adbprocess.h"
#include "yuvglwidget.h"
+#include "qyuvopenglwidget.h"
void saveAVFrame_YUV_ToTempFile(const AVFrame *pFrame)
{
@@ -38,16 +39,23 @@ void saveAVFrame_YUV_ToTempFile(const AVFrame *pFrame)
t_file.flush();
}
-
+#define OPENGL_EX
Dialog::Dialog(QWidget *parent) :
QDialog(parent),
ui(new Ui::Dialog)
{
ui->setupUi(this);
+ setWindowFlags(windowFlags()
+ | Qt::WindowMaximizeButtonHint
+ | Qt::WindowMinimizeButtonHint);
+#ifdef OPENGL_EX
+ w = new QYUVOpenGLWidget(this);
+ ui->verticalLayout->addWidget(w);
+#else
+ w2 = new YUVGLWidget(this);
+ ui->verticalLayout->addWidget(w2);
+#endif
- w2 = new YUVGLWidget(this);
- w2->resize(ui->imgLabel->size());
- w2->move(ui->imgLabel->pos());
Decoder::init();
@@ -73,8 +81,13 @@ Dialog::Dialog(QWidget *parent) :
frames.lock();
const AVFrame *frame = frames.consumeRenderedFrame();
//saveAVFrame_YUV_ToTempFile(frame);
+#ifdef OPENGL_EX
+ w->setFrameSize(QSize(frame->width, frame->height));
+ w->updateTextures(frame->data[0], frame->data[1], frame->data[2], frame->linesize[0], frame->linesize[1], frame->linesize[2]);
+#else
w2->setFrameSize(QSize(frame->width, frame->height));
w2->updateTextures(frame->data[0], frame->data[1], frame->data[2], frame->linesize[0], frame->linesize[1], frame->linesize[2]);
+#endif
frames.unLock();
},Qt::QueuedConnection);
}
diff --git a/src/dialog.h b/src/dialog.h
index 6d50357..777bdc4 100644
--- a/src/dialog.h
+++ b/src/dialog.h
@@ -12,6 +12,7 @@ class Dialog;
}
class YUVGLWidget;
+class QYUVOpenGLWidget;
class Dialog : public QDialog
{
Q_OBJECT
@@ -32,6 +33,7 @@ private:
Server* server;
Decoder decoder;
Frames frames;
+ QYUVOpenGLWidget* w;
YUVGLWidget* w2;
};
diff --git a/src/dialog.ui b/src/dialog.ui
index ec17742..1c02c34 100644
--- a/src/dialog.ui
+++ b/src/dialog.ui
@@ -13,61 +13,47 @@
Dialog
-
-
-
- 30
- 20
- 111
- 28
-
-
-
- adbProcess
-
-
-
-
-
- 160
- 20
- 111
- 28
-
-
-
- startServer
-
-
-
-
-
- 290
- 20
- 111
- 28
-
-
-
- stopServer
-
-
-
-
-
- 20
- 60
- 1051
- 621
-
-
-
- background-color: rgb(0, 0, 0);
-
-
-
-
-
+
+ -
+
+
+
+ 0
+ 50
+
+
+
+
+ 16777215
+ 50
+
+
+
+
-
+
+
+ adbProcess
+
+
+
+ -
+
+
+ startServer
+
+
+
+ -
+
+
+ stopServer
+
+
+
+
+
+
+
diff --git a/src/main.cpp b/src/main.cpp
index 5dee987..23767c6 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -7,8 +7,9 @@
int main(int argc, char *argv[])
{
- // only support AA_UseDesktopOpenGL
QApplication::setAttribute(Qt::AA_UseDesktopOpenGL);
+ //QApplication::setAttribute(Qt::AA_UseOpenGLES);
+ //QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);
QApplication a(argc, argv);
diff --git a/src/qyuvopenglwidget.cpp b/src/qyuvopenglwidget.cpp
new file mode 100644
index 0000000..6ad983d
--- /dev/null
+++ b/src/qyuvopenglwidget.cpp
@@ -0,0 +1,239 @@
+#include
+#include
+
+#include "qyuvopenglwidget.h"
+
+// 存储顶点坐标和纹理坐标
+// 存在一起缓存在vbo
+// 使用glVertexAttribPointer指定访问方式即可
+static const GLfloat coordinate[] = {
+ // 顶点坐标,存储4个xyz坐标
+ // 坐标范围为[-1,1],中心点为 0,0
+ // 二维图像z始终为0
+ // GL_TRIANGLE_STRIP的绘制方式:
+ // 使用前3个坐标绘制一个三角形,使用后三个坐标绘制一个三角形,正好为一个矩形
+ // x y z
+ -1.0f, -1.0f, 0.0f,
+ 1.0f, -1.0f, 0.0f,
+ -1.0f, 1.0f, 0.0f,
+ 1.0f, 1.0f, 0.0f,
+
+ // 纹理坐标,存储4个xy坐标
+ // 坐标范围为[0,1],左下角为 0,0
+ // TODO 为什么这个顺序指定四个顶点?顶点坐标和纹理坐标如何映射的?
+ 0.0f, 1.0f,
+ 1.0f, 1.0f,
+ 0.0f, 0.0f,
+ 1.0f, 0.0f
+};
+
+// 顶点着色器
+static const QString s_vertShader = R"(
+ attribute vec3 vertexIn; // xyz顶点坐标
+ attribute vec2 textureIn; // xy纹理坐标
+ varying vec2 textureOut; // 传递给片段着色器的纹理坐标
+ void main(void)
+ {
+ gl_Position = vec4(vertexIn, 1.0); // 1.0表示vertexIn是一个顶点位置
+ textureOut = textureIn; // 纹理坐标直接传递给片段着色器
+ }
+)";
+
+// 片段着色器
+static QString s_fragShader = R"(
+ varying vec2 textureOut; // 由顶点着色器传递过来的纹理坐标
+ uniform sampler2D textureY; // uniform 纹理单元,利用纹理单元可以使用多个纹理
+ uniform sampler2D textureU; // sampler2D是2D采样器
+ uniform sampler2D textureV; // 声明yuv三个纹理单元
+ void main(void)
+ {
+ vec3 yuv;
+ vec3 rgb;
+ // 根据指定的纹理textureY和坐标textureOut来采样
+ yuv.x = texture2D(textureY, textureOut).r;
+ yuv.y = texture2D(textureU, textureOut).r - 0.5;
+ yuv.z = texture2D(textureV, textureOut).r - 0.5;
+ // 采样完转为rgb
+ 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);
+ }
+)";
+
+QYUVOpenGLWidget::QYUVOpenGLWidget(QWidget *parent) : QOpenGLWidget(parent)
+{
+
+}
+
+QYUVOpenGLWidget::~QYUVOpenGLWidget()
+{
+ makeCurrent();
+ m_vbo.destroy();
+ deInitTextures();
+ doneCurrent();
+}
+
+QSize QYUVOpenGLWidget::minimumSizeHint() const
+{
+ return QSize(50, 50);
+}
+
+QSize QYUVOpenGLWidget::sizeHint() const
+{
+ return size();
+}
+
+void QYUVOpenGLWidget::setFrameSize(const QSize &frameSize)
+{
+ if (m_frameSize != frameSize) {
+ m_frameSize = frameSize;
+ m_needInit = true;
+ }
+}
+
+void QYUVOpenGLWidget::updateTextures(quint8 *dataY, quint8 *dataU, quint8 *dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV)
+{
+ updateTexture(m_texture[0], 0, dataY, linesizeY);
+ updateTexture(m_texture[1], 1, dataU, linesizeU);
+ updateTexture(m_texture[2], 2, dataV, linesizeV);
+ update();
+}
+
+void QYUVOpenGLWidget::initializeGL()
+{
+ initializeOpenGLFunctions();
+ glDisable(GL_DEPTH_TEST);
+
+ // 顶点缓冲对象初始化
+ m_vbo.create();
+ m_vbo.bind();
+ m_vbo.allocate(coordinate, sizeof(coordinate));
+ initShader();
+ // 设置背景清理色为黑色
+ glClearColor(0.0,0.0,0.0,0.0);
+ // 清理颜色背景
+ glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void QYUVOpenGLWidget::paintGL()
+{
+ if (m_needInit) {
+ //TODO 需要deInitTextures吗
+ initTextures();
+ m_needInit = false;
+ }
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, m_texture[0]);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, m_texture[1]);
+
+ glActiveTexture(GL_TEXTURE2);
+ glBindTexture(GL_TEXTURE_2D, m_texture[2]);
+
+ glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
+
+ // 没有画面则显示黑屏
+ //glClear(GL_COLOR_BUFFER_BIT);
+}
+
+void QYUVOpenGLWidget::resizeGL(int width, int height)
+{
+ glViewport(0, 0, width, height);
+}
+
+void QYUVOpenGLWidget::initShader()
+{
+ // opengles的float、int等要手动指定精度
+ if (QCoreApplication::testAttribute(Qt::AA_UseOpenGLES)) {
+ s_fragShader.prepend(R"(
+ precision mediump int;
+ precision mediump float;
+ )");
+ }
+ m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Vertex, s_vertShader);
+ m_shaderProgram.addShaderFromSourceCode(QOpenGLShader::Fragment, s_fragShader);
+ m_shaderProgram.link();
+ m_shaderProgram.bind();
+
+ // 指定顶点坐标在vbo中的访问方式
+ // 参数解释:顶点坐标在shader中的参数名称,顶点坐标为float,起始偏移为0,顶点坐标类型为vec3,步幅为3个float
+ m_shaderProgram.setAttributeBuffer("vertexIn", GL_FLOAT, 0, 3, 3 * sizeof(float));
+ // 启用顶点属性
+ m_shaderProgram.enableAttributeArray("vertexIn");
+
+ // 指定纹理坐标在vbo中的访问方式
+ // 参数解释:纹理坐标在shader中的参数名称,纹理坐标为float,起始偏移为12个float(跳过前面存储的12个顶点坐标),纹理坐标类型为vec2,步幅为2个float
+ m_shaderProgram.setAttributeBuffer("textureIn", GL_FLOAT, 12 * sizeof(float), 2, 2 * sizeof(float));
+ m_shaderProgram.enableAttributeArray("textureIn");
+
+ // 关联片段着色器中的纹理单元和opengl中的纹理单元(opengl一般提供16个纹理单元)
+ m_shaderProgram.setUniformValue("textureY", 0);
+ m_shaderProgram.setUniformValue("textureU", 1);
+ m_shaderProgram.setUniformValue("textureV", 2);
+}
+
+void QYUVOpenGLWidget::initTextures()
+{
+ /*
+ // 创建纹理
+ m_textrueY = new QOpenGLTexture(QOpenGLTexture::Target2D);
+ // 设置纹理缩放时的策略
+ m_textrueY->setMinificationFilter(QOpenGLTexture::Linear);
+ m_textrueY->setMagnificationFilter(QOpenGLTexture::Linear);
+ // 设置所有方向上纹理超出坐标时的显示策略(也可单个方向单独设置)
+ m_textrueY->setWrapMode(QOpenGLTexture::ClampToEdge);
+*/
+ // 创建纹理
+ glGenTextures(1, &m_texture[0]);
+ glBindTexture(GL_TEXTURE_2D, m_texture[0]);
+ // 设置纹理缩放时的策略
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // 设置st方向上纹理超出坐标时的显示策略
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width(), m_frameSize.height(), 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
+
+ glGenTextures(1, &m_texture[1]);
+ glBindTexture(GL_TEXTURE_2D, m_texture[1]);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width()/2, m_frameSize.height()/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
+
+ glGenTextures(1, &m_texture[2]);
+ glBindTexture(GL_TEXTURE_2D, m_texture[2]);
+ // 设置纹理缩放时的策略
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ // 设置st方向上纹理超出坐标时的显示策略
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, m_frameSize.width()/2, m_frameSize.height()/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL);
+
+}
+
+void QYUVOpenGLWidget::deInitTextures()
+{
+ glDeleteTextures(3, m_texture);
+ memset(m_texture, 0, 3);
+}
+
+void QYUVOpenGLWidget::updateTexture(GLuint texture, quint32 textureType, quint8 *pixels, quint32 stride)
+{
+ if (!pixels)
+ return;
+
+ QSize size = 0 == textureType ? m_frameSize : m_frameSize/2;
+
+ makeCurrent();
+ glBindTexture(GL_TEXTURE_2D, texture);
+ glPixelStorei(GL_UNPACK_ROW_LENGTH, stride);
+ glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, size.width(), size.height(), GL_RED, GL_UNSIGNED_BYTE, pixels);
+ doneCurrent();
+}
diff --git a/src/qyuvopenglwidget.h b/src/qyuvopenglwidget.h
new file mode 100644
index 0000000..bfc3fef
--- /dev/null
+++ b/src/qyuvopenglwidget.h
@@ -0,0 +1,53 @@
+#ifndef QYUVOPENGLWIDGET_H
+#define QYUVOPENGLWIDGET_H
+#include
+#include
+#include
+#include
+
+//QT_FORWARD_DECLARE_CLASS(QOpenGLTexture) //TODO先不用QOpenGLTexture,Texture先使用opengl原生方式
+class QYUVOpenGLWidget : public QOpenGLWidget, protected QOpenGLFunctions
+{
+ Q_OBJECT
+public:
+ explicit QYUVOpenGLWidget(QWidget *parent = nullptr);
+ virtual ~QYUVOpenGLWidget();
+
+ QSize minimumSizeHint() const override;
+ QSize sizeHint() const override;
+
+ void setFrameSize(const QSize& frameSize);
+ void updateTextures(quint8* dataY, quint8* dataU, quint8* dataV, quint32 linesizeY, quint32 linesizeU, quint32 linesizeV);
+
+protected:
+ void initializeGL();
+ void paintGL();
+ void resizeGL(int width, int height);
+
+private:
+ void initShader();
+ void initTextures();
+ void deInitTextures();
+ void updateTexture(GLuint texture, quint32 textureType, quint8* pixels, quint32 stride);
+
+private:
+ // 视频帧尺寸
+ QSize m_frameSize = {-1, -1};
+ bool m_needInit = false;
+
+ // 顶点缓冲对象(Vertex Buffer Objects, VBO):默认即为VertexBuffer(GL_ARRAY_BUFFER)类型
+ QOpenGLBuffer m_vbo;
+
+ // 着色器程序:编译链接着色器
+ QOpenGLShaderProgram m_shaderProgram;
+
+ // YUV纹理,用于生成纹理贴图
+ //QOpenGLTexture* m_textrueY = Q_NULLPTR;
+ //QOpenGLTexture* m_textrueU = Q_NULLPTR;
+ //QOpenGLTexture* m_textrueV = Q_NULLPTR;
+
+ // YUV纹理,用于生成纹理贴图
+ GLuint m_texture[3] = {0};
+};
+
+#endif // QYUVOPENGLWIDGET_H