[libcamera-devel] [RFC v2] [PATCH 1/1] qcam: Render YUV formats frame by OpenGL shader
Show Liu
show.liu at linaro.org
Tue May 26 09:52:03 CEST 2020
Signed-off-by: Show Liu <show.liu at linaro.org>
---
src/qcam/fshader.h | 86 ++++++++++
src/qcam/main.cpp | 2 +
src/qcam/main_window.cpp | 19 ++-
src/qcam/main_window.h | 3 +-
src/qcam/meson.build | 2 +
src/qcam/viewfinder.cpp | 18 +-
src/qcam/viewfinder.h | 23 ++-
src/qcam/viewfinderGL.cpp | 346 ++++++++++++++++++++++++++++++++++++++
src/qcam/viewfinderGL.h | 102 +++++++++++
9 files changed, 587 insertions(+), 14 deletions(-)
create mode 100644 src/qcam/fshader.h
create mode 100644 src/qcam/viewfinderGL.cpp
create mode 100644 src/qcam/viewfinderGL.h
diff --git a/src/qcam/fshader.h b/src/qcam/fshader.h
new file mode 100644
index 0000000..5769308
--- /dev/null
+++ b/src/qcam/fshader.h
@@ -0,0 +1,86 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * fshader.h - Fragment shader code
+ */
+#ifndef __FSHADER_H__
+#define __FSHADER_H__
+
+char NV_2_planes_UV[] = "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "varying vec2 textureOut;\n"
+ "uniform sampler2D tex_y;\n"
+ "uniform sampler2D tex_u;\n"
+ "void main(void)\n"
+ "{\n"
+ "vec3 yuv;\n"
+ "vec3 rgb;\n"
+ "yuv.x = texture2D(tex_y, textureOut).r - 0.0625;\n"
+ "yuv.y = texture2D(tex_u, textureOut).r - 0.5;\n"
+ "yuv.z = texture2D(tex_u, textureOut).g - 0.5;\n"
+ "rgb = mat3( 1.0, 1.0, 1.0,\n"
+ " 0.0, -0.39465, 2.03211,\n"
+ " 1.13983, -0.58060, 0.0) * yuv;\n"
+ "gl_FragColor = vec4(rgb, 1.0);\n"
+ "}\n";
+
+char NV_2_planes_VU[] = "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "varying vec2 textureOut;\n"
+ "uniform sampler2D tex_y;\n"
+ "uniform sampler2D tex_u;\n"
+ "void main(void)\n"
+ "{\n"
+ "vec3 yuv;\n"
+ "vec3 rgb;\n"
+ "yuv.x = texture2D(tex_y, textureOut).r - 0.0625;\n"
+ "yuv.y = texture2D(tex_u, textureOut).g - 0.5;\n"
+ "yuv.z = texture2D(tex_u, textureOut).r - 0.5;\n"
+ "rgb = mat3( 1.0, 1.0, 1.0,\n"
+ " 0.0, -0.39465, 2.03211,\n"
+ " 1.13983, -0.58060, 0.0) * yuv;\n"
+ "gl_FragColor = vec4(rgb, 1.0);\n"
+ "}\n";
+
+char NV_3_planes_UV[] = "#ifdef GL_ES\n"
+ "precision highp float;\n"
+ "#endif\n"
+ "varying vec2 textureOut;\n"
+ "uniform sampler2D tex_y;\n"
+ "uniform sampler2D tex_u;\n"
+ "uniform sampler2D tex_v;\n"
+ "void main(void)\n"
+ "{\n"
+ "vec3 yuv;\n"
+ "vec3 rgb;\n"
+ "yuv.x = texture2D(tex_y, textureOut).r - 0.0625;\n"
+ "yuv.y = texture2D(tex_u, textureOut).r - 0.5;\n"
+ "yuv.z = texture2D(tex_v, textureOut).g - 0.5;\n"
+ "rgb = mat3( 1, 1, 1,\n"
+ " 0, -0.39465, 2.03211,\n"
+ " 1.13983, -0.58060, 0) * yuv;\n"
+ "gl_FragColor = vec4(rgb, 1);\n"
+ "}\n";
+
+char NV_3_planes_VU[] = "precision highp float;\n"
+ "#endif\n"
+ "varying vec2 textureOut;\n"
+ "uniform sampler2D tex_y;\n"
+ "uniform sampler2D tex_u;\n"
+ "uniform sampler2D tex_v;\n"
+ "void main(void)\n"
+ "{\n"
+ "vec3 yuv;\n"
+ "vec3 rgb;\n"
+ "yuv.x = texture2D(tex_y, textureOut).r - 0.0625;\n"
+ "yuv.y = texture2D(tex_u, textureOut).g - 0.5;\n"
+ "yuv.z = texture2D(tex_v, textureOut).r - 0.5;\n"
+ "rgb = mat3( 1, 1, 1,\n"
+ " 0, -0.39465, 2.03211,\n"
+ " 1.13983, -0.58060, 0) * yuv;\n"
+ "gl_FragColor = vec4(rgb, 1);\n"
+ "}\n";
+#endif // __FSHADER_H__
diff --git a/src/qcam/main.cpp b/src/qcam/main.cpp
index b3468cb..a3ea471 100644
--- a/src/qcam/main.cpp
+++ b/src/qcam/main.cpp
@@ -35,6 +35,8 @@ OptionsParser::Options parseOptions(int argc, char *argv[])
"help");
parser.addOption(OptStream, &streamKeyValue,
"Set configuration of a camera stream", "stream", true);
+ parser.addOption(OptOpenGL, OptionNone, "Render YUV formats frame via OpenGL shader",
+ "opengl");
OptionsParser::Options options = parser.parse(argc, argv);
if (options.isSet(OptHelp))
diff --git a/src/qcam/main_window.cpp b/src/qcam/main_window.cpp
index 7de0895..a49a15a 100644
--- a/src/qcam/main_window.cpp
+++ b/src/qcam/main_window.cpp
@@ -28,6 +28,9 @@
#include <libcamera/version.h>
#include "dng_writer.h"
+#include "main_window.h"
+#include "viewfinder.h"
+#include "viewfinderGL.h"
using namespace libcamera;
@@ -65,10 +68,18 @@ MainWindow::MainWindow(CameraManager *cm, const OptionsParser::Options &options)
setWindowTitle(title_);
connect(&titleTimer_, SIGNAL(timeout()), this, SLOT(updateTitle()));
- viewfinder_ = new ViewFinder(this);
- connect(viewfinder_, &ViewFinder::renderComplete,
- this, &MainWindow::queueRequest);
- setCentralWidget(viewfinder_);
+ if (options_.isSet(OptOpenGL)) {
+ viewfinder_ = new ViewFinderGL(this);
+ connect(dynamic_cast<ViewFinderGL *>(viewfinder_), &ViewFinderGL::renderComplete,
+ this, &MainWindow::queueRequest);
+ setCentralWidget(dynamic_cast<ViewFinderGL *>(viewfinder_));
+ } else {
+ viewfinder_ = new ViewFinder(this);
+ connect(dynamic_cast<ViewFinder *>(viewfinder_), &ViewFinder::renderComplete,
+ this, &MainWindow::queueRequest);
+ setCentralWidget(dynamic_cast<ViewFinder *>(viewfinder_));
+ }
+
adjustSize();
/* Open the camera and start capture. */
diff --git a/src/qcam/main_window.h b/src/qcam/main_window.h
index 59fa2d9..2c9713c 100644
--- a/src/qcam/main_window.h
+++ b/src/qcam/main_window.h
@@ -36,6 +36,7 @@ enum {
OptCamera = 'c',
OptHelp = 'h',
OptStream = 's',
+ OptOpenGL = 'o',
};
class CaptureRequest
@@ -96,7 +97,7 @@ private:
QAction *startStopAction_;
QComboBox *cameraCombo_;
QAction *saveRaw_;
- ViewFinder *viewfinder_;
+ ViewFinderHandler *viewfinder_;
QIcon iconPlay_;
QIcon iconStop_;
diff --git a/src/qcam/meson.build b/src/qcam/meson.build
index 045db52..6a58947 100644
--- a/src/qcam/meson.build
+++ b/src/qcam/meson.build
@@ -7,11 +7,13 @@ qcam_sources = files([
'main.cpp',
'main_window.cpp',
'viewfinder.cpp',
+ 'viewfinderGL.cpp'
])
qcam_moc_headers = files([
'main_window.h',
'viewfinder.h',
+ 'viewfinderGL.h'
])
qcam_resources = files([
diff --git a/src/qcam/viewfinder.cpp b/src/qcam/viewfinder.cpp
index 0d68f62..2079e7e 100644
--- a/src/qcam/viewfinder.cpp
+++ b/src/qcam/viewfinder.cpp
@@ -31,22 +31,30 @@ static const QMap<libcamera::PixelFormat, QImage::Format> nativeFormats
{ libcamera::PixelFormat{ DRM_FORMAT_RGB888 }, QImage::Format_RGB888 },
};
-ViewFinder::ViewFinder(QWidget *parent)
- : QWidget(parent), buffer_(nullptr)
+ViewFinderHandler::ViewFinderHandler()
{
- icon_ = QIcon(":camera-off.svg");
}
-ViewFinder::~ViewFinder()
+ViewFinderHandler::~ViewFinderHandler()
{
}
-const QList<libcamera::PixelFormat> &ViewFinder::nativeFormats() const
+const QList<libcamera::PixelFormat> &ViewFinderHandler::nativeFormats() const
{
static const QList<libcamera::PixelFormat> formats = ::nativeFormats.keys();
return formats;
}
+ViewFinder::ViewFinder(QWidget *parent)
+ : QWidget(parent), buffer_(nullptr)
+{
+ icon_ = QIcon(":camera-off.svg");
+}
+
+ViewFinder::~ViewFinder()
+{
+}
+
int ViewFinder::setFormat(const libcamera::PixelFormat &format,
const QSize &size)
{
diff --git a/src/qcam/viewfinder.h b/src/qcam/viewfinder.h
index b3f1d25..3d0d725 100644
--- a/src/qcam/viewfinder.h
+++ b/src/qcam/viewfinder.h
@@ -13,6 +13,8 @@
#include <QList>
#include <QImage>
#include <QMutex>
+#include <QOpenGLWidget>
+#include <QOpenGLFunctions>
#include <QSize>
#include <QWidget>
@@ -28,7 +30,23 @@ struct MappedBuffer {
size_t size;
};
-class ViewFinder : public QWidget
+class ViewFinderHandler
+{
+public:
+ ViewFinderHandler();
+ virtual ~ViewFinderHandler();
+
+ const QList<libcamera::PixelFormat> &nativeFormats() const;
+
+ virtual int setFormat(const libcamera::PixelFormat &format, const QSize &size) =0;
+ virtual void render(libcamera::FrameBuffer *buffer, MappedBuffer *map) =0;
+ virtual void stop() =0;
+
+ virtual QImage getCurrentImage() =0;
+
+};
+
+class ViewFinder : public QWidget, public ViewFinderHandler
{
Q_OBJECT
@@ -36,8 +54,6 @@ public:
ViewFinder(QWidget *parent);
~ViewFinder();
- const QList<libcamera::PixelFormat> &nativeFormats() const;
-
int setFormat(const libcamera::PixelFormat &format, const QSize &size);
void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
void stop();
@@ -67,5 +83,4 @@ private:
QImage image_;
QMutex mutex_; /* Prevent concurrent access to image_ */
};
-
#endif /* __QCAM_VIEWFINDER__ */
diff --git a/src/qcam/viewfinderGL.cpp b/src/qcam/viewfinderGL.cpp
new file mode 100644
index 0000000..c24ccfb
--- /dev/null
+++ b/src/qcam/viewfinderGL.cpp
@@ -0,0 +1,346 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * viewfinderGL.cpp - Render YUV format frame by OpenGL shader
+ */
+#include <QImage>
+
+#include "fshader.h"
+#include "viewfinderGL.h"
+
+
+#define ATTRIB_VERTEX 0
+#define ATTRIB_TEXTURE 1
+
+ViewFinderGL::ViewFinderGL(QWidget *parent)
+ : QOpenGLWidget(parent),
+ glBuffer(QOpenGLBuffer::VertexBuffer),
+ pFShader(nullptr),
+ pVShader(nullptr),
+ textureU(QOpenGLTexture::Target2D),
+ textureV(QOpenGLTexture::Target2D),
+ textureY(QOpenGLTexture::Target2D),
+ yuvDataPtr(nullptr)
+
+{
+}
+
+ViewFinderGL::~ViewFinderGL()
+{
+ removeShader();
+
+ if(textureY.isCreated())
+ textureY.destroy();
+
+ if(textureU.isCreated())
+ textureU.destroy();
+
+ if(textureV.isCreated())
+ textureV.destroy();
+
+ glBuffer.destroy();
+}
+
+int ViewFinderGL::setFormat(const libcamera::PixelFormat &format,
+ const QSize &size)
+{
+ format_ = format;
+ size_ = size;
+
+ updateGeometry();
+ return 0;
+}
+
+void ViewFinderGL::stop()
+{
+ if (buffer_) {
+ renderComplete(buffer_);
+ buffer_ = nullptr;
+ }
+}
+
+QImage ViewFinderGL::getCurrentImage()
+{
+ QMutexLocker locker(&mutex_);
+
+ return(grabFramebuffer());
+}
+
+void ViewFinderGL::render(libcamera::FrameBuffer *buffer, MappedBuffer *map)
+{
+ if (buffer->planes().size() != 1) {
+ qWarning() << "Multi-planar buffers are not supported";
+ return;
+ }
+
+ unsigned char *memory = static_cast<unsigned char *>(map->memory);
+ if(memory) {
+ yuvDataPtr = memory;
+ update();
+ buffer_ = buffer;
+ }
+
+ if (buffer)
+ renderComplete(buffer);
+}
+
+void ViewFinderGL::updateFrame(unsigned char *buffer)
+{
+ if(buffer) {
+ yuvDataPtr = buffer;
+ update();
+ }
+}
+
+void ViewFinderGL::setFrameSize(int width, int height)
+{
+ if(width > 0 && height > 0) {
+ width_ = width;
+ height_ = height;
+ }
+}
+
+char *ViewFinderGL::selectFragmentShader(unsigned int format)
+{
+ char *fsrc = nullptr;
+
+ switch(format) {
+ case DRM_FORMAT_NV12:
+ horzSubSample_ = 2;
+ vertSubSample_ = 2;
+ fsrc = NV_2_planes_UV;
+ break;
+ case DRM_FORMAT_NV21:
+ horzSubSample_ = 2;
+ vertSubSample_ = 2;
+ fsrc = NV_2_planes_VU;
+ break;
+ case DRM_FORMAT_NV16:
+ horzSubSample_ = 2;
+ vertSubSample_ = 1;
+ fsrc = NV_2_planes_UV;
+ break;
+ case DRM_FORMAT_NV61:
+ horzSubSample_ = 2;
+ vertSubSample_ = 1;
+ fsrc = NV_2_planes_VU;
+ break;
+ case DRM_FORMAT_NV24:
+ horzSubSample_ = 1;
+ vertSubSample_ = 1;
+ fsrc = NV_2_planes_UV;
+ break;
+ case DRM_FORMAT_NV42:
+ horzSubSample_ = 1;
+ vertSubSample_ = 1;
+ fsrc = NV_2_planes_VU;
+ break;
+ case DRM_FORMAT_YUV420:
+ horzSubSample_ = 2;
+ vertSubSample_ = 2;
+ fsrc = NV_3_planes_UV;
+ break;
+ case DRM_FORMAT_YVU420:
+ horzSubSample_ = 2;
+ vertSubSample_ = 2;
+ fsrc = NV_3_planes_VU;
+ break;
+ default:
+ break;
+ };
+
+ if(fsrc == nullptr) {
+ qDebug() << __func__ << "[ERROR]:" <<" No suitable fragment shader can be select.";
+ }
+ return fsrc;
+}
+
+void ViewFinderGL::createFragmentShader()
+{
+ bool bCompile;
+
+ pFShader = new QOpenGLShader(QOpenGLShader::Fragment, this);
+ char *fsrc = selectFragmentShader(format_);
+
+ bCompile = pFShader->compileSourceCode(fsrc);
+ if(!bCompile)
+ {
+ qDebug() << __func__ << ":" << pFShader->log();
+ }
+
+ shaderProgram.addShader(pFShader);
+
+ // Link shader pipeline
+ if (!shaderProgram.link()) {
+ qDebug() << __func__ << ": shader program link failed.\n" << shaderProgram.log();
+ close();
+ }
+
+ // Bind shader pipeline for use
+ if (!shaderProgram.bind()) {
+ qDebug() << __func__ << ": shader program binding failed.\n" << shaderProgram.log();
+ close();
+ }
+
+ shaderProgram.enableAttributeArray(ATTRIB_VERTEX);
+ shaderProgram.enableAttributeArray(ATTRIB_TEXTURE);
+
+ shaderProgram.setAttributeBuffer(ATTRIB_VERTEX,GL_FLOAT,0,2,2*sizeof(GLfloat));
+ shaderProgram.setAttributeBuffer(ATTRIB_TEXTURE,GL_FLOAT,8*sizeof(GLfloat),2,2*sizeof(GLfloat));
+
+ textureUniformY = shaderProgram.uniformLocation("tex_y");
+ textureUniformU = shaderProgram.uniformLocation("tex_u");
+ textureUniformV = shaderProgram.uniformLocation("tex_v");
+
+ if(!textureY.isCreated())
+ textureY.create();
+
+ if(!textureU.isCreated())
+ textureU.create();
+
+ if(!textureV.isCreated())
+ textureV.create();
+
+ id_y = textureY.textureId();
+ id_u = textureU.textureId();
+ id_v = textureV.textureId();
+}
+
+void ViewFinderGL::configureTexture(unsigned int id)
+{
+ glBindTexture(GL_TEXTURE_2D, id);
+ 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 ViewFinderGL::removeShader()
+{
+ if (shaderProgram.isLinked()) {
+ shaderProgram.release();
+ shaderProgram.removeAllShaders();
+ }
+
+ if(pFShader)
+ delete pFShader;
+
+ if(pVShader)
+ delete pVShader;
+}
+
+void ViewFinderGL::initializeGL()
+{
+ bool bCompile;
+
+ initializeOpenGLFunctions();
+ glEnable(GL_TEXTURE_2D);
+ glDisable(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,
+ };
+
+ glBuffer.create();
+ glBuffer.bind();
+ glBuffer.allocate(vertices,sizeof(vertices));
+
+ /* Create Vertex Shader */
+ pVShader = new QOpenGLShader(QOpenGLShader::Vertex, this);
+ const char *vsrc = "attribute vec4 vertexIn;\n"
+ "attribute vec2 textureIn;\n"
+ "varying vec2 textureOut;\n"
+ "void main(void)\n"
+ "{\n"
+ "gl_Position = vertexIn;\n"
+ "textureOut = textureIn;\n"
+ "}\n";
+
+ bCompile = pVShader->compileSourceCode(vsrc);
+ if(!bCompile) {
+ qDebug() << __func__<< ":" << pVShader->log();
+ }
+
+ shaderProgram.addShader(pVShader);
+
+ glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
+}
+
+void ViewFinderGL::render()
+{
+ switch(format_) {
+ case DRM_FORMAT_NV12:
+ case DRM_FORMAT_NV21:
+ case DRM_FORMAT_NV16:
+ case DRM_FORMAT_NV61:
+ case DRM_FORMAT_NV24:
+ case DRM_FORMAT_NV42:
+ /* activate texture 0 */
+ glActiveTexture(GL_TEXTURE0);
+ configureTexture(id_y);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, size_.width(), size_.height(), 0, GL_RED, GL_UNSIGNED_BYTE, yuvDataPtr);
+ glUniform1i(textureUniformY, 0);
+
+ /* activate texture 1 */
+ glActiveTexture(GL_TEXTURE1);
+ configureTexture(id_u);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, size_.width()/horzSubSample_, size_.height()/vertSubSample_, 0, GL_RG, GL_UNSIGNED_BYTE, (char*)yuvDataPtr+size_.width()*size_.height());
+ glUniform1i(textureUniformU, 1);
+ break;
+ case DRM_FORMAT_YUV420:
+ case DRM_FORMAT_YVU420:
+ /* activate texture 0 */
+ glActiveTexture(GL_TEXTURE0);
+ configureTexture(id_y);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, size_.width(), size_.height(), 0, GL_RED, GL_UNSIGNED_BYTE, yuvDataPtr);
+ glUniform1i(textureUniformY, 0);
+
+ /* activate texture 1 */
+ glActiveTexture(GL_TEXTURE1);
+ configureTexture(id_u);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, size_.width()/horzSubSample_, size_.height()/vertSubSample_, 0, GL_RG, GL_UNSIGNED_BYTE, (char*)yuvDataPtr+size_.width()*size_.height());
+ glUniform1i(textureUniformU, 1);
+
+ /* activate texture 2 */
+ glActiveTexture(GL_TEXTURE2);
+ configureTexture(id_v);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RG, size_.width()/horzSubSample_, size_.height()/vertSubSample_, 0, GL_RG, GL_UNSIGNED_BYTE, (char*)yuvDataPtr+size_.width()*size_.height()*5/4);
+ glUniform1i(textureUniformV, 2);
+ break;
+ default:
+ break;
+ };
+}
+
+void ViewFinderGL::paintGL()
+{
+ if(pFShader == nullptr)
+ createFragmentShader();
+
+ if(yuvDataPtr)
+ {
+ glClearColor(0.0, 0.0, 0.0, 1.0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ render();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ }
+}
+
+void ViewFinderGL::resizeGL(int w, int h)
+{
+ glViewport(0,0,w,h);
+}
+
+QSize ViewFinderGL::sizeHint() const
+{
+ return size_.isValid() ? size_ : QSize(640, 480);
+}
diff --git a/src/qcam/viewfinderGL.h b/src/qcam/viewfinderGL.h
new file mode 100644
index 0000000..5366358
--- /dev/null
+++ b/src/qcam/viewfinderGL.h
@@ -0,0 +1,102 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+/*
+ * Copyright (C) 2020, Linaro
+ *
+ * viewfinderGL.h - Render YUV format frame by OpenGL shader
+ */
+#ifndef __VIEWFINDERGL_H__
+#define __VIEWFINDERGL_H__
+
+#include <fcntl.h>
+#include <linux/drm_fourcc.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <iomanip>
+#include <iostream>
+#include <sstream>
+
+#include <QImage>
+#include <QOpenGLBuffer>
+#include <QOpenGLFunctions>
+#include <QOpenGLShader>
+#include <QOpenGLShaderProgram>
+#include <QSize>
+#include <QOpenGLTexture>
+#include <QOpenGLWidget>
+
+#include <libcamera/buffer.h>
+#include <libcamera/pixelformats.h>
+#include "viewfinder.h"
+
+class ViewFinderGL : public QOpenGLWidget,
+ public ViewFinderHandler,
+ protected QOpenGLFunctions
+{
+ Q_OBJECT
+
+public:
+ ViewFinderGL(QWidget *parent = 0);
+ ~ViewFinderGL();
+
+ int setFormat(const libcamera::PixelFormat &format, const QSize &size);
+ void render(libcamera::FrameBuffer *buffer, MappedBuffer *map);
+ void stop();
+
+ QImage getCurrentImage();
+
+ void setFrameSize(int width, int height);
+ void updateFrame(unsigned char *buffer);
+
+ char *selectFragmentShader(unsigned int format);
+ void createFragmentShader();
+ void render();
+
+Q_SIGNALS:
+ void renderComplete(libcamera::FrameBuffer *buffer);
+
+protected:
+ void initializeGL() Q_DECL_OVERRIDE;
+ void paintGL() Q_DECL_OVERRIDE;
+ void resizeGL(int w, int h) Q_DECL_OVERRIDE;
+ QSize sizeHint() const override;
+
+private:
+
+ void configureTexture(unsigned int id);
+ void removeShader();
+
+ /* Captured image size, format and buffer */
+ libcamera::FrameBuffer *buffer_;
+ libcamera::PixelFormat format_;
+ QOpenGLBuffer glBuffer;
+ QSize size_;
+
+ GLuint id_u;
+ GLuint id_v;
+ GLuint id_y;
+
+ QMutex mutex_; /* Prevent concurrent access to image_ */
+
+ QOpenGLShader *pFShader;
+ QOpenGLShader *pVShader;
+ QOpenGLShaderProgram shaderProgram;
+
+ GLuint textureUniformU;
+ GLuint textureUniformV;
+ GLuint textureUniformY;
+
+ QOpenGLTexture textureU;
+ QOpenGLTexture textureV;
+ QOpenGLTexture textureY;
+
+ unsigned int width_;
+ unsigned int height_;
+
+ unsigned char* yuvDataPtr;
+
+ /* NV parameters */
+ unsigned int horzSubSample_ ;
+ unsigned int vertSubSample_;
+};
+#endif // __VIEWFINDERGL_H__
--
2.20.1
More information about the libcamera-devel
mailing list