From 37b872da9eced344dd5feaf1898cab0d02984ea5 Mon Sep 17 00:00:00 2001 From: Dmytro Poplavskiy Date: Fri, 17 Aug 2012 13:44:14 +1000 Subject: Initial implementation of Mac camera backend Based on AVFoundation framework Change-Id: If4cfd105a592f50b42606624548b9ffc870e3e47 Reviewed-by: Gunnar Sletta --- src/plugins/avfoundation/avfoundation.pro | 3 + .../camera/avfaudioinputselectorcontrol.h | 86 ++++++ .../camera/avfaudioinputselectorcontrol.mm | 117 +++++++ src/plugins/avfoundation/camera/avfcamera.json | 3 + src/plugins/avfoundation/camera/avfcameracontrol.h | 86 ++++++ .../avfoundation/camera/avfcameracontrol.mm | 135 ++++++++ src/plugins/avfoundation/camera/avfcameradebug.h | 59 ++++ .../avfoundation/camera/avfcamerametadatacontrol.h | 72 +++++ .../camera/avfcamerametadatacontrol.mm | 84 +++++ src/plugins/avfoundation/camera/avfcameraservice.h | 95 ++++++ .../avfoundation/camera/avfcameraservice.mm | 139 +++++++++ .../avfoundation/camera/avfcameraserviceplugin.h | 76 +++++ .../avfoundation/camera/avfcameraserviceplugin.mm | 112 +++++++ src/plugins/avfoundation/camera/avfcamerasession.h | 101 ++++++ .../avfoundation/camera/avfcamerasession.mm | 277 +++++++++++++++++ .../avfoundation/camera/avfimagecapturecontrol.h | 88 ++++++ .../avfoundation/camera/avfimagecapturecontrol.mm | 222 +++++++++++++ .../avfoundation/camera/avfmediarecordercontrol.h | 113 +++++++ .../avfoundation/camera/avfmediarecordercontrol.mm | 342 +++++++++++++++++++++ .../avfoundation/camera/avfstoragelocation.h | 73 +++++ .../avfoundation/camera/avfstoragelocation.mm | 137 +++++++++ .../avfoundation/camera/avfvideodevicecontrol.h | 89 ++++++ .../avfoundation/camera/avfvideodevicecontrol.mm | 119 +++++++ .../avfoundation/camera/avfvideorenderercontrol.h | 90 ++++++ .../avfoundation/camera/avfvideorenderercontrol.mm | 237 ++++++++++++++ src/plugins/avfoundation/camera/camera.pro | 52 ++++ src/plugins/plugins.pro | 2 + 27 files changed, 3009 insertions(+) create mode 100644 src/plugins/avfoundation/avfoundation.pro create mode 100644 src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h create mode 100644 src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfcamera.json create mode 100644 src/plugins/avfoundation/camera/avfcameracontrol.h create mode 100644 src/plugins/avfoundation/camera/avfcameracontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfcameradebug.h create mode 100644 src/plugins/avfoundation/camera/avfcamerametadatacontrol.h create mode 100644 src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfcameraservice.h create mode 100644 src/plugins/avfoundation/camera/avfcameraservice.mm create mode 100644 src/plugins/avfoundation/camera/avfcameraserviceplugin.h create mode 100644 src/plugins/avfoundation/camera/avfcameraserviceplugin.mm create mode 100644 src/plugins/avfoundation/camera/avfcamerasession.h create mode 100644 src/plugins/avfoundation/camera/avfcamerasession.mm create mode 100644 src/plugins/avfoundation/camera/avfimagecapturecontrol.h create mode 100644 src/plugins/avfoundation/camera/avfimagecapturecontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfmediarecordercontrol.h create mode 100644 src/plugins/avfoundation/camera/avfmediarecordercontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfstoragelocation.h create mode 100644 src/plugins/avfoundation/camera/avfstoragelocation.mm create mode 100644 src/plugins/avfoundation/camera/avfvideodevicecontrol.h create mode 100644 src/plugins/avfoundation/camera/avfvideodevicecontrol.mm create mode 100644 src/plugins/avfoundation/camera/avfvideorenderercontrol.h create mode 100644 src/plugins/avfoundation/camera/avfvideorenderercontrol.mm create mode 100644 src/plugins/avfoundation/camera/camera.pro diff --git a/src/plugins/avfoundation/avfoundation.pro b/src/plugins/avfoundation/avfoundation.pro new file mode 100644 index 000000000..9a3dbf6e0 --- /dev/null +++ b/src/plugins/avfoundation/avfoundation.pro @@ -0,0 +1,3 @@ +TEMPLATE = subdirs + +SUBDIRS += camera diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h new file mode 100644 index 000000000..a5358315e --- /dev/null +++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFAUDIOINPUTSELECTORCONTROL_H +#define AVFAUDIOINPUTSELECTORCONTROL_H + +#include +#include + +#import + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; + +class AVFAudioInputSelectorControl : public QAudioInputSelectorControl +{ +Q_OBJECT +public: + AVFAudioInputSelectorControl(AVFCameraService *service, QObject *parent = 0); + ~AVFAudioInputSelectorControl(); + + QList availableInputs() const; + QString inputDescription(const QString &name) const; + QString defaultInput() const; + QString activeInput() const; + +public Q_SLOTS: + void setActiveInput(const QString &name); + +public: + //device changed since the last createCaptureDevice() + bool isDirty() const { return m_dirty; } + AVCaptureDevice *createCaptureDevice(); + +private: + AVFCameraService *m_service; + + QString m_activeInput; + bool m_dirty; + QStringList m_devices; + QMap m_deviceDescriptions; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm new file mode 100644 index 000000000..7c31d7c2b --- /dev/null +++ b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm @@ -0,0 +1,117 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfaudioinputselectorcontrol.h" +#include "avfcameraservice.h" + +#import + +QT_USE_NAMESPACE + +AVFAudioInputSelectorControl::AVFAudioInputSelectorControl(AVFCameraService *service, QObject *parent) + : QAudioInputSelectorControl(parent) + , m_service(service) + , m_dirty(true) +{ + NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio]; + for (AVCaptureDevice *device in videoDevices) { + QString deviceId = QString::fromUtf8([[device uniqueID] UTF8String]); + m_devices << deviceId; + m_deviceDescriptions.insert(deviceId, + QString::fromUtf8([[device localizedName] UTF8String])); + } + + m_activeInput = m_devices.first(); +} + +AVFAudioInputSelectorControl::~AVFAudioInputSelectorControl() +{ +} + +QList AVFAudioInputSelectorControl::availableInputs() const +{ + return m_devices; +} + +QString AVFAudioInputSelectorControl::inputDescription(const QString &name) const +{ + return m_deviceDescriptions.value(name); +} + +QString AVFAudioInputSelectorControl::defaultInput() const +{ + return m_devices.first(); +} + +QString AVFAudioInputSelectorControl::activeInput() const +{ + return m_activeInput; +} + +void AVFAudioInputSelectorControl::setActiveInput(const QString &name) +{ + if (name != m_activeInput) { + m_activeInput = name; + m_dirty = true; + + Q_EMIT activeInputChanged(m_activeInput); + } +} + +AVCaptureDevice *AVFAudioInputSelectorControl::createCaptureDevice() +{ + m_dirty = false; + AVCaptureDevice *device = 0; + + if (!m_activeInput.isEmpty()) { + device = [AVCaptureDevice deviceWithUniqueID: + [NSString stringWithUTF8String: + m_activeInput.toUtf8().constData()]]; + } + + if (!device) + device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; + + return device; +} + +#include "moc_avfaudioinputselectorcontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcamera.json b/src/plugins/avfoundation/camera/avfcamera.json new file mode 100644 index 000000000..d3a58c758 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamera.json @@ -0,0 +1,3 @@ +{ + "Keys": ["org.qt-project.qt.camera"] +} diff --git a/src/plugins/avfoundation/camera/avfcameracontrol.h b/src/plugins/avfoundation/camera/avfcameracontrol.h new file mode 100644 index 000000000..a881b0ba8 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameracontrol.h @@ -0,0 +1,86 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERACONTROL_H +#define AVFCAMERACONTROL_H + +#include + +#include + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; + +class AVFCameraControl : public QCameraControl +{ +Q_OBJECT +public: + AVFCameraControl(AVFCameraService *service, QObject *parent = 0); + ~AVFCameraControl(); + + QCamera::State state() const; + void setState(QCamera::State state); + + QCamera::Status status() const; + + QCamera::CaptureModes captureMode() const; + void setCaptureMode(QCamera::CaptureModes); + bool isCaptureModeSupported(QCamera::CaptureModes mode) const; + + bool canChangeProperty(PropertyChangeType changeType, QCamera::Status status) const; + +private Q_SLOTS: + void updateStatus(); + +private: + AVFCameraService *m_service; + AVFCameraSession *m_session; + + QCamera::State m_state; + QCamera::Status m_lastStatus; + QCamera::CaptureModes m_captureMode; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcameracontrol.mm b/src/plugins/avfoundation/camera/avfcameracontrol.mm new file mode 100644 index 000000000..39f474d69 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameracontrol.mm @@ -0,0 +1,135 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfcameracontrol.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" + +QT_USE_NAMESPACE + +AVFCameraControl::AVFCameraControl(AVFCameraService *service, QObject *parent) + : QCameraControl(parent) + , m_service(service) + , m_session(service->session()) + , m_state(QCamera::UnloadedState) + , m_lastStatus(QCamera::UnloadedStatus) + , m_captureMode(QCamera::CaptureStillImage) +{ + connect(m_session, SIGNAL(stateChanged(QCamera::State)), SLOT(updateStatus())); +} + +AVFCameraControl::~AVFCameraControl() +{ +} + +QCamera::State AVFCameraControl::state() const +{ + return m_state; +} + +void AVFCameraControl::setState(QCamera::State state) +{ + if (m_state == state) + return; + m_state = state; + m_session->setState(state); + + Q_EMIT stateChanged(m_state); + updateStatus(); +} + +QCamera::Status AVFCameraControl::status() const +{ + static QCamera::Status statusTable[3][3] = { + { QCamera::UnloadedStatus, QCamera::UnloadingStatus, QCamera::StoppingStatus }, //Unloaded state + { QCamera::LoadingStatus, QCamera::LoadedStatus, QCamera::StoppingStatus }, //Loaded state + { QCamera::LoadingStatus, QCamera::StartingStatus, QCamera::ActiveStatus } //ActiveState + }; + + return statusTable[m_state][m_session->state()]; +} + +void AVFCameraControl::updateStatus() +{ + QCamera::Status newStatus = status(); + + if (m_lastStatus != newStatus) { + qDebugCamera() << "Camera status changed: " << m_lastStatus << " -> " << newStatus; + m_lastStatus = newStatus; + Q_EMIT statusChanged(m_lastStatus); + } +} + +QCamera::CaptureModes AVFCameraControl::captureMode() const +{ + return m_captureMode; +} + +void AVFCameraControl::setCaptureMode(QCamera::CaptureModes mode) +{ + if (m_captureMode == mode) + return; + + if (!isCaptureModeSupported(mode)) { + Q_EMIT error(QCamera::NotSupportedFeatureError, tr("Requested capture mode is not supported")); + return; + } + + m_captureMode = mode; + Q_EMIT captureModeChanged(mode); +} + +bool AVFCameraControl::isCaptureModeSupported(QCamera::CaptureModes mode) const +{ + //all the capture modes are supported, including QCamera::CaptureStillImage | QCamera::CaptureVideo + return (mode & (QCamera::CaptureStillImage | QCamera::CaptureVideo)) == mode; +} + +bool AVFCameraControl::canChangeProperty(QCameraControl::PropertyChangeType changeType, QCamera::Status status) const +{ + Q_UNUSED(changeType); + Q_UNUSED(status); + + return true; +} + +#include "moc_avfcameracontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameradebug.h b/src/plugins/avfoundation/camera/avfcameradebug.h new file mode 100644 index 000000000..73bf682e5 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameradebug.h @@ -0,0 +1,59 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFDEBUG_H +#define AVFDEBUG_H + +#include "qtmultimediadefs.h" + +#include + +QT_USE_NAMESPACE + +//#define AVF_DEBUG_CAMERA + +#ifdef AVF_DEBUG_CAMERA +#define qDebugCamera qDebug +#else +#define qDebugCamera QT_NO_QDEBUG_MACRO +#endif + +#endif diff --git a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h new file mode 100644 index 000000000..b77c228ef --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.h @@ -0,0 +1,72 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERAMETADATACONTROL_H +#define AVFCAMERAMETADATACONTROL_H + +#include + +QT_BEGIN_NAMESPACE + +class AVFCameraService; + +class AVFCameraMetaDataControl : public QMetaDataWriterControl +{ + Q_OBJECT +public: + AVFCameraMetaDataControl(AVFCameraService *service, QObject *parent=0); + virtual ~AVFCameraMetaDataControl(); + + bool isMetaDataAvailable() const; + bool isWritable() const; + + QVariant metaData(const QString &key) const; + void setMetaData(const QString &key, const QVariant &value); + QStringList availableMetaData() const; + +private: + AVFCameraService *m_service; + QMap m_tags; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm new file mode 100644 index 000000000..b1ad6beab --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm @@ -0,0 +1,84 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcamerametadatacontrol.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" + +QT_USE_NAMESPACE + +//metadata support is not implemented yet + +AVFCameraMetaDataControl::AVFCameraMetaDataControl(AVFCameraService *service, QObject *parent) + :QMetaDataWriterControl(parent), m_service(service) +{ +} + +AVFCameraMetaDataControl::~AVFCameraMetaDataControl() +{ +} + +bool AVFCameraMetaDataControl::isMetaDataAvailable() const +{ + return !m_tags.isEmpty(); +} + +bool AVFCameraMetaDataControl::isWritable() const +{ + return false; +} + +QVariant AVFCameraMetaDataControl::metaData(const QString &key) const +{ + return m_tags.value(key); +} + +void AVFCameraMetaDataControl::setMetaData(const QString &key, const QVariant &value) +{ + m_tags.insert(key, value); +} + +QStringList AVFCameraMetaDataControl::availableMetaData() const +{ + return m_tags.keys(); +} + +#include "moc_avfcamerametadatacontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameraservice.h b/src/plugins/avfoundation/camera/avfcameraservice.h new file mode 100644 index 000000000..f55cfcff4 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraservice.h @@ -0,0 +1,95 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERASERVICE_H +#define AVFCAMERASERVICE_H + +#include +#include +#include + + +QT_BEGIN_NAMESPACE +class QCameraControl; +class AVFCameraControl; +class AVFCameraMetaDataControl; +class AVFVideoWindowControl; +class AVFVideoWidgetControl; +class AVFVideoRendererControl; +class AVFMediaRecorderControl; +class AVFImageCaptureControl; +class AVFCameraSession; +class AVFVideoDeviceControl; +class AVFAudioInputSelectorControl; + +class AVFCameraService : public QMediaService +{ +Q_OBJECT +public: + AVFCameraService(QObject *parent = 0); + ~AVFCameraService(); + + QMediaControl* requestControl(const char *name); + void releaseControl(QMediaControl *control); + + AVFCameraSession *session() const { return m_session; } + AVFCameraControl *cameraControl() const { return m_cameraControl; } + AVFVideoDeviceControl *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; } + + +private: + AVFCameraSession *m_session; + AVFCameraControl *m_cameraControl; + AVFVideoDeviceControl *m_videoDeviceControl; + AVFAudioInputSelectorControl *m_audioInputSelectorControl; + AVFVideoRendererControl *m_videoOutput; + AVFCameraMetaDataControl *m_metaDataControl; + AVFMediaRecorderControl *m_recorderControl; + AVFImageCaptureControl *m_imageCaptureControl; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcameraservice.mm b/src/plugins/avfoundation/camera/avfcameraservice.mm new file mode 100644 index 000000000..cffdd3db1 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraservice.mm @@ -0,0 +1,139 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "avfcameraservice.h" +#include "avfcameracontrol.h" +#include "avfcamerasession.h" +#include "avfvideodevicecontrol.h" +#include "avfaudioinputselectorcontrol.h" +#include "avfcamerametadatacontrol.h" +#include "avfmediarecordercontrol.h" +#include "avfimagecapturecontrol.h" +#include "avfvideorenderercontrol.h" +#include "avfmediarecordercontrol.h" +#include "avfimagecapturecontrol.h" + +#include +#include + +QT_USE_NAMESPACE + +AVFCameraService::AVFCameraService(QObject *parent): + QMediaService(parent), + m_videoOutput(0) +{ + m_session = new AVFCameraSession(this); + m_cameraControl = new AVFCameraControl(this); + m_videoDeviceControl = new AVFVideoDeviceControl(this); + m_audioInputSelectorControl = new AVFAudioInputSelectorControl(this); + + m_metaDataControl = new AVFCameraMetaDataControl(this); + m_recorderControl = new AVFMediaRecorderControl(this); + m_imageCaptureControl = new AVFImageCaptureControl(this); +} + +AVFCameraService::~AVFCameraService() +{ + m_cameraControl->setState(QCamera::UnloadedState); + + if (m_videoOutput) { + m_session->setVideoOutput(0); + delete m_videoOutput; + m_videoOutput = 0; + } + + //delete controls before session, + //so they have a chance to do deinitialization + delete m_imageCaptureControl; + //delete m_recorderControl; + delete m_metaDataControl; + delete m_cameraControl; + + delete m_session; +} + +QMediaControl *AVFCameraService::requestControl(const char *name) +{ + if (qstrcmp(name, QCameraControl_iid) == 0) + return m_cameraControl; + + if (qstrcmp(name, QVideoDeviceSelectorControl_iid) == 0) + return m_videoDeviceControl; + + if (qstrcmp(name, QAudioInputSelectorControl_iid) == 0) + return m_audioInputSelectorControl; + + //metadata support is not implemented yet + //if (qstrcmp(name, QMetaDataWriterControl_iid) == 0) + // return m_metaDataControl; + + if (qstrcmp(name, QMediaRecorderControl_iid) == 0) + return m_recorderControl; + + if (qstrcmp(name, QCameraImageCaptureControl_iid) == 0) + return m_imageCaptureControl; + + if (!m_videoOutput) { + if (qstrcmp(name, QVideoRendererControl_iid) == 0) + m_videoOutput = new AVFVideoRendererControl(this); + + if (m_videoOutput) { + m_session->setVideoOutput(m_videoOutput); + return m_videoOutput; + } + } + + return 0; +} + +void AVFCameraService::releaseControl(QMediaControl *control) +{ + if (m_videoOutput == control) { + m_videoOutput = 0; + m_session->setVideoOutput(0); + delete control; + } +} + +#include "moc_avfcameraservice.cpp" diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.h b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h new file mode 100644 index 000000000..818d6bbfb --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.h @@ -0,0 +1,76 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + + +#ifndef AVFSERVICEPLUGIN_H +#define AVFSERVICEPLUGIN_H + +#include +#include + +QT_BEGIN_NAMESPACE + +class AVFServicePlugin : public QMediaServiceProviderPlugin, + public QMediaServiceSupportedDevicesInterface +{ + Q_OBJECT + Q_INTERFACES(QMediaServiceSupportedDevicesInterface) + Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0" FILE "avfcamera.json") + +public: + AVFServicePlugin(); + + QMediaService* create(QString const& key); + void release(QMediaService *service); + + QList devices(const QByteArray &service) const; + QString deviceDescription(const QByteArray &service, const QByteArray &device); + +private: + void updateDevices() const; + + mutable QList m_cameraDevices; + mutable QMap m_cameraDescriptions; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm new file mode 100644 index 000000000..f74b1d906 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcameraserviceplugin.mm @@ -0,0 +1,112 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include +#include + +#include "avfcameraserviceplugin.h" +#include "avfcameraservice.h" + +#include + +#import + + +QT_BEGIN_NAMESPACE + + +AVFServicePlugin::AVFServicePlugin() +{ +} + +QMediaService* AVFServicePlugin::create(QString const& key) +{ + if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) + return new AVFCameraService; + else + qWarning() << "unsupported key:" << key; + + return 0; +} + +void AVFServicePlugin::release(QMediaService *service) +{ + delete service; +} + +QList AVFServicePlugin::devices(const QByteArray &service) const +{ + if (service == Q_MEDIASERVICE_CAMERA) { + if (m_cameraDevices.isEmpty()) + updateDevices(); + + return m_cameraDevices; + } + + 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); + } + + return QString(); +} + +void AVFServicePlugin::updateDevices() const +{ + m_cameraDevices.clear(); + m_cameraDescriptions.clear(); + + 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])); + } +} + +QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfcamerasession.h b/src/plugins/avfoundation/camera/avfcamerasession.h new file mode 100644 index 000000000..24130b819 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerasession.h @@ -0,0 +1,101 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFCAMERASESSION_H +#define AVFCAMERASESSION_H + +#include +#include + +#import + +QT_BEGIN_NAMESPACE + +class AVFCameraControl; +class AVFCameraService; +class AVFVideoRendererControl; +@class AVFCameraSessionObserver; + +class AVFCameraSession : public QObject +{ + Q_OBJECT +public: + AVFCameraSession(AVFCameraService *service, QObject *parent = 0); + ~AVFCameraSession(); + + void setVideoOutput(AVFVideoRendererControl *output); + AVCaptureSession *captureSession() const { return m_captureSession; } + + QCamera::State state() const; + QCamera::State requestedState() const { return m_state; } + bool isActive() const { return m_active; } + +public Q_SLOTS: + void setState(QCamera::State state); + + void processRuntimeError(); + void processSessionStarted(); + void processSessionStopped(); + +Q_SIGNALS: + void readyToConfigureConnections(); + void stateChanged(QCamera::State newState); + void activeChanged(bool); + void error(int error, const QString &errorString); + +private: + void attachInputDevices(); + + AVFCameraService *m_service; + AVFVideoRendererControl *m_videoOutput; + + QCamera::State m_state; + bool m_active; + + AVCaptureSession *m_captureSession; + AVCaptureDeviceInput *m_videoInput; + AVCaptureDeviceInput *m_audioInput; + AVFCameraSessionObserver *m_observer; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfcamerasession.mm b/src/plugins/avfoundation/camera/avfcamerasession.mm new file mode 100644 index 000000000..acc32d781 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfcamerasession.mm @@ -0,0 +1,277 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameracontrol.h" +#include "avfvideorenderercontrol.h" +#include "avfvideodevicecontrol.h" +#include "avfaudioinputselectorcontrol.h" + +#include +#include + +#include +#include + +#include + +QT_USE_NAMESPACE + +@interface AVFCameraSessionObserver : NSObject +{ +@private + AVFCameraSession *m_session; + AVCaptureSession *m_captureSession; +} + +- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session; +- (void) processRuntimeError:(NSNotification *)notification; +- (void) processSessionStarted:(NSNotification *)notification; +- (void) processSessionStopped:(NSNotification *)notification; + +@end + +@implementation AVFCameraSessionObserver + +- (AVFCameraSessionObserver *) initWithCameraSession:(AVFCameraSession*)session +{ + if (!(self = [super init])) + return nil; + + self->m_session = session; + self->m_captureSession = session->captureSession(); + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processRuntimeError:) + name:AVCaptureSessionRuntimeErrorNotification + object:m_captureSession]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processSessionStarted:) + name:AVCaptureSessionDidStartRunningNotification + object:m_captureSession]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(processSessionStopped:) + name:AVCaptureSessionDidStopRunningNotification + object:m_captureSession]; + + return self; +} + + +- (void) processRuntimeError:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processRuntimeError", Qt::AutoConnection); +} + +- (void) processSessionStarted:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processSessionStarted", Qt::AutoConnection); +} + +- (void) processSessionStopped:(NSNotification *)notification +{ + Q_UNUSED(notification); + QMetaObject::invokeMethod(m_session, "processSessionStopped", Qt::AutoConnection); +} + +@end + +AVFCameraSession::AVFCameraSession(AVFCameraService *service, QObject *parent) + : QObject(parent) + , m_service(service) + , m_state(QCamera::UnloadedState) + , m_active(false) + , m_videoInput(nil) + , m_audioInput(nil) +{ + m_captureSession = [[AVCaptureSession alloc] init]; + m_observer = [[AVFCameraSessionObserver alloc] initWithCameraSession:this]; + + //configuration is commited during transition to Active state + [m_captureSession beginConfiguration]; +} + +AVFCameraSession::~AVFCameraSession() +{ + if (m_videoInput) { + [m_captureSession removeInput:m_videoInput]; + [m_videoInput release]; + } + + if (m_audioInput) { + [m_captureSession removeInput:m_audioInput]; + [m_audioInput release]; + } + + [m_observer release]; + [m_captureSession release]; +} + +void AVFCameraSession::setVideoOutput(AVFVideoRendererControl *output) +{ + m_videoOutput = output; + if (output) + output->configureAVCaptureSession(m_captureSession); +} + +QCamera::State AVFCameraSession::state() const +{ + if (m_active) + return QCamera::ActiveState; + + return m_state == QCamera::ActiveState ? QCamera::LoadedState : m_state; +} + +void AVFCameraSession::setState(QCamera::State newState) +{ + if (m_state == newState) + return; + + qDebugCamera() << Q_FUNC_INFO << m_state << " -> " << newState; + + QCamera::State oldState = m_state; + m_state = newState; + + //attach audio and video inputs during Unloaded->Loaded transition + if (oldState == QCamera::UnloadedState) { + attachInputDevices(); + } + + if (m_state == QCamera::ActiveState) { + Q_EMIT readyToConfigureConnections(); + [m_captureSession commitConfiguration]; + [m_captureSession startRunning]; + } + + if (oldState == QCamera::ActiveState) { + [m_captureSession stopRunning]; + [m_captureSession beginConfiguration]; + } + + Q_EMIT stateChanged(m_state); +} + +void AVFCameraSession::processRuntimeError() +{ + qWarning() << tr("Runtime camera error"); + Q_EMIT error(QCamera::CameraError, tr("Runtime camera error")); +} + +void AVFCameraSession::processSessionStarted() +{ + qDebugCamera() << Q_FUNC_INFO; + if (!m_active) { + m_active = true; + Q_EMIT activeChanged(m_active); + Q_EMIT stateChanged(state()); + } +} + +void AVFCameraSession::processSessionStopped() +{ + qDebugCamera() << Q_FUNC_INFO; + if (m_active) { + m_active = false; + Q_EMIT activeChanged(m_active); + Q_EMIT stateChanged(state()); + } +} + +void AVFCameraSession::attachInputDevices() +{ + //Attach video input device: + if (m_service->videoDeviceControl()->isDirty()) { + if (m_videoInput) { + [m_captureSession removeInput:m_videoInput]; + [m_videoInput release]; + m_videoInput = 0; + } + + AVCaptureDevice *videoDevice = m_service->videoDeviceControl()->createCaptureDevice(); + + NSError *error = nil; + m_videoInput = [AVCaptureDeviceInput + deviceInputWithDevice:videoDevice + error:&error]; + + if (!m_videoInput) { + qWarning() << "Failed to create video device input"; + } else { + if ([m_captureSession canAddInput:m_videoInput]) { + [m_videoInput retain]; + [m_captureSession addInput:m_videoInput]; + } else { + qWarning() << "Failed to connect video device input"; + } + } + } + + //Attach audio input device: + if (m_service->audioInputSelectorControl()->isDirty()) { + if (m_audioInput) { + [m_captureSession removeInput:m_audioInput]; + [m_audioInput release]; + m_audioInput = 0; + } + + AVCaptureDevice *audioDevice = m_service->audioInputSelectorControl()->createCaptureDevice(); + + NSError *error = nil; + m_audioInput = [AVCaptureDeviceInput + deviceInputWithDevice:audioDevice + error:&error]; + + if (!m_audioInput) { + qWarning() << "Failed to create audio device input"; + } else { + [m_audioInput retain]; + [m_captureSession addInput:m_audioInput]; + } + } +} + +#include "moc_avfcamerasession.cpp" diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.h b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h new file mode 100644 index 000000000..56e53a7d2 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.h @@ -0,0 +1,88 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFIMAGECAPTURECONTROL_H +#define AVFIMAGECAPTURECONTROL_H + +#import + +#include +#include "avfstoragelocation.h" + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; +class AVFCameraControl; + +class AVFImageCaptureControl : public QCameraImageCaptureControl +{ +Q_OBJECT +public: + AVFImageCaptureControl(AVFCameraService *service, QObject *parent = 0); + ~AVFImageCaptureControl(); + + bool isReadyForCapture() const; + + QCameraImageCapture::DriveMode driveMode() const { return QCameraImageCapture::SingleImageCapture; } + void setDriveMode(QCameraImageCapture::DriveMode ) {} + + int capture(const QString &fileName); + void cancelCapture(); + +private Q_SLOTS: + void updateCaptureConnection(); + void updateReadyStatus(); + +private: + AVFCameraService *m_service; + AVFCameraSession *m_session; + AVFCameraControl *m_cameraControl; + bool m_ready; + int m_lastCaptureId; + AVCaptureStillImageOutput *m_stillImageOutput; + AVCaptureConnection *m_videoConnection; + AVFStorageLocation m_storageLocation; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm new file mode 100644 index 000000000..3d19eccad --- /dev/null +++ b/src/plugins/avfoundation/camera/avfimagecapturecontrol.mm @@ -0,0 +1,222 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfimagecapturecontrol.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameracontrol.h" + +#include +#include +#include +#include + +QT_USE_NAMESPACE + +AVFImageCaptureControl::AVFImageCaptureControl(AVFCameraService *service, QObject *parent) + : QCameraImageCaptureControl(parent) + , m_service(service) + , m_session(service->session()) + , m_cameraControl(service->cameraControl()) + , m_ready(false) + , m_lastCaptureId(0) + , m_videoConnection(nil) +{ + m_stillImageOutput = [[AVCaptureStillImageOutput alloc] init]; + + NSDictionary *outputSettings = [[NSDictionary alloc] initWithObjectsAndKeys: + AVVideoCodecJPEG, AVVideoCodecKey, nil]; + + [m_stillImageOutput setOutputSettings:outputSettings]; + [outputSettings release]; + + connect(m_cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(updateReadyStatus())); + connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateReadyStatus())); + + connect(m_session, SIGNAL(readyToConfigureConnections()), SLOT(updateCaptureConnection())); +} + +AVFImageCaptureControl::~AVFImageCaptureControl() +{ +} + +bool AVFImageCaptureControl::isReadyForCapture() const +{ + return m_videoConnection && + m_cameraControl->captureMode().testFlag(QCamera::CaptureStillImage) && + m_cameraControl->status() == QCamera::ActiveStatus; +} + +void AVFImageCaptureControl::updateReadyStatus() +{ + if (m_ready != isReadyForCapture()) { + m_ready = !m_ready; + qDebugCamera() << "ReadyToCapture status changed:" << m_ready; + Q_EMIT readyForCaptureChanged(m_ready); + } +} + +int AVFImageCaptureControl::capture(const QString &fileName) +{ + m_lastCaptureId++; + + if (!isReadyForCapture()) { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, m_lastCaptureId), + Q_ARG(int, QCameraImageCapture::NotReadyError), + Q_ARG(QString, tr("Camera not ready"))); + return m_lastCaptureId; + } + + QString actualFileName = m_storageLocation.generateFileName(fileName, + QCamera::CaptureStillImage, + QLatin1String("img_"), + QLatin1String("jpg")); + + qDebugCamera() << "Capture image to" << actualFileName; + + int captureId = m_lastCaptureId; + [m_stillImageOutput captureStillImageAsynchronouslyFromConnection:m_videoConnection + completionHandler: ^(CMSampleBufferRef imageSampleBuffer, NSError *error) { + if (error) { + QStringList messageParts; + messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]); + messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]); + messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]); + + QString errorMessage = messageParts.join(" "); + qDebugCamera() << "Image capture failed:" << errorMessage; + + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, captureId), + Q_ARG(int, QCameraImageCapture::ResourceError), + Q_ARG(QString, errorMessage)); + } else { + qDebugCamera() << "Image captured:" << actualFileName; + //we can't find the exact time the image is exposed, + //but image capture is very fast on desktop, so emit it here + QMetaObject::invokeMethod(this, "imageExposed", Qt::QueuedConnection, + Q_ARG(int, captureId)); + + NSData *nsJpgData = [AVCaptureStillImageOutput jpegStillImageNSDataRepresentation:imageSampleBuffer]; + QByteArray jpgData = QByteArray::fromRawData((const char *)[nsJpgData bytes], [nsJpgData length]); + + //Generate snap preview as downscalled image + { + QBuffer buffer(&jpgData); + QImageReader imageReader(&buffer); + QSize imgSize = imageReader.size(); + int downScaleSteps = 0; + while (imgSize.width() > 800 && downScaleSteps < 8) { + imgSize.rwidth() /= 2; + imgSize.rheight() /= 2; + downScaleSteps++; + } + + imageReader.setScaledSize(imgSize); + QImage snapPreview = imageReader.read(); + + QMetaObject::invokeMethod(this, "imageCaptured", Qt::QueuedConnection, + Q_ARG(int, captureId), + Q_ARG(QImage, snapPreview)); + } + + qDebugCamera() << "Image captured" << actualFileName; + + QFile f(actualFileName); + if (f.open(QFile::WriteOnly)) { + if (f.write(jpgData) != -1) { + QMetaObject::invokeMethod(this, "imageSaved", Qt::QueuedConnection, + Q_ARG(int, captureId), + Q_ARG(QString, actualFileName)); + } else { + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, captureId), + Q_ARG(int, QCameraImageCapture::OutOfSpaceError), + Q_ARG(QString, f.errorString())); + } + } else { + QString errorMessage = tr("Could not open destination file:\n%1").arg(actualFileName); + QMetaObject::invokeMethod(this, "error", Qt::QueuedConnection, + Q_ARG(int, captureId), + Q_ARG(int, QCameraImageCapture::ResourceError), + Q_ARG(QString, errorMessage)); + } + } + }]; + + return captureId; +} + +void AVFImageCaptureControl::cancelCapture() +{ + //not supported +} + +void AVFImageCaptureControl::updateCaptureConnection() +{ + if (!m_videoConnection && + 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; + } + } + + updateReadyStatus(); + } +} + +#include "moc_avfimagecapturecontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.h b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h new file mode 100644 index 000000000..da29b78a5 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.h @@ -0,0 +1,113 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFMEDIARECORDERCONTROL_H +#define AVFMEDIARECORDERCONTROL_H + +#include +#include + +#import +#include "avfstoragelocation.h" + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraControl; +class AVFCameraService; +@class AVFMediaRecorderDelegate; + +class AVFMediaRecorderControl : public QMediaRecorderControl +{ +Q_OBJECT +public: + AVFMediaRecorderControl(AVFCameraService *service, QObject *parent = 0); + ~AVFMediaRecorderControl(); + + QUrl outputLocation() const; + bool setOutputLocation(const QUrl &location); + + QMediaRecorder::State state() const; + QMediaRecorder::Status status() const; + + qint64 duration() const; + + bool isMuted() const; + qreal volume() const; + + void applySettings(); + +public Q_SLOTS: + void setState(QMediaRecorder::State state); + void setMuted(bool muted); + void setVolume(qreal volume); + + void handleRecordingStarted(); + void handleRecordingFinished(); + void handleRecordingFailed(const QString &message); + +private Q_SLOTS: + void reconnectMovieOutput(); + void updateStatus(); + +private: + AVFCameraControl *m_cameraControl; + AVFCameraSession *m_session; + + bool m_connected; + QUrl m_outputLocation; + QMediaRecorder::State m_state; + QMediaRecorder::Status m_lastStatus; + + bool m_recordingStarted; + bool m_recordingFinished; + + bool m_muted; + qreal m_volume; + + AVCaptureMovieFileOutput *m_movieOutput; + AVFMediaRecorderDelegate *m_recorderDelagate; + AVFStorageLocation m_storageLocation; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm new file mode 100644 index 000000000..5278ee519 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfmediarecordercontrol.mm @@ -0,0 +1,342 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfmediarecordercontrol.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameracontrol.h" + +#include +#include +#include + + +QT_USE_NAMESPACE + +@interface AVFMediaRecorderDelegate : NSObject +{ +@private + AVFMediaRecorderControl *m_recorder; +} + +- (AVFMediaRecorderDelegate *) initWithRecorder:(AVFMediaRecorderControl*)recorder; + +- (void) captureOutput:(AVCaptureFileOutput *)captureOutput + didStartRecordingToOutputFileAtURL:(NSURL *)fileURL + fromConnections:(NSArray *)connections; + +- (void) captureOutput:(AVCaptureFileOutput *)captureOutput + didFinishRecordingToOutputFileAtURL:(NSURL *)fileURL + fromConnections:(NSArray *)connections + error:(NSError *)error; +@end + +@implementation AVFMediaRecorderDelegate + +- (AVFMediaRecorderDelegate *) initWithRecorder:(AVFMediaRecorderControl*)recorder +{ + if (!(self = [super init])) + return nil; + + self->m_recorder = recorder; + return self; +} + +- (void) captureOutput:(AVCaptureFileOutput *)captureOutput + didStartRecordingToOutputFileAtURL:(NSURL *)fileURL + fromConnections:(NSArray *)connections +{ + Q_UNUSED(captureOutput); + Q_UNUSED(fileURL); + Q_UNUSED(connections) + + QMetaObject::invokeMethod(m_recorder, "handleRecordingStarted", Qt::QueuedConnection); +} + +- (void) captureOutput:(AVCaptureFileOutput *)captureOutput + didFinishRecordingToOutputFileAtURL:(NSURL *)fileURL + fromConnections:(NSArray *)connections + error:(NSError *)error +{ + Q_UNUSED(captureOutput); + Q_UNUSED(fileURL); + Q_UNUSED(connections) + + if (error) { + QStringList messageParts; + messageParts << QString::fromUtf8([[error localizedDescription] UTF8String]); + messageParts << QString::fromUtf8([[error localizedFailureReason] UTF8String]); + messageParts << QString::fromUtf8([[error localizedRecoverySuggestion] UTF8String]); + + QString errorMessage = messageParts.join(" "); + + QMetaObject::invokeMethod(m_recorder, "handleRecordingFailed", Qt::QueuedConnection, + Q_ARG(QString, errorMessage)); + } else { + QMetaObject::invokeMethod(m_recorder, "handleRecordingFinished", Qt::QueuedConnection); + } +} + +@end + + +AVFMediaRecorderControl::AVFMediaRecorderControl(AVFCameraService *service, QObject *parent) + : QMediaRecorderControl(parent) + , m_cameraControl(service->cameraControl()) + , m_session(service->session()) + , m_connected(false) + , m_state(QMediaRecorder::StoppedState) + , m_lastStatus(QMediaRecorder::UnloadedStatus) + , m_recordingStarted(false) + , m_recordingFinished(false) + , m_muted(false) + , m_volume(1.0) +{ + m_movieOutput = [[AVCaptureMovieFileOutput alloc] init]; + m_recorderDelagate = [[AVFMediaRecorderDelegate alloc] initWithRecorder:this]; + + connect(m_cameraControl, SIGNAL(stateChanged(QCamera::State)), SLOT(updateStatus())); + connect(m_cameraControl, SIGNAL(statusChanged(QCamera::Status)), SLOT(updateStatus())); + connect(m_cameraControl, SIGNAL(captureModeChanged(QCamera::CaptureModes)), SLOT(reconnectMovieOutput())); + + reconnectMovieOutput(); +} + +AVFMediaRecorderControl::~AVFMediaRecorderControl() +{ + if (m_movieOutput) + [m_session->captureSession() removeOutput:m_movieOutput]; + + [m_recorderDelagate release]; +} + +QUrl AVFMediaRecorderControl::outputLocation() const +{ + return m_outputLocation; +} + +bool AVFMediaRecorderControl::setOutputLocation(const QUrl &location) +{ + m_outputLocation = location; + return location.scheme() == QLatin1String("file") || location.scheme().isEmpty(); +} + +QMediaRecorder::State AVFMediaRecorderControl::state() const +{ + return m_state; +} + +QMediaRecorder::Status AVFMediaRecorderControl::status() const +{ + QMediaRecorder::Status status = m_lastStatus; + //bool videoEnabled = m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo); + + if (m_cameraControl->status() == QCamera::ActiveStatus && m_connected) { + if (m_state == QMediaRecorder::StoppedState) { + if (m_recordingStarted && !m_recordingFinished) + status = QMediaRecorder::FinalizingStatus; + else + status = QMediaRecorder::LoadedStatus; + } else { + status = m_recordingStarted ? QMediaRecorder::RecordingStatus : + QMediaRecorder::StartingStatus; + } + } else { + //camera not started yet + status = m_cameraControl->state() == QCamera::ActiveState && m_connected ? + QMediaRecorder::LoadingStatus: + QMediaRecorder::UnloadedStatus; + } + + return status; +} + +void AVFMediaRecorderControl::updateStatus() +{ + QMediaRecorder::Status newStatus = status(); + + if (m_lastStatus != newStatus) { + qDebugCamera() << "Camera recorder status changed: " << m_lastStatus << " -> " << newStatus; + m_lastStatus = newStatus; + Q_EMIT statusChanged(m_lastStatus); + } +} + + +qint64 AVFMediaRecorderControl::duration() const +{ + if (!m_movieOutput) + return 0; + + return qint64(CMTimeGetSeconds(m_movieOutput.recordedDuration) * 1000); +} + +bool AVFMediaRecorderControl::isMuted() const +{ + return m_muted; +} + +qreal AVFMediaRecorderControl::volume() const +{ + return m_volume; +} + +void AVFMediaRecorderControl::applySettings() +{ +} + +void AVFMediaRecorderControl::setState(QMediaRecorder::State state) +{ + if (m_state == state) + return; + + qDebugCamera() << Q_FUNC_INFO << m_state << " -> " << state; + + switch (state) { + case QMediaRecorder::RecordingState: + { + if (m_connected) { + m_state = QMediaRecorder::RecordingState; + m_recordingStarted = false; + m_recordingFinished = false; + + QString outputLocationPath = m_outputLocation.scheme() == QLatin1String("file") ? + m_outputLocation.path() : m_outputLocation.toString(); + + QUrl actualLocation = QUrl::fromLocalFile( + m_storageLocation.generateFileName(outputLocationPath, + QCamera::CaptureVideo, + QLatin1String("clip_"), + QLatin1String("mp4"))); + + qDebugCamera() << "Video capture location:" << actualLocation.toString(); + + NSString *urlString = [NSString stringWithUTF8String:actualLocation.toString().toUtf8().constData()]; + NSURL *fileURL = [NSURL URLWithString:urlString]; + + [m_movieOutput startRecordingToOutputFileURL:fileURL recordingDelegate:m_recorderDelagate]; + + Q_EMIT actualLocationChanged(actualLocation); + } else { + Q_EMIT error(QMediaRecorder::FormatError, tr("Recorder not configured")); + } + + } break; + case QMediaRecorder::PausedState: + { + Q_EMIT error(QMediaRecorder::FormatError, tr("Recording pause not supported")); + return; + } break; + case QMediaRecorder::StoppedState: + { + m_state = QMediaRecorder::StoppedState; + [m_movieOutput stopRecording]; + } + } + + updateStatus(); + Q_EMIT stateChanged(m_state); +} + +void AVFMediaRecorderControl::setMuted(bool muted) +{ + if (m_muted != muted) { + m_muted = muted; + Q_EMIT mutedChanged(muted); + } +} + +void AVFMediaRecorderControl::setVolume(qreal volume) +{ + if (m_volume != volume) { + m_volume = volume; + Q_EMIT volumeChanged(volume); + } +} + +void AVFMediaRecorderControl::handleRecordingStarted() +{ + m_recordingStarted = true; + updateStatus(); +} + +void AVFMediaRecorderControl::handleRecordingFinished() +{ + m_recordingFinished = true; + updateStatus(); +} + +void AVFMediaRecorderControl::handleRecordingFailed(const QString &message) +{ + m_recordingFinished = true; + if (m_state != QMediaRecorder::StoppedState) { + m_state = QMediaRecorder::StoppedState; + Q_EMIT stateChanged(m_state); + } + updateStatus(); + + Q_EMIT error(QMediaRecorder::ResourceError, message); +} + +void AVFMediaRecorderControl::reconnectMovieOutput() +{ + //adding movie output causes high CPU usage even when while recording is not active, + //connect it only while video capture mode is enabled + AVCaptureSession *captureSession = m_session->captureSession(); + + if (!m_connected && m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) { + if ([captureSession canAddOutput:m_movieOutput]) { + [captureSession addOutput:m_movieOutput]; + m_connected = true; + } else { + Q_EMIT error(QMediaRecorder::ResourceError, tr("Could not connect the video recorder")); + qWarning() << "Could not connect the video recorder"; + } + } else if (m_connected && !m_cameraControl->captureMode().testFlag(QCamera::CaptureVideo)) { + [captureSession removeOutput:m_movieOutput]; + m_connected = false; + } + + updateStatus(); +} + +#include "moc_avfmediarecordercontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfstoragelocation.h b/src/plugins/avfoundation/camera/avfstoragelocation.h new file mode 100644 index 000000000..97ccaeca8 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfstoragelocation.h @@ -0,0 +1,73 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFSTORAGE_H +#define AVFSTORAGE_H + +#include "qtmultimediadefs.h" + +#include +#include + +QT_BEGIN_NAMESPACE + +class AVFStorageLocation +{ +public: + AVFStorageLocation(); + ~AVFStorageLocation(); + + QString generateFileName(const QString &requestedName, + QCamera::CaptureMode mode, + const QString &prefix, + const QString &ext) const; + + + QDir defaultDir(QCamera::CaptureMode mode) const; + QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const; + +private: + mutable QMap m_lastUsedIndex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfstoragelocation.mm b/src/plugins/avfoundation/camera/avfstoragelocation.mm new file mode 100644 index 000000000..24b8391e1 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfstoragelocation.mm @@ -0,0 +1,137 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfstoragelocation.h" +#include "QtCore/qstandardpaths.h" + + +QT_BEGIN_NAMESPACE + + +AVFStorageLocation::AVFStorageLocation() +{ +} + +AVFStorageLocation::~AVFStorageLocation() +{ +} + +/*! + * Generate the actual file name from user requested one. + * requestedName may be either empty (the default dir and naming theme is used), + * points to existing dir (the default name used) + * or specify the full actual path. + */ +QString AVFStorageLocation::generateFileName(const QString &requestedName, + QCamera::CaptureMode mode, + const QString &prefix, + const QString &ext) const +{ + if (requestedName.isEmpty()) + return generateFileName(prefix, defaultDir(mode), ext); + + if (QFileInfo(requestedName).isDir()) + return generateFileName(prefix, QDir(requestedName), ext); + + return requestedName; +} + +QDir AVFStorageLocation::defaultDir(QCamera::CaptureMode mode) const +{ + QStringList dirCandidates; + + if (mode == QCamera::CaptureVideo) { + dirCandidates << QStandardPaths::writableLocation(QStandardPaths::MoviesLocation); + } else { + dirCandidates << QStandardPaths::writableLocation(QStandardPaths::PicturesLocation); + } + + dirCandidates << QStandardPaths::writableLocation(QStandardPaths::DocumentsLocation); + dirCandidates << QDir::homePath(); + dirCandidates << QDir::currentPath(); + dirCandidates << QDir::tempPath(); + + Q_FOREACH (const QString &path, dirCandidates) { + if (QFileInfo(path).isWritable()) + return QDir(path); + } + + return QDir(); +} + +QString AVFStorageLocation::generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const +{ + QString lastClipKey = dir.absolutePath()+QLatin1Char(' ')+prefix+QLatin1Char(' ')+ext; + int lastClip = m_lastUsedIndex.value(lastClipKey, 0); + + if (lastClip == 0) { + //first run, find the maximum clip number during the fist capture + Q_FOREACH (const QString &fileName, dir.entryList(QStringList() << QString("%1*.%2").arg(prefix).arg(ext))) { + int imgNumber = fileName.mid(prefix.length(), fileName.size()-prefix.length()-ext.length()-1).toInt(); + lastClip = qMax(lastClip, imgNumber); + } + } + + + //don't just rely on cached lastClip value, + //someone else may create a file after camera started + while (true) { + QString name = QString("%1%2.%3").arg(prefix) + .arg(lastClip+1, + 4, //fieldWidth + 10, + QLatin1Char('0')) + .arg(ext); + + QString path = dir.absoluteFilePath(name); + if (!QFileInfo(path).exists()) { + m_lastUsedIndex[lastClipKey] = lastClip+1; + return path; + } + + lastClip++; + } + + return QString(); +} + + +QT_END_NAMESPACE diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.h b/src/plugins/avfoundation/camera/avfvideodevicecontrol.h new file mode 100644 index 000000000..6202777ba --- /dev/null +++ b/src/plugins/avfoundation/camera/avfvideodevicecontrol.h @@ -0,0 +1,89 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFVIDEODEVICECONTROL_H +#define AVFVIDEODEVICECONTROL_H + +#include +#include + +#import + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; + +class AVFVideoDeviceControl : public QVideoDeviceSelectorControl +{ +Q_OBJECT +public: + AVFVideoDeviceControl(AVFCameraService *service, QObject *parent = 0); + ~AVFVideoDeviceControl(); + + int deviceCount() const; + + QString deviceName(int index) const; + QString deviceDescription(int index) const; + + int defaultDevice() const; + int selectedDevice() const; + +public Q_SLOTS: + void setSelectedDevice(int index); + +public: + //device changed since the last createCaptureDevice() + bool isDirty() const { return m_dirty; } + AVCaptureDevice *createCaptureDevice(); + +private: + AVFCameraService *m_service; + + int m_selectedDevice; + bool m_dirty; + QStringList m_devices; + QStringList m_deviceDescriptions; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm new file mode 100644 index 000000000..fac60f086 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfvideodevicecontrol.mm @@ -0,0 +1,119 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfcameradebug.h" +#include "avfvideodevicecontrol.h" +#include "avfcameraservice.h" + +QT_USE_NAMESPACE + +AVFVideoDeviceControl::AVFVideoDeviceControl(AVFCameraService *service, QObject *parent) + : QVideoDeviceSelectorControl(parent) + , m_service(service) + , m_selectedDevice(0) + , m_dirty(true) +{ + NSArray *videoDevices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; + for (AVCaptureDevice *device in videoDevices) { + m_devices << QString::fromUtf8([[device uniqueID] UTF8String]); + m_deviceDescriptions << QString::fromUtf8([[device localizedName] UTF8String]); + } +} + +AVFVideoDeviceControl::~AVFVideoDeviceControl() +{ +} + +int AVFVideoDeviceControl::deviceCount() const +{ + return m_devices.size(); +} + +QString AVFVideoDeviceControl::deviceName(int index) const +{ + return m_devices[index]; +} + +QString AVFVideoDeviceControl::deviceDescription(int index) const +{ + return m_deviceDescriptions[index]; +} + +int AVFVideoDeviceControl::defaultDevice() const +{ + return 0; +} + +int AVFVideoDeviceControl::selectedDevice() const +{ + return m_selectedDevice; +} + +void AVFVideoDeviceControl::setSelectedDevice(int index) +{ + if (index != m_selectedDevice) { + m_dirty = true; + m_selectedDevice = index; + Q_EMIT selectedDeviceChanged(index); + Q_EMIT selectedDeviceChanged(m_devices[index]); + } +} + +AVCaptureDevice *AVFVideoDeviceControl::createCaptureDevice() +{ + m_dirty = false; + AVCaptureDevice *device = 0; + + if (!m_devices.isEmpty()) { + QString deviceId = m_devices.at(m_selectedDevice); + + device = [AVCaptureDevice deviceWithUniqueID: + [NSString stringWithUTF8String: + deviceId.toUtf8().constData()]]; + } + + if (!device) + device = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo]; + + return device; +} + +#include "moc_avfvideodevicecontrol.cpp" diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.h b/src/plugins/avfoundation/camera/avfvideorenderercontrol.h new file mode 100644 index 000000000..05361ef29 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfvideorenderercontrol.h @@ -0,0 +1,90 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#ifndef AVFVIDEORENDERERCONTROL_H +#define AVFVIDEORENDERERCONTROL_H + +#include +#include +#include + +#import + +QT_BEGIN_NAMESPACE + +class AVFCameraSession; +class AVFCameraService; +class AVFVideoRendererControl; + +@class AVFCaptureFramesDelegate; + +class AVFVideoRendererControl : public QVideoRendererControl +{ +Q_OBJECT +public: + AVFVideoRendererControl(QObject *parent = 0); + ~AVFVideoRendererControl(); + + QAbstractVideoSurface *surface() const; + void setSurface(QAbstractVideoSurface *surface); + + void configureAVCaptureSession(AVCaptureSession *captureSession); + void syncHandleViewfinderFrame(const QVideoFrame &frame); + +Q_SIGNALS: + void surfaceChanged(QAbstractVideoSurface *surface); + +private Q_SLOTS: + void handleViewfinderFrame(); + +private: + QAbstractVideoSurface *m_surface; + AVFCaptureFramesDelegate *m_viewfinderFramesDelegate; + AVCaptureSession *m_captureSession; + AVCaptureVideoDataOutput *m_videoDataOutput; + + QVideoFrame m_lastViewfinderFrame; + QMutex m_vfMutex; +}; + +QT_END_NAMESPACE + +#endif diff --git a/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm b/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm new file mode 100644 index 000000000..d6f2f8389 --- /dev/null +++ b/src/plugins/avfoundation/camera/avfvideorenderercontrol.mm @@ -0,0 +1,237 @@ +/**************************************************************************** +** +** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies). +** Contact: http://www.qt-project.org/ +** +** This file is part of the Qt Toolkit. +** +** $QT_BEGIN_LICENSE:LGPL$ +** GNU Lesser General Public License Usage +** 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, Nokia gives you certain additional +** rights. These rights are described in the Nokia 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. +** +** Other Usage +** Alternatively, this file may be used in accordance with the terms and +** conditions contained in a signed written agreement between you and Nokia. +** +** +** +** +** +** +** $QT_END_LICENSE$ +** +****************************************************************************/ + +#include "avfvideorenderercontrol.h" +#include "avfcamerasession.h" +#include "avfcameraservice.h" +#include "avfcameradebug.h" + +#include +#include +#include + +QT_USE_NAMESPACE + +class CVPixelBufferVideoBuffer : public QAbstractVideoBuffer +{ +public: + CVPixelBufferVideoBuffer(CVPixelBufferRef buffer) + : QAbstractVideoBuffer(NoHandle) + , m_buffer(buffer) + , m_mode(NotMapped) + { + CVPixelBufferRetain(m_buffer); + } + + virtual ~CVPixelBufferVideoBuffer() + { + CVPixelBufferRelease(m_buffer); + } + + MapMode mapMode() const { return m_mode; } + + uchar *map(MapMode mode, int *numBytes, int *bytesPerLine) + { + if (mode != NotMapped && m_mode == NotMapped) { + CVPixelBufferLockBaseAddress(m_buffer, 0); + + if (numBytes) + *numBytes = CVPixelBufferGetDataSize(m_buffer); + + if (bytesPerLine) + *bytesPerLine = CVPixelBufferGetBytesPerRow(m_buffer); + + m_mode = mode; + + return (uchar*)CVPixelBufferGetBaseAddress(m_buffer); + } else { + return 0; + } + } + + void unmap() + { + if (m_mode != NotMapped) { + m_mode = NotMapped; + CVPixelBufferUnlockBaseAddress(m_buffer, 0); + } + } + +private: + CVPixelBufferRef m_buffer; + MapMode m_mode; +}; + +@interface AVFCaptureFramesDelegate : NSObject +{ +@private + AVFVideoRendererControl *m_renderer; +} + +- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFVideoRendererControl*)renderer; + +- (void) captureOutput:(AVCaptureOutput *)captureOutput + didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection; +@end + +@implementation AVFCaptureFramesDelegate + +- (AVFCaptureFramesDelegate *) initWithRenderer:(AVFVideoRendererControl*)renderer +{ + if (!(self = [super init])) + return nil; + + self->m_renderer = renderer; + return self; +} + +- (void)captureOutput:(AVCaptureOutput *)captureOutput + didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer + fromConnection:(AVCaptureConnection *)connection +{ + Q_UNUSED(connection); + Q_UNUSED(captureOutput); + + CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer); + + int width = CVPixelBufferGetWidth(imageBuffer); + int height = CVPixelBufferGetHeight(imageBuffer); + + QAbstractVideoBuffer *buffer = new CVPixelBufferVideoBuffer(imageBuffer); + QVideoFrame frame(buffer, QSize(width, height), QVideoFrame::Format_RGB32); + m_renderer->syncHandleViewfinderFrame(frame); +} +@end + + +AVFVideoRendererControl::AVFVideoRendererControl(QObject *parent) + : QVideoRendererControl(parent) + , m_surface(0) +{ + m_viewfinderFramesDelegate = [[AVFCaptureFramesDelegate alloc] initWithRenderer:this]; +} + +AVFVideoRendererControl::~AVFVideoRendererControl() +{ + [m_captureSession removeOutput:m_videoDataOutput]; + [m_viewfinderFramesDelegate release]; +} + +QAbstractVideoSurface *AVFVideoRendererControl::surface() const +{ + return m_surface; +} + +void AVFVideoRendererControl::setSurface(QAbstractVideoSurface *surface) +{ + if (m_surface != surface) { + m_surface = surface; + Q_EMIT surfaceChanged(surface); + } +} + +void AVFVideoRendererControl::configureAVCaptureSession(AVCaptureSession *captureSession) +{ + m_captureSession = captureSession; + + m_videoDataOutput = [[[AVCaptureVideoDataOutput alloc] init] autorelease]; + + // Configure video output + dispatch_queue_t queue = dispatch_queue_create("vf_queue", NULL); + [m_videoDataOutput + setSampleBufferDelegate:m_viewfinderFramesDelegate + queue:queue]; + dispatch_release(queue); + + // Specify the pixel format + m_videoDataOutput.videoSettings = + [NSDictionary dictionaryWithObject: + [NSNumber numberWithInt:kCVPixelFormatType_32BGRA] + forKey:(id)kCVPixelBufferPixelFormatTypeKey]; + + [m_captureSession addOutput:m_videoDataOutput]; +} + +//can be called from non main thread +void AVFVideoRendererControl::syncHandleViewfinderFrame(const QVideoFrame &frame) +{ + QMutexLocker lock(&m_vfMutex); + if (!m_lastViewfinderFrame.isValid()) { + static QMetaMethod handleViewfinderFrameSlot = metaObject()->method( + metaObject()->indexOfMethod("handleViewfinderFrame()")); + + handleViewfinderFrameSlot.invoke(this, Qt::QueuedConnection); + } + + m_lastViewfinderFrame = frame; +} + +void AVFVideoRendererControl::handleViewfinderFrame() +{ + QVideoFrame frame; + { + QMutexLocker lock(&m_vfMutex); + frame = m_lastViewfinderFrame; + m_lastViewfinderFrame = QVideoFrame(); + } + + if (m_surface && frame.isValid()) { + if (m_surface->isActive() && m_surface->surfaceFormat().pixelFormat() != frame.pixelFormat()) + m_surface->stop(); + + if (!m_surface->isActive()) { + QVideoSurfaceFormat format(frame.size(), frame.pixelFormat()); + + if (!m_surface->start(format)) { + qWarning() << "Failed to start viewfinder m_surface, format:" << format; + } else { + qDebugCamera() << "Viewfinder started: " << format; + } + } + + if (m_surface->isActive()) + m_surface->present(frame); + } +} + + +#include "moc_avfvideorenderercontrol.cpp" diff --git a/src/plugins/avfoundation/camera/camera.pro b/src/plugins/avfoundation/camera/camera.pro new file mode 100644 index 000000000..7942c0f1b --- /dev/null +++ b/src/plugins/avfoundation/camera/camera.pro @@ -0,0 +1,52 @@ +load(qt_build_config) + +# Avoid clash with a variable named `slots' in a Quartz header +CONFIG += no_keywords + +TARGET = qavfcamera +QT += multimedia-private network + +PLUGIN_TYPE = mediaservice + +load(qt_plugin) +DESTDIR = $$QT.multimedia.plugins/$${PLUGIN_TYPE} + +LIBS += -framework AppKit -framework AudioUnit \ + -framework AudioToolbox -framework CoreAudio \ + -framework QuartzCore -framework AVFoundation \ + -framework CoreMedia + +target.path += $$[QT_INSTALL_PLUGINS]/$${PLUGIN_TYPE} +INSTALLS += target + +OTHER_FILES += avfcamera.json + +DEFINES += QMEDIA_AVF_CAMERA + +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 \ + +OBJECTIVE_SOURCES += \ + avfcameraserviceplugin.mm \ + avfcameracontrol.mm \ + avfvideorenderercontrol.mm \ + avfcamerametadatacontrol.mm \ + avfimagecapturecontrol.mm \ + avfmediarecordercontrol.mm \ + avfcameraservice.mm \ + avfcamerasession.mm \ + avfstoragelocation.mm \ + avfvideodevicecontrol.mm \ + avfaudioinputselectorcontrol.mm \ + diff --git a/src/plugins/plugins.pro b/src/plugins/plugins.pro index 951c91176..ecc6a55d5 100644 --- a/src/plugins/plugins.pro +++ b/src/plugins/plugins.pro @@ -38,5 +38,7 @@ unix:!mac { mac:!simulator { SUBDIRS += audiocapture qt7 + + config_avfoundation: SUBDIRS += avfoundation } -- cgit v1.2.3