diff --git a/src/QtScrcpy.pro b/src/QtScrcpy.pro index 1a3ed8b..a7f34ff 100644 --- a/src/QtScrcpy.pro +++ b/src/QtScrcpy.pro @@ -32,7 +32,8 @@ SOURCES += \ server.cpp \ convert.cpp \ glyuvwidget.cpp \ - frames.cpp + frames.cpp \ + yuvglwidget.cpp HEADERS += \ dialog.h \ @@ -41,7 +42,8 @@ HEADERS += \ server.h \ convert.h \ glyuvwidget.h \ - frames.h + frames.h \ + yuvglwidget.h FORMS += \ dialog.ui diff --git a/src/dialog.cpp b/src/dialog.cpp index 17ca4e1..e4e3187 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -1,8 +1,11 @@ #include "dialog.h" #include "ui_dialog.h" #include "adbprocess.h" -#include "glyuvwidget.h" +#include "glyuvwidget.h" +#include "yuvglwidget.h" + +//#define OPENGL_PLAN2 Dialog::Dialog(QWidget *parent) : QDialog(parent), @@ -10,9 +13,16 @@ Dialog::Dialog(QWidget *parent) : { ui->setupUi(this); +#ifdef OPENGL_PLAN2 + w2 = new YUVGLWidget(this); + w2->resize(ui->imgLabel->size()); + w2->move(230, 20); +#else w = new GLYuvWidget(this); w->resize(ui->imgLabel->size()); w->move(230, 20); +#endif + Decoder::init(); @@ -37,14 +47,23 @@ Dialog::Dialog(QWidget *parent) : QObject::connect(&decoder, &Decoder::newFrame, this, [this](){ frames.lock(); const AVFrame *frame = frames.consumeRenderedFrame(); - w->setVideoSize(frame->width, frame->height); - /* - if (!prepare_for_frame(screen, new_frame_size)) { - mutex_unlock(frames->mutex); - return SDL_FALSE; - } - */ - w->updateTexture(frame->data[0], frame->data[1], frame->data[2], frame->linesize[0], frame->linesize[1], frame->linesize[2]); +#ifdef OPENGL_PLAN2 + w2->setFrameSize(frame->width, frame->height); + w2->setYPixels(frame->data[0], frame->linesize[0]); + w2->setUPixels(frame->data[1], frame->linesize[1]); + w2->setVPixels(frame->data[2], frame->linesize[2]); + w2->update(); +#else + w->setVideoSize(frame->width, frame->height); + /* + if (!prepare_for_frame(screen, new_frame_size)) { + mutex_unlock(frames->mutex); + return SDL_FALSE; + } + */ + w->updateTexture(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 ef22fdf..2c3db67 100644 --- a/src/dialog.h +++ b/src/dialog.h @@ -12,6 +12,7 @@ class Dialog; } class GLYuvWidget; +class YUVGLWidget; class Dialog : public QDialog { Q_OBJECT @@ -33,6 +34,7 @@ private: Decoder decoder; Frames frames; GLYuvWidget* w; + YUVGLWidget* w2; }; #endif // DIALOG_H diff --git a/src/dialog.ui b/src/dialog.ui index 2b74cd0..bf3d1c0 100644 --- a/src/dialog.ui +++ b/src/dialog.ui @@ -6,8 +6,8 @@ 0 0 - 716 - 757 + 924 + 365 @@ -57,8 +57,8 @@ 230 20 - 451 - 701 + 651 + 301 diff --git a/src/glyuvwidget.h b/src/glyuvwidget.h index 4e9657f..352141b 100644 --- a/src/glyuvwidget.h +++ b/src/glyuvwidget.h @@ -46,8 +46,8 @@ private: GLuint m_idV = 0; // 视频宽高 - quint32 m_videoWidth = 1080; - quint32 m_videoHeight = 2160; + quint32 m_videoWidth = 2160; + quint32 m_videoHeight = 1080; quint8* m_bufferY = Q_NULLPTR; quint8* m_bufferU = Q_NULLPTR; diff --git a/src/yuvglwidget.cpp b/src/yuvglwidget.cpp new file mode 100644 index 0000000..b0d9b6f --- /dev/null +++ b/src/yuvglwidget.cpp @@ -0,0 +1,210 @@ +#include "yuvglwidget.h" + +YUVGLWidget::YUVGLWidget(QWidget *parent) : + QOpenGLWidget(parent) +{ + // 设置opengl兼容性格式为CoreProfile + QSurfaceFormat defaultFormat = QSurfaceFormat::defaultFormat(); + defaultFormat.setProfile(QSurfaceFormat::CoreProfile); + defaultFormat.setVersion(3, 3); // Adapt to your system + QSurfaceFormat::setDefaultFormat(defaultFormat); + + setFormat(defaultFormat); +} + +YUVGLWidget::~YUVGLWidget() +{ + makeCurrent(); + if (y_tex) glDeleteTextures(1, &y_tex); + if (u_tex) glDeleteTextures(1, &u_tex); + if (v_tex) glDeleteTextures(1, &v_tex); + doneCurrent(); +} + +QSize YUVGLWidget::minimumSizeHint() const +{ + return QSize(50, 50); +} + +QSize YUVGLWidget::sizeHint() const +{ + return QSize(3840, 2160); // 4k video +} + +void YUVGLWidget::setFrameSize(unsigned int width, unsigned int height) +{ + m_frameWidth = width; + m_frameHeight = height; +} + +void YUVGLWidget::initializeGL() +{ + initializeOpenGLFunctions(); + glDisable(GL_DEPTH_TEST); + + initializeTextures(); + + QString vert = R"( + #version 150 core + uniform mat4 u_pm; + uniform vec4 draw_pos; + + const vec2 verts[4] = vec2[] ( + vec2(-0.5, 0.5), + vec2(-0.5, -0.5), + vec2( 0.5, 0.5), + vec2( 0.5, -0.5) + ); + + const vec2 texcoords[4] = vec2[] ( + vec2(0.0, 1.0), + vec2(0.0, 0.0), + vec2(1.0, 1.0), + vec2(1.0, 0.0) + ); + + out vec2 v_coord; + + void main() { + vec2 vert = verts[gl_VertexID]; + vec4 p = vec4((0.5 * draw_pos.z) + draw_pos.x + (vert.x * draw_pos.z), + (0.5 * draw_pos.w) + draw_pos.y + (vert.y * draw_pos.w), + 0, 1); + gl_Position = u_pm * p; + v_coord = texcoords[gl_VertexID]; + } + )"; + + QString frag = R"( + #version 150 core + uniform sampler2D y_tex; + uniform sampler2D u_tex; + uniform sampler2D v_tex; + in vec2 v_coord; + //layout( location = 0 ) out vec4 fragcolor; + out vec4 fragcolor; + + const vec3 R_cf = vec3(1.164383, 0.000000, 1.596027); + const vec3 G_cf = vec3(1.164383, -0.391762, -0.812968); + const vec3 B_cf = vec3(1.164383, 2.017232, 0.000000); + const vec3 offset = vec3(-0.0625, -0.5, -0.5); + + void main() { + float y = texture(y_tex, v_coord).r; + float u = texture(u_tex, v_coord).r; + float v = texture(v_tex, v_coord).r; + vec3 yuv = vec3(y,u,v); + yuv += offset; + fragcolor = vec4(0.0, 0.0, 0.0, 1.0); + fragcolor.r = dot(yuv, R_cf); + fragcolor.g = dot(yuv, G_cf); + fragcolor.b = dot(yuv, B_cf); + } + )"; + // Setup shaders + m_program.addShaderFromSourceCode(QOpenGLShader::Vertex, vert); + m_program.addShaderFromSourceCode(QOpenGLShader::Fragment, frag); + +// m_program.bindAttributeLocation("y_tex", 0); +// m_program.bindAttributeLocation("u_tex", 1); +// m_program.bindAttributeLocation("v_tex", 2); + + m_program.link(); + m_program.bind(); + + m_program.setUniformValue("y_tex", 0); + m_program.setUniformValue("u_tex", 1); + m_program.setUniformValue("v_tex", 2); + + u_pos = m_program.uniformLocation("draw_pos"); + + m_vao.create(); +} + +void YUVGLWidget::paintGL() +{ + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + m_vao.bind(); + + QMatrix4x4 m; + m.ortho(0, width(), height(), 0, 0.0, 100.0f); + + m_program.setUniformValue("u_pm", m); + + glUniform4f(u_pos, 0, 0, width(), height()); + + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, y_tex); + + glActiveTexture(GL_TEXTURE1); + glBindTexture(GL_TEXTURE_2D, u_tex); + + glActiveTexture(GL_TEXTURE2); + glBindTexture(GL_TEXTURE_2D, v_tex); + + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); +} + + +void YUVGLWidget::setYPixels(uint8_t* pixels, int stride) +{ + bindPixelTexture(y_tex, YTexture, pixels, stride); +} + +void YUVGLWidget::setUPixels(uint8_t* pixels, int stride) +{ + bindPixelTexture(u_tex, UTexture, pixels, stride); +} + +void YUVGLWidget::setVPixels(uint8_t* pixels, int stride) +{ + bindPixelTexture(v_tex, VTexture, pixels, stride); +} + + +void YUVGLWidget::initializeTextures() +{ + //TODO: use FBO? + + // Setup textures + glGenTextures(1, &y_tex); + glBindTexture(GL_TEXTURE_2D, y_tex); + 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_R8, m_frameWidth, m_frameHeight, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + + glGenTextures(1, &u_tex); + glBindTexture(GL_TEXTURE_2D, u_tex); + 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_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + + glGenTextures(1, &v_tex); + glBindTexture(GL_TEXTURE_2D, v_tex); + 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_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); +} + +void YUVGLWidget::bindPixelTexture(GLuint texture, YUVGLWidget::YUVTextureType textureType, uint8_t* pixels, int stride) +{ + if (!pixels) + return; + + unsigned int const width = textureType == YTexture ? m_frameWidth : m_frameWidth/2; + unsigned int const height = textureType == YTexture ? m_frameHeight : m_frameHeight/2; + + makeCurrent(); + glBindTexture(GL_TEXTURE_2D, texture); + glPixelStorei(GL_UNPACK_ROW_LENGTH, stride); + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RED, GL_UNSIGNED_BYTE, pixels); + //glTexImage2D(GL_TEXTURE_2D, 0, GL_R8, m_frameWidth/2, m_frameHeight/2, 0, GL_RED, GL_UNSIGNED_BYTE, NULL); + doneCurrent(); +} diff --git a/src/yuvglwidget.h b/src/yuvglwidget.h new file mode 100644 index 0000000..01dace2 --- /dev/null +++ b/src/yuvglwidget.h @@ -0,0 +1,55 @@ +#ifndef YUVGLWIDGET_H +#define YUVGLWIDGET_H + +#include +#include +#include +#include +#include + +class YUVGLWidget : public QOpenGLWidget, protected QOpenGLFunctions +{ + Q_OBJECT +public: + explicit YUVGLWidget(QWidget* parent = 0); + ~YUVGLWidget(); + + QSize minimumSizeHint() const override; + QSize sizeHint() const override; + + void setFrameSize(unsigned int width, unsigned int height); + + void setYPixels(uint8_t* pixels, int stride); + void setUPixels(uint8_t* pixels, int stride); + void setVPixels(uint8_t* pixels, int stride); + +protected: + void initializeGL() override; + void paintGL() override; + //void resizeGL(int width, int height) override; + +private: + enum YUVTextureType { + YTexture, + UTexture, + VTexture + }; + + void initializeTextures(); + void bindPixelTexture(GLuint texture, YUVTextureType textureType, uint8_t* pixels, int stride); + + QOpenGLShaderProgram m_program; + QOpenGLVertexArrayObject m_vao; + + //unsigned int m_frameWidth {3840}; // 4k + //unsigned int m_frameHeight {2160}; + unsigned int m_frameWidth {2160}; + unsigned int m_frameHeight {1080}; + + GLuint y_tex {0}; + GLuint u_tex {0}; + GLuint v_tex {0}; + GLint u_pos {0}; +}; + +#endif // YUVGLWIDGET_H