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