Qt 6.x
The Qt SDK
Loading...
Searching...
No Matches
qwasmcamera.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd and/or its subsidiary(-ies).
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qwasmcamera_p.h"
5#include "qmediadevices.h"
6#include <qcameradevice.h>
7#include "private/qabstractvideobuffer_p.h"
8#include "private/qplatformvideosink_p.h"
9#include <private/qmemoryvideobuffer_p.h>
10#include <private/qvideotexturehelper_p.h>
11
14
15#include <emscripten/val.h>
16#include <emscripten/bind.h>
17#include <emscripten/html5.h>
18#include <QUuid>
19#include <QTimer>
20
21#include <private/qstdweb_p.h>
22
23Q_LOGGING_CATEGORY(qWasmCamera, "qt.multimedia.wasm.camera")
24
26 : QPlatformCamera(camera), m_cameraOutput(new QWasmVideoOutput)
27{
28}
29
31
33{
34 return m_cameraActive;
35}
36
37void QWasmCamera::setActive(bool active)
38{
39 if (!m_CaptureSession) {
40 emit error(QCamera::CameraError, QStringLiteral("video surface error"));
41 return;
42 }
43
44 m_cameraOutput->setSurface(m_CaptureSession->videoSink());
45
46 m_cameraActive = active;
47
48 if (m_cameraActive)
49 m_cameraOutput->start();
50 else
51 m_cameraOutput->pause();
52
53 updateCameraFeatures();
54 emit activeChanged(active);
55}
56
58{
60
61 constexpr QSize initialSize(0, 0);
62 constexpr QRect initialRect(QPoint(0, 0), initialSize);
63 m_cameraOutput->createVideoElement(camera.id().toStdString()); // videoElementId
64 m_cameraOutput->createOffscreenElement(initialSize);
65 m_cameraOutput->updateVideoElementGeometry(initialRect);
66
67 const auto cameras = QMediaDevices::videoInputs();
68 if (std::find(cameras.begin(), cameras.end(), camera) != cameras.end()) {
69 m_cameraDev = camera;
70 createCamera(m_cameraDev);
71 return;
72 }
73
74 if (cameras.count() > 0) {
75 m_cameraDev = camera;
76 createCamera(m_cameraDev);
77 } else {
78 emit error(QCamera::CameraError, QStringLiteral("Failed to find a camera"));
79 }
80}
81
83{
85
86 return true;
87}
88
90{
91 QWasmMediaCaptureSession *captureSession = static_cast<QWasmMediaCaptureSession *>(session);
92 if (m_CaptureSession == captureSession)
93 return;
94
95 m_CaptureSession = captureSession;
96}
97
99{
101 return;
102
103 static constexpr std::string_view focusModeString = "focusMode";
105 m_cameraOutput->setDeviceSetting(focusModeString.data(), emscripten::val("manual"));
107 m_cameraOutput->setDeviceSetting(focusModeString.data(), emscripten::val("continuous"));
109}
110
112{
113 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
114 if (caps.isUndefined())
115 return false;
116
117 emscripten::val focusMode = caps["focusMode"];
118 if (focusMode.isUndefined())
119 return false;
120
121 std::vector<std::string> focalModes;
122
123 for (int i = 0; i < focusMode["length"].as<int>(); i++)
124 focalModes.push_back(focusMode[i].as<std::string>());
125
126 // Do we need to take into account focusDistance
127 // it is not always available, and what distance
128 // would be far/near
129
130 bool found = false;
131 switch (mode) {
133 return std::find(focalModes.begin(), focalModes.end(), "continuous") != focalModes.end()
134 || std::find(focalModes.begin(), focalModes.end(), "single-shot")
135 != focalModes.end();
140 break;
142 found = std::find(focalModes.begin(), focalModes.end(), "manual") != focalModes.end();
143 };
144 return found;
145}
146
148{
150 return;
151
152 if (m_wasmTorchMode == mode)
153 return;
154
155 static constexpr std::string_view torchModeString = "torchMode";
156 bool hasChanged = false;
157 switch (mode) {
159 m_cameraOutput->setDeviceSetting(torchModeString.data(), emscripten::val(false));
160 hasChanged = true;
161 break;
162 case QCamera::TorchOn:
163 m_cameraOutput->setDeviceSetting(torchModeString.data(), emscripten::val(true));
164 hasChanged = true;
165 break;
167 break;
168 };
169 m_wasmTorchMode = mode;
170 if (hasChanged)
171 torchModeChanged(m_wasmTorchMode);
172}
173
175{
176 if (!m_cameraIsReady)
177 return false;
178
179 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
180 if (caps.isUndefined())
181 return false;
182
183 emscripten::val exposureMode = caps["torch"];
184 if (exposureMode.isUndefined())
185 return false;
186
187 return (mode != QCamera::TorchAuto);
188}
189
191{
192 // TODO manually come up with exposureTime values ?
194 return;
195
196 if (m_wasmExposureMode == mode)
197 return;
198
199 bool hasChanged = false;
200 static constexpr std::string_view exposureModeString = "exposureMode";
201 switch (mode) {
203 m_cameraOutput->setDeviceSetting(exposureModeString.data(), emscripten::val("manual"));
204 hasChanged = true;
205 break;
207 m_cameraOutput->setDeviceSetting(exposureModeString.data(), emscripten::val("continuous"));
208 hasChanged = true;
209 break;
210 default:
211 break;
212 };
213
214 if (hasChanged) {
215 m_wasmExposureMode = mode;
216 exposureModeChanged(m_wasmExposureMode);
217 }
218}
219
221{
222 if (!m_cameraIsReady)
223 return false;
224
225 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
226 if (caps.isUndefined())
227 return false;
228
229 emscripten::val exposureMode = caps["exposureMode"];
230 if (exposureMode.isUndefined())
231 return false;
232
233 std::vector<std::string> exposureModes;
234
235 for (int i = 0; i < exposureMode["length"].as<int>(); i++)
236 exposureModes.push_back(exposureMode[i].as<std::string>());
237
238 bool found = false;
239 switch (mode) {
241 found = std::find(exposureModes.begin(), exposureModes.end(), "continuous")
242 != exposureModes.end();
243 break;
245 found = std::find(exposureModes.begin(), exposureModes.end(), "manual")
246 != exposureModes.end();
247 break;
248 default:
249 break;
250 };
251
252 return found;
253}
254
256{
257 if (!m_cameraIsReady)
258 return;
259
260 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
261 if (caps.isUndefined())
262 return;
263
264 emscripten::val exposureComp = caps["exposureCompensation"];
265 if (exposureComp.isUndefined())
266 return;
267 if (m_wasmExposureCompensation == bias)
268 return;
269
270 static constexpr std::string_view exposureCompensationModeString = "exposureCompensation";
271 m_cameraOutput->setDeviceSetting(exposureCompensationModeString.data(), emscripten::val(bias));
272 m_wasmExposureCompensation = bias;
273 emit exposureCompensationChanged(m_wasmExposureCompensation);
274}
275
277{
278 if (m_wasmExposureTime == secs)
279 return;
280
281 if (!m_cameraIsReady)
282 return;
283
284 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
285 emscripten::val exposureTime = caps["exposureTime"];
286 if (exposureTime.isUndefined())
287 return;
288 static constexpr std::string_view exposureTimeString = "exposureTime";
289 m_cameraOutput->setDeviceSetting(exposureTimeString.data(), emscripten::val(secs));
290 m_wasmExposureTime = secs;
291 emit exposureTimeChanged(m_wasmExposureTime);
292}
293
295{
296 if (!m_cameraIsReady)
297 return 0;
298
299 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
300 if (caps.isUndefined())
301 return false;
302
303 emscripten::val isoSpeed = caps["iso"];
304 if (isoSpeed.isUndefined())
305 return 0;
306
307 return isoSpeed.as<double>();
308}
309
311{
312 if (!m_cameraIsReady)
313 return;
314
315 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
316 if (caps.isUndefined())
317 return;
318
319 emscripten::val isoSpeed = caps["iso"];
320 if (isoSpeed.isUndefined())
321 return;
322 if (m_wasmIsoSensitivity == sens)
323 return;
324 static constexpr std::string_view isoString = "iso";
325 m_cameraOutput->setDeviceSetting(isoString.data(), emscripten::val(sens));
326 m_wasmIsoSensitivity = sens;
327 emit isoSensitivityChanged(m_wasmIsoSensitivity);
328}
329
331{
332 if (!m_cameraIsReady)
333 return false;
334
335 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
336 if (caps.isUndefined())
337 return false;
338
339 emscripten::val whiteBalanceMode = caps["whiteBalanceMode"];
340 if (whiteBalanceMode.isUndefined())
341 return false;
342
344 return true;
345
346 return false;
347}
348
350{
352 return;
353
354 if (m_wasmWhiteBalanceMode == mode)
355 return;
356
357 bool hasChanged = false;
358 static constexpr std::string_view whiteBalanceModeString = "whiteBalanceMode";
359 switch (mode) {
361 m_cameraOutput->setDeviceSetting(whiteBalanceModeString.data(), emscripten::val("auto"));
362 hasChanged = true;
363 break;
365 m_cameraOutput->setDeviceSetting(whiteBalanceModeString.data(), emscripten::val("manual"));
366 hasChanged = true;
367 break;
368 default:
369 break;
370 };
371
372 if (hasChanged) {
373 m_wasmWhiteBalanceMode = mode;
374 emit whiteBalanceModeChanged(m_wasmWhiteBalanceMode);
375 }
376}
377
379{
380 if (!m_cameraIsReady)
381 return;
382
383 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
384 if (caps.isUndefined())
385 return;
386
387 emscripten::val whiteBalanceMode = caps["colorTemperature"];
388 if (whiteBalanceMode.isUndefined())
389 return;
390 if(m_wasmColorTemperature == temperature)
391 return;
392
393 static constexpr std::string_view colorBalanceString = "colorTemperature";
394 m_cameraOutput->setDeviceSetting(colorBalanceString.data(), emscripten::val(temperature));
395 m_wasmColorTemperature = temperature;
396 colorTemperatureChanged(m_wasmColorTemperature);
397}
398
399void QWasmCamera::createCamera(const QCameraDevice &camera)
400{
401 m_cameraOutput->addCameraSourceElement(camera.id().toStdString());
402 // getUserMedia is async
403 QTimer::singleShot(100, [this] () {
404 m_cameraIsReady = m_cameraOutput->isCameraReady();
405 });
406}
407
408void QWasmCamera::updateCameraFeatures()
409{
410 if (!m_cameraIsReady)
411 return;
412
413 emscripten::val caps = m_cameraOutput->getDeviceCapabilities();
414 if (caps.isUndefined())
415 return;
416
417 QCamera::Features cameraFeatures;
418
419 if (!caps["colorTemperature"].isUndefined())
420 cameraFeatures |= QCamera::Feature::ColorTemperature;
421
422 if (!caps["exposureCompensation"].isUndefined())
424
425 if (!caps["iso"].isUndefined())
426 cameraFeatures |= QCamera::Feature::IsoSensitivity;
427
428 if (!caps["exposureTime"].isUndefined())
429 cameraFeatures |= QCamera::Feature::ManualExposureTime;
430
431 if (!caps["focusDistance"].isUndefined())
432 cameraFeatures |= QCamera::Feature::FocusDistance;
433
434 supportedFeaturesChanged(cameraFeatures);
435}
The QCameraDevice class provides general information about camera devices.
The QCameraFormat class describes a video format supported by a camera device. \inmodule QtMultimedia...
The QCamera class provides interface for system camera devices.
Definition qcamera.h:28
WhiteBalanceMode
\value WhiteBalanceAuto Auto white balance mode.
Definition qcamera.h:112
@ WhiteBalanceManual
Definition qcamera.h:114
@ WhiteBalanceAuto
Definition qcamera.h:113
TorchMode
\value TorchOff Torch is Off.
Definition qcamera.h:84
@ TorchOn
Definition qcamera.h:86
@ TorchAuto
Definition qcamera.h:87
@ TorchOff
Definition qcamera.h:85
FocusMode
\value FocusModeAuto Continuous auto focus mode.
Definition qcamera.h:67
@ FocusModeAutoNear
Definition qcamera.h:69
@ FocusModeInfinity
Definition qcamera.h:72
@ FocusModeAutoFar
Definition qcamera.h:70
@ FocusModeAuto
Definition qcamera.h:68
@ FocusModeManual
Definition qcamera.h:73
@ FocusModeHyperfocal
Definition qcamera.h:71
ExposureMode
\value ExposureAuto Automatic mode.
Definition qcamera.h:91
@ ExposureManual
Definition qcamera.h:93
@ ExposureAuto
Definition qcamera.h:92
@ CameraError
Definition qcamera.h:63
QList< QCameraDevice > videoInputs
\qmlproperty list<cameraDevice> QtMultimedia::MediaDevices::videoInputs Contains a list of cameras on...
void isoSensitivityChanged(int iso)
void torchModeChanged(QCamera::TorchMode mode)
QCamera::WhiteBalanceMode whiteBalanceMode() const
void focusModeChanged(QCamera::FocusMode mode)
void exposureCompensationChanged(float compensation)
void whiteBalanceModeChanged(QCamera::WhiteBalanceMode mode)
QCamera::FocusMode focusMode() const
virtual float exposureTime() const
QCamera::ExposureMode exposureMode() const
void colorTemperatureChanged(int temperature)
void exposureModeChanged(QCamera::ExposureMode mode)
void supportedFeaturesChanged(QCamera::Features)
void error(int error, const QString &errorString)
QCameraFormat m_cameraFormat
void exposureTimeChanged(float speed)
void activeChanged(bool)
\inmodule QtCore\reentrant
Definition qpoint.h:23
\inmodule QtCore\reentrant
Definition qrect.h:30
\inmodule QtCore
Definition qsize.h:25
bool singleShot
whether the timer is a single-shot timer
Definition qtimer.h:22
bool isTorchModeSupported(QCamera::TorchMode mode) const override
void setManualExposureTime(float) override
void setExposureCompensation(float bias) override
void setColorTemperature(int temperature) override
int isoSensitivity() const override
void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override
void setTorchMode(QCamera::TorchMode mode) override
bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override
void setExposureMode(QCamera::ExposureMode mode) override
bool setCameraFormat(const QCameraFormat &format) override
void setManualIsoSensitivity(int) override
void setFocusMode(QCamera::FocusMode mode) override
void setActive(bool active) override
bool isFocusModeSupported(QCamera::FocusMode mode) const override
bool isActive() const override
void setCaptureSession(QPlatformMediaCaptureSession *session) override
bool isExposureModeSupported(QCamera::ExposureMode mode) const override
void setCamera(const QCameraDevice &camera) override
void addCameraSourceElement(const std::string &id)
void updateVideoElementGeometry(const QRect &windowGeometry)
bool setDeviceSetting(const std::string &key, emscripten::val value)
emscripten::val getDeviceCapabilities()
void setVideoMode(QWasmVideoOutput::WasmVideoMode mode)
void createVideoElement(const std::string &id)
void setSurface(QVideoSink *surface)
void createOffscreenElement(const QSize &offscreenSize)
QCamera * camera
Definition camera.cpp:19
#define Q_LOGGING_CATEGORY(name,...)
GLenum mode
GLint GLsizei GLsizei GLenum format
GLfloat bias
#define QStringLiteral(str)
#define emit