summaryrefslogtreecommitdiffstats
path: root/src/plugins/avfoundation/camera
diff options
context:
space:
mode:
authorDmytro Poplavskiy <dmytro.poplavskiy@nokia.com>2012-08-17 13:44:14 +1000
committerQt by Nokia <qt-info@nokia.com>2012-08-27 09:11:06 +0200
commit37b872da9eced344dd5feaf1898cab0d02984ea5 (patch)
treeceb6587fa1d229a0bd99961c6e8f9a963881eae0 /src/plugins/avfoundation/camera
parent09a7fda9711290ae00f74f5d762148c5b2f5f534 (diff)
Initial implementation of Mac camera backend
Based on AVFoundation framework Change-Id: If4cfd105a592f50b42606624548b9ffc870e3e47 Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
Diffstat (limited to 'src/plugins/avfoundation/camera')
-rw-r--r--src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h86
-rw-r--r--src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm117
-rw-r--r--src/plugins/avfoundation/camera/avfcamera.json3
-rw-r--r--src/plugins/avfoundation/camera/avfcameracontrol.h86
-rw-r--r--src/plugins/avfoundation/camera/avfcameracontrol.mm135
-rw-r--r--src/plugins/avfoundation/camera/avfcameradebug.h59
-rw-r--r--src/plugins/avfoundation/camera/avfcamerametadatacontrol.h72
-rw-r--r--src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm84
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.h95
-rw-r--r--src/plugins/avfoundation/camera/avfcameraservice.mm139
-rw-r--r--src/plugins/avfoundation/camera/avfcameraserviceplugin.h76
-rw-r--r--src/plugins/avfoundation/camera/avfcameraserviceplugin.mm112
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.h101
-rw-r--r--src/plugins/avfoundation/camera/avfcamerasession.mm277
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.h88
-rw-r--r--src/plugins/avfoundation/camera/avfimagecapturecontrol.mm222
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol.h113
-rw-r--r--src/plugins/avfoundation/camera/avfmediarecordercontrol.mm342
-rw-r--r--src/plugins/avfoundation/camera/avfstoragelocation.h73
-rw-r--r--src/plugins/avfoundation/camera/avfstoragelocation.mm137
-rw-r--r--src/plugins/avfoundation/camera/avfvideodevicecontrol.h89
-rw-r--r--src/plugins/avfoundation/camera/avfvideodevicecontrol.mm119
-rw-r--r--src/plugins/avfoundation/camera/avfvideorenderercontrol.h90
-rw-r--r--src/plugins/avfoundation/camera/avfvideorenderercontrol.mm237
-rw-r--r--src/plugins/avfoundation/camera/camera.pro52
25 files changed, 3004 insertions, 0 deletions
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 <QtMultimedia/qaudioinputselectorcontrol.h>
+#include <QtCore/qstringlist.h>
+
+#import <AVFoundation/AVFoundation.h>
+
+QT_BEGIN_NAMESPACE
+
+class AVFCameraSession;
+class AVFCameraService;
+
+class AVFAudioInputSelectorControl : public QAudioInputSelectorControl
+{
+Q_OBJECT
+public:
+ AVFAudioInputSelectorControl(AVFCameraService *service, QObject *parent = 0);
+ ~AVFAudioInputSelectorControl();
+
+ QList<QString> 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<QString, QString> 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 <AVFoundation/AVFoundation.h>
+
+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<QString> 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 <QtCore/qobject.h>
+
+#include <QtMultimedia/qcameracontrol.h>
+
+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 <QtCore/qdebug.h>
+
+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 <qmetadatawritercontrol.h>
+
+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<QString, QVariant> 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 <QtCore/qobject.h>
+#include <QtCore/qset.h>
+#include <qmediaservice.h>
+
+
+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 <QtCore/qvariant.h>
+#include <QtCore/qdebug.h>
+
+#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 <private/qmediaplaylistnavigator_p.h>
+#include <qmediaplaylist.h>
+
+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 <qmediaserviceproviderplugin.h>
+#include <QtCore/qmap.h>
+
+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<QByteArray> devices(const QByteArray &service) const;
+ QString deviceDescription(const QByteArray &service, const QByteArray &device);
+
+private:
+ void updateDevices() const;
+
+ mutable QList<QByteArray> m_cameraDevices;
+ mutable QMap<QByteArray, QString> 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 <QtCore/qstring.h>
+#include <QtCore/qdebug.h>
+
+#include "avfcameraserviceplugin.h"
+#include "avfcameraservice.h"
+
+#include <qmediaserviceproviderplugin.h>
+
+#import <AVFoundation/AVFoundation.h>
+
+
+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<QByteArray> AVFServicePlugin::devices(const QByteArray &service) const
+{
+ if (service == Q_MEDIASERVICE_CAMERA) {
+ if (m_cameraDevices.isEmpty())
+ updateDevices();
+
+ return m_cameraDevices;
+ }
+
+ return QList<QByteArray>();
+}
+
+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 <QtCore/qmutex.h>
+#include <QtMultimedia/qcamera.h>
+
+#import <AVFoundation/AVFoundation.h>
+
+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 <CoreFoundation/CoreFoundation.h>
+#include <Foundation/Foundation.h>
+
+#include <QtCore/qdatetime.h>
+#include <QtCore/qurl.h>
+
+#include <QtCore/qdebug.h>
+
+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 <AVFoundation/AVFoundation.h>
+
+#include <QtMultimedia/qcameraimagecapturecontrol.h>
+#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 <QtCore/qurl.h>
+#include <QtCore/qfile.h>
+#include <QtCore/qbuffer.h>
+#include <QtGui/qimagereader.h>
+
+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 <QtCore/qurl.h>
+#include <QtMultimedia/qmediarecordercontrol.h>
+
+#import <AVFoundation/AVFoundation.h>
+#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 <QtCore/qurl.h>
+#include <QtCore/qfileinfo.h>
+#include <QtMultimedia/qcameracontrol.h>
+
+
+QT_USE_NAMESPACE
+
+@interface AVFMediaRecorderDelegate : NSObject <AVCaptureFileOutputRecordingDelegate>
+{
+@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 <QtCore/qdir.h>
+#include <QtMultimedia/qcamera.h>
+
+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<QString, int> 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 <QtMultimedia/qvideodeviceselectorcontrol.h>
+#include <QtCore/qstringlist.h>
+
+#import <AVFoundation/AVFoundation.h>
+
+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 <QtMultimedia/qvideorenderercontrol.h>
+#include <QtMultimedia/qvideoframe.h>
+#include <QtCore/qmutex.h>
+
+#import <AVFoundation/AVFoundation.h>
+
+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 <QtMultimedia/qabstractvideosurface.h>
+#include <QtMultimedia/qabstractvideobuffer.h>
+#include <QtMultimedia/qvideosurfaceformat.h>
+
+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 <AVCaptureVideoDataOutputSampleBufferDelegate>
+{
+@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 \
+