summaryrefslogtreecommitdiff
path: root/src/apps
diff options
context:
space:
mode:
Diffstat (limited to 'src/apps')
-rw-r--r--src/apps/cam/camera_session.cpp30
-rw-r--r--src/apps/common/dng_writer.cpp39
-rw-r--r--src/apps/common/options.cpp8
-rw-r--r--src/apps/qcam/assets/shader/bayer_8.vert4
-rw-r--r--src/apps/qcam/assets/shader/identity.vert3
-rw-r--r--src/apps/qcam/cam_select_dialog.cpp10
-rw-r--r--src/apps/qcam/main_window.cpp10
-rw-r--r--src/apps/qcam/meson.build49
-rw-r--r--src/apps/qcam/viewfinder_gl.cpp52
-rw-r--r--src/apps/qcam/viewfinder_gl.h2
-rw-r--r--src/apps/qcam/viewfinder_qt.cpp51
-rw-r--r--src/apps/qcam/viewfinder_qt.h2
12 files changed, 164 insertions, 96 deletions
diff --git a/src/apps/cam/camera_session.cpp b/src/apps/cam/camera_session.cpp
index 097dc479..d24ecbb3 100644
--- a/src/apps/cam/camera_session.cpp
+++ b/src/apps/cam/camera_session.cpp
@@ -159,8 +159,34 @@ CameraSession::~CameraSession()
void CameraSession::listControls() const
{
for (const auto &[id, info] : camera_->controls()) {
- std::cout << "Control: " << id->name() << ": "
- << info.toString() << std::endl;
+ if (info.values().empty()) {
+ std::cout << "Control: " << id->name() << ": "
+ << info.toString() << std::endl;
+ } else {
+ std::cout << "Control: " << id->name() << ":" << std::endl;
+ for (const auto &value : info.values()) {
+ int32_t val = value.get<int32_t>();
+ const auto &it = id->enumerators().find(val);
+
+ std::cout << " - ";
+ if (it == id->enumerators().end())
+ std::cout << "UNKNOWN";
+ else
+ std::cout << it->second;
+ std::cout << " (" << val << ")" << std::endl;
+ }
+ }
+
+ if (id->isArray()) {
+ std::size_t size = id->size();
+
+ std::cout << " Size: ";
+ if (size == std::numeric_limits<std::size_t>::max())
+ std::cout << "n";
+ else
+ std::cout << std::to_string(size);
+ std::cout << std::endl;
+ }
}
}
diff --git a/src/apps/common/dng_writer.cpp b/src/apps/common/dng_writer.cpp
index 9241f23f..ac461951 100644
--- a/src/apps/common/dng_writer.cpp
+++ b/src/apps/common/dng_writer.cpp
@@ -8,8 +8,10 @@
#include "dng_writer.h"
#include <algorithm>
+#include <endian.h>
#include <iostream>
#include <map>
+#include <vector>
#include <tiffio.h>
@@ -138,29 +140,29 @@ void packScanlineRaw8(void *output, const void *input, unsigned int width)
void packScanlineRaw10(void *output, const void *input, unsigned int width)
{
- const uint16_t *in = static_cast<const uint16_t *>(input);
+ const uint8_t *in = static_cast<const uint8_t *>(input);
uint8_t *out = static_cast<uint8_t *>(output);
for (unsigned int i = 0; i < width; i += 4) {
- *out++ = (in[0] & 0x3fc) >> 2;
- *out++ = (in[0] & 0x003) << 6 | (in[1] & 0x3f0) >> 4;
- *out++ = (in[1] & 0x00f) << 4 | (in[2] & 0x3c0) >> 6;
- *out++ = (in[2] & 0x03f) << 2 | (in[3] & 0x300) >> 8;
- *out++ = (in[3] & 0x0ff);
- in += 4;
+ *out++ = in[1] << 6 | in[0] >> 2;
+ *out++ = in[0] << 6 | (in[3] & 0x03) << 4 | in[2] >> 4;
+ *out++ = in[2] << 4 | (in[5] & 0x03) << 2 | in[4] >> 6;
+ *out++ = in[4] << 2 | (in[7] & 0x03) << 0;
+ *out++ = in[6];
+ in += 8;
}
}
void packScanlineRaw12(void *output, const void *input, unsigned int width)
{
- const uint16_t *in = static_cast<const uint16_t *>(input);
+ const uint8_t *in = static_cast<const uint8_t *>(input);
uint8_t *out = static_cast<uint8_t *>(output);
for (unsigned int i = 0; i < width; i += 2) {
- *out++ = (in[0] & 0xff0) >> 4;
- *out++ = (in[0] & 0x00f) << 4 | (in[1] & 0xf00) >> 8;
- *out++ = (in[1] & 0x0ff);
- in += 2;
+ *out++ = in[1] << 4 | in[0] >> 4;
+ *out++ = in[0] << 4 | (in[3] & 0x0f);
+ *out++ = in[2];
+ in += 4;
}
}
@@ -185,7 +187,8 @@ void thumbScanlineRaw(const FormatInfo &info, void *output, const void *input,
/* Simple averaging that produces greyscale RGB values. */
for (unsigned int x = 0; x < width; x++) {
- uint16_t value = (in[0] + in[1] + in2[0] + in2[1]) >> 2;
+ uint16_t value = (le16toh(in[0]) + le16toh(in[1]) +
+ le16toh(in2[0]) + le16toh(in2[1])) >> 2;
value = value >> shift;
*out++ = value;
*out++ = value;
@@ -542,7 +545,7 @@ int DNGWriter::write(const char *filename, const Camera *camera,
* or a thumbnail scanline. The latter will always be much smaller than
* the former as we downscale by 16 in both directions.
*/
- uint8_t scanline[(config.size.width * info->bitsPerSample + 7) / 8];
+ std::vector<uint8_t> scanline((config.size.width * info->bitsPerSample + 7) / 8);
toff_t rawIFDOffset = 0;
toff_t exifIFDOffset = 0;
@@ -642,10 +645,10 @@ int DNGWriter::write(const char *filename, const Camera *camera,
/* Write the thumbnail. */
const uint8_t *row = static_cast<const uint8_t *>(data);
for (unsigned int y = 0; y < config.size.height / 16; y++) {
- info->thumbScanline(*info, &scanline, row,
+ info->thumbScanline(*info, scanline.data(), row,
config.size.width / 16, config.stride);
- if (TIFFWriteScanline(tif, &scanline, y, 0) != 1) {
+ if (TIFFWriteScanline(tif, scanline.data(), y, 0) != 1) {
std::cerr << "Failed to write thumbnail scanline"
<< std::endl;
TIFFClose(tif);
@@ -745,9 +748,9 @@ int DNGWriter::write(const char *filename, const Camera *camera,
/* Write RAW content. */
row = static_cast<const uint8_t *>(data);
for (unsigned int y = 0; y < config.size.height; y++) {
- info->packScanline(&scanline, row, config.size.width);
+ info->packScanline(scanline.data(), row, config.size.width);
- if (TIFFWriteScanline(tif, &scanline, y, 0) != 1) {
+ if (TIFFWriteScanline(tif, scanline.data(), y, 0) != 1) {
std::cerr << "Failed to write RAW scanline"
<< std::endl;
TIFFClose(tif);
diff --git a/src/apps/common/options.cpp b/src/apps/common/options.cpp
index ab19aa3d..ece268d0 100644
--- a/src/apps/common/options.cpp
+++ b/src/apps/common/options.cpp
@@ -10,6 +10,7 @@
#include <iomanip>
#include <iostream>
#include <string.h>
+#include <vector>
#include "options.h"
@@ -879,8 +880,8 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)
* Allocate short and long options arrays large enough to contain all
* options.
*/
- char shortOptions[optionsMap_.size() * 3 + 2];
- struct option longOptions[optionsMap_.size() + 1];
+ std::vector<char> shortOptions(optionsMap_.size() * 3 + 2);
+ std::vector<struct option> longOptions(optionsMap_.size() + 1);
unsigned int ids = 0;
unsigned int idl = 0;
@@ -922,7 +923,8 @@ OptionsParser::Options OptionsParser::parse(int argc, char **argv)
opterr = 0;
while (true) {
- int c = getopt_long(argc, argv, shortOptions, longOptions, nullptr);
+ int c = getopt_long(argc, argv, shortOptions.data(),
+ longOptions.data(), nullptr);
if (c == -1)
break;
diff --git a/src/apps/qcam/assets/shader/bayer_8.vert b/src/apps/qcam/assets/shader/bayer_8.vert
index 3695a5e9..fb5109ee 100644
--- a/src/apps/qcam/assets/shader/bayer_8.vert
+++ b/src/apps/qcam/assets/shader/bayer_8.vert
@@ -19,6 +19,8 @@ Copyright (C) 2021, Linaro
attribute vec4 vertexIn;
attribute vec2 textureIn;
+uniform mat4 proj_matrix;
+
uniform vec2 tex_size; /* The texture size in pixels */
uniform vec2 tex_step;
@@ -47,5 +49,5 @@ void main(void) {
yCoord = center.y + vec4(-2.0 * tex_step.y,
-tex_step.y, tex_step.y, 2.0 * tex_step.y);
- gl_Position = vertexIn;
+ gl_Position = proj_matrix * vertexIn;
}
diff --git a/src/apps/qcam/assets/shader/identity.vert b/src/apps/qcam/assets/shader/identity.vert
index 12c41377..907e8741 100644
--- a/src/apps/qcam/assets/shader/identity.vert
+++ b/src/apps/qcam/assets/shader/identity.vert
@@ -9,10 +9,11 @@ attribute vec4 vertexIn;
attribute vec2 textureIn;
varying vec2 textureOut;
+uniform mat4 proj_matrix;
uniform float stride_factor;
void main(void)
{
- gl_Position = vertexIn;
+ gl_Position = proj_matrix * vertexIn;
textureOut = vec2(textureIn.x * stride_factor, textureIn.y);
}
diff --git a/src/apps/qcam/cam_select_dialog.cpp b/src/apps/qcam/cam_select_dialog.cpp
index c51f5974..6b6d0713 100644
--- a/src/apps/qcam/cam_select_dialog.cpp
+++ b/src/apps/qcam/cam_select_dialog.cpp
@@ -15,7 +15,9 @@
#include <QComboBox>
#include <QDialogButtonBox>
#include <QFormLayout>
+#include <QGuiApplication>
#include <QLabel>
+#include <QScreen>
#include <QString>
CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManager,
@@ -53,6 +55,14 @@ CameraSelectorDialog::CameraSelectorDialog(libcamera::CameraManager *cameraManag
layout->addRow("Location:", cameraLocation_);
layout->addRow("Model:", cameraModel_);
layout->addWidget(buttonBox);
+
+ /*
+ * Decrease the minimum width of dialog to fit on narrow screens, with a
+ * 20 pixels margin.
+ */
+ QRect screenGeometry = qGuiApp->primaryScreen()->availableGeometry();
+ if (screenGeometry.width() < minimumWidth())
+ setMinimumWidth(screenGeometry.width() - 20);
}
CameraSelectorDialog::~CameraSelectorDialog() = default;
diff --git a/src/apps/qcam/main_window.cpp b/src/apps/qcam/main_window.cpp
index d515beed..dd2aa196 100644
--- a/src/apps/qcam/main_window.cpp
+++ b/src/apps/qcam/main_window.cpp
@@ -37,16 +37,6 @@
using namespace libcamera;
-#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0)
-/*
- * Qt::fixed was introduced in v5.14, and ::fixed deprecated in v5.15. Allow
- * usage of Qt::fixed unconditionally.
- */
-namespace Qt {
-constexpr auto fixed = ::fixed;
-} /* namespace Qt */
-#endif
-
/**
* \brief Custom QEvent to signal capture completion
*/
diff --git a/src/apps/qcam/meson.build b/src/apps/qcam/meson.build
index 6cf4c171..f7c14064 100644
--- a/src/apps/qcam/meson.build
+++ b/src/apps/qcam/meson.build
@@ -1,13 +1,13 @@
# SPDX-License-Identifier: CC0-1.0
-qt5 = import('qt5')
-qt5_dep = dependency('qt5',
+qt6 = import('qt6')
+qt6_dep = dependency('qt6',
method : 'pkg-config',
- modules : ['Core', 'Gui', 'Widgets'],
+ modules : ['Core', 'Gui', 'OpenGL', 'OpenGLWidgets', 'Widgets'],
required : get_option('qcam'),
- version : '>=5.4')
+ version : '>=6.2')
-if not qt5_dep.found()
+if not qt6_dep.found()
qcam_enabled = false
subdir_done()
endif
@@ -20,46 +20,31 @@ qcam_sources = files([
'main.cpp',
'main_window.cpp',
'message_handler.cpp',
+ 'viewfinder_gl.cpp',
'viewfinder_qt.cpp',
])
qcam_moc_headers = files([
'cam_select_dialog.h',
'main_window.h',
+ 'viewfinder_gl.h',
'viewfinder_qt.h',
])
qcam_resources = files([
'assets/feathericons/feathericons.qrc',
+ 'assets/shader/shaders.qrc',
])
-qt5_cpp_args = [apps_cpp_args, '-DQT_NO_KEYWORDS']
+qt6_cpp_args = [
+ apps_cpp_args,
+ '-DQT_NO_KEYWORDS',
+ '-Wno-extra-semi',
+]
-if cxx.has_header_symbol('QOpenGLWidget', 'QOpenGLWidget',
- dependencies : qt5_dep, args : '-fPIC')
- qcam_sources += files([
- 'viewfinder_gl.cpp',
- ])
- qcam_moc_headers += files([
- 'viewfinder_gl.h',
- ])
- qcam_resources += files([
- 'assets/shader/shaders.qrc'
- ])
-endif
-
-# gcc 9 introduced a deprecated-copy warning that is triggered by Qt until
-# Qt 5.13. clang 10 introduced the same warning, but detects more issues
-# that are not fixed in Qt yet. Disable the warning manually in both cases.
-if ((cc.get_id() == 'gcc' and cc.version().version_compare('>=9.0') and
- qt5_dep.version().version_compare('<5.13')) or
- (cc.get_id() == 'clang' and cc.version().version_compare('>=10.0')))
- qt5_cpp_args += ['-Wno-deprecated-copy']
-endif
-
-resources = qt5.preprocess(moc_headers : qcam_moc_headers,
+resources = qt6.preprocess(moc_headers : qcam_moc_headers,
qresources : qcam_resources,
- dependencies : qt5_dep)
+ dependencies : qt6_dep)
qcam = executable('qcam', qcam_sources, resources,
install : true,
@@ -69,6 +54,6 @@ qcam = executable('qcam', qcam_sources, resources,
libatomic,
libcamera_public,
libtiff,
- qt5_dep,
+ qt6_dep,
],
- cpp_args : qt5_cpp_args)
+ cpp_args : qt6_cpp_args)
diff --git a/src/apps/qcam/viewfinder_gl.cpp b/src/apps/qcam/viewfinder_gl.cpp
index 9d2a6960..f31956ff 100644
--- a/src/apps/qcam/viewfinder_gl.cpp
+++ b/src/apps/qcam/viewfinder_gl.cpp
@@ -12,6 +12,7 @@
#include <QByteArray>
#include <QFile>
#include <QImage>
+#include <QMatrix4x4>
#include <QStringList>
#include <libcamera/formats.h>
@@ -443,15 +444,11 @@ bool ViewFinderGL::createFragmentShader()
close();
}
- /* Bind shader pipeline for use */
- if (!shaderProgram_.bind()) {
- qWarning() << "[ViewFinderGL]:" << shaderProgram_.log();
- close();
- }
-
attributeVertex = shaderProgram_.attributeLocation("vertexIn");
attributeTexture = shaderProgram_.attributeLocation("textureIn");
+ vertexBuffer_.bind();
+
shaderProgram_.enableAttributeArray(attributeVertex);
shaderProgram_.setAttributeBuffer(attributeVertex,
GL_FLOAT,
@@ -466,6 +463,9 @@ bool ViewFinderGL::createFragmentShader()
2,
2 * sizeof(GLfloat));
+ vertexBuffer_.release();
+
+ projMatrixUniform_ = shaderProgram_.uniformLocation("proj_matrix");
textureUniformY_ = shaderProgram_.uniformLocation("tex_y");
textureUniformU_ = shaderProgram_.uniformLocation("tex_u");
textureUniformV_ = shaderProgram_.uniformLocation("tex_v");
@@ -511,7 +511,7 @@ void ViewFinderGL::initializeGL()
glEnable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
- static const GLfloat coordinates[2][4][2]{
+ const GLfloat coordinates[2][4][2]{
{
/* Vertex coordinates */
{ -1.0f, -1.0f },
@@ -535,8 +535,6 @@ void ViewFinderGL::initializeGL()
/* Create Vertex Shader */
if (!createVertexShader())
qWarning() << "[ViewFinderGL]: create vertex shader failed.";
-
- glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
}
void ViewFinderGL::doRender()
@@ -805,28 +803,42 @@ void ViewFinderGL::doRender()
shaderProgram_.setUniformValue(textureUniformStrideFactor_,
static_cast<float>(size_.width() - 1) /
(stridePixels - 1));
+
+ /*
+ * Place the viewfinder in the centre of the widget, preserving the
+ * aspect ratio of the image.
+ */
+ QMatrix4x4 projMatrix;
+ QSizeF scaledSize = size_.scaled(size(), Qt::KeepAspectRatio);
+ projMatrix.scale(scaledSize.width() / size().width(),
+ scaledSize.height() / size().height());
+
+ shaderProgram_.setUniformValue(projMatrixUniform_, projMatrix);
}
void ViewFinderGL::paintGL()
{
- if (!fragmentShader_)
+ if (!fragmentShader_) {
if (!createFragmentShader()) {
qWarning() << "[ViewFinderGL]:"
<< "create fragment shader failed.";
}
+ }
- if (image_) {
- glClearColor(0.0, 0.0, 0.0, 1.0);
- glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
-
- doRender();
- glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
+ /* Bind shader pipeline for use. */
+ if (!shaderProgram_.bind()) {
+ qWarning() << "[ViewFinderGL]:" << shaderProgram_.log();
+ close();
}
-}
-void ViewFinderGL::resizeGL(int w, int h)
-{
- glViewport(0, 0, w, h);
+ if (!image_)
+ return;
+
+ glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ doRender();
+ glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
}
QSize ViewFinderGL::sizeHint() const
diff --git a/src/apps/qcam/viewfinder_gl.h b/src/apps/qcam/viewfinder_gl.h
index 23744b41..23c657bc 100644
--- a/src/apps/qcam/viewfinder_gl.h
+++ b/src/apps/qcam/viewfinder_gl.h
@@ -51,7 +51,6 @@ Q_SIGNALS:
protected:
void initializeGL() override;
void paintGL() override;
- void resizeGL(int w, int h) override;
QSize sizeHint() const override;
private:
@@ -88,6 +87,7 @@ private:
/* Common texture parameters */
GLuint textureMinMagFilters_;
+ GLuint projMatrixUniform_;
/* YUV texture parameters */
GLuint textureUniformU_;
diff --git a/src/apps/qcam/viewfinder_qt.cpp b/src/apps/qcam/viewfinder_qt.cpp
index 4821c27d..1a238922 100644
--- a/src/apps/qcam/viewfinder_qt.cpp
+++ b/src/apps/qcam/viewfinder_qt.cpp
@@ -18,6 +18,7 @@
#include <QMap>
#include <QMutexLocker>
#include <QPainter>
+#include <QResizeEvent>
#include <QtDebug>
#include "../common/image.h"
@@ -26,23 +27,23 @@
static const QMap<libcamera::PixelFormat, QImage::Format> nativeFormats
{
-#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
{ libcamera::formats::ABGR8888, QImage::Format_RGBX8888 },
{ libcamera::formats::XBGR8888, QImage::Format_RGBX8888 },
-#endif
{ libcamera::formats::ARGB8888, QImage::Format_RGB32 },
{ libcamera::formats::XRGB8888, QImage::Format_RGB32 },
-#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
{ libcamera::formats::RGB888, QImage::Format_BGR888 },
-#endif
{ libcamera::formats::BGR888, QImage::Format_RGB888 },
{ libcamera::formats::RGB565, QImage::Format_RGB16 },
};
ViewFinderQt::ViewFinderQt(QWidget *parent)
- : QWidget(parent), buffer_(nullptr)
+ : QWidget(parent), place_(rect()), buffer_(nullptr)
{
icon_ = QIcon(":camera-off.svg");
+
+ QPalette pal = palette();
+ pal.setColor(QPalette::Window, Qt::black);
+ setPalette(pal);
}
ViewFinderQt::~ViewFinderQt()
@@ -117,6 +118,11 @@ void ViewFinderQt::render(libcamera::FrameBuffer *buffer, Image *image)
}
}
+ /*
+ * Indicate the widget paints all its pixels, to optimize rendering by
+ * skipping erasing the widget before painting.
+ */
+ setAttribute(Qt::WA_OpaquePaintEvent, true);
update();
if (buffer)
@@ -132,6 +138,11 @@ void ViewFinderQt::stop()
buffer_ = nullptr;
}
+ /*
+ * The logo has a transparent background, reenable erasing the widget
+ * before painting.
+ */
+ setAttribute(Qt::WA_OpaquePaintEvent, false);
update();
}
@@ -146,9 +157,23 @@ void ViewFinderQt::paintEvent(QPaintEvent *)
{
QPainter painter(this);
- /* If we have an image, draw it. */
+ painter.setBrush(palette().window());
+
+ /* If we have an image, draw it, with black letterbox rectangles. */
if (!image_.isNull()) {
- painter.drawImage(rect(), image_, image_.rect());
+ if (place_.width() < width()) {
+ QRect rect{ 0, 0, (width() - place_.width()) / 2, height() };
+ painter.drawRect(rect);
+ rect.moveLeft(place_.right());
+ painter.drawRect(rect);
+ } else {
+ QRect rect{ 0, 0, width(), (height() - place_.height()) / 2 };
+ painter.drawRect(rect);
+ rect.moveTop(place_.bottom());
+ painter.drawRect(rect);
+ }
+
+ painter.drawImage(place_, image_, image_.rect());
return;
}
@@ -173,7 +198,6 @@ void ViewFinderQt::paintEvent(QPaintEvent *)
else
point.setY((height() - pixmap_.height()) / 2);
- painter.setBackgroundMode(Qt::OpaqueMode);
painter.drawPixmap(point, pixmap_);
}
@@ -181,3 +205,14 @@ QSize ViewFinderQt::sizeHint() const
{
return size_.isValid() ? size_ : QSize(640, 480);
}
+
+void ViewFinderQt::resizeEvent(QResizeEvent *event)
+{
+ if (!size_.isValid())
+ return;
+
+ place_.setSize(size_.scaled(event->size(), Qt::KeepAspectRatio));
+ place_.moveCenter(rect().center());
+
+ QWidget::resizeEvent(event);
+}
diff --git a/src/apps/qcam/viewfinder_qt.h b/src/apps/qcam/viewfinder_qt.h
index 4f4b9f11..50fde88e 100644
--- a/src/apps/qcam/viewfinder_qt.h
+++ b/src/apps/qcam/viewfinder_qt.h
@@ -44,6 +44,7 @@ Q_SIGNALS:
protected:
void paintEvent(QPaintEvent *) override;
+ void resizeEvent(QResizeEvent *) override;
QSize sizeHint() const override;
private:
@@ -51,6 +52,7 @@ private:
libcamera::PixelFormat format_;
QSize size_;
+ QRect place_;
/* Camera stopped icon */
QSize vfSize_;