summaryrefslogtreecommitdiff
path: root/utils/raspberrypi/delayedctrls_parse.py
AgeCommit message (Collapse)Author
2022-09-30utils: raspberrypi: Add missing SPDX header to delayedctrls_parse.pyLaurent Pinchart
The delayedctrls_parse.py script is missing license information. Add an SPDX header to fix it. Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Reviewed-by: Naushir Patuck <naush@raspberrypi.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> Reviewed-by: Jacopo Mondi <jacopo@jmondi.org>
2021-03-12utils: raspberrypi: Add a DelayedControls log parserNaushir Patuck
This script will parse log output from the DelayedControls helper, when enabled with: LIBCAMERA_LOG_LEVELS=DelayedControls:0 It tabulates all control queuing/writing/getting per frame and warns about potential issues related to frame delays not being account for, or writes that are lagging behind or missed. Run with the following command: python3 ./delayedctrls_parse.py <logfile> Signed-off-by: Naushir Patuck <naush@raspberrypi.com> Tested-by: David Plowman <david.plowman@raspberrypi.com> Acked-by: Paul Elder <paul.elder@ideasonboard.com> Tested-by: Jean-Michel Hautbois <jeanmichel.hautbois@ideasonboard.com> Reviewed-by: Kieran Bingham <kieran.bingham@ideasonboard.com> [Kieran: Fix python raw strings] Signed-off-by: Kieran Bingham <kieran.bingham@ideasonboard.com>
a> 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * viewfinder_qt.cpp - qcam - QPainter-based ViewFinder
 */

#include "viewfinder_qt.h"

#include <stdint.h>
#include <utility>

#include <QImage>
#include <QImageWriter>
#include <QMap>
#include <QMutexLocker>
#include <QPainter>
#include <QtDebug>

#include <libcamera/formats.h>

#include "format_converter.h"

static const QMap<libcamera::PixelFormat, QImage::Format> nativeFormats
{
#if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0)
	{ libcamera::formats::ABGR8888, QImage::Format_RGBA8888 },
#endif
	{ libcamera::formats::ARGB8888, 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 },
};

ViewFinderQt::ViewFinderQt(QWidget *parent)
	: QWidget(parent), buffer_(nullptr)
{
	icon_ = QIcon(":camera-off.svg");
}

ViewFinderQt::~ViewFinderQt()
{
}

const QList<libcamera::PixelFormat> &ViewFinderQt::nativeFormats() const
{
	static const QList<libcamera::PixelFormat> formats = ::nativeFormats.keys();
	return formats;
}

int ViewFinderQt::setFormat(const libcamera::PixelFormat &format,
			    const QSize &size)
{
	image_ = QImage();

	/*
	 * If format conversion is needed, configure the converter and allocate
	 * the destination image.
	 */
	if (!::nativeFormats.contains(format)) {
		int ret = converter_.configure(format, size);
		if (ret < 0)
			return ret;

		image_ = QImage(size, QImage::Format_RGB32);

		qInfo() << "Using software format conversion from"
			<< format.toString().c_str();
	} else {
		qInfo() << "Zero-copy enabled";
	}

	format_ = format;
	size_ = size;

	updateGeometry();
	return 0;
}

void ViewFinderQt::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);
	size_t size = buffer->metadata().planes[0].bytesused;

	{
		QMutexLocker locker(&mutex_);

		if (::nativeFormats.contains(format_)) {
			/*
			 * If the frame format is identical to the display
			 * format, create a QImage that references the frame
			 * and store a reference to the frame buffer. The
			 * previously stored frame buffer, if any, will be
			 * released.
			 *
			 * \todo Get the stride from the buffer instead of
			 * computing it naively
			 */
			image_ = QImage(memory, size_.width(), size_.height(),
					size / size_.height(),
					::nativeFormats[format_]);
			std::swap(buffer, buffer_);
		} else {
			/*
			 * Otherwise, convert the format and release the frame
			 * buffer immediately.
			 */
			converter_.convert(memory, size, &image_);
		}
	}

	update();

	if (buffer)
		renderComplete(buffer);
}

void ViewFinderQt::stop()
{
	image_ = QImage();

	if (buffer_) {
		renderComplete(buffer_);
		buffer_ = nullptr;
	}

	update();
}

QImage ViewFinderQt::getCurrentImage()
{
	QMutexLocker locker(&mutex_);

	return image_.copy();
}

void ViewFinderQt::paintEvent(QPaintEvent *)
{
	QPainter painter(this);

	/* If we have an image, draw it. */
	if (!image_.isNull()) {
		painter.drawImage(rect(), image_, image_.rect());
		return;
	}

	/*
	 * Otherwise, draw the camera stopped icon. Render it to the pixmap if
	 * the size has changed.
	 */
	constexpr int margin = 20;

	if (vfSize_ != size() || pixmap_.isNull()) {
		QSize vfSize = size() - QSize{ 2 * margin, 2 * margin };
		QSize pixmapSize{ 1, 1 };
		pixmapSize.scale(vfSize, Qt::KeepAspectRatio);
		pixmap_ = icon_.pixmap(pixmapSize);

		vfSize_ = size();
	}

	QPoint point{ margin, margin };
	if (pixmap_.width() < width() - 2 * margin)
		point.setX((width() - pixmap_.width()) / 2);
	else
		point.setY((height() - pixmap_.height()) / 2);

	painter.setBackgroundMode(Qt::OpaqueMode);
	painter.drawPixmap(point, pixmap_);
}

QSize ViewFinderQt::sizeHint() const
{
	return size_.isValid() ? size_ : QSize(640, 480);
}