diff options
Diffstat (limited to 'src/plugins/avfoundation/camera')
42 files changed, 4140 insertions, 434 deletions
diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h index 2f499f0ab..8ad89bcc2 100644 --- a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h +++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm index 51a4eb4e6..d0d0c8209 100644 --- a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm +++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfcameracontrol.h b/src/plugins/avfoundation/camera/avfcameracontrol.h index a1ca52de5..4d146537e 100644 --- a/src/plugins/avfoundation/camera/avfcameracontrol.h +++ b/src/plugins/avfoundation/camera/avfcameracontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfcameracontrol.mm b/src/plugins/avfoundation/camera/avfcameracontrol.mm index e3727b1e7..bfd14a20e 100644 --- a/src/plugins/avfoundation/camera/avfcameracontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameracontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfcameradebug.h b/src/plugins/avfoundation/camera/avfcameradebug.h index a700ddfb1..bb236da4c 100644 --- a/src/plugins/avfoundation/camera/avfcameradebug.h +++ b/src/plugins/avfoundation/camera/avfcameradebug.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.h b/src/plugins/avfoundation/camera/avfcameradevicecontrol.h index c46d1bd67..c6a859332 100644 --- a/src/plugins/avfoundation/camera/avfvideodevicecontrol.h +++ b/src/plugins/avfoundation/camera/avfcameradevicecontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,16 +23,16 @@ ** 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 +** 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$ ** ****************************************************************************/ -#ifndef AVFVIDEODEVICECONTROL_H -#define AVFVIDEODEVICECONTROL_H +#ifndef AVFCAMERADEVICECONTROL_H +#define AVFCAMERADEVICECONTROL_H #include <QtMultimedia/qvideodeviceselectorcontrol.h> #include <QtCore/qstringlist.h> @@ -44,12 +44,12 @@ QT_BEGIN_NAMESPACE class AVFCameraSession; class AVFCameraService; -class AVFVideoDeviceControl : public QVideoDeviceSelectorControl +class AVFCameraDeviceControl : public QVideoDeviceSelectorControl { Q_OBJECT public: - AVFVideoDeviceControl(AVFCameraService *service, QObject *parent = 0); - ~AVFVideoDeviceControl(); + AVFCameraDeviceControl(AVFCameraService *service, QObject *parent = 0); + ~AVFCameraDeviceControl(); int deviceCount() const; diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm b/src/plugins/avfoundation/camera/avfcameradevicecontrol.mm index 1730437f8..80347ed93 100644 --- a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm +++ b/src/plugins/avfoundation/camera/avfcameradevicecontrol.mm @@ -1,69 +1,62 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "avfcameradebug.h" -#include "avfvideodevicecontrol.h" +#include "avfcameradevicecontrol.h" #include "avfcameraservice.h" #include "avfcamerasession.h" QT_USE_NAMESPACE -AVFVideoDeviceControl::AVFVideoDeviceControl(AVFCameraService *service, QObject *parent) +AVFCameraDeviceControl::AVFCameraDeviceControl(AVFCameraService *service, QObject *parent) : QVideoDeviceSelectorControl(parent) , m_service(service) , m_selectedDevice(0) , m_dirty(true) { + Q_UNUSED(m_service); } -AVFVideoDeviceControl::~AVFVideoDeviceControl() +AVFCameraDeviceControl::~AVFCameraDeviceControl() { } -int AVFVideoDeviceControl::deviceCount() const +int AVFCameraDeviceControl::deviceCount() const { return AVFCameraSession::availableCameraDevices().count(); } -QString AVFVideoDeviceControl::deviceName(int index) const +QString AVFCameraDeviceControl::deviceName(int index) const { const QList<AVFCameraInfo> &devices = AVFCameraSession::availableCameraDevices(); if (index < 0 || index >= devices.count()) @@ -72,7 +65,7 @@ QString AVFVideoDeviceControl::deviceName(int index) const return QString::fromUtf8(devices.at(index).deviceId); } -QString AVFVideoDeviceControl::deviceDescription(int index) const +QString AVFCameraDeviceControl::deviceDescription(int index) const { const QList<AVFCameraInfo> &devices = AVFCameraSession::availableCameraDevices(); if (index < 0 || index >= devices.count()) @@ -81,17 +74,17 @@ QString AVFVideoDeviceControl::deviceDescription(int index) const return devices.at(index).description; } -int AVFVideoDeviceControl::defaultDevice() const +int AVFCameraDeviceControl::defaultDevice() const { return AVFCameraSession::defaultCameraIndex(); } -int AVFVideoDeviceControl::selectedDevice() const +int AVFCameraDeviceControl::selectedDevice() const { return m_selectedDevice; } -void AVFVideoDeviceControl::setSelectedDevice(int index) +void AVFCameraDeviceControl::setSelectedDevice(int index) { if (index >= 0 && index < deviceCount() && @@ -103,7 +96,7 @@ void AVFVideoDeviceControl::setSelectedDevice(int index) } } -AVCaptureDevice *AVFVideoDeviceControl::createCaptureDevice() +AVCaptureDevice *AVFCameraDeviceControl::createCaptureDevice() { m_dirty = false; AVCaptureDevice *device = 0; @@ -121,4 +114,4 @@ AVCaptureDevice *AVFVideoDeviceControl::createCaptureDevice() return device; } -#include "moc_avfvideodevicecontrol.cpp" +#include "moc_avfcameradevicecontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameraexposurecontrol.h b/src/plugins/avfoundation/camera/avfcameraexposurecontrol.h new file mode 100644 index 000000000..5bbf0e6d9 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraexposurecontrol.h @@ -0,0 +1,83 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#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 diff --git a/src/plugins/avfoundation/camera/avfcameraexposurecontrol.mm b/src/plugins/avfoundation/camera/avfcameraexposurecontrol.mm new file mode 100644 index 000000000..9e56ce194 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraexposurecontrol.mm @@ -0,0 +1,656 @@ +/**************************************************************************** +** +** 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" diff --git a/src/plugins/avfoundation/camera/avfcameraflashcontrol.h b/src/plugins/avfoundation/camera/avfcameraflashcontrol.h new file mode 100644 index 000000000..96722c6f4 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraflashcontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAFLASHCONTROL_H +#define AVFCAMERAFLASHCONTROL_H + +#include <QtMultimedia/qcameraflashcontrol.h> +#include <QtMultimedia/qcamera.h> + +#include <QtCore/qlist.h> + +QT_BEGIN_NAMESPACE + +class AVFCameraService; +class AVFCameraSession; + +class AVFCameraFlashControl : public QCameraFlashControl +{ + Q_OBJECT +public: + AVFCameraFlashControl(AVFCameraService *service); + + QCameraExposure::FlashModes flashMode() const Q_DECL_OVERRIDE; + void setFlashMode(QCameraExposure::FlashModes mode) Q_DECL_OVERRIDE; + bool isFlashModeSupported(QCameraExposure::FlashModes mode) const Q_DECL_OVERRIDE; + bool isFlashReady() const Q_DECL_OVERRIDE; + +private Q_SLOTS: + void cameraStateChanged(QCamera::State newState); + +private: + bool applyFlashSettings(); + + AVFCameraService *m_service; + AVFCameraSession *m_session; + + // Set of bits: + QCameraExposure::FlashModes m_supportedModes; + // Only one bit set actually: + QCameraExposure::FlashModes m_flashMode; +}; + +QT_END_NAMESPACE + + +#endif // AVFCAMERAFLASHCONTROL_H + diff --git a/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm b/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm new file mode 100644 index 000000000..0eef95e92 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraflashcontrol.mm @@ -0,0 +1,227 @@ +/**************************************************************************** +** +** 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 "avfcameraflashcontrol.h" +#include "avfcamerautility.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameradebug.h" + +#include <QtCore/qdebug.h> + +#include <AVFoundation/AVFoundation.h> + + +AVFCameraFlashControl::AVFCameraFlashControl(AVFCameraService *service) + : m_service(service) + , m_session(0) + , m_supportedModes(QCameraExposure::FlashOff) + , m_flashMode(QCameraExposure::FlashOff) +{ + Q_ASSERT(service); + m_session = m_service->session(); + Q_ASSERT(m_session); + + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(cameraStateChanged(QCamera::State))); +} + +QCameraExposure::FlashModes AVFCameraFlashControl::flashMode() const +{ + return m_flashMode; +} + +void AVFCameraFlashControl::setFlashMode(QCameraExposure::FlashModes mode) +{ + if (m_flashMode == mode) + return; + + if (m_session->state() == QCamera::ActiveState && !isFlashModeSupported(mode)) { + qDebugCamera() << Q_FUNC_INFO << "unsupported mode" << mode; + return; + } + + m_flashMode = mode; + + if (m_session->state() != QCamera::ActiveState) + return; + + applyFlashSettings(); +} + +bool AVFCameraFlashControl::isFlashModeSupported(QCameraExposure::FlashModes mode) const +{ + // From what QCameraExposure has, we can support only these: + // FlashAuto = 0x1, + // FlashOff = 0x2, + // FlashOn = 0x4, + // AVCaptureDevice has these flash modes: + // AVCaptureFlashModeAuto + // AVCaptureFlashModeOff + // AVCaptureFlashModeOn + // QCameraExposure also has: + // FlashTorch = 0x20, --> "Constant light source." + // FlashVideoLight = 0x40. --> "Constant light source." + // AVCaptureDevice: + // AVCaptureTorchModeOff (no mapping) + // AVCaptureTorchModeOn --> FlashVideoLight + // AVCaptureTorchModeAuto (no mapping) + + return m_supportedModes & mode; +} + +bool AVFCameraFlashControl::isFlashReady() const +{ + if (m_session->state() != QCamera::ActiveState) + return false; + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) + return false; + + if (!captureDevice.hasFlash && !captureDevice.hasTorch) + return false; + + if (!isFlashModeSupported(m_flashMode)) + return false; + +#ifdef Q_OS_IOS + // AVCaptureDevice's docs: + // "The flash may become unavailable if, for example, + // the device overheats and needs to cool off." + if (m_flashMode != QCameraExposure::FlashVideoLight) + return [captureDevice isFlashAvailable]; + + return [captureDevice isTorchAvailable]; +#endif + + return true; +} + +void AVFCameraFlashControl::cameraStateChanged(QCamera::State newState) +{ + if (newState == QCamera::UnloadedState) { + m_supportedModes = QCameraExposure::FlashOff; + Q_EMIT flashReady(false); + } else if (newState == QCamera::ActiveState) { + m_supportedModes = QCameraExposure::FlashOff; + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) { + qDebugCamera() << Q_FUNC_INFO << "no capture device in 'Active' state"; + Q_EMIT flashReady(false); + return; + } + + if (captureDevice.hasFlash) { + if ([captureDevice isFlashModeSupported:AVCaptureFlashModeOn]) + m_supportedModes |= QCameraExposure::FlashOn; + if ([captureDevice isFlashModeSupported:AVCaptureFlashModeAuto]) + m_supportedModes |= QCameraExposure::FlashAuto; + } + + if (captureDevice.hasTorch && [captureDevice isTorchModeSupported:AVCaptureTorchModeOn]) + m_supportedModes |= QCameraExposure::FlashVideoLight; + + Q_EMIT flashReady(applyFlashSettings()); + } +} + +bool AVFCameraFlashControl::applyFlashSettings() +{ + Q_ASSERT(m_session->state() == QCamera::ActiveState); + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) { + qDebugCamera() << Q_FUNC_INFO << "no capture device found"; + return false; + } + + if (!isFlashModeSupported(m_flashMode)) { + qDebugCamera() << Q_FUNC_INFO << "unsupported mode" << m_flashMode; + return false; + } + + if (!captureDevice.hasFlash && !captureDevice.hasTorch) { + // FlashOff is the only mode we support. + // Return false - flash is not ready. + return false; + } + + const AVFConfigurationLock lock(captureDevice); + + if (m_flashMode != QCameraExposure::FlashVideoLight) { + if (captureDevice.torchMode != AVCaptureTorchModeOff) { +#ifdef Q_OS_IOS + if (![captureDevice isTorchAvailable]) { + qDebugCamera() << Q_FUNC_INFO << "torch is not available at the moment"; + return false; + } +#endif + captureDevice.torchMode = AVCaptureTorchModeOff; + } +#ifdef Q_OS_IOS + if (![captureDevice isFlashAvailable]) { + // We'd like to switch flash (into some mode), but it's not available: + qDebugCamera() << Q_FUNC_INFO << "flash is not available at the moment"; + return false; + } +#endif + } else { + if (captureDevice.flashMode != AVCaptureFlashModeOff) { +#ifdef Q_OS_IOS + if (![captureDevice isFlashAvailable]) { + qDebugCamera() << Q_FUNC_INFO << "flash is not available at the moment"; + return false; + } +#endif + captureDevice.flashMode = AVCaptureFlashModeOff; + } + +#ifdef Q_OS_IOS + if (![captureDevice isTorchAvailable]) { + qDebugCamera() << Q_FUNC_INFO << "torch is not available at the moment"; + return false; + } +#endif + } + + if (m_flashMode == QCameraExposure::FlashOff) + captureDevice.flashMode = AVCaptureFlashModeOff; + else if (m_flashMode == QCameraExposure::FlashOn) + captureDevice.flashMode = AVCaptureFlashModeOn; + else if (m_flashMode == QCameraExposure::FlashAuto) + captureDevice.flashMode = AVCaptureFlashModeAuto; + else if (m_flashMode == QCameraExposure::FlashVideoLight) + captureDevice.torchMode = AVCaptureTorchModeOn; + + return true; +} diff --git a/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h new file mode 100644 index 000000000..d4213960c --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAFOCUSCONTROL_H +#define AVFCAMERAFOCUSCONTROL_H + +#include <QtCore/qscopedpointer.h> +#include <QtCore/qglobal.h> + +#include <qcamerafocuscontrol.h> + +@class AVCaptureDevice; + +QT_BEGIN_NAMESPACE + +class AVFCameraService; +class AVFCameraSession; + +class AVFCameraFocusControl : public QCameraFocusControl +{ + Q_OBJECT +public: + explicit AVFCameraFocusControl(AVFCameraService *service); + + QCameraFocus::FocusModes focusMode() const Q_DECL_OVERRIDE; + void setFocusMode(QCameraFocus::FocusModes mode) Q_DECL_OVERRIDE; + bool isFocusModeSupported(QCameraFocus::FocusModes mode) const Q_DECL_OVERRIDE; + + QCameraFocus::FocusPointMode focusPointMode() const Q_DECL_OVERRIDE; + void setFocusPointMode(QCameraFocus::FocusPointMode mode) Q_DECL_OVERRIDE; + bool isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const Q_DECL_OVERRIDE; + QPointF customFocusPoint() const Q_DECL_OVERRIDE; + void setCustomFocusPoint(const QPointF &point) Q_DECL_OVERRIDE; + + QCameraFocusZoneList focusZones() const Q_DECL_OVERRIDE; + +private Q_SLOTS: + void cameraStateChanged(); + +private: + + AVFCameraSession *m_session; + QCameraFocus::FocusModes m_focusMode; + QCameraFocus::FocusPointMode m_focusPointMode; + QPointF m_customFocusPoint; + QPointF m_actualFocusPoint; +}; + +QT_END_NAMESPACE + +#endif // AVFCAMERAFOCUSCONTROL_H diff --git a/src/plugins/avfoundation/camera/avfcamerafocuscontrol.mm b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.mm new file mode 100644 index 000000000..25c69c743 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.mm @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** 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 "avfcamerafocuscontrol.h" +#include "avfcamerautility.h" +#include "avfcameraservice.h" +#include "avfcamerasession.h" +#include "avfcameradebug.h" + +#include <QtCore/qdebug.h> + +#include <AVFoundation/AVFoundation.h> + +QT_BEGIN_NAMESPACE + +namespace { + +bool qt_focus_mode_supported(QCameraFocus::FocusModes mode) +{ + // Check if QCameraFocus::FocusMode has counterpart in AVFoundation. + + // AVFoundation has 'Manual', 'Auto' and 'Continuous', + // where 'Manual' is actually 'Locked' + writable property 'lensPosition'. + // Since Qt does not provide an API to manipulate a lens position, 'Maual' mode + // (at the moment) is not supported. + return mode == QCameraFocus::AutoFocus + || mode == QCameraFocus::ContinuousFocus; +} + +bool qt_focus_point_mode_supported(QCameraFocus::FocusPointMode mode) +{ + return mode == QCameraFocus::FocusPointAuto + || mode == QCameraFocus::FocusPointCustom + || mode == QCameraFocus::FocusPointCenter; +} + +AVCaptureFocusMode avf_focus_mode(QCameraFocus::FocusModes requestedMode) +{ + if (requestedMode == QCameraFocus::AutoFocus) + return AVCaptureFocusModeAutoFocus; + + return AVCaptureFocusModeContinuousAutoFocus; +} + +} + +AVFCameraFocusControl::AVFCameraFocusControl(AVFCameraService *service) + : m_session(service->session()), + m_focusMode(QCameraFocus::ContinuousFocus), + m_focusPointMode(QCameraFocus::FocusPointAuto), + m_customFocusPoint(0.5f, 0.5f), + m_actualFocusPoint(m_customFocusPoint) +{ + Q_ASSERT(m_session); + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(cameraStateChanged())); +} + +QCameraFocus::FocusModes AVFCameraFocusControl::focusMode() const +{ + return m_focusMode; +} + +void AVFCameraFocusControl::setFocusMode(QCameraFocus::FocusModes mode) +{ + if (m_focusMode == mode) + return; + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) { + if (qt_focus_mode_supported(mode)) { + m_focusMode = mode; + Q_EMIT focusModeChanged(m_focusMode); + } else { + qDebugCamera() << Q_FUNC_INFO + << "focus mode not supported"; + } + return; + } + + if (isFocusModeSupported(mode)) { + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO + << "failed to lock for configuration"; + return; + } + + captureDevice.focusMode = avf_focus_mode(mode); + m_focusMode = mode; + } else { + qDebugCamera() << Q_FUNC_INFO << "focus mode not supported"; + return; + } + + Q_EMIT focusModeChanged(m_focusMode); +} + +bool AVFCameraFocusControl::isFocusModeSupported(QCameraFocus::FocusModes mode) const +{ + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) + return false; + + if (!qt_focus_mode_supported(mode)) + return false; + + return [captureDevice isFocusModeSupported:avf_focus_mode(mode)]; +} + +QCameraFocus::FocusPointMode AVFCameraFocusControl::focusPointMode() const +{ + return m_focusPointMode; +} + +void AVFCameraFocusControl::setFocusPointMode(QCameraFocus::FocusPointMode mode) +{ + if (m_focusPointMode == mode) + return; + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) { + if (qt_focus_point_mode_supported(mode)) { + m_focusPointMode = mode; + Q_EMIT focusPointModeChanged(mode); + } + return; + } + + if (isFocusPointModeSupported(mode)) { + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + bool resetPOI = false; + if (mode == QCameraFocus::FocusPointCenter || mode == QCameraFocus::FocusPointAuto) { + if (m_actualFocusPoint != QPointF(0.5, 0.5)) { + m_actualFocusPoint = QPointF(0.5, 0.5); + resetPOI = true; + } + } else if (mode == QCameraFocus::FocusPointCustom) { + if (m_actualFocusPoint != m_customFocusPoint) { + m_actualFocusPoint = m_customFocusPoint; + resetPOI = true; + } + } // else for any other mode in future. + + if (resetPOI) { + const CGPoint focusPOI = CGPointMake(m_actualFocusPoint.x(), m_actualFocusPoint.y()); + [captureDevice setFocusPointOfInterest:focusPOI]; + } + m_focusPointMode = mode; + } else { + qDebugCamera() << Q_FUNC_INFO << "focus point mode is not supported"; + return; + } + + Q_EMIT focusPointModeChanged(mode); +} + +bool AVFCameraFocusControl::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const +{ + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) + return false; + + if (!qt_focus_point_mode_supported(mode)) + return false; + + return [captureDevice isFocusPointOfInterestSupported]; +} + +QPointF AVFCameraFocusControl::customFocusPoint() const +{ + return m_customFocusPoint; +} + +void AVFCameraFocusControl::setCustomFocusPoint(const QPointF &point) +{ + if (m_customFocusPoint == point) + return; + + if (!QRectF(0.f, 0.f, 1.f, 1.f).contains(point)) { + qDebugCamera() << Q_FUNC_INFO << "invalid focus point (out of range)"; + return; + } + + m_customFocusPoint = point; + Q_EMIT customFocusPointChanged(m_customFocusPoint); + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice || m_focusPointMode != QCameraFocus::FocusPointCustom) + return; + + if ([captureDevice isFocusPointOfInterestSupported]) { + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + m_actualFocusPoint = m_customFocusPoint; + const CGPoint focusPOI = CGPointMake(point.x(), point.y()); + [captureDevice setFocusPointOfInterest:focusPOI]; + if (m_focusMode != QCameraFocus::ContinuousFocus) + [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus]; + } else { + qDebugCamera() << Q_FUNC_INFO << "focus point of interest not supported"; + return; + } +} + +QCameraFocusZoneList AVFCameraFocusControl::focusZones() const +{ + // Unsupported. + return QCameraFocusZoneList(); +} + +void AVFCameraFocusControl::cameraStateChanged() +{ + if (m_session->state() != QCamera::ActiveState) + return; + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice) { + qDebugCamera() << Q_FUNC_INFO << "capture device is nil in 'active' state"; + return; + } + + const AVFConfigurationLock lock(captureDevice); + if (m_customFocusPoint != m_actualFocusPoint + && m_focusPointMode == QCameraFocus::FocusPointCustom) { + if (![captureDevice isFocusPointOfInterestSupported]) { + qDebugCamera() << Q_FUNC_INFO + << "focus point of interest not supported"; + return; + } + + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + m_actualFocusPoint = m_customFocusPoint; + const CGPoint focusPOI = CGPointMake(m_customFocusPoint.x(), m_customFocusPoint.y()); + [captureDevice setFocusPointOfInterest:focusPOI]; + } + + if (m_focusMode != QCameraFocus::ContinuousFocus) { + const AVCaptureFocusMode avMode = avf_focus_mode(m_focusMode); + if (captureDevice.focusMode != avMode) { + if (![captureDevice isFocusModeSupported:avMode]) { + qDebugCamera() << Q_FUNC_INFO << "focus mode not supported"; + return; + } + + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + [captureDevice setFocusMode:avMode]; + } + } +} + +QT_END_NAMESPACE + +#include "moc_avfcamerafocuscontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcamerainfocontrol.h b/src/plugins/avfoundation/camera/avfcamerainfocontrol.h index 934fb5755..dd223f4d4 100644 --- a/src/plugins/avfoundation/camera/avfcamerainfocontrol.h +++ b/src/plugins/avfoundation/camera/avfcamerainfocontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm b/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm index 8ae908ada..91286a7c5 100644 --- a/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h index 2f81b5b38..8e73e677f 100644 --- a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h +++ b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm index 520e48c3e..a13f6e91f 100644 --- a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.h b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h index 0f4f6ba70..92ab75bd0 100644 --- a/src/plugins/avfoundation/camera/avfvideorenderercontrol.h +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,16 +23,16 @@ ** 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 +** 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$ ** ****************************************************************************/ -#ifndef AVFVIDEORENDERERCONTROL_H -#define AVFVIDEORENDERERCONTROL_H +#ifndef AVFCAMERARENDERERCONTROL_H +#define AVFCAMERARENDERERCONTROL_H #include <QtMultimedia/qvideorenderercontrol.h> #include <QtMultimedia/qvideoframe.h> @@ -46,14 +46,14 @@ QT_BEGIN_NAMESPACE class AVFCameraSession; class AVFCameraService; -class AVFVideoRendererControl; +class AVFCameraRendererControl; -class AVFVideoRendererControl : public QVideoRendererControl +class AVFCameraRendererControl : public QVideoRendererControl { Q_OBJECT public: - AVFVideoRendererControl(QObject *parent = 0); - ~AVFVideoRendererControl(); + AVFCameraRendererControl(QObject *parent = 0); + ~AVFCameraRendererControl(); QAbstractVideoSurface *surface() const; void setSurface(QAbstractVideoSurface *surface); @@ -61,6 +61,8 @@ public: void configureAVCaptureSession(AVFCameraSession *cameraSession); void syncHandleViewfinderFrame(const QVideoFrame &frame); + AVCaptureVideoDataOutput *videoDataOutput() const; + Q_SIGNALS: void surfaceChanged(QAbstractVideoSurface *surface); diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm index 1a2054452..cf13635f0 100644 --- a/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm +++ b/src/plugins/avfoundation/camera/avfcamerarenderercontrol.mm @@ -1,60 +1,56 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ -#include "avfvideorenderercontrol.h" +#include "avfcameraviewfindersettingscontrol.h" +#include "private/qabstractvideobuffer_p.h" +#include "avfcamerarenderercontrol.h" #include "avfcamerasession.h" #include "avfcameraservice.h" #include "avfcameradebug.h" #include <QtMultimedia/qabstractvideosurface.h> #include <QtMultimedia/qabstractvideobuffer.h> + #include <QtMultimedia/qvideosurfaceformat.h> QT_USE_NAMESPACE -class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +class CVPixelBufferVideoBuffer : public QAbstractPlanarVideoBuffer { + friend class CVPixelBufferVideoBufferPrivate; public: CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) - : QAbstractVideoBuffer(NoHandle) + : QAbstractPlanarVideoBuffer(NoHandle) , m_buffer(buffer) , m_mode(NotMapped) { @@ -68,6 +64,42 @@ public: MapMode mapMode() const { return m_mode; } + int map(QAbstractVideoBuffer::MapMode mode, int *numBytes, int bytesPerLine[4], uchar *data[4]) + { + // We only support RGBA or NV12 (or Apple's version of NV12), + // they are either 0 planes or 2. + const size_t nPlanes = CVPixelBufferGetPlaneCount(m_buffer); + Q_ASSERT(nPlanes <= 2); + + if (!nPlanes) { + data[0] = map(mode, numBytes, bytesPerLine); + return data[0] ? 1 : 0; + } + + // For a bi-planar format we have to set the parameters correctly: + if (mode != QAbstractVideoBuffer::NotMapped && m_mode == QAbstractVideoBuffer::NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) { + // At the moment we handle only bi-planar format. + bytesPerLine[0] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, 0); + bytesPerLine[1] = CVPixelBufferGetBytesPerRowOfPlane(m_buffer, 1); + } + + if (data) { + data[0] = (uchar *)CVPixelBufferGetBaseAddressOfPlane(m_buffer, 0); + data[1] = (uchar *)CVPixelBufferGetBaseAddressOfPlane(m_buffer, 1); + } + + m_mode = mode; + } + + return nPlanes; + } + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) { if (mode != NotMapped && m_mode == NotMapped) { @@ -80,7 +112,6 @@ public: *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); m_mode = mode; - return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); } else { return 0; @@ -100,13 +131,14 @@ private: MapMode m_mode; }; + @interface AVFCaptureFramesDelegate : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate> { @private - AVFVideoRendererControl *m_renderer; + AVFCameraRendererControl *m_renderer; } -- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFVideoRendererControl*)renderer; +- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRendererControl*)renderer; - (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer @@ -115,7 +147,7 @@ private: @implementation AVFCaptureFramesDelegate -- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFVideoRendererControl*)renderer +- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFCameraRendererControl*)renderer { if (!(self = [super init])) return nil; @@ -137,13 +169,23 @@ private: int height = CVPixelBufferGetHeight(imageBuffer); QAbstractVideoBuffer *buffer = new CVPixelBufferVideoBuffer(imageBuffer); - QVideoFrame frame(buffer, QSize(width, height), QVideoFrame::Format_RGB32); + + QVideoFrame::PixelFormat format = QVideoFrame::Format_RGB32; + if ([captureOutput isKindOfClass:[AVCaptureVideoDataOutput class]]) { + NSDictionary *settings = ((AVCaptureVideoDataOutput *)captureOutput).videoSettings; + if (settings && [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) { + NSNumber *avf = [settings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]; + format = AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat([avf unsignedIntValue]); + } + } + + QVideoFrame frame(buffer, QSize(width, height), format); m_renderer->syncHandleViewfinderFrame(frame); } @end -AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent) +AVFCameraRendererControl::AVFCameraRendererControl(QObject *parent) : QVideoRendererControl(parent) , m_surface(0) , m_needsHorizontalMirroring(false) @@ -151,18 +193,18 @@ AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent) m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this]; } -AVFVideoRendererControl::~AVFVideoRendererControl() +AVFCameraRendererControl::~AVFCameraRendererControl() { [m_cameraSession->captureSession() removeOutput:m_videoDataOutput]; [m_viewfinderFramesDelegate release]; } -QAbstractVideoSurface *AVFVideoRendererControl::surface() const +QAbstractVideoSurface *AVFCameraRendererControl::surface() const { return m_surface; } -void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +void AVFCameraRendererControl::setSurface(QAbstractVideoSurface *surface) { if (m_surface != surface) { m_surface = surface; @@ -170,7 +212,7 @@ void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) } } -void AVFVideoRendererControl::configureAVCaptureSession(AVFCameraSession *cameraSession) +void AVFCameraRendererControl::configureAVCaptureSession(AVFCameraSession *cameraSession) { m_cameraSession = cameraSession; connect(m_cameraSession, SIGNAL(readyToConfigureConnections()), @@ -196,7 +238,7 @@ void AVFVideoRendererControl::configureAVCaptureSession(AVFCameraSession *camera [m_cameraSession->captureSession() addOutput:m_videoDataOutput]; } -void AVFVideoRendererControl::updateCaptureConnection() +void AVFCameraRendererControl::updateCaptureConnection() { AVCaptureConnection *connection = [m_videoDataOutput connectionWithMediaType:AVMediaTypeVideo]; if (connection == nil || !m_cameraSession->videoCaptureDevice()) @@ -213,7 +255,7 @@ void AVFVideoRendererControl::updateCaptureConnection() } //can be called from non main thread -void AVFVideoRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame) +void AVFCameraRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame) { QMutexLocker lock(&m_vfMutex); if (!m_lastViewfinderFrame.isValid()) { @@ -240,9 +282,16 @@ void AVFVideoRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame m_lastViewfinderFrame.unmap(); m_lastViewfinderFrame = QVideoFrame(mirrored); } + if (m_cameraSession && m_lastViewfinderFrame.isValid()) + m_cameraSession->onCameraFrameFetched(m_lastViewfinderFrame); +} + +AVCaptureVideoDataOutput *AVFCameraRendererControl::videoDataOutput() const +{ + return m_videoDataOutput; } -void AVFVideoRendererControl::handleViewfinderFrame() +void AVFCameraRendererControl::handleViewfinderFrame() { QVideoFrame frame; { @@ -271,4 +320,4 @@ void AVFVideoRendererControl::handleViewfinderFrame() } -#include "moc_avfvideorenderercontrol.cpp" +#include "moc_avfcamerarenderercontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h index 6e5465395..d557872a9 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.h +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ @@ -46,12 +46,19 @@ class AVFCameraInfoControl; class AVFCameraMetaDataControl; class AVFVideoWindowControl; class AVFVideoWidgetControl; -class AVFVideoRendererControl; +class AVFCameraRendererControl; class AVFMediaRecorderControl; class AVFImageCaptureControl; class AVFCameraSession; -class AVFVideoDeviceControl; +class AVFCameraDeviceControl; class AVFAudioInputSelectorControl; +class AVFCameraFocusControl; +class AVFCameraExposureControl; +class AVFCameraZoomControl; +class AVFCameraViewfinderSettingsControl2; +class AVFCameraViewfinderSettingsControl; +class AVFImageEncoderControl; +class AVFCameraFlashControl; class AVFCameraService : public QMediaService { @@ -65,23 +72,37 @@ public: AVFCameraSession *session() const { return m_session; } AVFCameraControl *cameraControl() const { return m_cameraControl; } - AVFVideoDeviceControl *videoDeviceControl() const { return m_videoDeviceControl; } + AVFCameraDeviceControl *videoDeviceControl() const { return m_videoDeviceControl; } AVFAudioInputSelectorControl *audioInputSelectorControl() const { return m_audioInputSelectorControl; } AVFCameraMetaDataControl *metaDataControl() const { return m_metaDataControl; } AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; } AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; } - + AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; } + AVFCameraExposureControl *cameraExposureControl() const {return m_cameraExposureControl; } + AVFCameraZoomControl *cameraZoomControl() const {return m_cameraZoomControl; } + AVFCameraRendererControl *videoOutput() const {return m_videoOutput; } + AVFCameraViewfinderSettingsControl2 *viewfinderSettingsControl2() const {return m_viewfinderSettingsControl2; } + AVFCameraViewfinderSettingsControl *viewfinderSettingsControl() const {return m_viewfinderSettingsControl; } + AVFImageEncoderControl *imageEncoderControl() const {return m_imageEncoderControl; } + AVFCameraFlashControl *flashControl() const {return m_flashControl; } private: AVFCameraSession *m_session; AVFCameraControl *m_cameraControl; AVFCameraInfoControl *m_cameraInfoControl; - AVFVideoDeviceControl *m_videoDeviceControl; + AVFCameraDeviceControl *m_videoDeviceControl; AVFAudioInputSelectorControl *m_audioInputSelectorControl; - AVFVideoRendererControl *m_videoOutput; + AVFCameraRendererControl *m_videoOutput; AVFCameraMetaDataControl *m_metaDataControl; AVFMediaRecorderControl *m_recorderControl; AVFImageCaptureControl *m_imageCaptureControl; + AVFCameraFocusControl *m_cameraFocusControl; + AVFCameraExposureControl *m_cameraExposureControl; + AVFCameraZoomControl *m_cameraZoomControl; + AVFCameraViewfinderSettingsControl2 *m_viewfinderSettingsControl2; + AVFCameraViewfinderSettingsControl *m_viewfinderSettingsControl; + AVFImageEncoderControl *m_imageEncoderControl; + AVFCameraFlashControl *m_flashControl; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 966202ede..f163e1299 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -1,59 +1,62 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include <QtCore/qvariant.h> #include <QtCore/qdebug.h> +#include <QtCore/qsysinfo.h> #include "avfcameraservice.h" #include "avfcameracontrol.h" #include "avfcamerainfocontrol.h" #include "avfcamerasession.h" -#include "avfvideodevicecontrol.h" +#include "avfcameradevicecontrol.h" #include "avfaudioinputselectorcontrol.h" #include "avfcamerametadatacontrol.h" #include "avfmediarecordercontrol.h" #include "avfimagecapturecontrol.h" -#include "avfvideorenderercontrol.h" +#include "avfcamerarenderercontrol.h" #include "avfmediarecordercontrol.h" #include "avfimagecapturecontrol.h" +#include "avfmediavideoprobecontrol.h" +#include "avfcamerafocuscontrol.h" +#include "avfcameraexposurecontrol.h" +#include "avfcameraviewfindersettingscontrol.h" +#include "avfimageencodercontrol.h" +#include "avfcameraflashcontrol.h" + +#ifdef Q_OS_IOS +#include "avfcamerazoomcontrol.h" +#endif #include <private/qmediaplaylistnavigator_p.h> #include <qmediaplaylist.h> @@ -67,12 +70,27 @@ AVFCameraService::AVFCameraService(QObject *parent): m_session = new AVFCameraSession(this); m_cameraControl = new AVFCameraControl(this); m_cameraInfoControl = new AVFCameraInfoControl(this); - m_videoDeviceControl = new AVFVideoDeviceControl(this); + m_videoDeviceControl = new AVFCameraDeviceControl(this); m_audioInputSelectorControl = new AVFAudioInputSelectorControl(this); m_metaDataControl = new AVFCameraMetaDataControl(this); m_recorderControl = new AVFMediaRecorderControl(this); m_imageCaptureControl = new AVFImageCaptureControl(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 + + m_cameraZoomControl = 0; +#ifdef Q_OS_IOS + m_cameraZoomControl = new AVFCameraZoomControl(this); +#endif + m_viewfinderSettingsControl2 = new AVFCameraViewfinderSettingsControl2(this); + m_viewfinderSettingsControl = new AVFCameraViewfinderSettingsControl(this); + m_imageEncoderControl = new AVFImageEncoderControl(this); + m_flashControl = new AVFCameraFlashControl(this); } AVFCameraService::~AVFCameraService() @@ -91,6 +109,15 @@ AVFCameraService::~AVFCameraService() //delete m_recorderControl; delete m_metaDataControl; delete m_cameraControl; + delete m_cameraFocusControl; + delete m_cameraExposureControl; +#ifdef Q_OS_IOS + delete m_cameraZoomControl; +#endif + delete m_viewfinderSettingsControl2; + delete m_viewfinderSettingsControl; + delete m_imageEncoderControl; + delete m_flashControl; delete m_session; } @@ -119,9 +146,39 @@ QMediaControl *AVFCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) return m_imageCaptureControl; + if (qstrcmp(name, QCameraExposureControl_iid) == 0) + return m_cameraExposureControl; + + if (qstrcmp(name, QCameraFocusControl_iid) == 0) + return m_cameraFocusControl; + + if (qstrcmp(name, QCameraViewfinderSettingsControl2_iid) == 0) + return m_viewfinderSettingsControl2; + + if (qstrcmp(name, QCameraViewfinderSettingsControl_iid) == 0) + return m_viewfinderSettingsControl; + + if (qstrcmp(name, QImageEncoderControl_iid) == 0) + return m_imageEncoderControl; + + if (qstrcmp(name, QCameraFlashControl_iid) == 0) + return m_flashControl; + + if (qstrcmp(name,QMediaVideoProbeControl_iid) == 0) { + AVFMediaVideoProbeControl *videoProbe = 0; + videoProbe = new AVFMediaVideoProbeControl(this); + m_session->addProbe(videoProbe); + return videoProbe; + } + +#ifdef Q_OS_IOS + if (qstrcmp(name, QCameraZoomControl_iid) == 0) + return m_cameraZoomControl; +#endif + if (!m_videoOutput) { if (qstrcmp(name, QVideoRendererControl_iid) == 0) - m_videoOutput = new AVFVideoRendererControl(this); + m_videoOutput = new AVFCameraRendererControl(this); if (m_videoOutput) { m_session->setVideoOutput(m_videoOutput); @@ -139,6 +196,13 @@ void AVFCameraService::releaseControl(QMediaControl *control) delete m_videoOutput; m_videoOutput = 0; } + AVFMediaVideoProbeControl *videoProbe = qobject_cast<AVFMediaVideoProbeControl *>(control); + if (videoProbe) { + m_session->removeProbe(videoProbe); + delete videoProbe; + return; + } + } #include "moc_avfcameraservice.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.h b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h index 52e327aff..27b4bb2b1 100644 --- a/src/plugins/avfoundation/camera/avfcameraserviceplugin.h +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm index 99966f09b..bf2f4a24b 100644 --- a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 0a2ca214c..7b25a99c3 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ @@ -36,6 +36,7 @@ #include <QtCore/qmutex.h> #include <QtMultimedia/qcamera.h> +#include <QVideoFrame> #import <AVFoundation/AVFoundation.h> @@ -45,7 +46,8 @@ QT_BEGIN_NAMESPACE class AVFCameraControl; class AVFCameraService; -class AVFVideoRendererControl; +class AVFCameraRendererControl; +class AVFMediaVideoProbeControl; struct AVFCameraInfo { @@ -69,7 +71,7 @@ public: static const QList<AVFCameraInfo> &availableCameraDevices(); static AVFCameraInfo cameraDeviceInfo(const QByteArray &device); - void setVideoOutput(AVFVideoRendererControl *output); + void setVideoOutput(AVFCameraRendererControl *output); AVCaptureSession *captureSession() const { return m_captureSession; } AVCaptureDevice *videoCaptureDevice() const; @@ -77,6 +79,10 @@ public: QCamera::State requestedState() const { return m_state; } bool isActive() const { return m_active; } + void addProbe(AVFMediaVideoProbeControl *probe); + void removeProbe(AVFMediaVideoProbeControl *probe); + FourCharCode defaultCodec(); + public Q_SLOTS: void setState(QCamera::State state); @@ -84,6 +90,7 @@ public Q_SLOTS: void processSessionStarted(); void processSessionStopped(); + void onCameraFrameFetched(const QVideoFrame &frame); Q_SIGNALS: void readyToConfigureConnections(); void stateChanged(QCamera::State newState); @@ -93,12 +100,14 @@ Q_SIGNALS: private: static void updateCameraDevices(); void attachVideoInputDevice(); + void applyImageEncoderSettings(); + void applyViewfinderSettings(); static int m_defaultCameraIndex; static QList<AVFCameraInfo> m_cameraDevices; AVFCameraService *m_service; - AVFVideoRendererControl *m_videoOutput; + AVFCameraRendererControl *m_videoOutput; QCamera::State m_state; bool m_active; @@ -106,6 +115,11 @@ private: AVCaptureSession *m_captureSession; AVCaptureDeviceInput *m_videoInput; AVFCameraSessionObserver *m_observer; + + QSet<AVFMediaVideoProbeControl *> m_videoProbes; + QMutex m_videoProbesMutex; + + FourCharCode m_defaultCodec; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index d0bb0e51a..6e4803f30 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -43,9 +35,13 @@ #include "avfcamerasession.h" #include "avfcameraservice.h" #include "avfcameracontrol.h" -#include "avfvideorenderercontrol.h" -#include "avfvideodevicecontrol.h" +#include "avfcamerarenderercontrol.h" +#include "avfcameradevicecontrol.h" #include "avfaudioinputselectorcontrol.h" +#include "avfmediavideoprobecontrol.h" +#include "avfcameraviewfindersettingscontrol.h" +#include "avfimageencodercontrol.h" +#include "avfcamerautility.h" #include <CoreFoundation/CoreFoundation.h> #include <Foundation/Foundation.h> @@ -147,6 +143,7 @@ AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent) , m_state(QCamera::UnloadedState) , m_active(false) , m_videoInput(nil) + , m_defaultCodec(0) { m_captureSession = [[AVCaptureSession alloc] init]; m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:this]; @@ -247,7 +244,7 @@ void AVFCameraSession::updateCameraDevices() #endif } -void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output) +void AVFCameraSession::setVideoOutput(AVFCameraRendererControl *output) { m_videoOutput = output; if (output) @@ -288,6 +285,10 @@ void AVFCameraSession::setState(QCamera::State newState) Q_EMIT readyToConfigureConnections(); [m_captureSession commitConfiguration]; [m_captureSession startRunning]; + m_defaultCodec = 0; + defaultCodec(); + applyImageEncoderSettings(); + applyViewfinderSettings(); } if (oldState == QCamera::ActiveState) { @@ -354,4 +355,73 @@ void AVFCameraSession::attachVideoInputDevice() } } +void AVFCameraSession::applyImageEncoderSettings() +{ + if (AVFImageEncoderControl *control = m_service->imageEncoderControl()) + control->applySettings(); +} + +void AVFCameraSession::applyViewfinderSettings() +{ + if (AVFCameraViewfinderSettingsControl2 *vfControl = m_service->viewfinderSettingsControl2()) { + QCameraViewfinderSettings vfSettings(vfControl->requestedSettings()); + if (AVFImageEncoderControl *imControl = m_service->imageEncoderControl()) { + const QSize imageResolution(imControl->imageSettings().resolution()); + if (!imageResolution.isNull() && imageResolution.isValid()) { + vfSettings.setResolution(imageResolution); + vfControl->setViewfinderSettings(vfSettings); + return; + } + } + + if (!vfSettings.isNull()) + vfControl->applySettings(); + } +} + +void AVFCameraSession::addProbe(AVFMediaVideoProbeControl *probe) +{ + m_videoProbesMutex.lock(); + if (probe) + m_videoProbes << probe; + m_videoProbesMutex.unlock(); +} + +void AVFCameraSession::removeProbe(AVFMediaVideoProbeControl *probe) +{ + m_videoProbesMutex.lock(); + m_videoProbes.remove(probe); + m_videoProbesMutex.unlock(); +} + +FourCharCode AVFCameraSession::defaultCodec() +{ + if (!m_defaultCodec) { +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + if (AVCaptureDevice *device = videoCaptureDevice()) { + AVCaptureDeviceFormat *format = device.activeFormat; + if (!format || !format.formatDescription) + return m_defaultCodec; + m_defaultCodec = CMVideoFormatDescriptionGetCodecType(format.formatDescription); + } + } +#else + // TODO: extract media subtype. +#endif + } + return m_defaultCodec; +} + +void AVFCameraSession::onCameraFrameFetched(const QVideoFrame &frame) +{ + m_videoProbesMutex.lock(); + QSet<AVFMediaVideoProbeControl *>::const_iterator i = m_videoProbes.constBegin(); + while (i != m_videoProbes.constEnd()) { + (*i)->newFrameProbed(frame); + ++i; + } + m_videoProbesMutex.unlock(); +} + #include "moc_avfcamerasession.cpp" diff --git a/src/plugins/avfoundation/camera/avfcamerautility.h b/src/plugins/avfoundation/camera/avfcamerautility.h new file mode 100644 index 000000000..03a61460f --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerautility.h @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAUTILITY_H +#define AVFCAMERAUTILITY_H + +#include <QtCore/qsysinfo.h> +#include <QtCore/qglobal.h> +#include <QtCore/qvector.h> +#include <QtCore/qdebug.h> +#include <QtCore/qsize.h> +#include <QtCore/qpair.h> + +#include <AVFoundation/AVFoundation.h> + +// In case we have SDK below 10.7/7.0: +@class AVCaptureDeviceFormat; + +QT_BEGIN_NAMESPACE + +class AVFConfigurationLock +{ +public: + explicit AVFConfigurationLock(AVCaptureDevice *captureDevice) + : m_captureDevice(captureDevice), + m_locked(false) + { + Q_ASSERT(m_captureDevice); + NSError *error = nil; + m_locked = [m_captureDevice lockForConfiguration:&error]; + } + + ~AVFConfigurationLock() + { + if (m_locked) + [m_captureDevice unlockForConfiguration]; + } + + operator bool() const + { + return m_locked; + } + +private: + Q_DISABLE_COPY(AVFConfigurationLock) + + AVCaptureDevice *m_captureDevice; + bool m_locked; +}; + +inline QSysInfo::MacVersion qt_OS_limit(QSysInfo::MacVersion osxVersion, + QSysInfo::MacVersion iosVersion) +{ +#ifdef Q_OS_OSX + Q_UNUSED(iosVersion) + return osxVersion; +#else + Q_UNUSED(osxVersion) + return iosVersion; +#endif +} + +typedef QPair<qreal, qreal> AVFPSRange; +AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection); +typedef QPair<int, int> AVFRational; +AVFRational qt_float_to_rational(qreal par, int limit); + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + +QVector<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice, + FourCharCode preferredFormat); +QSize qt_device_format_resolution(AVCaptureDeviceFormat *format); +QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format); +QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format); +QVector<AVFPSRange> qt_device_format_framerates(AVCaptureDeviceFormat *format); +AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, const QSize &res, + FourCharCode preferredFormat); +AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice, + FourCharCode preferredFormat, + Float64 fps); +AVFrameRateRange *qt_find_supported_framerate_range(AVCaptureDeviceFormat *format, Float64 fps); + +#endif + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcamerautility.mm b/src/plugins/avfoundation/camera/avfcamerautility.mm new file mode 100644 index 000000000..f8d5647eb --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerautility.mm @@ -0,0 +1,411 @@ +/**************************************************************************** +** +** 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 "avfcamerautility.h" +#include "avfcameradebug.h" + +#include <QtCore/qvector.h> +#include <QtCore/qpair.h> + +#include <functional> +#include <algorithm> +#include <limits> + +QT_BEGIN_NAMESPACE + +AVFPSRange qt_connection_framerates(AVCaptureConnection *videoConnection) +{ + Q_ASSERT(videoConnection); + + AVFPSRange newRange; + // "The value in the videoMinFrameDuration is equivalent to the reciprocal + // of the maximum framerate, the value in the videoMaxFrameDuration is equivalent + // to the reciprocal of the minimum framerate." + if (videoConnection.supportsVideoMinFrameDuration) { + const CMTime cmMin = videoConnection.videoMinFrameDuration; + if (CMTimeCompare(cmMin, kCMTimeInvalid)) { // Has some non-default value: + if (const Float64 minSeconds = CMTimeGetSeconds(cmMin)) + newRange.second = 1. / minSeconds; + } + } + + if (videoConnection.supportsVideoMaxFrameDuration) { + const CMTime cmMax = videoConnection.videoMaxFrameDuration; + if (CMTimeCompare(cmMax, kCMTimeInvalid)) { + if (const Float64 maxSeconds = CMTimeGetSeconds(cmMax)) + newRange.first = 1. / maxSeconds; + } + } + + return newRange; +} + +AVFRational qt_float_to_rational(qreal par, int limit) +{ + Q_ASSERT(limit > 0); + + // In Qt we represent pixel aspect ratio + // as a rational number (we use QSize). + // AVFoundation describes dimensions in pixels + // and in pixels with width multiplied by PAR. + // Represent this PAR as a ratio. + int a = 0, b = 1, c = 1, d = 1; + qreal mid = 0.; + while (b <= limit && d <= limit) { + mid = qreal(a + c) / (b + d); + + if (qAbs(par - mid) < 0.000001) { + if (b + d <= limit) + return AVFRational(a + c, b + d); + else if (d > b) + return AVFRational(c, d); + else + return AVFRational(a, b); + } else if (par > mid) { + a = a + c; + b = b + d; + } else { + c = a + c; + d = b + d; + } + } + + if (b > limit) + return AVFRational(c, d); + + return AVFRational(a, b); +} + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + +namespace { + +inline bool qt_area_sane(const QSize &size) +{ + return !size.isNull() && size.isValid() + && std::numeric_limits<int>::max() / size.width() >= size.height(); +} + +struct ResolutionPredicate : std::binary_function<AVCaptureDeviceFormat *, AVCaptureDeviceFormat *, bool> +{ + bool operator() (AVCaptureDeviceFormat *f1, AVCaptureDeviceFormat *f2)const + { + Q_ASSERT(f1 && f2); + const QSize r1(qt_device_format_resolution(f1)); + const QSize r2(qt_device_format_resolution(f2)); + return r1.width() < r2.width() || (r2.width() == r1.width() && r1.height() < r2.height()); + } +}; + +struct FormatHasNoFPSRange : std::unary_function<AVCaptureDeviceFormat *, bool> +{ + bool operator() (AVCaptureDeviceFormat *format) + { + Q_ASSERT(format); + return !format.videoSupportedFrameRateRanges || !format.videoSupportedFrameRateRanges.count; + } +}; + +Float64 qt_find_min_framerate_distance(AVCaptureDeviceFormat *format, Float64 fps) +{ + Q_ASSERT(format && format.videoSupportedFrameRateRanges + && format.videoSupportedFrameRateRanges.count); + + AVFrameRateRange *range = [format.videoSupportedFrameRateRanges objectAtIndex:0]; + Float64 distance = qAbs(range.maxFrameRate - fps); + for (NSUInteger i = 1, e = format.videoSupportedFrameRateRanges.count; i < e; ++i) { + range = [format.videoSupportedFrameRateRanges objectAtIndex:i]; + distance = qMin(distance, qAbs(range.maxFrameRate - fps)); + } + + return distance; +} + +} // Unnamed namespace. + +QVector<AVCaptureDeviceFormat *> qt_unique_device_formats(AVCaptureDevice *captureDevice, FourCharCode filter) +{ + // 'filter' is the format we prefer if we have duplicates. + Q_ASSERT(captureDevice); + + QVector<AVCaptureDeviceFormat *> formats; + + if (!captureDevice.formats || !captureDevice.formats.count) + return formats; + + formats.reserve(captureDevice.formats.count); + for (AVCaptureDeviceFormat *format in captureDevice.formats) { + const QSize resolution(qt_device_format_resolution(format)); + if (resolution.isNull() || !resolution.isValid()) + continue; + formats << format; + } + + if (!formats.size()) + return formats; + + std::sort(formats.begin(), formats.end(), ResolutionPredicate()); + + QSize size(qt_device_format_resolution(formats[0])); + FourCharCode codec = CMVideoFormatDescriptionGetCodecType(formats[0].formatDescription); + int last = 0; + for (int i = 1; i < formats.size(); ++i) { + const QSize nextSize(qt_device_format_resolution(formats[i])); + if (nextSize == size) { + if (codec == filter) + continue; + formats[last] = formats[i]; + } else { + ++last; + formats[last] = formats[i]; + size = nextSize; + } + codec = CMVideoFormatDescriptionGetCodecType(formats[i].formatDescription); + } + formats.resize(last + 1); + + return formats; +} + +QSize qt_device_format_resolution(AVCaptureDeviceFormat *format) +{ + Q_ASSERT(format); + if (!format.formatDescription) + return QSize(); + + const CMVideoDimensions res = CMVideoFormatDescriptionGetDimensions(format.formatDescription); + return QSize(res.width, res.height); +} + +QSize qt_device_format_high_resolution(AVCaptureDeviceFormat *format) +{ + Q_ASSERT(format); + QSize res; +#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + const CMVideoDimensions hrDim(format.highResolutionStillImageDimensions); + res.setWidth(hrDim.width); + res.setHeight(hrDim.height); + } +#endif + return res; +} + +QVector<AVFPSRange> qt_device_format_framerates(AVCaptureDeviceFormat *format) +{ + Q_ASSERT(format); + + QVector<AVFPSRange> qtRanges; + + if (!format.videoSupportedFrameRateRanges || !format.videoSupportedFrameRateRanges.count) + return qtRanges; + + qtRanges.reserve(format.videoSupportedFrameRateRanges.count); + for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) + qtRanges << AVFPSRange(range.minFrameRate, range.maxFrameRate); + + return qtRanges; +} + +QSize qt_device_format_pixel_aspect_ratio(AVCaptureDeviceFormat *format) +{ + Q_ASSERT(format); + + if (!format.formatDescription) { + qDebugCamera() << Q_FUNC_INFO << "no format description found"; + return QSize(); + } + + const CMVideoDimensions res = CMVideoFormatDescriptionGetDimensions(format.formatDescription); + const CGSize resPAR = CMVideoFormatDescriptionGetPresentationDimensions(format.formatDescription, true, false); + + if (qAbs(resPAR.width - res.width) < 1.) { + // "Pixel aspect ratio is used to adjust the width, leaving the height alone." + return QSize(1, 1); + } + + if (!res.width || !resPAR.width) + return QSize(); + + const AVFRational asRatio(qt_float_to_rational(resPAR.width > res.width + ? res.width / qreal(resPAR.width) + : resPAR.width / qreal(res.width), 200)); + return QSize(asRatio.first, asRatio.second); +} + +AVCaptureDeviceFormat *qt_find_best_resolution_match(AVCaptureDevice *captureDevice, + const QSize &request, + FourCharCode filter) +{ + Q_ASSERT(captureDevice); + Q_ASSERT(!request.isNull() && request.isValid()); + + if (!captureDevice.formats || !captureDevice.formats.count) + return 0; + + QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(captureDevice, filter)); + + for (int i = 0; i < formats.size(); ++i) { + AVCaptureDeviceFormat *format = formats[i]; + if (qt_device_format_resolution(format) == request) + return format; + // iOS only (still images). + if (qt_device_format_high_resolution(format) == request) + return format; + } + + if (!qt_area_sane(request)) + return 0; + + typedef QPair<QSize, AVCaptureDeviceFormat *> FormatPair; + + QVector<FormatPair> pairs; // default|HR sizes + pairs.reserve(formats.size()); + + for (int i = 0; i < formats.size(); ++i) { + AVCaptureDeviceFormat *format = formats[i]; + const QSize res(qt_device_format_resolution(format)); + if (!res.isNull() && res.isValid() && qt_area_sane(res)) + pairs << FormatPair(res, format); + const QSize highRes(qt_device_format_high_resolution(format)); + if (!highRes.isNull() && highRes.isValid() && qt_area_sane(highRes)) + pairs << FormatPair(highRes, format); + } + + if (!pairs.size()) + return 0; + + AVCaptureDeviceFormat *best = pairs[0].second; + QSize next(pairs[0].first); + int wDiff = qAbs(request.width() - next.width()); + int hDiff = qAbs(request.height() - next.height()); + const int area = request.width() * request.height(); + int areaDiff = qAbs(area - next.width() * next.height()); + for (int i = 1; i < pairs.size(); ++i) { + next = pairs[i].first; + const int newWDiff = qAbs(next.width() - request.width()); + const int newHDiff = qAbs(next.height() - request.height()); + const int newAreaDiff = qAbs(area - next.width() * next.height()); + + if ((newWDiff < wDiff && newHDiff < hDiff) + || ((newWDiff <= wDiff || newHDiff <= hDiff) && newAreaDiff <= areaDiff)) { + wDiff = newWDiff; + hDiff = newHDiff; + best = pairs[i].second; + areaDiff = newAreaDiff; + } + } + + return best; +} + +AVCaptureDeviceFormat *qt_find_best_framerate_match(AVCaptureDevice *captureDevice, + FourCharCode filter, + Float64 fps) +{ + Q_ASSERT(captureDevice); + Q_ASSERT(fps > 0.); + + const qreal epsilon = 0.1; + + QVector<AVCaptureDeviceFormat *>sorted(qt_unique_device_formats(captureDevice, filter)); + // Sort formats by their resolution in decreasing order: + std::sort(sorted.begin(), sorted.end(), std::not2(ResolutionPredicate())); + // We can use only formats with framerate ranges: + sorted.erase(std::remove_if(sorted.begin(), sorted.end(), FormatHasNoFPSRange()), sorted.end()); + + if (!sorted.size()) + return nil; + + for (int i = 0; i < sorted.size(); ++i) { + AVCaptureDeviceFormat *format = sorted[i]; + for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { + if (range.maxFrameRate - range.minFrameRate < epsilon) { + // On OS X ranges are points (built-in camera). + if (qAbs(fps - range.maxFrameRate) < epsilon) + return format; + } + + if (fps >= range.minFrameRate && fps <= range.maxFrameRate) + return format; + } + } + + Float64 distance = qt_find_min_framerate_distance(sorted[0], fps); + AVCaptureDeviceFormat *match = sorted[0]; + for (int i = 1; i < sorted.size(); ++i) { + const Float64 newDistance = qt_find_min_framerate_distance(sorted[i], fps); + if (newDistance < distance) { + distance = newDistance; + match = sorted[i]; + } + } + + return match; +} + +AVFrameRateRange *qt_find_supported_framerate_range(AVCaptureDeviceFormat *format, Float64 fps) +{ + Q_ASSERT(format && format.videoSupportedFrameRateRanges + && format.videoSupportedFrameRateRanges.count); + + const qreal epsilon = 0.1; + + for (AVFrameRateRange *range in format.videoSupportedFrameRateRanges) { + if (range.maxFrameRate - range.minFrameRate < epsilon) { + // On OS X ranges are points (built-in camera). + if (qAbs(fps - range.maxFrameRate) < epsilon) + return range; + } + + if (fps >= range.minFrameRate && fps <= range.maxFrameRate) + return range; + } + + AVFrameRateRange *match = [format.videoSupportedFrameRateRanges objectAtIndex:0]; + Float64 distance = qAbs(match.maxFrameRate - fps); + for (NSUInteger i = 1, e = format.videoSupportedFrameRateRanges.count; i < e; ++i) { + AVFrameRateRange *range = [format.videoSupportedFrameRateRanges objectAtIndex:i]; + const Float64 newDistance = qAbs(range.maxFrameRate - fps); + if (newDistance < distance) { + distance = newDistance; + match = range; + } + } + + return match; +} + +#endif // SDK + +QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h new file mode 100644 index 000000000..cf2f512a7 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.h @@ -0,0 +1,115 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAVIEWFINDERSETTINGSCONTROL_H +#define AVFCAMERAVIEWFINDERSETTINGSCONTROL_H + +#include <QtMultimedia/qcameraviewfindersettingscontrol.h> +#include <QtMultimedia/qcameraviewfindersettings.h> +#include <QtMultimedia/qvideoframe.h> + +#include <QtCore/qpointer.h> +#include <QtCore/qglobal.h> +#include <QtCore/qsize.h> + +@class AVCaptureDevice; +@class AVCaptureVideoDataOutput; +@class AVCaptureConnection; +@class AVCaptureDeviceFormat; + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; + +class AVFCameraViewfinderSettingsControl2 : public QCameraViewfinderSettingsControl2 +{ + Q_OBJECT + + friend class AVFCameraSession; + friend class AVFCameraViewfinderSettingsControl; +public: + AVFCameraViewfinderSettingsControl2(AVFCameraService *service); + + QList<QCameraViewfinderSettings> supportedViewfinderSettings() const Q_DECL_OVERRIDE; + QCameraViewfinderSettings viewfinderSettings() const Q_DECL_OVERRIDE; + void setViewfinderSettings(const QCameraViewfinderSettings &settings) Q_DECL_OVERRIDE; + + // "Converters": + static QVideoFrame::PixelFormat QtPixelFormatFromCVFormat(unsigned avPixelFormat); + static bool CVPixelFormatFromQtFormat(QVideoFrame::PixelFormat qtFormat, unsigned &conv); + +private: + void setResolution(const QSize &resolution); + void setFramerate(qreal minFPS, qreal maxFPS, bool useActive); + void setPixelFormat(QVideoFrame::PixelFormat newFormat); + AVCaptureDeviceFormat *findBestFormatMatch(const QCameraViewfinderSettings &settings) const; + QVector<QVideoFrame::PixelFormat> viewfinderPixelFormats() const; + bool convertPixelFormatIfSupported(QVideoFrame::PixelFormat format, unsigned &avfFormat) const; + void applySettings(); + QCameraViewfinderSettings requestedSettings() const; + // Aux. function to extract things like captureDevice, videoOutput, etc. + bool updateAVFoundationObjects() const; + + AVFCameraService *m_service; + mutable AVFCameraSession *m_session; + QCameraViewfinderSettings m_settings; + mutable AVCaptureDevice *m_captureDevice; + mutable AVCaptureVideoDataOutput *m_videoOutput; + mutable AVCaptureConnection *m_videoConnection; +}; + +class AVFCameraViewfinderSettingsControl : public QCameraViewfinderSettingsControl +{ + Q_OBJECT +public: + AVFCameraViewfinderSettingsControl(AVFCameraService *service); + + bool isViewfinderParameterSupported(ViewfinderParameter parameter) const Q_DECL_OVERRIDE; + QVariant viewfinderParameter(ViewfinderParameter parameter) const Q_DECL_OVERRIDE; + void setViewfinderParameter(ViewfinderParameter parameter, const QVariant &value) Q_DECL_OVERRIDE; + +private: + void setResolution(const QVariant &resolution); + void setAspectRatio(const QVariant &aspectRatio); + void setFrameRate(const QVariant &fps, bool max); + void setPixelFormat(const QVariant &pf); + bool initSettingsControl() const; + + AVFCameraService *m_service; + mutable QPointer<AVFCameraViewfinderSettingsControl2> m_settingsControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm new file mode 100644 index 000000000..60df1e2ed --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraviewfindersettingscontrol.mm @@ -0,0 +1,762 @@ +/**************************************************************************** +** +** 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 "avfcameraviewfindersettingscontrol.h" +#include "avfcamerarenderercontrol.h" +#include "avfcamerautility.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameradebug.h" + +#include <QtMultimedia/qabstractvideosurface.h> + +#include <QtCore/qvariant.h> +#include <QtCore/qsysinfo.h> +#include <QtCore/qvector.h> +#include <QtCore/qdebug.h> +#include <QtCore/qlist.h> + +#include <algorithm> + +#include <AVFoundation/AVFoundation.h> + +QT_BEGIN_NAMESPACE + +namespace { + +bool qt_framerates_sane(const QCameraViewfinderSettings &settings) +{ + const qreal minFPS = settings.minimumFrameRate(); + const qreal maxFPS = settings.maximumFrameRate(); + + if (minFPS < 0. || maxFPS < 0.) + return false; + + return !maxFPS || maxFPS >= minFPS; +} + +void qt_set_framerate_limits(AVCaptureConnection *videoConnection, + const QCameraViewfinderSettings &settings) +{ + Q_ASSERT(videoConnection); + + if (!qt_framerates_sane(settings)) { + qDebugCamera() << Q_FUNC_INFO << "invalid framerate (min, max):" + << settings.minimumFrameRate() << settings.maximumFrameRate(); + return; + } + + const qreal minFPS = settings.minimumFrameRate(); + const qreal maxFPS = settings.maximumFrameRate(); + + CMTime minDuration = kCMTimeInvalid; + CMTime maxDuration = kCMTimeInvalid; + if (minFPS > 0. || maxFPS > 0.) { + if (maxFPS) { + if (!videoConnection.supportsVideoMinFrameDuration) + qDebugCamera() << Q_FUNC_INFO << "maximum framerate is not supported"; + else + minDuration = CMTimeMake(1, maxFPS); + } + + if (minFPS) { + if (!videoConnection.supportsVideoMaxFrameDuration) + qDebugCamera() << Q_FUNC_INFO << "minimum framerate is not supported"; + else + maxDuration = CMTimeMake(1, minFPS); + } + } + + if (videoConnection.supportsVideoMinFrameDuration) + videoConnection.videoMinFrameDuration = minDuration; + if (videoConnection.supportsVideoMaxFrameDuration) + videoConnection.videoMaxFrameDuration = maxDuration; +} + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + +CMTime qt_adjusted_frame_duration(AVFrameRateRange *range, qreal fps) +{ + Q_ASSERT(range); + Q_ASSERT(fps > 0.); + + if (range.maxFrameRate - range.minFrameRate < 0.1) { + // Can happen on OS X. + return range.minFrameDuration; + } + + if (fps <= range.minFrameRate) + return range.maxFrameDuration; + if (fps >= range.maxFrameRate) + return range.minFrameDuration; + + const AVFRational timeAsRational(qt_float_to_rational(1. / fps, 1000)); + return CMTimeMake(timeAsRational.first, timeAsRational.second); +} + +void qt_set_framerate_limits(AVCaptureDevice *captureDevice, + const QCameraViewfinderSettings &settings) +{ + Q_ASSERT(captureDevice); + if (!captureDevice.activeFormat) { + qDebugCamera() << Q_FUNC_INFO << "no active capture device format"; + return; + } + + const qreal minFPS = settings.minimumFrameRate(); + const qreal maxFPS = settings.maximumFrameRate(); + if (!qt_framerates_sane(settings)) { + qDebugCamera() << Q_FUNC_INFO << "invalid framerates (min, max):" + << minFPS << maxFPS; + return; + } + + CMTime minFrameDuration = kCMTimeInvalid; + CMTime maxFrameDuration = kCMTimeInvalid; + if (maxFPS || minFPS) { + AVFrameRateRange *range = qt_find_supported_framerate_range(captureDevice.activeFormat, + maxFPS ? maxFPS : minFPS); + if (!range) { + qDebugCamera() << Q_FUNC_INFO << "no framerate range found, (min, max):" + << minFPS << maxFPS; + return; + } + + if (maxFPS) + minFrameDuration = qt_adjusted_frame_duration(range, maxFPS); + if (minFPS) + maxFrameDuration = qt_adjusted_frame_duration(range, minFPS); + } + + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + // While Apple's docs say kCMTimeInvalid will end in default + // settings for this format, kCMTimeInvalid on OS X ends with a runtime + // exception: + // "The activeVideoMinFrameDuration passed is not supported by the device." +#ifdef Q_OS_IOS + [captureDevice setActiveVideoMinFrameDuration:minFrameDuration]; + [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration]; +#else + if (CMTimeCompare(minFrameDuration, kCMTimeInvalid)) + [captureDevice setActiveVideoMinFrameDuration:minFrameDuration]; + if (CMTimeCompare(maxFrameDuration, kCMTimeInvalid)) + [captureDevice setActiveVideoMaxFrameDuration:maxFrameDuration]; +#endif +} + +#endif // Platform SDK >= 10.9, >= 7.0. + +// 'Dispatchers': + +AVFPSRange qt_current_framerates(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection) +{ + Q_ASSERT(captureDevice); + Q_ASSERT(videoConnection); + + AVFPSRange fps; +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + const CMTime minDuration = captureDevice.activeVideoMinFrameDuration; + if (CMTimeCompare(minDuration, kCMTimeInvalid)) { + if (const Float64 minSeconds = CMTimeGetSeconds(minDuration)) + fps.second = 1. / minSeconds; // Max FPS = 1 / MinDuration. + } + + const CMTime maxDuration = captureDevice.activeVideoMaxFrameDuration; + if (CMTimeCompare(maxDuration, kCMTimeInvalid)) { + if (const Float64 maxSeconds = CMTimeGetSeconds(maxDuration)) + fps.first = 1. / maxSeconds; // Min FPS = 1 / MaxDuration. + } + } else { +#else + { +#endif + fps = qt_connection_framerates(videoConnection); + } + + return fps; +} + +void qt_set_framerate_limits(AVCaptureDevice *captureDevice, AVCaptureConnection *videoConnection, + const QCameraViewfinderSettings &settings) +{ + Q_ASSERT(captureDevice); + Q_ASSERT(videoConnection); +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_9, QSysInfo::MV_IOS_7_0)) + qt_set_framerate_limits(captureDevice, settings); + else + qt_set_framerate_limits(videoConnection, settings); +#else + qt_set_framerate_limits(videoConnection, settings); +#endif +} + +} // Unnamed namespace. + +AVFCameraViewfinderSettingsControl2::AVFCameraViewfinderSettingsControl2(AVFCameraService *service) + : m_service(service), + m_captureDevice(0), + m_videoOutput(0), + m_videoConnection(0) +{ + Q_ASSERT(service); +} + +QList<QCameraViewfinderSettings> AVFCameraViewfinderSettingsControl2::supportedViewfinderSettings() const +{ + QList<QCameraViewfinderSettings> supportedSettings; + + if (!updateAVFoundationObjects()) { + qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found"; + return supportedSettings; + } + + QVector<AVFPSRange> framerates; + + QVector<QVideoFrame::PixelFormat> pixelFormats(viewfinderPixelFormats()); + + if (!pixelFormats.size()) + pixelFormats << QVideoFrame::Format_Invalid; // The default value. +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + if (!m_captureDevice.formats || !m_captureDevice.formats.count) { + qDebugCamera() << Q_FUNC_INFO << "no capture device formats found"; + return supportedSettings; + } + + const QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(m_captureDevice, + m_session->defaultCodec())); + for (int i = 0; i < formats.size(); ++i) { + AVCaptureDeviceFormat *format = formats[i]; + + const QSize res(qt_device_format_resolution(format)); + if (res.isNull() || !res.isValid()) + continue; + const QSize par(qt_device_format_pixel_aspect_ratio(format)); + if (par.isNull() || !par.isValid()) + continue; + + framerates = qt_device_format_framerates(format); + if (!framerates.size()) + framerates << AVFPSRange(); // The default value. + + for (int i = 0; i < pixelFormats.size(); ++i) { + for (int j = 0; j < framerates.size(); ++j) { + QCameraViewfinderSettings newSet; + newSet.setResolution(res); + newSet.setPixelAspectRatio(par); + newSet.setPixelFormat(pixelFormats[i]); + newSet.setMinimumFrameRate(framerates[j].first); + newSet.setMaximumFrameRate(framerates[j].second); + supportedSettings << newSet; + } + } + } + } else { +#else + { +#endif + // TODO: resolution and PAR. + framerates << qt_connection_framerates(m_videoConnection); + for (int i = 0; i < pixelFormats.size(); ++i) { + for (int j = 0; j < framerates.size(); ++j) { + QCameraViewfinderSettings newSet; + newSet.setPixelFormat(pixelFormats[i]); + newSet.setMinimumFrameRate(framerates[j].first); + newSet.setMaximumFrameRate(framerates[j].second); + supportedSettings << newSet; + } + } + } + + return supportedSettings; +} + +QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::viewfinderSettings() const +{ + QCameraViewfinderSettings settings; + + if (!updateAVFoundationObjects()) { + qDebugCamera() << Q_FUNC_INFO << "no capture device or video output found"; + return settings; + } + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + if (!m_captureDevice.activeFormat) { + qDebugCamera() << Q_FUNC_INFO << "no active capture device format"; + return settings; + } + + const QSize res(qt_device_format_resolution(m_captureDevice.activeFormat)); + const QSize par(qt_device_format_pixel_aspect_ratio(m_captureDevice.activeFormat)); + if (res.isNull() || !res.isValid() || par.isNull() || !par.isValid()) { + qDebugCamera() << Q_FUNC_INFO << "failed to obtain resolution/pixel aspect ratio"; + return settings; + } + + settings.setResolution(res); + settings.setPixelAspectRatio(par); + } +#endif + // TODO: resolution and PAR before 7.0. + const AVFPSRange fps = qt_current_framerates(m_captureDevice, m_videoConnection); + settings.setMinimumFrameRate(fps.first); + settings.setMaximumFrameRate(fps.second); + + if (NSObject *obj = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) { + if ([obj isKindOfClass:[NSNumber class]]) { + NSNumber *nsNum = static_cast<NSNumber *>(obj); + settings.setPixelFormat(QtPixelFormatFromCVFormat([nsNum unsignedIntValue])); + } + } + + return settings; +} + +void AVFCameraViewfinderSettingsControl2::setViewfinderSettings(const QCameraViewfinderSettings &settings) +{ + if (settings.isNull()) { + qDebugCamera() << Q_FUNC_INFO << "empty viewfinder settings"; + return; + } + + if (m_settings == settings) + return; + + m_settings = settings; + applySettings(); +} + +QVideoFrame::PixelFormat AVFCameraViewfinderSettingsControl2::QtPixelFormatFromCVFormat(unsigned avPixelFormat) +{ + // BGRA <-> ARGB "swap" is intentional: + // to work correctly with GL_RGBA, color swap shaders + // (in QSG node renderer etc.). + switch (avPixelFormat) { + case kCVPixelFormatType_32ARGB: + return QVideoFrame::Format_BGRA32; + case kCVPixelFormatType_32BGRA: + return QVideoFrame::Format_ARGB32; + case kCVPixelFormatType_24RGB: + return QVideoFrame::Format_RGB24; + case kCVPixelFormatType_24BGR: + return QVideoFrame::Format_BGR24; + case kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange: + case kCVPixelFormatType_420YpCbCr8BiPlanarFullRange: + return QVideoFrame::Format_NV12; + default: + return QVideoFrame::Format_Invalid; + } +} + +bool AVFCameraViewfinderSettingsControl2::CVPixelFormatFromQtFormat(QVideoFrame::PixelFormat qtFormat, unsigned &conv) +{ + // BGRA <-> ARGB "swap" is intentional: + // to work correctly with GL_RGBA, color swap shaders + // (in QSG node renderer etc.). + switch (qtFormat) { + case QVideoFrame::Format_ARGB32: + conv = kCVPixelFormatType_32BGRA; + break; + case QVideoFrame::Format_BGRA32: + conv = kCVPixelFormatType_32ARGB; + break; + case QVideoFrame::Format_NV12: + conv = kCVPixelFormatType_420YpCbCr8BiPlanarFullRange; + break; + // These two formats below are not supported + // by QSGVideoNodeFactory_RGB, so for now I have to + // disable them. + /* + case QVideoFrame::Format_RGB24: + conv = kCVPixelFormatType_24RGB; + break; + case QVideoFrame::Format_BGR24: + conv = kCVPixelFormatType_24BGR; + break; + */ + default: + return false; + } + + return true; +} + +AVCaptureDeviceFormat *AVFCameraViewfinderSettingsControl2::findBestFormatMatch(const QCameraViewfinderSettings &settings) const +{ +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + Q_ASSERT(m_captureDevice); + Q_ASSERT(m_session); + + const QSize &resolution = settings.resolution(); + if (!resolution.isNull() && resolution.isValid()) { + // Either the exact match (including high resolution for images on iOS) + // or a format with a resolution close to the requested one. + return qt_find_best_resolution_match(m_captureDevice, resolution, + m_session->defaultCodec()); + } + + // No resolution requested, what about framerates? + if (!qt_framerates_sane(settings)) { + qDebugCamera() << Q_FUNC_INFO << "invalid framerate requested (min/max):" + << settings.minimumFrameRate() << settings.maximumFrameRate(); + return nil; + } + + const qreal minFPS(settings.minimumFrameRate()); + const qreal maxFPS(settings.maximumFrameRate()); + if (minFPS || maxFPS) + return qt_find_best_framerate_match(m_captureDevice, maxFPS ? maxFPS : minFPS, + m_session->defaultCodec()); + // Ignore PAR for the moment (PAR without resolution can + // pick a format with really bad resolution). + // No need to test pixel format, just return settings. + } +#endif + return nil; +} + +QVector<QVideoFrame::PixelFormat> AVFCameraViewfinderSettingsControl2::viewfinderPixelFormats() const +{ + Q_ASSERT(m_videoOutput); + + QVector<QVideoFrame::PixelFormat> qtFormats; + QList<QVideoFrame::PixelFormat> filter; + + NSArray *pixelFormats = [m_videoOutput availableVideoCVPixelFormatTypes]; + const QAbstractVideoSurface *surface = m_service->videoOutput() ? m_service->videoOutput()->surface() : 0; + + if (surface) + filter = surface->supportedPixelFormats(); + + for (NSObject *obj in pixelFormats) { + if (![obj isKindOfClass:[NSNumber class]]) + continue; + + NSNumber *formatAsNSNumber = static_cast<NSNumber *>(obj); + // It's actually FourCharCode (== UInt32): + const QVideoFrame::PixelFormat qtFormat(QtPixelFormatFromCVFormat([formatAsNSNumber unsignedIntValue])); + if (qtFormat != QVideoFrame::Format_Invalid && (!surface || filter.contains(qtFormat)) + && !qtFormats.contains(qtFormat)) { // Can happen, for example, with 8BiPlanar existing in video/full range. + qtFormats << qtFormat; + } + } + + return qtFormats; +} + +bool AVFCameraViewfinderSettingsControl2::convertPixelFormatIfSupported(QVideoFrame::PixelFormat qtFormat, + unsigned &avfFormat)const +{ + Q_ASSERT(m_videoOutput); + + unsigned conv = 0; + if (!CVPixelFormatFromQtFormat(qtFormat, conv)) + return false; + + NSArray *formats = [m_videoOutput availableVideoCVPixelFormatTypes]; + if (!formats || !formats.count) + return false; + + if (m_service->videoOutput() && m_service->videoOutput()->surface()) { + const QAbstractVideoSurface *surface = m_service->videoOutput()->surface(); + if (!surface->supportedPixelFormats().contains(qtFormat)) + return false; + } + + bool found = false; + for (NSObject *obj in formats) { + if (![obj isKindOfClass:[NSNumber class]]) + continue; + + NSNumber *nsNum = static_cast<NSNumber *>(obj); + if ([nsNum unsignedIntValue] == conv) { + avfFormat = conv; + found = true; + } + } + + return found; +} + +void AVFCameraViewfinderSettingsControl2::applySettings() +{ + if (m_settings.isNull()) + return; + + if (!updateAVFoundationObjects()) + return; + + if (m_session->state() != QCamera::LoadedState && + m_session->state() != QCamera::ActiveState) { + return; + } + + NSMutableDictionary *videoSettings = [NSMutableDictionary dictionaryWithCapacity:1]; +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + AVCaptureDeviceFormat *match = findBestFormatMatch(m_settings); + if (match) { + if (match != m_captureDevice.activeFormat) { + const AVFConfigurationLock lock(m_captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + m_captureDevice.activeFormat = match; + } + } else { + qDebugCamera() << Q_FUNC_INFO << "matching device format not found"; + // We still can update the pixel format at least. + } +#endif + + unsigned avfPixelFormat = 0; + if (m_settings.pixelFormat() != QVideoFrame::Format_Invalid && + convertPixelFormatIfSupported(m_settings.pixelFormat(), avfPixelFormat)) { + [videoSettings setObject:[NSNumber numberWithUnsignedInt:avfPixelFormat] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + } else { + // We have to set the pixel format, otherwise AVFoundation can change it to something we do not support. + if (NSObject *oldFormat = [m_videoOutput.videoSettings objectForKey:(id)kCVPixelBufferPixelFormatTypeKey]) { + [videoSettings setObject:oldFormat forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + } else { + [videoSettings setObject:[NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + } + } + + if (videoSettings.count) + m_videoOutput.videoSettings = videoSettings; + + qt_set_framerate_limits(m_captureDevice, m_videoConnection, m_settings); +} + +QCameraViewfinderSettings AVFCameraViewfinderSettingsControl2::requestedSettings() const +{ + return m_settings; +} + +bool AVFCameraViewfinderSettingsControl2::updateAVFoundationObjects() const +{ + m_session = 0; + m_captureDevice = 0; + m_videoOutput = 0; + m_videoConnection = 0; + + if (!m_service->session()) + return false; + + if (!m_service->session()->videoCaptureDevice()) + return false; + + if (!m_service->videoOutput() || !m_service->videoOutput()->videoDataOutput()) + return false; + + AVCaptureVideoDataOutput *output = m_service->videoOutput()->videoDataOutput(); + AVCaptureConnection *connection = [output connectionWithMediaType:AVMediaTypeVideo]; + if (!connection) + return false; + + m_session = m_service->session(); + m_captureDevice = m_session->videoCaptureDevice(); + m_videoOutput = output; + m_videoConnection = connection; + + return true; +} + +AVFCameraViewfinderSettingsControl::AVFCameraViewfinderSettingsControl(AVFCameraService *service) + : m_service(service) +{ + // Legacy viewfinder settings control. + Q_ASSERT(service); + initSettingsControl(); +} + +bool AVFCameraViewfinderSettingsControl::isViewfinderParameterSupported(ViewfinderParameter parameter) const +{ + return parameter == Resolution + || parameter == PixelAspectRatio + || parameter == MinimumFrameRate + || parameter == MaximumFrameRate + || parameter == PixelFormat; +} + +QVariant AVFCameraViewfinderSettingsControl::viewfinderParameter(ViewfinderParameter parameter) const +{ + if (!isViewfinderParameterSupported(parameter)) { + qDebugCamera() << Q_FUNC_INFO << "parameter is not supported"; + return QVariant(); + } + + if (!initSettingsControl()) { + qDebugCamera() << Q_FUNC_INFO << "initialization failed"; + return QVariant(); + } + + const QCameraViewfinderSettings settings(m_settingsControl->viewfinderSettings()); + if (parameter == Resolution) + return settings.resolution(); + if (parameter == PixelAspectRatio) + return settings.pixelAspectRatio(); + if (parameter == MinimumFrameRate) + return settings.minimumFrameRate(); + if (parameter == MaximumFrameRate) + return settings.maximumFrameRate(); + if (parameter == PixelFormat) + return QVariant::fromValue(settings.pixelFormat()); + + return QVariant(); +} + +void AVFCameraViewfinderSettingsControl::setViewfinderParameter(ViewfinderParameter parameter, const QVariant &value) +{ + if (!isViewfinderParameterSupported(parameter)) { + qDebugCamera() << Q_FUNC_INFO << "parameter is not supported"; + return; + } + + if (parameter == Resolution) + setResolution(value); + if (parameter == PixelAspectRatio) + setAspectRatio(value); + if (parameter == MinimumFrameRate) + setFrameRate(value, false); + if (parameter == MaximumFrameRate) + setFrameRate(value, true); + if (parameter == PixelFormat) + setPixelFormat(value); +} + +void AVFCameraViewfinderSettingsControl::setResolution(const QVariant &newValue) +{ + if (!newValue.canConvert<QSize>()) { + qDebugCamera() << Q_FUNC_INFO << "QSize type expected"; + return; + } + + if (!initSettingsControl()) { + qDebugCamera() << Q_FUNC_INFO << "initialization failed"; + return; + } + + const QSize res(newValue.toSize()); + if (res.isNull() || !res.isValid()) { + qDebugCamera() << Q_FUNC_INFO << "invalid resolution:" << res; + return; + } + + QCameraViewfinderSettings settings(m_settingsControl->viewfinderSettings()); + settings.setResolution(res); + m_settingsControl->setViewfinderSettings(settings); +} + +void AVFCameraViewfinderSettingsControl::setAspectRatio(const QVariant &newValue) +{ + if (!newValue.canConvert<QSize>()) { + qDebugCamera() << Q_FUNC_INFO << "QSize type expected"; + return; + } + + if (!initSettingsControl()) { + qDebugCamera() << Q_FUNC_INFO << "initialization failed"; + return; + } + + const QSize par(newValue.value<QSize>()); + if (par.isNull() || !par.isValid()) { + qDebugCamera() << Q_FUNC_INFO << "invalid pixel aspect ratio:" << par; + return; + } + + QCameraViewfinderSettings settings(m_settingsControl->viewfinderSettings()); + settings.setPixelAspectRatio(par); + m_settingsControl->setViewfinderSettings(settings); +} + +void AVFCameraViewfinderSettingsControl::setFrameRate(const QVariant &newValue, bool max) +{ + if (!newValue.canConvert<qreal>()) { + qDebugCamera() << Q_FUNC_INFO << "qreal type expected"; + return; + } + + if (!initSettingsControl()) { + qDebugCamera() << Q_FUNC_INFO << "initialization failed"; + return; + } + + const qreal fps(newValue.toReal()); + QCameraViewfinderSettings settings(m_settingsControl->viewfinderSettings()); + max ? settings.setMaximumFrameRate(fps) : settings.setMinimumFrameRate(fps); + m_settingsControl->setViewfinderSettings(settings); +} + +void AVFCameraViewfinderSettingsControl::setPixelFormat(const QVariant &newValue) +{ + if (!newValue.canConvert<QVideoFrame::PixelFormat>()) { + qDebugCamera() << Q_FUNC_INFO + << "QVideoFrame::PixelFormat type expected"; + return; + } + + if (!initSettingsControl()) { + qDebugCamera() << Q_FUNC_INFO << "initialization failed"; + return; + } + + QCameraViewfinderSettings settings(m_settingsControl->viewfinderSettings()); + settings.setPixelFormat(newValue.value<QVideoFrame::PixelFormat>()); + m_settingsControl->setViewfinderSettings(settings); +} + +bool AVFCameraViewfinderSettingsControl::initSettingsControl()const +{ + if (!m_settingsControl) + m_settingsControl = m_service->viewfinderSettingsControl2(); + + return !m_settingsControl.isNull(); +} + +QT_END_NAMESPACE + +#include "moc_avfcameraviewfindersettingscontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcamerazoomcontrol.h b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.h new file mode 100644 index 000000000..8556db50a --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.h @@ -0,0 +1,79 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAZOOMCONTROL_H +#define AVFCAMERAZOOMCONTROL_H + +#include <QtMultimedia/qcamerazoomcontrol.h> +#include <QtMultimedia/qcamera.h> + +#include <AVFoundation/AVFoundation.h> + +QT_BEGIN_NAMESPACE + +class AVFCameraService; +class AVFCameraSession; +class AVFCameraControl; + +class AVFCameraZoomControl : public QCameraZoomControl +{ + Q_OBJECT +public: + AVFCameraZoomControl(AVFCameraService *service); + + qreal maximumOpticalZoom() const Q_DECL_OVERRIDE; + qreal maximumDigitalZoom() const Q_DECL_OVERRIDE; + + qreal requestedOpticalZoom() const Q_DECL_OVERRIDE; + qreal requestedDigitalZoom() const Q_DECL_OVERRIDE; + qreal currentOpticalZoom() const Q_DECL_OVERRIDE; + qreal currentDigitalZoom() const Q_DECL_OVERRIDE; + + void zoomTo(qreal optical, qreal digital) Q_DECL_OVERRIDE; + +private Q_SLOTS: + void cameraStateChanged(); + +private: + void zoomToRequestedDigital(); + + AVFCameraSession *m_session; + + CGFloat m_maxZoomFactor; + CGFloat m_zoomFactor; + CGFloat m_requestedZoomFactor; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm new file mode 100644 index 000000000..8206112bb --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerazoomcontrol.mm @@ -0,0 +1,188 @@ +/**************************************************************************** +** +** 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 "avfcamerazoomcontrol.h" +#include "avfcameraservice.h" +#include "avfcamerautility.h" +#include "avfcamerasession.h" +#include "avfcameracontrol.h" +#include "avfcameradebug.h" + +#include <QtCore/qsysinfo.h> +#include <QtCore/qglobal.h> +#include <QtCore/qdebug.h> + +QT_BEGIN_NAMESPACE + +AVFCameraZoomControl::AVFCameraZoomControl(AVFCameraService *service) + : m_session(service->session()), + m_maxZoomFactor(1.), + m_zoomFactor(1.), + m_requestedZoomFactor(1.) +{ + Q_ASSERT(m_session); + connect(m_session, SIGNAL(stateChanged(QCamera::State)), + SLOT(cameraStateChanged())); +} + +qreal AVFCameraZoomControl::maximumOpticalZoom() const +{ + // Not supported. + return 1.; +} + +qreal AVFCameraZoomControl::maximumDigitalZoom() const +{ + return m_maxZoomFactor; +} + +qreal AVFCameraZoomControl::requestedOpticalZoom() const +{ + // Not supported. + return 1; +} + +qreal AVFCameraZoomControl::requestedDigitalZoom() const +{ + return m_requestedZoomFactor; +} + +qreal AVFCameraZoomControl::currentOpticalZoom() const +{ + // Not supported. + return 1.; +} + +qreal AVFCameraZoomControl::currentDigitalZoom() const +{ + return m_zoomFactor; +} + +void AVFCameraZoomControl::zoomTo(qreal optical, qreal digital) +{ + Q_UNUSED(optical) + Q_UNUSED(digital) +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) + if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) + return; + + if (qFuzzyCompare(CGFloat(digital), m_requestedZoomFactor)) + return; + + m_requestedZoomFactor = digital; + Q_EMIT requestedDigitalZoomChanged(digital); + + zoomToRequestedDigital(); +#endif +} + +void AVFCameraZoomControl::cameraStateChanged() +{ +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) + if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) + return; + + const QCamera::State state = m_session->state(); + if (state != QCamera::ActiveState) { + if (state == QCamera::UnloadedState && m_maxZoomFactor > 1.) { + m_maxZoomFactor = 1.; + Q_EMIT maximumDigitalZoomChanged(1.); + } + return; + } + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice || !captureDevice.activeFormat) { + qDebugCamera() << Q_FUNC_INFO << "camera state is active, but" + << "video capture device and/or active format is nil"; + return; + } + + if (captureDevice.activeFormat.videoMaxZoomFactor > 1. + && !qFuzzyCompare(m_maxZoomFactor, captureDevice.activeFormat.videoMaxZoomFactor)) { + m_maxZoomFactor = captureDevice.activeFormat.videoMaxZoomFactor; + + Q_EMIT maximumDigitalZoomChanged(m_maxZoomFactor); + } else if (!qFuzzyCompare(m_maxZoomFactor, CGFloat(1.))) { + m_maxZoomFactor = 1.; + + Q_EMIT maximumDigitalZoomChanged(1.); + } + + zoomToRequestedDigital(); +#endif +} + +void AVFCameraZoomControl::zoomToRequestedDigital() +{ +#if QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_7_0) + if (QSysInfo::MacintoshVersion < QSysInfo::MV_IOS_7_0) + return; + + AVCaptureDevice *captureDevice = m_session->videoCaptureDevice(); + if (!captureDevice || !captureDevice.activeFormat) + return; + + if (qFuzzyCompare(captureDevice.activeFormat.videoMaxZoomFactor, CGFloat(1.))) + return; + + const CGFloat clampedZoom = qBound(CGFloat(1.), m_requestedZoomFactor, + captureDevice.activeFormat.videoMaxZoomFactor); + const CGFloat deviceZoom = captureDevice.videoZoomFactor; + if (qFuzzyCompare(clampedZoom, deviceZoom)) { + // Nothing to set, but check if a signal must be emitted: + if (!qFuzzyCompare(m_zoomFactor, deviceZoom)) { + m_zoomFactor = deviceZoom; + Q_EMIT currentDigitalZoomChanged(deviceZoom); + } + return; + } + + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + + captureDevice.videoZoomFactor = clampedZoom; + + if (!qFuzzyCompare(clampedZoom, m_zoomFactor)) { + m_zoomFactor = clampedZoom; + Q_EMIT currentDigitalZoomChanged(clampedZoom); + } +#endif +} + +QT_END_NAMESPACE + +#include "moc_avfcamerazoomcontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h index fecf0be74..c27abd39b 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ @@ -56,6 +56,7 @@ public: QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } void setDriveMode(QCameraImageCapture::DriveMode ) {} + AVCaptureStillImageOutput *stillImageOutput() const {return m_stillImageOutput;} int capture(const QString &fileName); void cancelCapture(); diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm index 2da2f1834..0d245fc57 100644 --- a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ @@ -194,28 +186,19 @@ void AVFImageCaptureControl::cancelCapture() void AVFImageCaptureControl::updateCaptureConnection() { - if (!m_videoConnection && - m_cameraControl->captureMode().testFlag(QCamera::CaptureStillImage)) { + if (m_cameraControl->captureMode().testFlag(QCamera::CaptureStillImage)) { qDebugCamera() << Q_FUNC_INFO; AVCaptureSession *captureSession = m_session->captureSession(); - if ([captureSession canAddOutput:m_stillImageOutput]) { - [captureSession addOutput:m_stillImageOutput]; - - for (AVCaptureConnection *connection in m_stillImageOutput.connections) { - for (AVCaptureInputPort *port in [connection inputPorts]) { - if ([[port mediaType] isEqual:AVMediaTypeVideo] ) { - m_videoConnection = connection; - break; - } - } - - if (m_videoConnection) - break; + if (![captureSession.outputs containsObject:m_stillImageOutput]) { + if ([captureSession canAddOutput:m_stillImageOutput]) { + [captureSession addOutput:m_stillImageOutput]; + m_videoConnection = [m_stillImageOutput connectionWithMediaType:AVMediaTypeVideo]; + updateReadyStatus(); } + } else { + m_videoConnection = [m_stillImageOutput connectionWithMediaType:AVMediaTypeVideo]; } - - updateReadyStatus(); } } diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.h b/src/plugins/avfoundation/camera/avfimageencodercontrol.h new file mode 100644 index 000000000..fcb665a03 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.h @@ -0,0 +1,77 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFIMAGEENCODERCONTROL_H +#define AVFIMAGEENCODERCONTROL_H + +#include <QtMultimedia/qmediaencodersettings.h> +#include <QtMultimedia/qimageencodercontrol.h> + +#include <QtCore/qglobal.h> +#include <QtCore/qstring.h> +#include <QtCore/qlist.h> + +@class AVCaptureDeviceFormat; + +QT_BEGIN_NAMESPACE + +class AVFCameraService; + +class AVFImageEncoderControl : public QImageEncoderControl +{ + Q_OBJECT + + friend class AVFCameraSession; +public: + AVFImageEncoderControl(AVFCameraService *service); + + QStringList supportedImageCodecs() const Q_DECL_OVERRIDE; + QString imageCodecDescription(const QString &codecName) const Q_DECL_OVERRIDE; + QList<QSize> supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous) const Q_DECL_OVERRIDE; + QImageEncoderSettings imageSettings() const Q_DECL_OVERRIDE; + void setImageSettings(const QImageEncoderSettings &settings) Q_DECL_OVERRIDE; + +private: + AVFCameraService *m_service; + QImageEncoderSettings m_settings; + + void applySettings(); + bool videoCaptureDeviceIsValid() const; +}; + +QSize qt_image_high_resolution(AVCaptureDeviceFormat *fomat); + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfimageencodercontrol.mm b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm new file mode 100644 index 000000000..36050c3a2 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfimageencodercontrol.mm @@ -0,0 +1,261 @@ +/**************************************************************************** +** +** 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 "avfcameraviewfindersettingscontrol.h" +#include "avfimageencodercontrol.h" +#include "avfimagecapturecontrol.h" +#include "avfcamerautility.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameradebug.h" + +#include <QtMultimedia/qmediaencodersettings.h> + +#include <QtCore/qsysinfo.h> +#include <QtCore/qdebug.h> + +#include <AVFoundation/AVFoundation.h> + +QT_BEGIN_NAMESPACE + +AVFImageEncoderControl::AVFImageEncoderControl(AVFCameraService *service) + : m_service(service) +{ + Q_ASSERT(service); +} + +QStringList AVFImageEncoderControl::supportedImageCodecs() const +{ + return QStringList() << QLatin1String("jpeg"); +} + +QString AVFImageEncoderControl::imageCodecDescription(const QString &codecName) const +{ + if (codecName == QLatin1String("jpeg")) + return tr("JPEG image"); + + return QString(); +} + +QList<QSize> AVFImageEncoderControl::supportedResolutions(const QImageEncoderSettings &settings, + bool *continuous) const +{ + Q_UNUSED(settings) + + QList<QSize> resolutions; + + if (!videoCaptureDeviceIsValid()) + return resolutions; + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + const QVector<AVCaptureDeviceFormat *> formats(qt_unique_device_formats(captureDevice, + m_service->session()->defaultCodec())); + + for (int i = 0; i < formats.size(); ++i) { + AVCaptureDeviceFormat *format = formats[i]; + + const QSize res(qt_device_format_resolution(format)); + if (!res.isNull() && res.isValid()) + resolutions << res; +#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + // From Apple's docs (iOS): + // By default, AVCaptureStillImageOutput emits images with the same dimensions as + // its source AVCaptureDevice instance’s activeFormat.formatDescription. However, + // if you set this property to YES, the receiver emits still images at the capture + // device’s highResolutionStillImageDimensions value. + const QSize hrRes(qt_device_format_high_resolution(format)); + if (!hrRes.isNull() && hrRes.isValid()) + resolutions << res; + } +#endif + } + } else { +#else + { +#endif + // TODO: resolutions without AVCaptureDeviceFormat ... + } + + if (continuous) + *continuous = false; + + return resolutions; +} + +QImageEncoderSettings AVFImageEncoderControl::imageSettings() const +{ + QImageEncoderSettings settings; + + if (!videoCaptureDeviceIsValid()) + return settings; + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice.activeFormat) { + qDebugCamera() << Q_FUNC_INFO << "no active format"; + return settings; + } + + QSize res(qt_device_format_resolution(captureDevice.activeFormat)); +#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + if (!m_service->imageCaptureControl() || !m_service->imageCaptureControl()->stillImageOutput()) { + qDebugCamera() << Q_FUNC_INFO << "no still image output"; + return settings; + } + + AVCaptureStillImageOutput *stillImageOutput = m_service->imageCaptureControl()->stillImageOutput(); + if (stillImageOutput.highResolutionStillImageOutputEnabled) + res = qt_device_format_high_resolution(captureDevice.activeFormat); + } +#endif + if (res.isNull() || !res.isValid()) { + qDebugCamera() << Q_FUNC_INFO << "failed to exctract the image resolution"; + return settings; + } + + settings.setResolution(res); + } else { +#else + { +#endif + // TODO: resolution without AVCaptureDeviceFormat. + } + + settings.setCodec(QLatin1String("jpeg")); + + return settings; +} + +void AVFImageEncoderControl::setImageSettings(const QImageEncoderSettings &settings) +{ + if (m_settings == settings || settings.isNull()) + return; + + m_settings = settings; + applySettings(); +} + +void AVFImageEncoderControl::applySettings() +{ + if (!videoCaptureDeviceIsValid()) + return; + + AVFCameraSession *session = m_service->session(); + if (!session || (session->state() != QCamera::ActiveState + && session->state() != QCamera::LoadedState)) { + return; + } + + if (!m_service->imageCaptureControl() + || !m_service->imageCaptureControl()->stillImageOutput()) { + qDebugCamera() << Q_FUNC_INFO << "no still image output"; + return; + } + + if (m_settings.codec().size() + && m_settings.codec() != QLatin1String("jpeg")) { + qDebugCamera() << Q_FUNC_INFO << "unsupported codec:" << m_settings.codec(); + return; + } + + QSize res(m_settings.resolution()); + if (res.isNull()) { + qDebugCamera() << Q_FUNC_INFO << "invalid resolution:" << res; + return; + } + + if (!res.isValid()) { + // Invalid == default value. + // Here we could choose the best format available, but + // activeFormat is already equal to 'preset high' by default, + // which is good enough, otherwise we can end in some format with low framerates. + return; + } + +#if QT_MAC_PLATFORM_SDK_EQUAL_OR_ABOVE(__MAC_10_7, __IPHONE_7_0) + if (QSysInfo::MacintoshVersion >= qt_OS_limit(QSysInfo::MV_10_7, QSysInfo::MV_IOS_7_0)) { + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + AVCaptureDeviceFormat *match = qt_find_best_resolution_match(captureDevice, res, + m_service->session()->defaultCodec()); + + if (!match) { + qDebugCamera() << Q_FUNC_INFO << "unsupported resolution:" << res; + return; + } + + if (match != captureDevice.activeFormat) { + const AVFConfigurationLock lock(captureDevice); + if (!lock) { + qDebugCamera() << Q_FUNC_INFO << "failed to lock for configuration"; + return; + } + captureDevice.activeFormat = match; + } + +#if defined(Q_OS_IOS) && QT_IOS_PLATFORM_SDK_EQUAL_OR_ABOVE(__IPHONE_8_0) + if (QSysInfo::MacintoshVersion >= QSysInfo::MV_IOS_8_0) { + AVCaptureStillImageOutput *imageOutput = m_service->imageCaptureControl()->stillImageOutput(); + if (res == qt_device_format_high_resolution(captureDevice.activeFormat)) + imageOutput.highResolutionStillImageOutputEnabled = YES; + else + imageOutput.highResolutionStillImageOutputEnabled = NO; + } +#endif + } else { +#else + { +#endif + // TODO: resolution without capture device format ... + } +} + +bool AVFImageEncoderControl::videoCaptureDeviceIsValid() const +{ + if (!m_service->session() || !m_service->session()->videoCaptureDevice()) + return false; + + AVCaptureDevice *captureDevice = m_service->session()->videoCaptureDevice(); + if (!captureDevice.formats || !captureDevice.formats.count) + return false; + + return true; +} + +QT_END_NAMESPACE + +#include "moc_avfimageencodercontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h index fb181a67b..4ea25ae2b 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.h +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm index 3e855b46f..412dab76c 100644 --- a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.h b/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.h new file mode 100644 index 000000000..b0073bd72 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.h @@ -0,0 +1,54 @@ +/**************************************************************************** +** +** 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$ +** +****************************************************************************/ + +#ifndef AVFMEDIAVIDEOPROBECONTROL_H +#define AVFMEDIAVIDEOPROBECONTROL_H + +#include <qmediavideoprobecontrol.h> + +QT_BEGIN_NAMESPACE + +class AVFMediaVideoProbeControl : public QMediaVideoProbeControl +{ + Q_OBJECT +public: + explicit AVFMediaVideoProbeControl(QObject *parent = 0); + ~AVFMediaVideoProbeControl(); + + void newFrameProbed(const QVideoFrame& frame); + +}; + +QT_END_NAMESPACE + +#endif // AVFMEDIAVIDEOPROBECONTROL_H diff --git a/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.mm b/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.mm new file mode 100644 index 000000000..e36d775c5 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediavideoprobecontrol.mm @@ -0,0 +1,55 @@ +/**************************************************************************** +** +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Copyright (C) 2013 Integrated Computer Solutions, Inc +** 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 "avfmediavideoprobecontrol.h" +#include <qvideoframe.h> + +QT_BEGIN_NAMESPACE + +AVFMediaVideoProbeControl::AVFMediaVideoProbeControl(QObject *parent) : + QMediaVideoProbeControl(parent) +{ +} + +AVFMediaVideoProbeControl::~AVFMediaVideoProbeControl() +{ + +} + +void AVFMediaVideoProbeControl::newFrameProbed(const QVideoFrame &frame) +{ + Q_EMIT videoFrameProbed(frame); +} + +QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfstoragelocation.h b/src/plugins/avfoundation/camera/avfstoragelocation.h index b115871d5..c56084145 100644 --- a/src/plugins/avfoundation/camera/avfstoragelocation.h +++ b/src/plugins/avfoundation/camera/avfstoragelocation.h @@ -1,7 +1,7 @@ /**************************************************************************** ** -** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd. +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** @@ -10,9 +10,9 @@ ** 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. +** 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 @@ -23,8 +23,8 @@ ** 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 +** 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$ diff --git a/src/plugins/avfoundation/camera/avfstoragelocation.mm b/src/plugins/avfoundation/camera/avfstoragelocation.mm index c63abbc30..3bb62ed93 100644 --- a/src/plugins/avfoundation/camera/avfstoragelocation.mm +++ b/src/plugins/avfoundation/camera/avfstoragelocation.mm @@ -1,40 +1,32 @@ /**************************************************************************** ** -** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies). -** Contact: http://www.qt-project.org/legal +** Copyright (C) 2015 The Qt Company Ltd and/or its subsidiary(-ies). +** Contact: http://www.qt.io/licensing/ ** ** This file is part of the Qt Toolkit. ** -** $QT_BEGIN_LICENSE:LGPL$ +** $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. +** 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 as published by the Free Software -** Foundation and appearing in the file LICENSE.LGPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU Lesser General Public License version 2.1 requirements -** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** 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 +** 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. ** -** GNU General Public License Usage -** Alternatively, this file may be used under the terms of the GNU -** General Public License version 3.0 as published by the Free Software -** Foundation and appearing in the file LICENSE.GPL included in the -** packaging of this file. Please review the following information to -** ensure the GNU General Public License version 3.0 requirements will be -** met: http://www.gnu.org/copyleft/gpl.html. -** -** ** $QT_END_LICENSE$ ** ****************************************************************************/ diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro index 1dac45f86..ac389df77 100644 --- a/src/plugins/avfoundation/camera/camera.pro +++ b/src/plugins/avfoundation/camera/camera.pro @@ -25,28 +25,50 @@ HEADERS += \ avfcameradebug.h \ avfcameraserviceplugin.h \ avfcameracontrol.h \ - avfvideorenderercontrol.h \ avfcamerametadatacontrol.h \ avfimagecapturecontrol.h \ avfmediarecordercontrol.h \ avfcameraservice.h \ avfcamerasession.h \ avfstoragelocation.h \ - avfvideodevicecontrol.h \ avfaudioinputselectorcontrol.h \ - avfcamerainfocontrol.h + avfcamerainfocontrol.h \ + avfmediavideoprobecontrol.h \ + avfcamerainfocontrol.h \ + avfcamerarenderercontrol.h \ + avfcameradevicecontrol.h \ + avfcamerafocuscontrol.h \ + avfcameraexposurecontrol.h \ + avfcamerautility.h \ + avfcameraviewfindersettingscontrol.h \ + avfimageencodercontrol.h \ + avfcameraflashcontrol.h OBJECTIVE_SOURCES += \ avfcameraserviceplugin.mm \ avfcameracontrol.mm \ - avfvideorenderercontrol.mm \ avfcamerametadatacontrol.mm \ avfimagecapturecontrol.mm \ avfmediarecordercontrol.mm \ avfcameraservice.mm \ avfcamerasession.mm \ avfstoragelocation.mm \ - avfvideodevicecontrol.mm \ avfaudioinputselectorcontrol.mm \ - avfcamerainfocontrol.mm + avfcamerainfocontrol.mm \ + avfmediavideoprobecontrol.mm \ + avfcamerainfocontrol.mm \ + avfcameradevicecontrol.mm \ + avfcamerarenderercontrol.mm \ + avfcamerafocuscontrol.mm \ + avfcameraexposurecontrol.mm \ + avfcamerautility.mm \ + avfcameraviewfindersettingscontrol.mm \ + avfimageencodercontrol.mm \ + avfcameraflashcontrol.mm +ios { + +HEADERS += avfcamerazoomcontrol.h +OBJECTIVE_SOURCES += avfcamerazoomcontrol.mm + +} |