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