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
qgstreamercamera.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
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 <mediacapture/qgstreamercamera_p.h>
5
6#include <QtMultimedia/qcameradevice.h>
7#include <QtMultimedia/qmediacapturesession.h>
8#include <QtMultimedia/private/qcameradevice_p.h>
9#include <QtMultimedia/private/qmultimediautils_p.h>
10#include <QtCore/qdebug.h>
11
12#include <common/qgst_debug_p.h>
13#include <qgstreamervideodevices_p.h>
14#include <qgstreamerintegration_p.h>
15
16#if QT_CONFIG(linux_v4l)
17#include <linux/videodev2.h>
18#include <private/qcore_unix_p.h>
19#endif
20
21
23
24q23::expected<QPlatformCamera *, QString> QGstreamerCamera::create(QCamera *camera)
25{
26 static const auto error = qGstErrorMessageIfElementsNotAvailable(
27 "videotestsrc", "capsfilter", "videoconvert", "videoscale", "identity");
28 if (error)
29 return q23::unexpected{ *error };
30
31 return new QGstreamerCamera(camera);
32}
33
34QGstreamerCamera::QGstreamerCamera(QCamera *camera)
35 : QGstreamerCameraBase(camera),
36 gstCameraBin{
37 QGstBin::create("camerabin"),
38 },
39 gstCamera{
40 QGstElement::createFromFactory("videotestsrc"),
41 },
42 gstCapsFilter{
43 QGstElement::createFromFactory("capsfilter", "videoCapsFilter"),
44 },
45 gstDecode{
46 QGstElement::createFromFactory("identity"),
47 },
48 gstVideoConvert{
49 QGstElement::createFromFactory("videoconvert", "videoConvert"),
50 },
51 gstVideoScale{
52 QGstElement::createFromFactory("videoscale", "videoScale"),
53 }
54{
55 gstCameraBin.add(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
56 qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert, gstVideoScale);
57 gstCameraBin.addGhostPad(gstVideoScale, "src");
58}
59
61{
62 gstCameraBin.setStateSync(GST_STATE_NULL);
63}
64
66{
67 return m_active;
68}
69
70void QGstreamerCamera::setActive(bool active)
71{
72 if (m_active == active)
73 return;
74 if (m_cameraDevice.isNull() && active)
75 return;
76
77 m_active = active;
78
79 Q_EMIT activeChanged(active);
80}
81
82void QGstreamerCamera::setCamera(const QCameraDevice &camera)
83{
84 using namespace Qt::Literals;
85
86 if (m_cameraDevice == camera)
87 return;
88
89 m_cameraDevice = camera;
90
91 QGstElement newGstCamera;
92 if (camera.isNull()) {
93 newGstCamera = QGstElement::createFromFactory("videotestsrc");
94 } else {
95 auto *integration = static_cast<QGstreamerIntegration *>(QGstreamerIntegration::instance());
96 GstDevice *device = integration->videoDevice(camera.id());
97
98 if (!device) {
99 updateError(QCamera::Error::CameraError,
100 u"Failed to create GstDevice for camera: "_s
101 + QString::fromUtf8(camera.id()));
102 return;
103 }
104
105 newGstCamera = QGstElement::createFromDevice(device, "camerasrc");
106
107 static const auto ioMode = [] {
108 bool ok = false;
109 int ioMode = qEnvironmentVariableIntValue("QT_GSTREAMER_V4L2SRC_IOMODE", &ok);
110 return ok ? std::optional(ioMode) : std::nullopt;
111 }();
112 if (ioMode && newGstCamera.factoryName() == "v4l2src")
113 newGstCamera.set("io-mode", *ioMode);
114
115 QUniqueGstStructureHandle properties{
116 gst_device_get_properties(device),
117 };
118
119 if (properties) {
120 QGstStructureView propertiesView{ properties };
121 if (propertiesView.name() == "v4l2deviceprovider")
122 m_v4l2DevicePath = QString::fromUtf8(propertiesView["device.path"].toString());
123 }
124 }
125
126 QCameraFormat f = findBestCameraFormat(camera);
127 m_currentCameraFormat = f;
128
129 QGstElement newGstDecode;
130 if (f.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
132 QGstElement::findFactory("v4l2jpegdec") ? "v4l2jpegdec" : "jpegdec");
133 } else
134 newGstDecode = QGstElement::createFromFactory("identity");
135
136 auto caps = QGstCaps::fromCameraFormat(f);
137 updateCamera([&] {
138 qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
139 gstCameraBin.stopAndRemoveElements(gstCamera, gstDecode);
140
141 gstCapsFilter.set("caps", caps);
142
143 gstCamera = std::move(newGstCamera);
144 gstDecode = std::move(newGstDecode);
145
146 gstCameraBin.add(gstCamera, gstDecode);
147 qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
148 gstCameraBin.syncChildrenState();
149 });
150
151 updateCameraProperties();
152}
153
154bool QGstreamerCamera::setCameraFormat(const QCameraFormat &format)
155{
156 if (!format.isNull() && !m_cameraDevice.videoFormats().contains(format))
157 return false;
158
159 QCameraFormat f = format;
160 if (f.isNull())
161 f = findBestCameraFormat(m_cameraDevice);
162
163 if (f == m_currentCameraFormat)
164 return true;
165
166 m_currentCameraFormat = f;
167
168 QGstElement newGstDecode;
169 if (f.pixelFormat() == QVideoFrameFormat::Format_Jpeg) {
171 QGstElement::findFactory("v4l2jpegdec") ? "v4l2jpegdec" : "jpegdec");
172 } else
173 newGstDecode = QGstElement::createFromFactory("identity");
174
175 auto caps = QGstCaps::fromCameraFormat(f);
176 updateCamera([&] {
177 qUnlinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
178 gstCameraBin.stopAndRemoveElements(gstDecode);
179
180 gstCapsFilter.set("caps", caps);
181
182 gstDecode = std::move(newGstDecode);
183
184 gstCameraBin.add(gstDecode);
185 qLinkGstElements(gstCamera, gstCapsFilter, gstDecode, gstVideoConvert);
186 gstCameraBin.syncChildrenState();
187 });
188
189 return true;
190}
191
192void QGstreamerCamera::updateCameraProperties()
193{
194#if QT_CONFIG(linux_v4l)
195 if (isV4L2Camera()) {
196 initV4L2Controls();
197 return;
198 }
199#endif
200#if QT_CONFIG(gstreamer_photography)
201 if (auto *p = photography())
202 gst_photography_set_white_balance_mode(p, GST_PHOTOGRAPHY_WB_MODE_AUTO);
203 QCamera::Features f = QCamera::Feature::ColorTemperature | QCamera::Feature::ExposureCompensation |
204 QCamera::Feature::IsoSensitivity | QCamera::Feature::ManualExposureTime;
205 supportedFeaturesChanged(f);
206#endif
207
208}
209
210#if QT_CONFIG(gstreamer_photography)
211GstPhotography *QGstreamerCamera::photography() const
212{
213 if (gstCamera && GST_IS_PHOTOGRAPHY(gstCamera.element()))
214 return GST_PHOTOGRAPHY(gstCamera.element());
215 return nullptr;
216}
217#endif
218
219void QGstreamerCamera::setFocusMode(QCamera::FocusMode mode)
220{
221 if (mode == focusMode())
222 return;
223
224#if QT_CONFIG(gstreamer_photography)
225 auto p = photography();
226 if (p) {
227 GstPhotographyFocusMode photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_CONTINUOUS_NORMAL;
228
229 switch (mode) {
230 case QCamera::FocusModeAutoNear:
231 photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MACRO;
232 break;
233 case QCamera::FocusModeAutoFar:
234 // not quite, but hey :)
235 Q_FALLTHROUGH();
236 case QCamera::FocusModeHyperfocal:
237 photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_HYPERFOCAL;
238 break;
239 case QCamera::FocusModeInfinity:
240 photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_INFINITY;
241 break;
242 case QCamera::FocusModeManual:
243 photographyMode = GST_PHOTOGRAPHY_FOCUS_MODE_MANUAL;
244 break;
245 default: // QCamera::FocusModeAuto:
246 break;
247 }
248
249 if (gst_photography_set_focus_mode(p, photographyMode))
250 focusModeChanged(mode);
251 }
252#endif
253}
254
255bool QGstreamerCamera::isFocusModeSupported(QCamera::FocusMode mode) const
256{
257#if QT_CONFIG(gstreamer_photography)
258 if (photography())
259 return true;
260#endif
261 return mode == QCamera::FocusModeAuto;
262}
263
264void QGstreamerCamera::setFlashMode(QCamera::FlashMode mode)
265{
266 Q_UNUSED(mode);
267
268#if QT_CONFIG(gstreamer_photography)
269 if (auto *p = photography()) {
270 GstPhotographyFlashMode flashMode;
271 gst_photography_get_flash_mode(p, &flashMode);
272
273 switch (mode) {
274 case QCamera::FlashAuto:
275 flashMode = GST_PHOTOGRAPHY_FLASH_MODE_AUTO;
276 break;
277 case QCamera::FlashOff:
278 flashMode = GST_PHOTOGRAPHY_FLASH_MODE_OFF;
279 break;
280 case QCamera::FlashOn:
281 flashMode = GST_PHOTOGRAPHY_FLASH_MODE_ON;
282 break;
283 }
284
285 if (gst_photography_set_flash_mode(p, flashMode))
286 flashModeChanged(mode);
287 }
288#endif
289}
290
291bool QGstreamerCamera::isFlashModeSupported(QCamera::FlashMode mode) const
292{
293#if QT_CONFIG(gstreamer_photography)
294 if (photography())
295 return true;
296#endif
297
298 return mode == QCamera::FlashAuto;
299}
300
302{
303#if QT_CONFIG(gstreamer_photography)
304 if (photography())
305 return true;
306#endif
307
308 return false;
309}
310
311void QGstreamerCamera::setExposureMode(QCamera::ExposureMode mode)
312{
313 Q_UNUSED(mode);
314#if QT_CONFIG(linux_v4l)
315 if (isV4L2Camera() && v4l2AutoExposureSupported && v4l2ManualExposureSupported) {
316 if (mode != QCamera::ExposureAuto && mode != QCamera::ExposureManual)
317 return;
318 int value = QCamera::ExposureAuto ? V4L2_EXPOSURE_AUTO : V4L2_EXPOSURE_MANUAL;
319 setV4L2Parameter(V4L2_CID_EXPOSURE_AUTO, value);
320 exposureModeChanged(mode);
321 return;
322 }
323#endif
324
325#if QT_CONFIG(gstreamer_photography)
326 auto *p = photography();
327 if (!p)
328 return;
329
330 GstPhotographySceneMode sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
331
332 switch (mode) {
333 case QCamera::ExposureManual:
334 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_MANUAL;
335 break;
336 case QCamera::ExposurePortrait:
337 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PORTRAIT;
338 break;
339 case QCamera::ExposureSports:
340 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SPORT;
341 break;
342 case QCamera::ExposureNight:
343 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT;
344 break;
345 case QCamera::ExposureAuto:
346 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_AUTO;
347 break;
348 case QCamera::ExposureLandscape:
349 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_LANDSCAPE;
350 break;
351 case QCamera::ExposureSnow:
352 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SNOW;
353 break;
354 case QCamera::ExposureBeach:
355 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BEACH;
356 break;
357 case QCamera::ExposureAction:
358 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_ACTION;
359 break;
360 case QCamera::ExposureNightPortrait:
361 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_NIGHT_PORTRAIT;
362 break;
363 case QCamera::ExposureTheatre:
364 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_THEATRE;
365 break;
366 case QCamera::ExposureSunset:
367 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_SUNSET;
368 break;
369 case QCamera::ExposureSteadyPhoto:
370 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_STEADY_PHOTO;
371 break;
372 case QCamera::ExposureFireworks:
373 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_FIREWORKS;
374 break;
375 case QCamera::ExposureParty:
376 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_PARTY;
377 break;
378 case QCamera::ExposureCandlelight:
379 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_CANDLELIGHT;
380 break;
381 case QCamera::ExposureBarcode:
382 sceneMode = GST_PHOTOGRAPHY_SCENE_MODE_BARCODE;
383 break;
384 default:
385 return;
386 }
387
388 if (gst_photography_set_scene_mode(p, sceneMode))
389 exposureModeChanged(mode);
390#endif
391}
392
393bool QGstreamerCamera::isExposureModeSupported(QCamera::ExposureMode mode) const
394{
395 if (mode == QCamera::ExposureAuto)
396 return true;
397#if QT_CONFIG(linux_v4l)
398 if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported)
399 return mode == QCamera::ExposureManual;
400#endif
401#if QT_CONFIG(gstreamer_photography)
402 if (photography())
403 return true;
404#endif
405
406 return false;
407}
408
410{
411 Q_UNUSED(compensation);
412#if QT_CONFIG(linux_v4l)
413 if (isV4L2Camera() && (v4l2MinExposureAdjustment != 0 || v4l2MaxExposureAdjustment != 0)) {
414 int value = qBound(v4l2MinExposureAdjustment, (int)(compensation*1000), v4l2MaxExposureAdjustment);
415 setV4L2Parameter(V4L2_CID_AUTO_EXPOSURE_BIAS, value);
416 exposureCompensationChanged(value/1000.);
417 return;
418 }
419#endif
420
421#if QT_CONFIG(gstreamer_photography)
422 if (auto *p = photography()) {
423 if (gst_photography_set_ev_compensation(p, compensation))
424 exposureCompensationChanged(compensation);
425 }
426#endif
427}
428
430{
431 Q_UNUSED(iso);
432#if QT_CONFIG(linux_v4l)
433 if (isV4L2Camera()) {
434 if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
435 return;
436 setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY_AUTO, iso <= 0 ? V4L2_ISO_SENSITIVITY_AUTO : V4L2_ISO_SENSITIVITY_MANUAL);
437 if (iso > 0) {
438 iso = qBound(minIso(), iso, maxIso());
439 setV4L2Parameter(V4L2_CID_ISO_SENSITIVITY, iso);
440 }
441 return;
442 }
443#endif
444#if QT_CONFIG(gstreamer_photography)
445 if (auto *p = photography()) {
446 if (gst_photography_set_iso_speed(p, iso))
447 isoSensitivityChanged(iso);
448 }
449#endif
450}
451
453{
454#if QT_CONFIG(linux_v4l)
455 if (isV4L2Camera()) {
456 if (!(supportedFeatures() & QCamera::Feature::IsoSensitivity))
457 return -1;
458 return getV4L2Parameter(V4L2_CID_ISO_SENSITIVITY);
459 }
460#endif
461#if QT_CONFIG(gstreamer_photography)
462 if (auto *p = photography()) {
463 guint speed = 0;
464 if (gst_photography_get_iso_speed(p, &speed))
465 return speed;
466 }
467#endif
468 return 100;
469}
470
472{
473 Q_UNUSED(secs);
474#if QT_CONFIG(linux_v4l)
475 if (isV4L2Camera() && v4l2ManualExposureSupported && v4l2AutoExposureSupported) {
476 int exposure = qBound(v4l2MinExposure, qRound(secs*10000.), v4l2MaxExposure);
477 setV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE, exposure);
478 exposureTimeChanged(exposure/10000.);
479 return;
480 }
481#endif
482
483#if QT_CONFIG(gstreamer_photography)
484 if (auto *p = photography()) {
485 if (gst_photography_set_exposure(p, guint(secs*1000000)))
486 exposureTimeChanged(secs);
487 }
488#endif
489}
490
492{
493#if QT_CONFIG(linux_v4l)
494 if (isV4L2Camera()) {
495 return getV4L2Parameter(V4L2_CID_EXPOSURE_ABSOLUTE)/10000.;
496 }
497#endif
498#if QT_CONFIG(gstreamer_photography)
499 if (auto *p = photography()) {
500 guint32 exposure = 0;
501 if (gst_photography_get_exposure(p, &exposure))
502 return exposure/1000000.;
503 }
504#endif
505 return -1;
506}
507
508bool QGstreamerCamera::isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const
509{
510 if (mode == QCamera::WhiteBalanceAuto)
511 return true;
512
513#if QT_CONFIG(linux_v4l)
514 if (isV4L2Camera()) {
515 if (v4l2AutoWhiteBalanceSupported && v4l2ColorTemperatureSupported)
516 return true;
517 }
518#endif
519#if QT_CONFIG(gstreamer_photography)
520 if (auto *p = photography()) {
521 Q_UNUSED(p);
522 switch (mode) {
523 case QCamera::WhiteBalanceAuto:
524 case QCamera::WhiteBalanceSunlight:
525 case QCamera::WhiteBalanceCloudy:
526 case QCamera::WhiteBalanceShade:
527 case QCamera::WhiteBalanceSunset:
528 case QCamera::WhiteBalanceTungsten:
529 case QCamera::WhiteBalanceFluorescent:
530 return true;
531 case QCamera::WhiteBalanceManual: {
532 GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
533 if (iface->set_color_temperature && iface->get_color_temperature)
534 return true;
535 break;
536 }
537 default:
538 break;
539 }
540 }
541#endif
542
543 return mode == QCamera::WhiteBalanceAuto;
544}
545
546void QGstreamerCamera::setWhiteBalanceMode(QCamera::WhiteBalanceMode mode)
547{
548 Q_ASSERT(isWhiteBalanceModeSupported(mode));
549
550#if QT_CONFIG(linux_v4l)
551 if (isV4L2Camera()) {
552 int temperature = colorTemperatureForWhiteBalance(mode);
553 int t = setV4L2ColorTemperature(temperature);
554 if (t == 0)
555 mode = QCamera::WhiteBalanceAuto;
556 whiteBalanceModeChanged(mode);
557 return;
558 }
559#endif
560
561#if QT_CONFIG(gstreamer_photography)
562 if (auto *p = photography()) {
563 GstPhotographyWhiteBalanceMode gstMode = GST_PHOTOGRAPHY_WB_MODE_AUTO;
564 switch (mode) {
565 case QCamera::WhiteBalanceSunlight:
566 gstMode = GST_PHOTOGRAPHY_WB_MODE_DAYLIGHT;
567 break;
568 case QCamera::WhiteBalanceCloudy:
569 gstMode = GST_PHOTOGRAPHY_WB_MODE_CLOUDY;
570 break;
571 case QCamera::WhiteBalanceShade:
572 gstMode = GST_PHOTOGRAPHY_WB_MODE_SHADE;
573 break;
574 case QCamera::WhiteBalanceSunset:
575 gstMode = GST_PHOTOGRAPHY_WB_MODE_SUNSET;
576 break;
577 case QCamera::WhiteBalanceTungsten:
578 gstMode = GST_PHOTOGRAPHY_WB_MODE_TUNGSTEN;
579 break;
580 case QCamera::WhiteBalanceFluorescent:
581 gstMode = GST_PHOTOGRAPHY_WB_MODE_FLUORESCENT;
582 break;
583 case QCamera::WhiteBalanceAuto:
584 default:
585 break;
586 }
587 if (gst_photography_set_white_balance_mode(p, gstMode)) {
588 whiteBalanceModeChanged(mode);
589 return;
590 }
591 }
592#endif
593}
594
596{
597 if (temperature == 0) {
598 setWhiteBalanceMode(QCamera::WhiteBalanceAuto);
599 return;
600 }
601
602 Q_ASSERT(isWhiteBalanceModeSupported(QCamera::WhiteBalanceManual));
603
604#if QT_CONFIG(linux_v4l)
605 if (isV4L2Camera()) {
606 int t = setV4L2ColorTemperature(temperature);
607 if (t)
608 colorTemperatureChanged(t);
609 return;
610 }
611#endif
612
613#if QT_CONFIG(gstreamer_photography)
614 if (auto *p = photography()) {
615 GstPhotographyInterface *iface = GST_PHOTOGRAPHY_GET_INTERFACE(p);
616 Q_ASSERT(iface->set_color_temperature);
617 iface->set_color_temperature(p, temperature);
618 return;
619 }
620#endif
621}
622
623#if QT_CONFIG(linux_v4l)
624bool QGstreamerCamera::isV4L2Camera() const
625{
626 return !m_v4l2DevicePath.isEmpty();
627}
628
629void QGstreamerCamera::initV4L2Controls()
630{
631 using namespace QtMultimediaPrivate;
632
633 v4l2AutoWhiteBalanceSupported = false;
634 v4l2ColorTemperatureSupported = false;
635 QCamera::Features features{};
636
637 Q_ASSERT(!m_v4l2DevicePath.isEmpty());
638
639
640 withV4L2DeviceFileDescriptor([&](int fd) {
641 struct v4l2_queryctrl queryControl = {};
642 queryControl.id = V4L2_CID_AUTO_WHITE_BALANCE;
643
644 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
645 v4l2AutoWhiteBalanceSupported = true;
646 setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, true);
647 }
648
649 queryControl = {};
650 queryControl.id = V4L2_CID_WHITE_BALANCE_TEMPERATURE;
651 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
652 v4l2MinColorTemp = queryControl.minimum;
653 v4l2MaxColorTemp = queryControl.maximum;
654 v4l2ColorTemperatureSupported = true;
655 features |= QCamera::Feature::ColorTemperature;
656 }
657
658 queryControl = {};
659 queryControl.id = V4L2_CID_EXPOSURE_AUTO;
660 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
661 v4l2AutoExposureSupported = true;
662 }
663
664 queryControl = {};
665 queryControl.id = V4L2_CID_EXPOSURE_ABSOLUTE;
666 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
667 v4l2ManualExposureSupported = true;
668 v4l2MinExposure = queryControl.minimum;
669 v4l2MaxExposure = queryControl.maximum;
670 features |= QCamera::Feature::ManualExposureTime;
671 }
672
673 queryControl = {};
674 queryControl.id = V4L2_CID_AUTO_EXPOSURE_BIAS;
675 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
676 v4l2MinExposureAdjustment = queryControl.minimum;
677 v4l2MaxExposureAdjustment = queryControl.maximum;
678 features |= QCamera::Feature::ExposureCompensation;
679 }
680
681 queryControl = {};
682 queryControl.id = V4L2_CID_ISO_SENSITIVITY_AUTO;
683 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
684 queryControl.id = V4L2_CID_ISO_SENSITIVITY;
685 if (qt_safe_ioctl(fd, VIDIOC_QUERYCTRL, &queryControl) == 0) {
686 features |= QCamera::Feature::IsoSensitivity;
687 minIsoChanged(queryControl.minimum);
688 maxIsoChanged(queryControl.minimum);
689 }
690 }
691 });
692
693 supportedFeaturesChanged(features);
694}
695
696int QGstreamerCamera::setV4L2ColorTemperature(int temperature)
697{
698 if (v4l2AutoWhiteBalanceSupported) {
699 setV4L2Parameter(V4L2_CID_AUTO_WHITE_BALANCE, temperature == 0 ? true : false);
700 } else if (temperature == 0) {
701 temperature = 5600;
702 }
703
704 if (temperature != 0 && v4l2ColorTemperatureSupported) {
705 temperature = qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp);
706 if (!setV4L2Parameter(V4L2_CID_WHITE_BALANCE_TEMPERATURE, qBound(v4l2MinColorTemp, temperature, v4l2MaxColorTemp)))
707 temperature = 0;
708 } else {
709 temperature = 0;
710 }
711
712 return temperature;
713}
714
715bool QGstreamerCamera::setV4L2Parameter(quint32 id, qint32 value)
716{
717 return withV4L2DeviceFileDescriptor([&](int fd) {
718 v4l2_control control{ id, value };
719 if (QtMultimediaPrivate::qt_safe_ioctl(fd, VIDIOC_S_CTRL, &control) != 0) {
720 qWarning() << "Unable to set the V4L2 Parameter" << Qt::hex << id << "to" << value
721 << qt_error_string(errno);
722 return false;
723 }
724 return true;
725 });
726}
727
728int QGstreamerCamera::getV4L2Parameter(quint32 id) const
729{
730 return withV4L2DeviceFileDescriptor([&](int fd) {
731 v4l2_control control{ id, 0 };
732 if (QtMultimediaPrivate::qt_safe_ioctl(fd, VIDIOC_G_CTRL, &control) != 0) {
733 qWarning() << "Unable to get the V4L2 Parameter" << Qt::hex << id
734 << qt_error_string(errno);
735 return 0;
736 }
737 return control.value;
738 });
739}
740
741#endif // QT_CONFIG(linux_v4l)
742
747
749{
750 return m_active;
751}
752
754{
755 if (m_active == active)
756 return;
757
758 m_active = active;
759
760 Q_EMIT activeChanged(active);
761}
762
763QT_END_NAMESPACE
static QGstCaps fromCameraFormat(const QCameraFormat &format)
Definition qgst.cpp:541
QGstElement & operator=(QGstElement &&) noexcept=default
QGstElement & operator=(const QGstElement &)=default
static QGstElement createFromFactory(const char *factory, const char *name=nullptr)
Definition qgst.cpp:1013
void setWhiteBalanceMode(QCamera::WhiteBalanceMode mode) override
~QGstreamerCamera() override
bool isFocusModeSupported(QCamera::FocusMode mode) const override
bool isActive() const override
bool isFlashModeSupported(QCamera::FlashMode mode) const override
bool isExposureModeSupported(QCamera::ExposureMode mode) const override
bool setCameraFormat(const QCameraFormat &format) override
void setColorTemperature(int temperature) override
void setExposureMode(QCamera::ExposureMode) override
bool isFlashReady() const override
int isoSensitivity() const override
float exposureTime() const override
bool isWhiteBalanceModeSupported(QCamera::WhiteBalanceMode mode) const override
void setFlashMode(QCamera::FlashMode mode) override
void setFocusMode(QCamera::FocusMode mode) override
void setActive(bool active) override
void setManualIsoSensitivity(int) override
void setCamera(const QCameraDevice &camera) override
void setManualExposureTime(float) override
void setExposureCompensation(float) override
void setActive(bool) override
QGstreamerCustomCamera(QObject *, QGstElement element)
bool isActive() const override
static QGstreamerIntegration * instance()
Combined button and popup list for selecting options.