From 60541844c10f86288a847728b71b211f5fa958b4 Mon Sep 17 00:00:00 2001 From: Timur Pocheptsov Date: Tue, 13 Jan 2015 17:32:27 +0100 Subject: [PATCH] AVFCameraFocusControl - focus control for iOS / OS X Camera focus control for AVFoundation plugin (iOS/OS X). Change-Id: I0a79e7057ecbb66413debb8eac0f48ff679fc7ba Reviewed-by: Yoann Lopes --- .../avfoundation/camera/avfcamerafocuscontrol.h | 81 ++++++ .../avfoundation/camera/avfcamerafocuscontrol.mm | 300 +++++++++++++++++++++ src/plugins/avfoundation/camera/avfcameraservice.h | 4 +- .../avfoundation/camera/avfcameraservice.mm | 7 + .../avfoundation/camera/avfconfigurationlock.h | 78 ++++++ src/plugins/avfoundation/camera/camera.pro | 7 +- 6 files changed, 474 insertions(+), 3 deletions(-) create mode 100644 src/plugins/avfoundation/camera/avfcamerafocuscontrol.h create mode 100644 src/plugins/avfoundation/camera/avfcamerafocuscontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfconfigurationlock.h diff --git a/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h new file mode 100644 index 0000000..4eca029 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.h @@ -0,0 +1,81 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERAFOCUSCONTROL_H +#define AVFCAMERAFOCUSCONTROL_H + +#include +#include + +#include + +@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 0000000..84f05c5 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerafocuscontrol.mm @@ -0,0 +1,300 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcamerafocuscontrol.h" +#include "avfconfigurationlock.h" +#include "avfcameraservice.h" +#include "avfcamerasession.h" +#include "avfcameradebug.h" + +#include + +#include + +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/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h index 5d5d3b9..d948b0e 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.h +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -52,6 +52,7 @@ class AVFImageCaptureControl; class AVFCameraSession; class AVFCameraDeviceControl; class AVFAudioInputSelectorControl; +class AVFCameraFocusControl; class AVFCameraService : public QMediaService { @@ -70,7 +71,7 @@ public: AVFCameraMetaDataControl *metaDataControl() const { return m_metaDataControl; } AVFMediaRecorderControl *recorderControl() const { return m_recorderControl; } AVFImageCaptureControl *imageCaptureControl() const { return m_imageCaptureControl; } - + AVFCameraFocusControl *cameraFocusControl() const { return m_cameraFocusControl; } private: AVFCameraSession *m_session; @@ -82,6 +83,7 @@ private: AVFCameraMetaDataControl *m_metaDataControl; AVFMediaRecorderControl *m_recorderControl; AVFImageCaptureControl *m_imageCaptureControl; + AVFCameraFocusControl *m_cameraFocusControl; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index cdd983a..d617dc9 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -55,6 +55,7 @@ #include "avfmediarecordercontrol.h" #include "avfimagecapturecontrol.h" #include "avfmediavideoprobecontrol.h" +#include "avfcamerafocuscontrol.h" #include #include @@ -74,6 +75,8 @@ AVFCameraService::AVFCameraService(QObject *parent): m_metaDataControl = new AVFCameraMetaDataControl(this); m_recorderControl = new AVFMediaRecorderControl(this); m_imageCaptureControl = new AVFImageCaptureControl(this); + + m_cameraFocusControl = new AVFCameraFocusControl(this); } AVFCameraService::~AVFCameraService() @@ -92,6 +95,7 @@ AVFCameraService::~AVFCameraService() //delete m_recorderControl; delete m_metaDataControl; delete m_cameraControl; + delete m_cameraFocusControl; delete m_session; } @@ -120,6 +124,9 @@ QMediaControl *AVFCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) return m_imageCaptureControl; + if (qstrcmp(name, QCameraFocusControl_iid) == 0) + return m_cameraFocusControl; + if (qstrcmp(name,QMediaVideoProbeControl_iid) == 0) { AVFMediaVideoProbeControl *videoProbe = 0; videoProbe = new AVFMediaVideoProbeControl(this); diff --git a/src/plugins/avfoundation/camera/avfconfigurationlock.h b/src/plugins/avfoundation/camera/avfconfigurationlock.h new file mode 100644 index 0000000..c85070b --- /dev/null +++ b/src/plugins/avfoundation/camera/avfconfigurationlock.h @@ -0,0 +1,78 @@ +/**************************************************************************** +** +** Copyright (C) 2015 Digia Plc and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/legal +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL21$ +** Commercial License Usage +** Licensees holding valid commercial Qt licenses may use this file in +** accordance with the commercial license agreement provided with the +** Software or, alternatively, in accordance with the terms contained in +** a written agreement between you and Digia. For licensing terms and +** conditions see http://qt.digia.com/licensing. For further information +** use the contact form at http://qt.digia.com/contact-us. +** +** GNU Lesser General Public License Usage +** Alternatively, this file may be used under the terms of the GNU Lesser +** General Public License version 2.1 or version 3 as published by the Free +** Software Foundation and appearing in the file LICENSE.LGPLv21 and +** LICENSE.LGPLv3 included in the packaging of this file. Please review the +** following information to ensure the GNU Lesser General Public License +** requirements will be met: https://www.gnu.org/licenses/lgpl.html and +** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. +** +** In addition, as a special exception, Digia gives you certain additional +** rights. These rights are described in the Digia Qt LGPL Exception +** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCONFIGURATIONLOCK_H +#define AVFCONFIGURATIONLOCK_H + +#include +#include + +#include + +@class AVCaptureDevice; + +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; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro index 0ceeb19..4e49ebe 100644 --- a/src/plugins/avfoundation/camera/camera.pro +++ b/src/plugins/avfoundation/camera/camera.pro @@ -36,7 +36,9 @@ HEADERS += \ avfmediavideoprobecontrol.h \ avfcamerainfocontrol.h \ avfcamerarenderercontrol.h \ - avfcameradevicecontrol.h + avfcameradevicecontrol.h \ + avfcamerafocuscontrol.h \ + avfconfigurationlock.h OBJECTIVE_SOURCES += \ avfcameraserviceplugin.mm \ @@ -52,5 +54,6 @@ OBJECTIVE_SOURCES += \ avfmediavideoprobecontrol.mm \ avfcamerainfocontrol.mm \ avfcameradevicecontrol.mm \ - avfcamerarenderercontrol.mm + avfcamerarenderercontrol.mm \ + avfcamerafocuscontrol.mm -- 2.7.4