From 9a55f5ce5746fa1df6daa62a7111cb2d5ff5138d Mon Sep 17 00:00:00 2001 From: Yoann Lopes Date: Fri, 7 Feb 2014 14:20:28 +0100 Subject: AVFoundation: implement QCameraInfoControl. Change-Id: I05f3daa5c4acb90e046e26d6d577ae40dfed0e30 Reviewed-by: Andy Nichols --- .../avfoundation/camera/avfcamerainfocontrol.h | 61 ++++++++++++++++++ .../avfoundation/camera/avfcamerainfocontrol.mm | 62 +++++++++++++++++++ src/plugins/avfoundation/camera/avfcameraservice.h | 2 + .../avfoundation/camera/avfcameraservice.mm | 5 ++ .../avfoundation/camera/avfcameraserviceplugin.h | 12 ++-- .../avfoundation/camera/avfcameraserviceplugin.mm | 51 +++++---------- src/plugins/avfoundation/camera/avfcamerasession.h | 19 ++++++ .../avfoundation/camera/avfcamerasession.mm | 72 ++++++++++++++++++++++ .../avfoundation/camera/avfvideodevicecontrol.h | 3 - .../avfoundation/camera/avfvideodevicecontrol.mm | 35 +++++------ src/plugins/avfoundation/camera/camera.pro | 2 + 11 files changed, 258 insertions(+), 66 deletions(-) create mode 100644 src/plugins/avfoundation/camera/avfcamerainfocontrol.h create mode 100644 src/plugins/avfoundation/camera/avfcamerainfocontrol.mm diff --git a/src/plugins/avfoundation/camera/avfcamerainfocontrol.h b/src/plugins/avfoundation/camera/avfcamerainfocontrol.h new file mode 100644 index 000000000..3cf867217 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerainfocontrol.h @@ -0,0 +1,61 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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:LGPL$ +** 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 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 +** 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$ +** +****************************************************************************/ + +#ifndef AVFCAMERAINFOCONTROL_H +#define AVFCAMERAINFOCONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class AVFCameraInfoControl : public QCameraInfoControl +{ + Q_OBJECT +public: + explicit AVFCameraInfoControl(QObject *parent = 0); + + QCamera::Position cameraPosition(const QString &deviceName) const; + int cameraOrientation(const QString &deviceName) const; +}; + +QT_END_NAMESPACE + +#endif // AVFCAMERAINFOCONTROL_H diff --git a/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm b/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm new file mode 100644 index 000000000..8ae908ada --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerainfocontrol.mm @@ -0,0 +1,62 @@ +/**************************************************************************** +** +** Copyright (C) 2014 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:LGPL$ +** 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 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 +** 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 "avfcamerainfocontrol.h" +#include "avfcamerasession.h" + +QT_BEGIN_NAMESPACE + +AVFCameraInfoControl::AVFCameraInfoControl(QObject *parent) + : QCameraInfoControl(parent) +{ +} + +QCamera::Position AVFCameraInfoControl::cameraPosition(const QString &deviceName) const +{ + return AVFCameraSession::cameraDeviceInfo(deviceName.toUtf8()).position; +} + +int AVFCameraInfoControl::cameraOrientation(const QString &deviceName) const +{ + return AVFCameraSession::cameraDeviceInfo(deviceName.toUtf8()).orientation; +} + +QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h index e619c44b3..b468a3b92 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.h +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -50,6 +50,7 @@ QT_BEGIN_NAMESPACE class QCameraControl; class AVFCameraControl; +class AVFCameraInfoControl; class AVFCameraMetaDataControl; class AVFVideoWindowControl; class AVFVideoWidgetControl; @@ -82,6 +83,7 @@ public: private: AVFCameraSession *m_session; AVFCameraControl *m_cameraControl; + AVFCameraInfoControl *m_cameraInfoControl; AVFVideoDeviceControl *m_videoDeviceControl; AVFAudioInputSelectorControl *m_audioInputSelectorControl; AVFVideoRendererControl *m_videoOutput; diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm index 094f1b402..25111c5cc 100644 --- a/src/plugins/avfoundation/camera/avfcameraservice.mm +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -44,6 +44,7 @@ #include "avfcameraservice.h" #include "avfcameracontrol.h" +#include "avfcamerainfocontrol.h" #include "avfcamerasession.h" #include "avfvideodevicecontrol.h" #include "avfaudioinputselectorcontrol.h" @@ -65,6 +66,7 @@ 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_audioInputSelectorControl = new AVFAudioInputSelectorControl(this); @@ -98,6 +100,9 @@ QMediaControl *AVFCameraService::requestControl(const char *name) if (qstrcmp(name, QCameraControl_iid) == 0) return m_cameraControl; + if (qstrcmp(name, QCameraInfoControl_iid) == 0) + return m_cameraInfoControl; + if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0) return m_videoDeviceControl; diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.h b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h index f974bcf0b..3a00c0be9 100644 --- a/src/plugins/avfoundation/camera/avfcameraserviceplugin.h +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h @@ -50,11 +50,13 @@ QT_BEGIN_NAMESPACE class AVFServicePlugin : public QMediaServiceProviderPlugin, public QMediaServiceSupportedDevicesInterface, - public QMediaServiceDefaultDeviceInterface + public QMediaServiceDefaultDeviceInterface, + public QMediaServiceCameraInfoInterface { Q_OBJECT Q_INTERFACES(QMediaServiceSupportedDevicesInterface) Q_INTERFACES(QMediaServiceDefaultDeviceInterface) + Q_INTERFACES(QMediaServiceCameraInfoInterface) Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0" FILE "avfcamera.json") public: @@ -67,12 +69,8 @@ public: QList devices(const QByteArray &service) const; QString deviceDescription(const QByteArray &service, const QByteArray &device); -private: - void updateDevices() const; - - mutable QByteArray m_defaultCameraDevice; - mutable QList m_cameraDevices; - mutable QMap m_cameraDescriptions; + QCamera::Position cameraPosition(const QByteArray &device) const; + int cameraOrientation(const QByteArray &device) const; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm index 8ec3390e9..414a84751 100644 --- a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm @@ -44,15 +44,12 @@ #include "avfcameraserviceplugin.h" #include "avfcameraservice.h" +#include "avfcamerasession.h" #include -#import - - QT_BEGIN_NAMESPACE - AVFServicePlugin::AVFServicePlugin() { } @@ -74,56 +71,36 @@ void AVFServicePlugin::release(QMediaService *service) QByteArray AVFServicePlugin::defaultDevice(const QByteArray &service) const { - if (service == Q_MEDIASERVICE_CAMERA) { - if (m_cameraDevices.isEmpty()) - updateDevices(); - - return m_defaultCameraDevice; - } + if (service == Q_MEDIASERVICE_CAMERA) + return AVFCameraSession::defaultCameraDevice(); return QByteArray(); } QList AVFServicePlugin::devices(const QByteArray &service) const { - if (service == Q_MEDIASERVICE_CAMERA) { - if (m_cameraDevices.isEmpty()) - updateDevices(); - - return m_cameraDevices; - } + if (service == Q_MEDIASERVICE_CAMERA) + return AVFCameraSession::availableCameraDevices(); return QList(); } QString AVFServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) { - if (service == Q_MEDIASERVICE_CAMERA) { - if (m_cameraDevices.isEmpty()) - updateDevices(); - - return m_cameraDescriptions.value(device); - } + if (service == Q_MEDIASERVICE_CAMERA) + return AVFCameraSession::cameraDeviceInfo(device).description; return QString(); } -void AVFServicePlugin::updateDevices() const +QCamera::Position AVFServicePlugin::cameraPosition(const QByteArray &device) const +{ + return AVFCameraSession::cameraDeviceInfo(device).position; +} + +int AVFServicePlugin::cameraOrientation(const QByteArray &device) const { - m_defaultCameraDevice.clear(); - m_cameraDevices.clear(); - m_cameraDescriptions.clear(); - - AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - if (defaultDevice) - m_defaultCameraDevice = QByteArray([[defaultDevice uniqueID] UTF8String]); - - NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - for (AVCaptureDevice *device in videoDevices) { - QByteArray deviceId([[device uniqueID] UTF8String]); - m_cameraDevices << deviceId; - m_cameraDescriptions.insert(deviceId, QString::fromUtf8([[device localizedName] UTF8String])); - } + return AVFCameraSession::cameraDeviceInfo(device).orientation; } QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h index 2630a35f7..5cc779f8b 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.h +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -55,6 +55,16 @@ class AVFCameraControl; class AVFCameraService; class AVFVideoRendererControl; +struct AVFCameraInfo +{ + AVFCameraInfo() : position(QCamera::UnspecifiedPosition), orientation(0) + { } + + QString description; + QCamera::Position position; + int orientation; +}; + class AVFCameraSession : public QObject { Q_OBJECT @@ -62,6 +72,10 @@ public: AVFCameraSession(AVFCameraService *service, QObject *parent = 0); ~AVFCameraSession(); + static const QByteArray &defaultCameraDevice(); + static const QList &availableCameraDevices(); + static AVFCameraInfo cameraDeviceInfo(const QByteArray &device); + void setVideoOutput(AVFVideoRendererControl *output); AVCaptureSession *captureSession() const { return m_captureSession; } AVCaptureDevice *videoCaptureDevice() const; @@ -84,8 +98,13 @@ Q_SIGNALS: void error(int error, const QString &errorString); private: + static void updateCameraDevices(); void attachInputDevices(); + static QByteArray m_defaultCameraDevice; + static QList m_cameraDevices; + static QMap m_cameraInfo; + AVFCameraService *m_service; AVFVideoRendererControl *m_videoOutput; diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm index 93c2bacd0..042855aa4 100644 --- a/src/plugins/avfoundation/camera/avfcamerasession.mm +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -57,6 +57,10 @@ QT_USE_NAMESPACE +QByteArray AVFCameraSession::m_defaultCameraDevice; +QList AVFCameraSession::m_cameraDevices; +QMap AVFCameraSession::m_cameraInfo; + @interface AVFCameraSessionObserver : NSObject { @private @@ -151,6 +155,74 @@ AVFCameraSession::~AVFCameraSession() [m_captureSession release]; } +const QByteArray &AVFCameraSession::defaultCameraDevice() +{ + if (m_cameraDevices.isEmpty()) + updateCameraDevices(); + + return m_defaultCameraDevice; +} + +const QList &AVFCameraSession::availableCameraDevices() +{ + if (m_cameraDevices.isEmpty()) + updateCameraDevices(); + + return m_cameraDevices; +} + +AVFCameraInfo AVFCameraSession::cameraDeviceInfo(const QByteArray &device) +{ + if (m_cameraDevices.isEmpty()) + updateCameraDevices(); + + return m_cameraInfo.value(device); +} + +void AVFCameraSession::updateCameraDevices() +{ + m_defaultCameraDevice.clear(); + m_cameraDevices.clear(); + m_cameraInfo.clear(); + + AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + if (defaultDevice) + m_defaultCameraDevice = QByteArray([[defaultDevice uniqueID] UTF8String]); + + NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + for (AVCaptureDevice *device in videoDevices) { + QByteArray deviceId([[device uniqueID] UTF8String]); + + AVFCameraInfo info; + info.description = QString::fromNSString([device localizedName]); + + // There is no API to get the camera sensor orientation, however, cameras are always + // mounted in landscape on iDevices. + // - Back-facing cameras have the top side of the sensor aligned with the right side of + // the screen when held in portrait ==> 270 degrees clockwise angle + // - Front-facing cameras have the top side of the sensor aligned with the left side of + // the screen when held in portrait ==> 270 degrees clockwise angle + // On Mac OS, the position will always be unspecified and the sensor orientation unknown. + switch (device.position) { + case AVCaptureDevicePositionBack: + info.position = QCamera::BackFace; + info.orientation = 270; + break; + case AVCaptureDevicePositionFront: + info.position = QCamera::FrontFace; + info.orientation = 270; + break; + default: + info.position = QCamera::UnspecifiedPosition; + info.orientation = 0; + break; + } + + m_cameraDevices << deviceId; + m_cameraInfo.insert(deviceId, info); + } +} + void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output) { m_videoOutput = output; diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.h b/src/plugins/avfoundation/camera/avfvideodevicecontrol.h index fe27906cf..4f7380222 100644 --- a/src/plugins/avfoundation/camera/avfvideodevicecontrol.h +++ b/src/plugins/avfoundation/camera/avfvideodevicecontrol.h @@ -80,9 +80,6 @@ private: int m_selectedDevice; bool m_dirty; - int m_defaultDevice; - QStringList m_devices; - QStringList m_deviceDescriptions; }; QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm index 776707549..d049859c3 100644 --- a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm +++ b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm @@ -42,6 +42,7 @@ #include "avfcameradebug.h" #include "avfvideodevicecontrol.h" #include "avfcameraservice.h" +#include "avfcamerasession.h" QT_USE_NAMESPACE @@ -50,18 +51,7 @@ AVFVideoDeviceControl::AVFVideoDeviceControl(AVFCameraService *service, QObject , m_service(service) , m_selectedDevice(0) , m_dirty(true) - , m_defaultDevice(0) { - AVCaptureDevice *defaultDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; - NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; - int i = 0; - for (AVCaptureDevice *device in videoDevices) { - m_devices << QString::fromUtf8([[device uniqueID] UTF8String]); - m_deviceDescriptions << QString::fromUtf8([[device localizedName] UTF8String]); - if (defaultDevice && [[device uniqueID] isEqualToString:[defaultDevice uniqueID]]) - m_defaultDevice = i; - ++i; - } } AVFVideoDeviceControl::~AVFVideoDeviceControl() @@ -70,22 +60,30 @@ AVFVideoDeviceControl::~AVFVideoDeviceControl() int AVFVideoDeviceControl::deviceCount() const { - return m_devices.size(); + return AVFCameraSession::availableCameraDevices().count(); } QString AVFVideoDeviceControl::deviceName(int index) const { - return m_devices[index]; + const QList &devices = AVFCameraSession::availableCameraDevices(); + if (index >= devices.count()) + return QString(); + + return QString::fromUtf8(devices.at(index)); } QString AVFVideoDeviceControl::deviceDescription(int index) const { - return m_deviceDescriptions[index]; + const QList &devices = AVFCameraSession::availableCameraDevices(); + if (index >= devices.count()) + return QString(); + + return AVFCameraSession::cameraDeviceInfo(devices.at(index)).description; } int AVFVideoDeviceControl::defaultDevice() const { - return m_defaultDevice; + return AVFCameraSession::availableCameraDevices().indexOf(AVFCameraSession::defaultCameraDevice()); } int AVFVideoDeviceControl::selectedDevice() const @@ -99,7 +97,7 @@ void AVFVideoDeviceControl::setSelectedDevice(int index) m_dirty = true; m_selectedDevice = index; Q_EMIT selectedDeviceChanged(index); - Q_EMIT selectedDeviceChanged(m_devices[index]); + Q_EMIT selectedDeviceChanged(deviceName(index)); } } @@ -108,9 +106,8 @@ AVCaptureDevice *AVFVideoDeviceControl::createCaptureDevice() m_dirty = false; AVCaptureDevice *device = 0; - if (!m_devices.isEmpty()) { - QString deviceId = m_devices.at(m_selectedDevice); - + QString deviceId = deviceName(m_selectedDevice); + if (!deviceId.isEmpty()) { device = [AVCaptureDevice deviceWithUniqueID: [NSString stringWithUTF8String: deviceId.toUtf8().constData()]]; diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro index 791ab8c48..1dac45f86 100644 --- a/src/plugins/avfoundation/camera/camera.pro +++ b/src/plugins/avfoundation/camera/camera.pro @@ -34,6 +34,7 @@ HEADERS += \ avfstoragelocation.h \ avfvideodevicecontrol.h \ avfaudioinputselectorcontrol.h \ + avfcamerainfocontrol.h OBJECTIVE_SOURCES += \ avfcameraserviceplugin.mm \ @@ -47,4 +48,5 @@ OBJECTIVE_SOURCES += \ avfstoragelocation.mm \ avfvideodevicecontrol.mm \ avfaudioinputselectorcontrol.mm \ + avfcamerainfocontrol.mm -- cgit v1.2.3