Move configuration lock class into avfutility.h + add several standalone functions to work with AVCaptureDeviceFormat/AVCaptureDevice etc. - utility functions that are not specific to any class. Change-Id: Idba544248772a3b2a4e00dddb377b1c0e62b8085 Reviewed-by: Yoann Lopes <yoann.lopes@theqtcompany.com>
657 lines
23 KiB
Plaintext
657 lines
23 KiB
Plaintext
/****************************************************************************
|
|
**
|
|
** Copyright (C) 2015 The Qt Company Ltd.
|
|
** Contact: http://www.qt.io/licensing/
|
|
**
|
|
** This file is part of the Qt Toolkit.
|
|
**
|
|
** $QT_BEGIN_LICENSE:LGPL21$
|
|
** Commercial License Usage
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
** accordance with the commercial license agreement provided with the
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
** and conditions see http://www.qt.io/terms-conditions. For further
|
|
** information use the contact form at http://www.qt.io/contact-us.
|
|
**
|
|
** GNU Lesser General Public License Usage
|
|
** Alternatively, this file may be used under the terms of the GNU Lesser
|
|
** General Public License version 2.1 or version 3 as published by the Free
|
|
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
|
|
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
|
|
** following information to ensure the GNU Lesser General Public License
|
|
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
|
|
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
|
|
**
|
|
** As a special exception, The Qt Company gives you certain additional
|
|
** rights. These rights are described in The Qt Company LGPL Exception
|
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
|
**
|
|
** $QT_END_LICENSE$
|
|
**
|
|
****************************************************************************/
|
|
|
|
#include "avfcameraexposurecontrol.h"
|
|
#include "avfcamerautility.h"
|
|
#include "avfcamerasession.h"
|
|
#include "avfcameraservice.h"
|
|
#include "avfcameradebug.h"
|
|
|
|
#include <QtCore/qvariant.h>
|
|
#include <QtCore/qpointer.h>
|
|
#include <QtCore/qdebug.h>
|
|
#include <QtCore/qpair.h>
|
|
|
|
#include <AVFoundation/AVFoundation.h>
|
|
|
|
#include <limits>
|
|
|
|
QT_BEGIN_NAMESPACE
|
|
|
|
namespace {
|
|
|
|
// All these methods to work with exposure/ISO/SS in custom mode
|
|
// are quite new (iOS 8 or later and no OS X support).
|
|
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
|
|
// Misc. helpers to check values/ranges:
|
|
|
|
bool qt_check_ISO_conversion(float isoValue)
|
|
{
|
|
if (isoValue >= std::numeric_limits<int>::max())
|
|
return false;
|
|
if (isoValue <= std::numeric_limits<int>::min())
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
bool qt_check_ISO_range(AVCaptureDeviceFormat *format)
|
|
{
|
|
// Qt is using int for ISO, AVFoundation - float. It looks like the ISO range
|
|
// at the moment can be represented by int (it's max - min > 100, etc.).
|
|
Q_ASSERT(format);
|
|
if (format.maxISO - format.minISO < 1.) {
|
|
// ISO is in some strange units?
|
|
return false;
|
|
}
|
|
|
|
return qt_check_ISO_conversion(format.minISO)
|
|
&& qt_check_ISO_conversion(format.maxISO);
|
|
}
|
|
|
|
bool qt_check_exposure_duration(AVCaptureDevice *captureDevice, CMTime duration)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
|
|
AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
|
|
if (!activeFormat) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
|
|
return false;
|
|
}
|
|
|
|
return CMTimeCompare(duration, activeFormat.minExposureDuration) != -1
|
|
&& CMTimeCompare(activeFormat.maxExposureDuration, duration) != -1;
|
|
}
|
|
|
|
bool qt_check_ISO_value(AVCaptureDevice *captureDevice, int newISO)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
|
|
AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
|
|
if (!activeFormat) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
|
|
return false;
|
|
}
|
|
|
|
return !(newISO < activeFormat.minISO || newISO > activeFormat.maxISO);
|
|
}
|
|
|
|
bool qt_exposure_duration_equal(AVCaptureDevice *captureDevice, qreal qDuration)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
const CMTime avDuration = CMTimeMakeWithSeconds(qDuration, captureDevice.exposureDuration.timescale);
|
|
return !CMTimeCompare(avDuration, captureDevice.exposureDuration);
|
|
}
|
|
|
|
bool qt_iso_equal(AVCaptureDevice *captureDevice, int iso)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
return qFuzzyCompare(float(iso), captureDevice.ISO);
|
|
}
|
|
|
|
bool qt_exposure_bias_equal(AVCaptureDevice *captureDevice, qreal bias)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
return qFuzzyCompare(bias, qreal(captureDevice.exposureTargetBias));
|
|
}
|
|
|
|
// Converters:
|
|
|
|
bool qt_convert_exposure_mode(AVCaptureDevice *captureDevice, QCameraExposure::ExposureMode mode,
|
|
AVCaptureExposureMode &avMode)
|
|
{
|
|
// Test if mode supported and convert.
|
|
Q_ASSERT(captureDevice);
|
|
|
|
if (mode == QCameraExposure::ExposureAuto) {
|
|
if ([captureDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure]) {
|
|
avMode = AVCaptureExposureModeContinuousAutoExposure;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
if (mode == QCameraExposure::ExposureManual) {
|
|
if ([captureDevice isExposureModeSupported:AVCaptureExposureModeCustom]) {
|
|
avMode = AVCaptureExposureModeCustom;
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// We set ISO/exposure duration with completion handlers, completion handlers try
|
|
// to avoid dangling pointers (thus QPointer for QObjects) and not to create
|
|
// a reference loop (in case we have ARC).
|
|
|
|
void qt_set_exposure_bias(QPointer<AVFCameraService> service, QPointer<AVFCameraExposureControl> control,
|
|
AVCaptureDevice *captureDevice, float bias)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
|
|
__block AVCaptureDevice *device = captureDevice; //For ARC.
|
|
|
|
void (^completionHandler)(CMTime syncTime) = ^(CMTime) {
|
|
// Test that service control is still alive and that
|
|
// capture device is our device, if yes - emit actual value changed.
|
|
if (service) {
|
|
if (control) {
|
|
if (service->session() && service->session()->videoCaptureDevice() == device)
|
|
Q_EMIT control->actualValueChanged(int(QCameraExposureControl::ExposureCompensation));
|
|
}
|
|
}
|
|
device = nil;
|
|
};
|
|
|
|
[captureDevice setExposureTargetBias:bias completionHandler:completionHandler];
|
|
}
|
|
|
|
void qt_set_duration_iso(QPointer<AVFCameraService> service, QPointer<AVFCameraExposureControl> control,
|
|
AVCaptureDevice *captureDevice, CMTime duration, float iso)
|
|
{
|
|
Q_ASSERT(captureDevice);
|
|
|
|
__block AVCaptureDevice *device = captureDevice; //For ARC.
|
|
const bool setDuration = CMTimeCompare(duration, AVCaptureExposureDurationCurrent);
|
|
const bool setISO = !qFuzzyCompare(iso, AVCaptureISOCurrent);
|
|
|
|
void (^completionHandler)(CMTime syncTime) = ^(CMTime) {
|
|
// Test that service control is still alive and that
|
|
// capture device is our device, if yes - emit actual value changed.
|
|
if (service) {
|
|
if (control) {
|
|
if (service->session() && service->session()->videoCaptureDevice() == device) {
|
|
if (setDuration)
|
|
Q_EMIT control->actualValueChanged(int(QCameraExposureControl::ShutterSpeed));
|
|
if (setISO)
|
|
Q_EMIT control->actualValueChanged(int(QCameraExposureControl::ISO));
|
|
}
|
|
}
|
|
}
|
|
device = nil;
|
|
};
|
|
|
|
[captureDevice setExposureModeCustomWithDuration:duration
|
|
ISO:iso
|
|
completionHandler:completionHandler];
|
|
}
|
|
|
|
#endif // QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
|
|
} // Unnamed namespace.
|
|
|
|
AVFCameraExposureControl::AVFCameraExposureControl(AVFCameraService *service)
|
|
: m_service(service),
|
|
m_session(Q_NULLPTR)
|
|
{
|
|
Q_ASSERT(service);
|
|
m_session = m_service->session();
|
|
Q_ASSERT(m_session);
|
|
|
|
connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(cameraStateChanged()));
|
|
}
|
|
|
|
bool AVFCameraExposureControl::isParameterSupported(ExposureParameter parameter) const
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice)
|
|
return false;
|
|
|
|
// These are the parameters we have an API to support:
|
|
return parameter == QCameraExposureControl::ISO
|
|
|| parameter == QCameraExposureControl::ShutterSpeed
|
|
|| parameter == QCameraExposureControl::ExposureCompensation
|
|
|| parameter == QCameraExposureControl::ExposureMode;
|
|
#else
|
|
Q_UNUSED(parameter)
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
QVariantList AVFCameraExposureControl::supportedParameterRange(ExposureParameter parameter,
|
|
bool *continuous) const
|
|
{
|
|
QVariantList parameterRange;
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice || !isParameterSupported(parameter)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "parameter not supported";
|
|
return parameterRange;
|
|
}
|
|
|
|
if (continuous)
|
|
*continuous = false;
|
|
|
|
AVCaptureDeviceFormat *activeFormat = captureDevice.activeFormat;
|
|
|
|
if (parameter == QCameraExposureControl::ISO) {
|
|
if (!activeFormat) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
|
|
return parameterRange;
|
|
}
|
|
|
|
if (!qt_check_ISO_range(activeFormat)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "ISO range can not be represented as int";
|
|
return parameterRange;
|
|
}
|
|
|
|
parameterRange << QVariant(int(activeFormat.minISO));
|
|
parameterRange << QVariant(int(activeFormat.maxISO));
|
|
if (continuous)
|
|
*continuous = true;
|
|
} else if (parameter == QCameraExposureControl::ExposureCompensation) {
|
|
parameterRange << captureDevice.minExposureTargetBias;
|
|
parameterRange << captureDevice.maxExposureTargetBias;
|
|
if (continuous)
|
|
*continuous = true;
|
|
} else if (parameter == QCameraExposureControl::ShutterSpeed) {
|
|
if (!activeFormat) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to obtain capture device format";
|
|
return parameterRange;
|
|
}
|
|
|
|
// CMTimeGetSeconds returns Float64, test the conversion below, if it's valid?
|
|
parameterRange << qreal(CMTimeGetSeconds(activeFormat.minExposureDuration));
|
|
parameterRange << qreal(CMTimeGetSeconds(activeFormat.maxExposureDuration));
|
|
|
|
if (continuous)
|
|
*continuous = true;
|
|
} else if (parameter == QCameraExposureControl::ExposureMode) {
|
|
if ([captureDevice isExposureModeSupported:AVCaptureExposureModeCustom])
|
|
parameterRange << QVariant::fromValue(QCameraExposure::ExposureManual);
|
|
|
|
if ([captureDevice isExposureModeSupported:AVCaptureExposureModeContinuousAutoExposure])
|
|
parameterRange << QVariant::fromValue(QCameraExposure::ExposureAuto);
|
|
}
|
|
#else
|
|
Q_UNUSED(parameter)
|
|
Q_UNUSED(continuous)
|
|
#endif
|
|
return parameterRange;
|
|
}
|
|
|
|
QVariant AVFCameraExposureControl::requestedValue(ExposureParameter parameter) const
|
|
{
|
|
if (!isParameterSupported(parameter)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "parameter not supported";
|
|
return QVariant();
|
|
}
|
|
|
|
if (parameter == QCameraExposureControl::ExposureMode)
|
|
return m_requestedMode;
|
|
|
|
if (parameter == QCameraExposureControl::ExposureCompensation)
|
|
return m_requestedCompensation;
|
|
|
|
if (parameter == QCameraExposureControl::ShutterSpeed)
|
|
return m_requestedShutterSpeed;
|
|
|
|
if (parameter == QCameraExposureControl::ISO)
|
|
return m_requestedISO;
|
|
|
|
return QVariant();
|
|
}
|
|
|
|
QVariant AVFCameraExposureControl::actualValue(ExposureParameter parameter) const
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice || !isParameterSupported(parameter)) {
|
|
// Actually, at the moment !captiredevice => !isParameterSupported.
|
|
qDebugCamera() << Q_FUNC_INFO << "parameter not supported";
|
|
return QVariant();
|
|
}
|
|
|
|
if (parameter == QCameraExposureControl::ExposureMode) {
|
|
// This code expects exposureMode to be continuous by default ...
|
|
if (captureDevice.exposureMode == AVCaptureExposureModeContinuousAutoExposure)
|
|
return QVariant::fromValue(QCameraExposure::ExposureAuto);
|
|
return QVariant::fromValue(QCameraExposure::ExposureManual);
|
|
}
|
|
|
|
if (parameter == QCameraExposureControl::ExposureCompensation)
|
|
return captureDevice.exposureTargetBias;
|
|
|
|
if (parameter == QCameraExposureControl::ShutterSpeed)
|
|
return qreal(CMTimeGetSeconds(captureDevice.exposureDuration));
|
|
|
|
if (parameter == QCameraExposureControl::ISO) {
|
|
if (captureDevice.activeFormat && qt_check_ISO_range(captureDevice.activeFormat)
|
|
&& qt_check_ISO_conversion(captureDevice.ISO)) {
|
|
// Can be represented as int ...
|
|
return int(captureDevice.ISO);
|
|
} else {
|
|
qDebugCamera() << Q_FUNC_INFO << "ISO can not be represented as int";
|
|
return QVariant();
|
|
}
|
|
}
|
|
#else
|
|
Q_UNUSED(parameter)
|
|
#endif
|
|
return QVariant();
|
|
}
|
|
|
|
bool AVFCameraExposureControl::setValue(ExposureParameter parameter, const QVariant &value)
|
|
{
|
|
if (parameter == QCameraExposureControl::ExposureMode)
|
|
return setExposureMode(value);
|
|
else if (parameter == QCameraExposureControl::ExposureCompensation)
|
|
return setExposureCompensation(value);
|
|
else if (parameter == QCameraExposureControl::ShutterSpeed)
|
|
return setShutterSpeed(value);
|
|
else if (parameter == QCameraExposureControl::ISO)
|
|
return setISO(value);
|
|
|
|
return false;
|
|
}
|
|
|
|
bool AVFCameraExposureControl::setExposureMode(const QVariant &value)
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
if (!value.canConvert<QCameraExposure::ExposureMode>()) {
|
|
qDebugCamera() << Q_FUNC_INFO << "invalid exposure mode value,"
|
|
<< "QCameraExposure::ExposureMode expected";
|
|
return false;
|
|
}
|
|
|
|
const QCameraExposure::ExposureMode qtMode = value.value<QCameraExposure::ExposureMode>();
|
|
if (qtMode != QCameraExposure::ExposureAuto && qtMode != QCameraExposure::ExposureManual) {
|
|
qDebugCamera() << Q_FUNC_INFO << "exposure mode not supported";
|
|
return false;
|
|
}
|
|
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice) {
|
|
m_requestedMode = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ExposureMode));
|
|
return true;
|
|
}
|
|
|
|
AVCaptureExposureMode avMode = AVCaptureExposureModeAutoExpose;
|
|
if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "exposure mode not supported";
|
|
return false;
|
|
}
|
|
|
|
const AVFConfigurationLock lock(captureDevice);
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
|
|
<< "for configuration";
|
|
return false;
|
|
}
|
|
|
|
m_requestedMode = value;
|
|
[captureDevice setExposureMode:avMode];
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ExposureMode));
|
|
Q_EMIT actualValueChanged(int(QCameraExposureControl::ExposureMode));
|
|
|
|
return true;
|
|
#else
|
|
Q_UNUSED(value)
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool AVFCameraExposureControl::setExposureCompensation(const QVariant &value)
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
if (!value.canConvert<qreal>()) {
|
|
qDebugCamera() << Q_FUNC_INFO << "invalid exposure compensation"
|
|
<<"value, floating point number expected";
|
|
return false;
|
|
}
|
|
|
|
const qreal bias = value.toReal();
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice) {
|
|
m_requestedCompensation = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ExposureCompensation));
|
|
return true;
|
|
}
|
|
|
|
if (bias < captureDevice.minExposureTargetBias || bias > captureDevice.maxExposureTargetBias) {
|
|
// TODO: mixed fp types!
|
|
qDebugCamera() << Q_FUNC_INFO << "exposure compenstation value is"
|
|
<< "out of range";
|
|
return false;
|
|
}
|
|
|
|
const AVFConfigurationLock lock(captureDevice);
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
|
|
return false;
|
|
}
|
|
|
|
qt_set_exposure_bias(m_service, this, captureDevice, bias);
|
|
m_requestedCompensation = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ExposureCompensation));
|
|
|
|
return true;
|
|
#else
|
|
Q_UNUSED(value)
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool AVFCameraExposureControl::setShutterSpeed(const QVariant &value)
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
if (value.isNull())
|
|
return setExposureMode(QVariant::fromValue(QCameraExposure::ExposureAuto));
|
|
|
|
if (!value.canConvert<qreal>()) {
|
|
qDebugCamera() << Q_FUNC_INFO << "invalid shutter speed"
|
|
<< "value, floating point number expected";
|
|
return false;
|
|
}
|
|
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice) {
|
|
m_requestedShutterSpeed = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ShutterSpeed));
|
|
return true;
|
|
}
|
|
|
|
const CMTime newDuration = CMTimeMakeWithSeconds(value.toReal(),
|
|
captureDevice.exposureDuration.timescale);
|
|
if (!qt_check_exposure_duration(captureDevice, newDuration)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "shutter speed value is out of range";
|
|
return false;
|
|
}
|
|
|
|
const AVFConfigurationLock lock(captureDevice);
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
|
|
return false;
|
|
}
|
|
|
|
// Setting the shutter speed (exposure duration in Apple's terms,
|
|
// since there is no shutter actually) will also reset
|
|
// exposure mode into custom mode.
|
|
qt_set_duration_iso(m_service, this, captureDevice, newDuration, AVCaptureISOCurrent);
|
|
|
|
m_requestedShutterSpeed = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ShutterSpeed));
|
|
|
|
return true;
|
|
#else
|
|
Q_UNUSED(value)
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
bool AVFCameraExposureControl::setISO(const QVariant &value)
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
if (value.isNull())
|
|
return setExposureMode(QVariant::fromValue(QCameraExposure::ExposureAuto));
|
|
|
|
if (!value.canConvert<int>()) {
|
|
qDebugCamera() << Q_FUNC_INFO << "invalid ISO value, int expected";
|
|
return false;
|
|
}
|
|
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice) {
|
|
m_requestedISO = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ISO));
|
|
return true;
|
|
}
|
|
|
|
if (!qt_check_ISO_value(captureDevice, value.toInt())) {
|
|
qDebugCamera() << Q_FUNC_INFO << "ISO value is out of range";
|
|
return false;
|
|
}
|
|
|
|
const AVFConfigurationLock lock(captureDevice);
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock a capture device"
|
|
<< "for configuration";
|
|
return false;
|
|
}
|
|
|
|
// Setting the ISO will also reset
|
|
// exposure mode to the custom mode.
|
|
qt_set_duration_iso(m_service, this, captureDevice, AVCaptureExposureDurationCurrent, value.toInt());
|
|
|
|
m_requestedISO = value;
|
|
Q_EMIT requestedValueChanged(int(QCameraExposureControl::ISO));
|
|
|
|
return true;
|
|
#else
|
|
Q_UNUSED(value)
|
|
return false;
|
|
#endif
|
|
}
|
|
|
|
void AVFCameraExposureControl::cameraStateChanged()
|
|
{
|
|
#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
|
if (m_session->state() != QCamera::ActiveState)
|
|
return;
|
|
|
|
AVCaptureDevice *captureDevice = m_session->videoCaptureDevice();
|
|
if (!captureDevice) {
|
|
qDebugCamera() << Q_FUNC_INFO << "capture device is nil, but the session"
|
|
<< "state is 'active'";
|
|
return;
|
|
}
|
|
|
|
Q_EMIT parameterRangeChanged(int(QCameraExposureControl::ExposureCompensation));
|
|
Q_EMIT parameterRangeChanged(int(QCameraExposureControl::ExposureMode));
|
|
Q_EMIT parameterRangeChanged(int(QCameraExposureControl::ShutterSpeed));
|
|
Q_EMIT parameterRangeChanged(int(QCameraExposureControl::ISO));
|
|
|
|
const AVFConfigurationLock lock(captureDevice);
|
|
|
|
CMTime newDuration = AVCaptureExposureDurationCurrent;
|
|
bool setCustomMode = false;
|
|
|
|
if (!m_requestedShutterSpeed.isNull()
|
|
&& !qt_exposure_duration_equal(captureDevice, m_requestedShutterSpeed.toReal())) {
|
|
newDuration = CMTimeMakeWithSeconds(m_requestedShutterSpeed.toReal(),
|
|
captureDevice.exposureDuration.timescale);
|
|
if (!qt_check_exposure_duration(captureDevice, newDuration)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "requested exposure duration is out of range";
|
|
return;
|
|
}
|
|
setCustomMode = true;
|
|
}
|
|
|
|
float newISO = AVCaptureISOCurrent;
|
|
if (!m_requestedISO.isNull() && !qt_iso_equal(captureDevice, m_requestedISO.toInt())) {
|
|
newISO = m_requestedISO.toInt();
|
|
if (!qt_check_ISO_value(captureDevice, newISO)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "requested ISO value is out of range";
|
|
return;
|
|
}
|
|
setCustomMode = true;
|
|
}
|
|
|
|
if (!m_requestedCompensation.isNull()
|
|
&& !qt_exposure_bias_equal(captureDevice, m_requestedCompensation.toReal())) {
|
|
// TODO: mixed fpns.
|
|
const qreal bias = m_requestedCompensation.toReal();
|
|
if (bias < captureDevice.minExposureTargetBias || bias > captureDevice.maxExposureTargetBias) {
|
|
qDebugCamera() << Q_FUNC_INFO << "exposure compenstation value is"
|
|
<< "out of range";
|
|
return;
|
|
}
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
|
|
return;
|
|
}
|
|
qt_set_exposure_bias(m_service, this, captureDevice, bias);
|
|
}
|
|
|
|
// Setting shutter speed (exposure duration) or ISO values
|
|
// also reset exposure mode into Custom. With this settings
|
|
// we ignore any attempts to set exposure mode.
|
|
|
|
if (setCustomMode) {
|
|
if (!lock)
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
|
|
else
|
|
qt_set_duration_iso(m_service, this, captureDevice, newDuration, newISO);
|
|
return;
|
|
}
|
|
|
|
if (!m_requestedMode.isNull()) {
|
|
QCameraExposure::ExposureMode qtMode = m_requestedMode.value<QCameraExposure::ExposureMode>();
|
|
AVCaptureExposureMode avMode = AVCaptureExposureModeContinuousAutoExposure;
|
|
if (!qt_convert_exposure_mode(captureDevice, qtMode, avMode)) {
|
|
qDebugCamera() << Q_FUNC_INFO << "requested exposure mode is not supported";
|
|
return;
|
|
}
|
|
|
|
if (avMode == captureDevice.exposureMode)
|
|
return;
|
|
|
|
if (!lock) {
|
|
qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration";
|
|
return;
|
|
}
|
|
|
|
[captureDevice setExposureMode:avMode];
|
|
Q_EMIT actualValueChanged(int(QCameraExposureControl::ExposureMode));
|
|
}
|
|
#endif
|
|
}
|
|
|
|
QT_END_NAMESPACE
|
|
|
|
#include "moc_avfcameraexposurecontrol.cpp"
|