AVFCameraExposureControl - exposure control for iOS
Exposure control, version for AVFoundation plugin (this code is using quite a new API, iOS >=8 only). Change-Id: I6871a758e8dfb98ab46b66d91a44142163e0bb44 Reviewed-by: Yoann Lopes <yoann.lopes@theqtcompany.com>
This commit is contained in:
83
src/plugins/avfoundation/camera/avfcameraexposurecontrol.h
Normal file
83
src/plugins/avfoundation/camera/avfcameraexposurecontrol.h
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** 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 Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/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.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef AVFCAMERAEXPOSURECONTROL_H
|
||||||
|
#define AVFCAMERAEXPOSURECONTROL_H
|
||||||
|
|
||||||
|
#include <QtMultimedia/qcameraexposurecontrol.h>
|
||||||
|
#include <QtMultimedia/qcameraexposure.h>
|
||||||
|
|
||||||
|
#include <QtCore/qglobal.h>
|
||||||
|
|
||||||
|
QT_BEGIN_NAMESPACE
|
||||||
|
|
||||||
|
class AVFCameraSession;
|
||||||
|
class AVFCameraService;
|
||||||
|
|
||||||
|
class AVFCameraExposureControl : public QCameraExposureControl
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
AVFCameraExposureControl(AVFCameraService *service);
|
||||||
|
|
||||||
|
bool isParameterSupported(ExposureParameter parameter) const Q_DECL_OVERRIDE;
|
||||||
|
QVariantList supportedParameterRange(ExposureParameter parameter,
|
||||||
|
bool *continuous) const Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
QVariant requestedValue(ExposureParameter parameter) const Q_DECL_OVERRIDE;
|
||||||
|
QVariant actualValue(ExposureParameter parameter) const Q_DECL_OVERRIDE;
|
||||||
|
bool setValue(ExposureParameter parameter, const QVariant &value) Q_DECL_OVERRIDE;
|
||||||
|
|
||||||
|
private Q_SLOTS:
|
||||||
|
void cameraStateChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
AVFCameraService *m_service;
|
||||||
|
AVFCameraSession *m_session;
|
||||||
|
|
||||||
|
QVariant m_requestedMode;
|
||||||
|
QVariant m_requestedCompensation;
|
||||||
|
QVariant m_requestedShutterSpeed;
|
||||||
|
QVariant m_requestedISO;
|
||||||
|
|
||||||
|
// Aux. setters:
|
||||||
|
bool setExposureMode(const QVariant &value);
|
||||||
|
bool setExposureCompensation(const QVariant &value);
|
||||||
|
bool setShutterSpeed(const QVariant &value);
|
||||||
|
bool setISO(const QVariant &value);
|
||||||
|
};
|
||||||
|
|
||||||
|
QT_END_NAMESPACE
|
||||||
|
|
||||||
|
#endif
|
||||||
656
src/plugins/avfoundation/camera/avfcameraexposurecontrol.mm
Normal file
656
src/plugins/avfoundation/camera/avfcameraexposurecontrol.mm
Normal file
@@ -0,0 +1,656 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
**
|
||||||
|
** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies).
|
||||||
|
** Contact: http://www.qt-project.org/legal
|
||||||
|
**
|
||||||
|
** 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 Digia. For licensing terms and
|
||||||
|
** conditions see http://qt.digia.com/licensing. For further information
|
||||||
|
** use the contact form at http://qt.digia.com/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.
|
||||||
|
**
|
||||||
|
** In addition, as a special exception, Digia gives you certain additional
|
||||||
|
** rights. These rights are described in the Digia Qt LGPL Exception
|
||||||
|
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
|
||||||
|
**
|
||||||
|
** $QT_END_LICENSE$
|
||||||
|
**
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#include "avfcameraexposurecontrol.h"
|
||||||
|
#include "avfconfigurationlock.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"
|
||||||
@@ -53,6 +53,7 @@ class AVFCameraSession;
|
|||||||
class AVFCameraDeviceControl;
|
class AVFCameraDeviceControl;
|
||||||
class AVFAudioInputSelectorControl;
|
class AVFAudioInputSelectorControl;
|
||||||
class AVFCameraFocusControl;
|
class AVFCameraFocusControl;
|
||||||
|
class AVFCameraExposureControl;
|
||||||
|
|
||||||
class AVFCameraService : public QMediaService
|
class AVFCameraService : public QMediaService
|
||||||
{
|
{
|
||||||
@@ -72,6 +73,7 @@ public:
|
|||||||
AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; }
|
AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; }
|
||||||
AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; }
|
AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; }
|
||||||
AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; }
|
AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; }
|
||||||
|
AVFCameraExposureControl *cameraExposureControl() const {return m_cameraExposureControl; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AVFCameraSession *m_session;
|
AVFCameraSession *m_session;
|
||||||
@@ -84,6 +86,7 @@ private:
|
|||||||
AVFMediaRecorderControl *m_recorderControl;
|
AVFMediaRecorderControl *m_recorderControl;
|
||||||
AVFImageCaptureControl *m_imageCaptureControl;
|
AVFImageCaptureControl *m_imageCaptureControl;
|
||||||
AVFCameraFocusControl *m_cameraFocusControl;
|
AVFCameraFocusControl *m_cameraFocusControl;
|
||||||
|
AVFCameraExposureControl *m_cameraExposureControl;
|
||||||
};
|
};
|
||||||
|
|
||||||
QT_END_NAMESPACE
|
QT_END_NAMESPACE
|
||||||
|
|||||||
@@ -41,6 +41,7 @@
|
|||||||
|
|
||||||
#include <QtCore/qvariant.h>
|
#include <QtCore/qvariant.h>
|
||||||
#include <QtCore/qdebug.h>
|
#include <QtCore/qdebug.h>
|
||||||
|
#include <QtCore/qsysinfo.h>
|
||||||
|
|
||||||
#include "avfcameraservice.h"
|
#include "avfcameraservice.h"
|
||||||
#include "avfcameracontrol.h"
|
#include "avfcameracontrol.h"
|
||||||
@@ -56,6 +57,7 @@
|
|||||||
#include "avfimagecapturecontrol.h"
|
#include "avfimagecapturecontrol.h"
|
||||||
#include "avfmediavideoprobecontrol.h"
|
#include "avfmediavideoprobecontrol.h"
|
||||||
#include "avfcamerafocuscontrol.h"
|
#include "avfcamerafocuscontrol.h"
|
||||||
|
#include "avfcameraexposurecontrol.h"
|
||||||
|
|
||||||
#include <private/qmediaplaylistnavigator_p.h>
|
#include <private/qmediaplaylistnavigator_p.h>
|
||||||
#include <qmediaplaylist.h>
|
#include <qmediaplaylist.h>
|
||||||
@@ -75,8 +77,12 @@ AVFCameraService::AVFCameraService(QObject *parent):
|
|||||||
m_metaDataControl = new AVFCameraMetaDataControl(this);
|
m_metaDataControl = new AVFCameraMetaDataControl(this);
|
||||||
m_recorderControl = new AVFMediaRecorderControl(this);
|
m_recorderControl = new AVFMediaRecorderControl(this);
|
||||||
m_imageCaptureControl = new AVFImageCaptureControl(this);
|
m_imageCaptureControl = new AVFImageCaptureControl(this);
|
||||||
|
|
||||||
m_cameraFocusControl = new AVFCameraFocusControl(this);
|
m_cameraFocusControl = new AVFCameraFocusControl(this);
|
||||||
|
m_cameraExposureControl = 0;
|
||||||
|
#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0)
|
||||||
|
if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0)
|
||||||
|
m_cameraExposureControl = new AVFCameraExposureControl(this);
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
AVFCameraService::~AVFCameraService()
|
AVFCameraService::~AVFCameraService()
|
||||||
@@ -96,6 +102,7 @@ AVFCameraService::~AVFCameraService()
|
|||||||
delete m_metaDataControl;
|
delete m_metaDataControl;
|
||||||
delete m_cameraControl;
|
delete m_cameraControl;
|
||||||
delete m_cameraFocusControl;
|
delete m_cameraFocusControl;
|
||||||
|
delete m_cameraExposureControl;
|
||||||
|
|
||||||
delete m_session;
|
delete m_session;
|
||||||
}
|
}
|
||||||
@@ -124,6 +131,9 @@ QMediaControl *AVFCameraService::requestControl(const char *name)
|
|||||||
if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0)
|
if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0)
|
||||||
return m_imageCaptureControl;
|
return m_imageCaptureControl;
|
||||||
|
|
||||||
|
if (qstrcmp(name, QCameraExposureControl_iid) == 0)
|
||||||
|
return m_cameraExposureControl;
|
||||||
|
|
||||||
if (qstrcmp(name, QCameraFocusControl_iid) == 0)
|
if (qstrcmp(name, QCameraFocusControl_iid) == 0)
|
||||||
return m_cameraFocusControl;
|
return m_cameraFocusControl;
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ HEADERS += \
|
|||||||
avfcamerarenderercontrol.h \
|
avfcamerarenderercontrol.h \
|
||||||
avfcameradevicecontrol.h \
|
avfcameradevicecontrol.h \
|
||||||
avfcamerafocuscontrol.h \
|
avfcamerafocuscontrol.h \
|
||||||
|
avfcameraexposurecontrol.h \
|
||||||
avfconfigurationlock.h
|
avfconfigurationlock.h
|
||||||
|
|
||||||
OBJECTIVE_SOURCES += \
|
OBJECTIVE_SOURCES += \
|
||||||
@@ -55,5 +56,6 @@ OBJECTIVE_SOURCES += \
|
|||||||
avfcamerainfocontrol.mm \
|
avfcamerainfocontrol.mm \
|
||||||
avfcameradevicecontrol.mm \
|
avfcameradevicecontrol.mm \
|
||||||
avfcamerarenderercontrol.mm \
|
avfcamerarenderercontrol.mm \
|
||||||
avfcamerafocuscontrol.mm
|
avfcamerafocuscontrol.mm \
|
||||||
|
avfcameraexposurecontrol.mm
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user