Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qqnxplatformcamera.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 Research In Motion
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#undef QT_NO_CONTEXTLESS_CONNECT // Remove after porting connect() calls
5
10
11#include <qcameradevice.h>
12#include <qmediadevices.h>
13
14#include <private/qmediastoragelocation_p.h>
15#include <private/qvideoframe_p.h>
16
17#include <camera/camera_api.h>
18#include <camera/camera_3a.h>
19
20#include <algorithm>
21#include <array>
22
23#include <dlfcn.h>
24
30
31constexpr std::array<FocusModeMapping, 6> focusModes {{
32 { QCamera::FocusModeAuto, CAMERA_FOCUSMODE_CONTINUOUS_AUTO },
33 { QCamera::FocusModeAutoFar, CAMERA_FOCUSMODE_CONTINUOUS_AUTO },
34 { QCamera::FocusModeInfinity, CAMERA_FOCUSMODE_CONTINUOUS_AUTO },
35 { QCamera::FocusModeAutoNear, CAMERA_FOCUSMODE_CONTINUOUS_MACRO },
36 { QCamera::FocusModeHyperfocal, CAMERA_FOCUSMODE_EDOF },
37 { QCamera::FocusModeManual, CAMERA_FOCUSMODE_MANUAL },
38}};
39
40template <typename Mapping, typename From, typename To, size_t N>
41static constexpr To convert(const std::array<Mapping, N> &mapping,
42 From Mapping::* from, To Mapping::* to, From value, To defaultValue)
43{
44 for (const Mapping &m : mapping) {
45 const auto fromValue = m.*from;
46 const auto toValue = m.*to;
47
48 if (value == fromValue)
49 return toValue;
50 }
51
52 return defaultValue;
53}
54
55static constexpr camera_focusmode_t qnxFocusMode(QCamera::FocusMode mode)
56{
57 return convert(focusModes, &FocusModeMapping::qt,
58 &FocusModeMapping::qnx, mode, CAMERA_FOCUSMODE_CONTINUOUS_AUTO);
59}
60
61static constexpr QCamera::FocusMode qtFocusMode(camera_focusmode_t mode)
62{
63 return convert(focusModes, &FocusModeMapping::qnx,
64 &FocusModeMapping::qt, mode, QCamera::FocusModeAuto);
65}
66
67QT_BEGIN_NAMESPACE
68
69QQnxPlatformCamera::QQnxPlatformCamera(QCamera *parent)
70 : QPlatformCamera(parent)
71{
72 if (parent)
73 setCamera(parent->cameraDevice());
74 else
75 setCamera(QMediaDevices::defaultVideoInput());
76}
77
82
84{
85 return m_qnxCamera && m_qnxCamera->isActive();
86}
87
88void QQnxPlatformCamera::setActive(bool active)
89{
90 if (active)
91 start();
92 else
93 stop();
94}
95
97{
98 if (!m_qnxCamera || isActive())
99 return;
100
101 if (m_session)
102 m_videoSink = m_session->videoSink();
103
104 m_qnxCamera->start();
105
106 Q_EMIT activeChanged(true);
107}
108
110{
111 if (!m_qnxCamera)
112 return;
113
114 m_qnxCamera->stop();
115
116 m_videoSink = nullptr;
117
118 Q_EMIT activeChanged(false);
119}
120
121void QQnxPlatformCamera::setCamera(const QCameraDevice &camera)
122{
123 if (m_cameraDevice == camera)
124 return;
125
126 const auto cameraUnit = static_cast<camera_unit_t>(camera.id().toUInt());
127
128 m_qnxCamera = std::make_unique<QQnxCamera>(cameraUnit);
129
130 connect(m_qnxCamera.get(), &QQnxCamera::focusModeChanged,
131 [this](camera_focusmode_t mode) { Q_EMIT focusModeChanged(qtFocusMode(mode)); });
132 connect(m_qnxCamera.get(), &QQnxCamera::customFocusPointChanged,
133 this, &QQnxPlatformCamera::customFocusPointChanged);
134 connect(m_qnxCamera.get(), &QQnxCamera::frameAvailable,
135 this, &QQnxPlatformCamera::onFrameAvailable, Qt::QueuedConnection);
136
137 m_cameraDevice = camera;
138
139 updateCameraFeatures();
140}
141
142bool QQnxPlatformCamera::setCameraFormat(const QCameraFormat &format)
143{
144 const QSize resolution = format.resolution();
145
146 if (resolution.isEmpty()) {
147 qWarning("QQnxPlatformCamera: invalid resolution requested");
148 return false;
149 }
150
151 return m_qnxCamera->setCameraFormat(resolution.width(),
152 resolution.height(), format.maxFrameRate());
153}
154
155void QQnxPlatformCamera::setCaptureSession(QPlatformMediaCaptureSession *session)
156{
157 if (m_session == session)
158 return;
159
160 m_session = static_cast<QQnxMediaCaptureSession *>(session);
161}
162
163bool QQnxPlatformCamera::isFocusModeSupported(QCamera::FocusMode mode) const
164{
165 if (!m_qnxCamera)
166 return false;
167
168 return m_qnxCamera->supportedFocusModes().contains(::qnxFocusMode(mode));
169}
170
171void QQnxPlatformCamera::setFocusMode(QCamera::FocusMode mode)
172{
173 if (!m_qnxCamera)
174 return;
175
176 m_qnxCamera->setFocusMode(::qnxFocusMode(mode));
177}
178
179void QQnxPlatformCamera::setCustomFocusPoint(const QPointF &point)
180{
181 if (!m_qnxCamera)
182 return;
183
184 m_qnxCamera->setCustomFocusPoint(point);
185}
186
188{
189 if (!m_qnxCamera)
190 return;
191
192 const int maxDistance = m_qnxCamera->maxFocusStep();
193
194 if (maxDistance < 0)
195 return;
196
197 const int qnxDistance = maxDistance * std::min(distance, 1.0f);
198
199 m_qnxCamera->setManualFocusStep(qnxDistance);
200}
201
202void QQnxPlatformCamera::zoomTo(float factor, float)
203{
204 if (!m_qnxCamera)
205 return;
206
207 const uint32_t minZoom = m_qnxCamera->minimumZoomLevel();
208 const uint32_t maxZoom = m_qnxCamera->maximumZoomLevel();
209
210 if (maxZoom <= minZoom)
211 return;
212
213 // QNX has an integer based API. Interpolate between the levels according to the factor we get
214 const float max = maxZoomFactor();
215 const float min = minZoomFactor();
216
217 if (max <= min)
218 return;
219
220 factor = qBound(min, factor, max) - min;
221
222 const uint32_t zoom = minZoom
223 + static_cast<uint32_t>(qRound(factor*(maxZoom - minZoom)/(max - min)));
224
225 if (m_qnxCamera->setZoomFactor(zoom))
226 zoomFactorChanged(factor);
227}
228
230{
231 if (!m_qnxCamera)
232 return;
233
234 m_qnxCamera->setEvOffset(ev);
235}
236
238{
239 if (!m_qnxCamera)
240 return 0;
241
242 return m_qnxCamera->manualIsoSensitivity();
243}
244
246{
247 if (!m_qnxCamera)
248 return;
249
250 const uint32_t isoValue = std::max(0, value);
251
252 m_qnxCamera->setManualIsoSensitivity(isoValue);
253}
254
256{
257 if (!m_qnxCamera)
258 return;
259
260 m_qnxCamera->setManualExposureTime(seconds);
261}
262
264{
265 if (!m_qnxCamera)
266 return 0.0;
267
268 return static_cast<float>(m_qnxCamera->manualExposureTime());
269}
270
271bool QQnxPlatformCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
272{
273 if (m_maxColorTemperature != 0)
274 return true;
275
276 return mode == QCamera::WhiteBalanceAuto;
277}
278
279void QQnxPlatformCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
280{
281 if (!m_qnxCamera)
282 return;
283
284 if (mode == QCamera::WhiteBalanceAuto) {
285 m_qnxCamera->setWhiteBalanceMode(CAMERA_WHITEBALANCEMODE_AUTO);
286 } else {
287 m_qnxCamera->setWhiteBalanceMode(CAMERA_WHITEBALANCEMODE_MANUAL);
288 setColorTemperature(colorTemperatureForWhiteBalance(mode));
289 }
290}
291
293{
294 if (!m_qnxCamera)
295 return;
296
297 const auto normalizedTemp = std::clamp<uint32_t>(std::max(0, temperature),
298 m_minColorTemperature, m_maxColorTemperature);
299
300 if (m_qnxCamera->hasContinuousWhiteBalanceValues()) {
301 m_qnxCamera->setManualWhiteBalance(normalizedTemp);
302 } else {
303 uint32_t delta = std::numeric_limits<uint32_t>::max();
304 uint32_t closestTemp = 0;
305
306 for (uint32_t value : m_qnxCamera->supportedWhiteBalanceValues()) {
307 const auto &[min, max] = std::minmax(value, normalizedTemp);
308 const uint32_t currentDelta = max - min;
309
310 if (currentDelta < delta) {
311 closestTemp = value;
312 delta = currentDelta;
313 }
314 }
315
316 m_qnxCamera->setManualWhiteBalance(closestTemp);
317 }
318}
319
321{
322 if (!m_qnxCamera) {
323 qWarning("QQnxPlatformCamera: cannot start video recording - no no camera assigned");
324 return false;
325 }
326
327 if (!isVideoEncodingSupported()) {
328 qWarning("QQnxPlatformCamera: cannot start video recording - not supported");
329 return false;
330 }
331
332 if (!m_qnxCamera->isActive()) {
333 qWarning("QQnxPlatformCamera: cannot start video recording - camera not started");
334 return false;
335 }
336
337 const QString container = m_encoderSettings.preferredSuffix();
338 const QString location = QMediaStorageLocation::generateFileName(m_outputUrl.toLocalFile(),
339 QStandardPaths::MoviesLocation, container);
340
341#if 0
342 {
343 static void *libScreen = nullptr;
344
345 if (!libScreen)
346 libScreen = dlopen("/usr/lib/libscreen.so.1", RTLD_GLOBAL);
347 }
348#endif
349
350 qDebug() << "Recording to" << location;
351 return m_qnxCamera->startVideoRecording(location);
352}
353
354void QQnxPlatformCamera::requestVideoFrame(VideoFrameCallback cb)
355{
356 m_videoFrameRequests.emplace_back(std::move(cb));
357}
358
359bool QQnxPlatformCamera::isVideoEncodingSupported() const
360{
361 return m_qnxCamera && m_qnxCamera->hasFeature(CAMERA_FEATURE_VIDEO);
362}
363
364void QQnxPlatformCamera::setOutputUrl(const QUrl &url)
365{
366 m_outputUrl = url;
367}
368
369void QQnxPlatformCamera::setMediaEncoderSettings(const QMediaEncoderSettings &settings)
370{
371 m_encoderSettings = settings;
372}
373
374void QQnxPlatformCamera::updateCameraFeatures()
375{
376 if (!m_qnxCamera)
377 return;
378
379 QCamera::Features features = {};
380
381 if (m_qnxCamera->hasFeature(CAMERA_FEATURE_REGIONFOCUS))
382 features |= QCamera::Feature::CustomFocusPoint;
383
384 supportedFeaturesChanged(features);
385
386 minimumZoomFactorChanged(m_qnxCamera->minimumZoomLevel());
387 maximumZoomFactorChanged(m_qnxCamera->maximumZoomLevel());
388
389 const QList<uint32_t> wbValues = m_qnxCamera->supportedWhiteBalanceValues();
390
391 if (wbValues.isEmpty()) {
392 m_minColorTemperature = m_maxColorTemperature = 0;
393 } else {
394 const auto &[minTemp, maxTemp] = std::minmax_element(wbValues.begin(), wbValues.end());
395
396 m_minColorTemperature = *minTemp;
397 m_maxColorTemperature = *maxTemp;
398 }
399}
400
401void QQnxPlatformCamera::onFrameAvailable()
402{
403 if (!m_videoSink)
404 return;
405
406 std::unique_ptr<QQnxCameraFrameBuffer> currentFrameBuffer = m_qnxCamera->takeCurrentFrame();
407
408 if (!currentFrameBuffer)
409 return;
410
411 QVideoFrameFormat format(currentFrameBuffer->size(), currentFrameBuffer->pixelFormat());
412 const QVideoFrame actualFrame =
413 QVideoFramePrivate::createFrame(std::move(currentFrameBuffer), std::move(format));
414
415 m_videoSink->setVideoFrame(actualFrame);
416
417 if (!m_videoFrameRequests.empty()) {
418 VideoFrameCallback cb = std::move(m_videoFrameRequests.front());
419 m_videoFrameRequests.pop_front();
420 cb(actualFrame);
421 }
422}
423
424QT_END_NAMESPACE
425
426#include "moc_qqnxplatformcamera_p.cpp"
QQnxVideoSink * videoSink() const
void setManualExposureTime(float seconds) override
void setMediaEncoderSettings(const QMediaEncoderSettings &settings)
void setExposureCompensation(float ev) override
void requestVideoFrame(VideoFrameCallback cb)
void setCaptureSession(QPlatformMediaCaptureSession *session) override
void setOutputUrl(const QUrl &url)
void setManualIsoSensitivity(int value) override
bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override
void setCustomFocusPoint(const QPointF &point) override
int isoSensitivity() const override
void setColorTemperature(int temperature) override
void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override
float exposureTime() const override
bool isFocusModeSupported(QCamera::FocusMode mode) const override
void setFocusDistance(float distance) override
void zoomTo(float newZoomFactor, float rate=-1.) override
bool isActive() const override
void setFocusMode(QCamera::FocusMode mode) override
bool setCameraFormat(const QCameraFormat &format) override
void setActive(bool active) override
static constexpr To convert(const std::array< Mapping, N > &mapping, From Mapping::*from, To Mapping::*to, From value, To defaultValue)
static constexpr camera_focusmode_t qnxFocusMode(QCamera::FocusMode mode)
constexpr std::array< FocusModeMapping, 6 > focusModes
static constexpr QCamera::FocusMode qtFocusMode(camera_focusmode_t mode)
QCamera::FocusMode qt
camera_focusmode_t qnx