7#include <private/qcameradevice_p.h>
9#include <private/qplatformmediaintegration_p.h>
10#include <QtCore/qset.h>
11#include <QtCore/qsystemdetection.h>
23bool qt_check_exposure_duration(AVCaptureDevice *captureDevice, CMTime duration)
27 AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
33 return CMTimeCompare(duration, activeFormat.minExposureDuration) != -1
34 && CMTimeCompare(activeFormat.maxExposureDuration, duration) != -1;
37bool qt_check_ISO_value(AVCaptureDevice *captureDevice,
int newISO)
41 AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
47 return !(newISO < activeFormat.minISO || newISO > activeFormat.maxISO);
50bool qt_exposure_duration_equal(AVCaptureDevice *captureDevice,
qreal qDuration)
53 const CMTime avDuration = CMTimeMakeWithSeconds(qDuration, captureDevice.exposureDuration.timescale);
54 return !CMTimeCompare(avDuration, captureDevice.exposureDuration);
57bool qt_iso_equal(AVCaptureDevice *captureDevice,
int iso)
63bool qt_exposure_bias_equal(AVCaptureDevice *captureDevice,
qreal bias)
72 AVCaptureExposureMode &avMode)
78 if ([captureDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
79 avMode = AVCaptureExposureModeContinuousAutoExposure;
85 if ([captureDevice isExposureModeSupported:AVCaptureExposureModeCustom]) {
86 avMode = AVCaptureExposureModeCustom;
102 NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
103 m_deviceConnectedObserver = [notificationCenter addObserverForName:AVCaptureDeviceWasConnectedNotification
105 queue:[NSOperationQueue mainQueue]
106 usingBlock:^(NSNotification *) {
107 this->updateCameraDevices();
110 m_deviceDisconnectedObserver = [notificationCenter addObserverForName:AVCaptureDeviceWasDisconnectedNotification
112 queue:[NSOperationQueue mainQueue]
113 usingBlock:^(NSNotification *) {
114 this->updateCameraDevices();
116 updateCameraDevices();
121 NSNotificationCenter* notificationCenter = [NSNotificationCenter defaultCenter];
122 [notificationCenter removeObserver:(
id)m_deviceConnectedObserver];
123 [notificationCenter removeObserver:(
id)m_deviceDisconnectedObserver];
128 return m_cameraDevices;
131void QAVFVideoDevices::updateCameraDevices()
135 if (!m_cameraDevices.
isEmpty())
139 QList<QCameraDevice> cameras;
146 NSArray *discoveryDevices = @[
148 AVCaptureDeviceTypeBuiltInTripleCamera,
149 AVCaptureDeviceTypeBuiltInDualCamera,
151 AVCaptureDeviceTypeBuiltInDualWideCamera,
154 AVCaptureDeviceTypeBuiltInWideAngleCamera,
157 AVCaptureDeviceTypeBuiltInTelephotoCamera,
159 AVCaptureDeviceTypeBuiltInUltraWideCamera,
163#if QT_DARWIN_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_14_0, __IPHONE_17_0, __TVOS_NA, __WATCHOS_NA)
164 if (@available(macOS 14,
iOS 17, *)) {
165 discoveryDevices = [discoveryDevices arrayByAddingObjectsFromArray: @[
166 AVCaptureDeviceTypeExternal,
167 AVCaptureDeviceTypeContinuityCamera
175 discoveryDevices = [discoveryDevices arrayByAddingObjectsFromArray: @[
176 AVCaptureDeviceTypeExternalUnknown
183 AVCaptureDeviceDiscoverySession *discoverySession = [AVCaptureDeviceDiscoverySession
184 discoverySessionWithDeviceTypes:discoveryDevices
185 mediaType:AVMediaTypeVideo
186 position:AVCaptureDevicePositionUnspecified];
187 NSArray<AVCaptureDevice *> *
videoDevices = discoverySession.devices;
190 auto info = std::make_unique<QCameraDevicePrivate>();
192 info->isDefault = true;
194 info->description = QString::fromNSString([
device localizedName]);
196 qCDebug(qLcCamera) <<
"Handling camera info" <<
info->description
197 << (
info->isDefault ?
"(default)" :
"");
199 QSet<QSize> photoResolutions;
200 QList<QCameraFormat> videoFormats;
203 if (![
format.mediaType isEqualToString:AVMediaTypeVideo])
206 auto dimensions = CMVideoFormatDescriptionGetDimensions(
format.formatDescription);
207 QSize resolution(dimensions.width, dimensions.height);
208 photoResolutions.insert(resolution);
210 float maxFrameRate = 0;
211 float minFrameRate = 1.e6;
213 auto encoding = CMVideoFormatDescriptionGetCodecType(
format.formatDescription);
218 qCDebug(qLcCamera) <<
"ignore camera CV format" << encoding
219 <<
"as no matching video format found";
223 for (AVFrameRateRange *frameRateRange
in format.videoSupportedFrameRateRanges) {
224 if (frameRateRange.minFrameRate < minFrameRate)
225 minFrameRate = frameRateRange.minFrameRate;
226 if (frameRateRange.maxFrameRate > maxFrameRate)
227 maxFrameRate = frameRateRange.maxFrameRate;
237 if (!hrRes.isNull() && hrRes.isValid())
238 photoResolutions.insert(hrRes);
241 qCDebug(qLcCamera) <<
"Add camera format. pixelFormat:" << pixelFormat
242 <<
"colorRange:" << colorRange <<
"cvPixelFormat" << encoding
243 <<
"resolution:" << resolution <<
"frameRate: [" << minFrameRate
244 << maxFrameRate <<
"]";
247 minFrameRate, maxFrameRate, colorRange };
248 videoFormats <<
f->create();
250 if (videoFormats.isEmpty()) {
253 <<
"Skip camera" <<
info->description <<
"without supported formats";
256 info->videoFormats = videoFormats;
257 info->photoResolutions = photoResolutions.values();
259 cameras.append(
info.release()->create());
262 if (cameras != m_cameraDevices) {
263 m_cameraDevices = cameras;
318 AVCaptureDevice *
device =
nullptr;
321 device = [AVCaptureDevice deviceWithUniqueID:
322 [NSString stringWithUTF8String:
344 switch (requestedMode) {
348 return AVCaptureFocusModeLocked;
350 return AVCaptureFocusModeContinuousAutoFocus;
364 AVCaptureDevice *captureDevice =
device();
365 if (!captureDevice) {
366 if (qt_focus_mode_supported(
mode)) {
370 <<
"focus mode not supported";
379 <<
"failed to lock for configuration";
383 captureDevice.focusMode = avf_focus_mode(
mode);
398 AVCaptureDevice *captureDevice =
device();
400 AVCaptureFocusMode avMode = avf_focus_mode(
mode);
410 return captureDevice.autoFocusRangeRestrictionSupported
429 AVCaptureDevice *captureDevice =
device();
433 if ([captureDevice isFocusPointOfInterestSupported]) {
440 const CGPoint focusPOI = CGPointMake(point.
x(), point.
y());
441 [captureDevice setFocusPointOfInterest:focusPOI];
443 [captureDevice
setFocusMode:AVCaptureFocusModeAutoFocus];
452 AVCaptureDevice *captureDevice =
device();
456 if (captureDevice.lockingFocusWithCustomLensPositionSupported) {
467 [captureDevice setFocusModeLockedWithLensPosition:
d completionHandler:nil];
477 AVCaptureDevice *captureDevice =
device();
478 if (!captureDevice) {
489 if ([captureDevice isFocusPointOfInterestSupported]) {
491 const CGPoint focusPOI = CGPointMake(point.x(), point.y());
492 [captureDevice setFocusPointOfInterest:focusPOI];
497 const AVCaptureFocusMode avMode = avf_focus_mode(
focusMode());
498 if (captureDevice.focusMode != avMode) {
507 if (!captureDevice.activeFormat) {
508 qCDebug(qLcCamera) <<
Q_FUNC_INFO <<
"camera state is active, but active format is nil";
517 CMTime newDuration = AVCaptureExposureDurationCurrent;
518 bool setCustomMode =
false;
522 && !qt_exposure_duration_equal(captureDevice,
exposureTime)) {
523 newDuration = CMTimeMakeWithSeconds(
exposureTime, captureDevice.exposureDuration.timescale);
524 if (!qt_check_exposure_duration(captureDevice, newDuration)) {
528 setCustomMode =
true;
531 float newISO = AVCaptureISOCurrent;
533 if (iso > 0 && !qt_iso_equal(captureDevice, iso)) {
535 if (!qt_check_ISO_value(captureDevice, newISO)) {
539 setCustomMode =
true;
543 if (
bias != 0 && !qt_exposure_bias_equal(captureDevice,
bias)) {
545 if (bias < captureDevice.minExposureTargetBias || bias > captureDevice.maxExposureTargetBias) {
550 [captureDevice setExposureTargetBias:
bias completionHandler:nil];
558 [captureDevice setExposureModeCustomWithDuration:newDuration
560 completionHandler:nil];
565 AVCaptureExposureMode avMode = AVCaptureExposureModeContinuousAutoExposure;
566 if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
571 captureDevice.exposureMode = avMode;
574 isFlashSupported = isFlashAutoSupported =
false;
575 isTorchSupported = isTorchAutoSupported =
false;
577 if (captureDevice.hasFlash) {
579 isFlashSupported =
true;
581 isFlashAutoSupported =
true;
584 if (captureDevice.hasTorch) {
586 isTorchSupported =
true;
588 isTorchAutoSupported =
true;
597 QCamera::Features features;
598 AVCaptureDevice *captureDevice =
device();
604 if (captureDevice && [captureDevice isLockingFocusWithCustomLensPositionSupported])
608 if (captureDevice && [captureDevice isFocusPointOfInterestSupported])
623 AVCaptureDevice *captureDevice =
device();
624 if (!captureDevice || !captureDevice.activeFormat)
627 factor =
qBound(captureDevice.minAvailableVideoZoomFactor, factor,
628 captureDevice.activeFormat.videoMaxZoomFactor);
637 captureDevice.videoZoomFactor = factor;
639 [captureDevice rampToVideoZoomFactor:factor withRate:
rate];
666 return isFlashSupported;
668 return isFlashAutoSupported;
676 AVCaptureDevice *captureDevice =
device();
680 if (!captureDevice.hasFlash)
689 return [captureDevice isFlashAvailable];
715 return isTorchSupported;
717 return isTorchAutoSupported;
728 AVCaptureDevice *captureDevice =
device();
729 if (!captureDevice) {
734 AVCaptureExposureMode avMode = AVCaptureExposureModeContinuousAutoExposure;
735 if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
743 <<
"for configuration";
761 if (@available(macOS 10.15, *)) {
762 AVCaptureDevice *captureDevice =
device();
773 AVCaptureDevice *captureDevice =
device();
774 if (!captureDevice) {
781 if (captureDevice.hasFlash) {
784 auto setAvFlashModeSafe = [&captureDevice](AVCaptureFlashMode avFlashMode) {
788 captureDevice.flashMode = avFlashMode;
790 qCDebug(qLcCamera) <<
"Attempt to setup unsupported flash mode " << avFlashMode;
794 setAvFlashModeSafe(AVCaptureFlashModeOff);
796 if ([captureDevice isFlashAvailable]) {
798 setAvFlashModeSafe(AVCaptureFlashModeOn);
800 setAvFlashModeSafe(AVCaptureFlashModeAuto);
807 if (captureDevice.hasTorch) {
810 auto setAvTorchModeSafe = [&captureDevice](AVCaptureTorchMode avTorchMode) {
812 captureDevice.torchMode = avTorchMode;
814 qCDebug(qLcCamera) <<
"Attempt to setup unsupported torch mode " << avTorchMode;
818 setAvTorchModeSafe(AVCaptureTorchModeOff);
820 if ([captureDevice isTorchAvailable]) {
822 setAvTorchModeSafe(AVCaptureTorchModeOn);
824 setAvTorchModeSafe(AVCaptureTorchModeAuto);
836 AVCaptureDevice *captureDevice =
device();
837 if (!captureDevice) {
842 bias =
qBound(captureDevice.minExposureTargetBias,
bias, captureDevice.maxExposureTargetBias);
850 [captureDevice setExposureTargetBias:
bias completionHandler:nil];
865 AVCaptureDevice *captureDevice =
device();
866 if (!captureDevice) {
871 const CMTime newDuration = CMTimeMakeWithSeconds(
value, captureDevice.exposureDuration.timescale);
872 if (!qt_check_exposure_duration(captureDevice, newDuration)) {
886 [captureDevice setExposureModeCustomWithDuration:newDuration
887 ISO:AVCaptureISOCurrent
888 completionHandler:nil];
900 AVCaptureDevice *captureDevice =
device();
903 auto duration = captureDevice.exposureDuration;
904 return CMTimeGetSeconds(duration);
914 AVCaptureWhiteBalanceMode &avMode)
917 avMode = AVCaptureWhiteBalanceModeContinuousAutoWhiteBalance;
919 avMode = AVCaptureWhiteBalanceModeLocked;
922bool avf_set_white_balance_mode(AVCaptureDevice *captureDevice,
923 AVCaptureWhiteBalanceMode avMode)
927 const bool lock = [captureDevice lockForConfiguration:nil];
929 qDebug() <<
"Failed to lock a capture device for configuration\n";
933 captureDevice.whiteBalanceMode = avMode;
934 [captureDevice unlockForConfiguration];
938bool avf_convert_temp_and_tint_to_wb_gains(AVCaptureDevice *captureDevice,
939 float temp,
float tint, AVCaptureWhiteBalanceGains &wbGains)
943 AVCaptureWhiteBalanceTemperatureAndTintValues wbTTValues = {
947 wbGains = [captureDevice deviceWhiteBalanceGainsForTemperatureAndTintValues:wbTTValues];
949 if (wbGains.redGain >= 1.0 && wbGains.redGain <= captureDevice.maxWhiteBalanceGain
950 && wbGains.greenGain >= 1.0 && wbGains.greenGain <= captureDevice.maxWhiteBalanceGain
951 && wbGains.blueGain >= 1.0 && wbGains.blueGain <= captureDevice.maxWhiteBalanceGain)
957bool avf_set_white_balance_gains(AVCaptureDevice *captureDevice,
958 AVCaptureWhiteBalanceGains wbGains)
960 const bool lock = [captureDevice lockForConfiguration:nil];
962 qDebug() <<
"Failed to lock a capture device for configuration\n";
966 [captureDevice setWhiteBalanceModeLockedWithDeviceWhiteBalanceGains:wbGains
967 completionHandler:nil];
968 [captureDevice unlockForConfiguration];
978 AVCaptureDevice *captureDevice =
device();
989 AVCaptureDevice *captureDevice =
device();
995 <<
"for configuration";
999 AVCaptureWhiteBalanceMode avMode;
1000 avf_convert_white_balance_mode(
mode, avMode);
1001 avf_set_white_balance_mode(captureDevice, avMode);
1009 AVCaptureWhiteBalanceGains wbGains;
1010 if (avf_convert_temp_and_tint_to_wb_gains(captureDevice, colorTemp, 0., wbGains)
1011 && avf_set_white_balance_gains(captureDevice, wbGains))
1017 if (colorTemp == 0) {
1022 AVCaptureDevice *captureDevice =
device();
1029 <<
"for configuration";
1033 AVCaptureWhiteBalanceGains wbGains;
1034 if (avf_convert_temp_and_tint_to_wb_gains(captureDevice, colorTemp, 0., wbGains)
1035 && avf_set_white_balance_gains(captureDevice, wbGains))
1048 AVCaptureDevice *captureDevice =
device();
1049 if (!captureDevice) {
1054 if (!qt_check_ISO_value(captureDevice,
value)) {
1062 <<
"for configuration";
1068 [captureDevice setExposureModeCustomWithDuration:AVCaptureExposureDurationCurrent
1070 completionHandler:nil];
1084#include "moc_qavfcamerabase_p.cpp"
QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format)
IOBluetoothDevice * device
virtual int isoSensitivity() const override
void setFocusDistance(float d) override
bool isTorchModeSupported(QCamera::TorchMode mode) const override
void setCamera(const QCameraDevice &camera) override
QCameraDevice m_cameraDevice
bool isFlashModeSupported(QCamera::FlashMode mode) const override
void setManualIsoSensitivity(int value) override
void setExposureMode(QCamera::ExposureMode) override
bool setCameraFormat(const QCameraFormat &format) override
void setActive(bool activce) override
void updateCameraConfiguration()
void setFocusMode(QCamera::FocusMode mode) override
void setCustomFocusPoint(const QPointF &point) override
void setFlashMode(QCamera::FlashMode mode) override
void setManualExposureTime(float value) override
bool isActive() const override
QAVFCameraBase(QCamera *camera)
virtual float exposureTime() const override
void setTorchMode(QCamera::TorchMode mode) override
bool isFlashReady() const override
void zoomTo(float factor, float rate) override
bool isExposureModeSupported(QCamera::ExposureMode mode) const override
AVCaptureDevice * device() const
void updateCameraProperties()
void applyFlashSettings()
void setExposureCompensation(float bias) override
bool isFocusModeSupported(QCamera::FocusMode mode) const override
QList< QCameraDevice > videoDevices() const override
QAVFVideoDevices(QPlatformMediaIntegration *integration)
const char * constData() const noexcept
Returns a pointer to the const data stored in the byte array.
bool isEmpty() const noexcept
Returns true if the byte array has size 0; otherwise returns false.
The QCameraDevice class provides general information about camera devices.
bool isNull() const
Returns true if this QCameraDevice is null or invalid.
QList< QCameraFormat > videoFormats
\qmlproperty CameraFormat QtMultimedia::cameraDevice::videoFormats
QByteArray id
\qmlproperty string QtMultimedia::cameraDevice::id
The QCamera class provides interface for system camera devices.
WhiteBalanceMode
\value WhiteBalanceAuto Auto white balance mode.
TorchMode
\value TorchOff Torch is Off.
FocusMode
\value FocusModeAuto Continuous auto focus mode.
FlashMode
\value FlashOff Flash is Off.
ExposureMode
\value ExposureAuto Automatic mode.
bool isEmpty() const noexcept
\inmodule QtCore\reentrant
constexpr qreal x() const noexcept
Returns the x coordinate of this point.
constexpr qreal y() const noexcept
Returns the y coordinate of this point.
\inmodule QtCore\reentrant
QVideoFrameFormat::ColorRange colorRangeForCVPixelFormat(CvPixelFormat cvPixelFormat)
QVideoFrameFormat::PixelFormat fromCVPixelFormat(CvPixelFormat cvPixelFormat)
#define QT_WARNING_DISABLE_DEPRECATED
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
bool qFuzzyCompare(qfloat16 p1, qfloat16 p2) noexcept
#define qCWarning(category,...)
#define qCDebug(category,...)
constexpr const T & qBound(const T &min, const T &val, const T &max)
static bool contains(const QJsonArray &haystack, unsigned needle)
GLint GLsizei GLsizei GLenum format
static qreal position(const QQuickItem *item, QQuickAnchors::Anchor anchorLine)
bool contains(const AT &t) const noexcept