summaryrefslogtreecommitdiff
path: root/src/qcam/viewfinder.cpp
blob: 3f984efbf4343aaf4826e47289a25456ead65653 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
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
/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
 * Copyright (C) 2019, Google Inc.
 *
 * viewfinder.cpp - qcam - Viewfinder
 */

#include "viewfinder.h"

#include <utility>

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

#include "format_converter.h"

ViewFinder::ViewFinder(QWidget *parent)
	: QWidget(parent), buffer_(nullptr)
{
}

ViewFinder::~ViewFinder()
{
}

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

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

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

	format_ = format;
	size_ = size;

	updateGeometry();
	return 0;
}

void ViewFinder::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 (format_ == DRM_FORMAT_ARGB8888) {
			/*
			 * 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(), QImage::Format_RGB32);
			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 ViewFinder::stop()
{
	image_ = QImage();

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

	update();
}

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

	return image_.copy();
}

void ViewFinder::paintEvent(QPaintEvent *)
{
	QPainter painter(this);
	painter.drawImage(rect(), image_, image_.rect());
}

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