Initial implementation of Mac camera backend
authorDmytro Poplavskiy <dmytro.poplavskiy@nokia.com>
Fri, 17 Aug 2012 03:44:14 +0000 (13:44 +1000)
committerQt by Nokia <qt-info@nokia.com>
Mon, 27 Aug 2012 07:11:06 +0000 (09:11 +0200)
Based on AVFoundation framework

Change-Id: If4cfd105a592f50b42606624548b9ffc870e3e47
Reviewed-by: Gunnar Sletta <gunnar.sletta@nokia.com>
27 files changed:
src/plugins/avfoundation/avfoundation.pro [new file with mode: 0644]
src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcamera.json [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameracontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameracontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameradebug.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcamerametadatacontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcamerametadatacontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameraservice.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameraservice.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameraserviceplugin.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcameraserviceplugin.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcamerasession.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfcamerasession.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfimagecapturecontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfimagecapturecontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfmediarecordercontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfmediarecordercontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfstoragelocation.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfstoragelocation.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfvideodevicecontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfvideodevicecontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/avfvideorenderercontrol.h [new file with mode: 0644]
src/plugins/avfoundation/camera/avfvideorenderercontrol.mm [new file with mode: 0644]
src/plugins/avfoundation/camera/camera.pro [new file with mode: 0644]
src/plugins/plugins.pro

diff --git a/src/plugins/avfoundation/avfoundation.pro b/src/plugins/avfoundation/avfoundation.pro
new file mode 100644 (file)
index 0000000..9a3dbf6
--- /dev/null
@@ -0,0 +1,3 @@
+TEMPLATE = subdirs
+
+SUBDIRS += camera
diff --git a/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h b/src/plugins/avfoundation/camera/avfaudioinputselectorcontrol.h
new file mode 100644 (file)
index 0000000..a535831
--- /dev/null
@@ -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 (file)
index 0000000..7c31d7c
--- /dev/null
@@ -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 (file)
index 0000000..d3a58c7
--- /dev/null
@@ -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 (file)
index 0000000..a881b0b
--- /dev/null
@@ -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 (file)
index 0000000..39f474d
--- /dev/null
@@ -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 (file)
index 0000000..73bf682
--- /dev/null
@@ -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 (file)
index 0000000..b77c228
--- /dev/null
@@ -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 (file)
index 0000000..b1ad6be
--- /dev/null
@@ -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 (file)
index 0000000..f55cfcf
--- /dev/null
@@ -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 (file)
index 0000000..cffdd3d
--- /dev/null
@@ -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 (file)
index 0000000..818d6bb
--- /dev/null
@@ -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 (file)
index 0000000..f74b1d9
--- /dev/null
@@ -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 (file)
index 0000000..24130b8
--- /dev/null
@@ -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 (file)
index 0000000..acc32d7
--- /dev/null
@@ -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 (file)
index 0000000..56e53a7
--- /dev/null
@@ -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 (file)
index 0000000..3d19ecc
--- /dev/null
@@ -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 (file)
index 0000000..da29b78
--- /dev/null
@@ -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 (file)
index 0000000..5278ee5
--- /dev/null
@@ -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 (file)
index 0000000..97ccaec
--- /dev/null
@@ -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 (file)
index 0000000..24b8391
--- /dev/null
@@ -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 (file)
index 0000000..6202777
--- /dev/null
@@ -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 (file)
index 0000000..fac60f0
--- /dev/null
@@ -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 (file)
index 0000000..05361ef
--- /dev/null
@@ -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 (file)
index 0000000..d6f2f83
--- /dev/null
@@ -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 (file)
index 0000000..7942c0f
--- /dev/null
@@ -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 \
+
index 951c911..ecc6a55 100644 (file)
@@ -38,5 +38,7 @@ unix:!mac {
 
 mac:!simulator {
     SUBDIRS += audiocapture qt7
+
+    config_avfoundation: SUBDIRS += avfoundation
 }