Provide face and orientation info from gstreamer camera backend.
authorAndrew den Exter <andrew.den.exter@jollamobile.com>
Tue, 8 Jul 2014 05:56:05 +0000 (15:56 +1000)
committerAndrew den Exter <andrew.den.exter@qinetic.com.au>
Sat, 12 Jul 2014 00:46:10 +0000 (02:46 +0200)
Cleans up duplicate device enumeration code so the devices listed by
the QMediaServiceProviderPlugin are the same as those in the
QVideoInputDeviceControl and includes face and orientation information
if available.

Change-Id: Iaa4c303c973bcf3e0f7c8c2fd7a7de629bccec86
Reviewed-by: Yoann Lopes <yoann.lopes@digia.com>
15 files changed:
src/gsttools/qgstreamervideoinputdevicecontrol.cpp
src/gsttools/qgstutils.cpp
src/multimedia/gsttools_headers/qgstreamervideoinputdevicecontrol_p.h
src/multimedia/gsttools_headers/qgstutils_p.h
src/plugins/gstreamer/camerabin/camerabin.pro
src/plugins/gstreamer/camerabin/camerabininfocontrol.cpp [new file with mode: 0644]
src/plugins/gstreamer/camerabin/camerabininfocontrol.h [new file with mode: 0644]
src/plugins/gstreamer/camerabin/camerabinservice.cpp
src/plugins/gstreamer/camerabin/camerabinservice.h
src/plugins/gstreamer/camerabin/camerabinserviceplugin.cpp
src/plugins/gstreamer/camerabin/camerabinserviceplugin.h
src/plugins/gstreamer/camerabin/camerabinsession.cpp
src/plugins/gstreamer/camerabin/camerabinsession.h
src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.cpp
src/plugins/gstreamer/mediacapture/qgstreamercaptureserviceplugin.h

index e4e202c..c26029c 100644 (file)
 #include <QtCore/QDir>
 #include <QtCore/QDebug>
 
-#include <private/qcore_unix_p.h>
-#include <linux/videodev2.h>
+#include <private/qgstutils_p.h>
 
 QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent)
-    :QVideoDeviceSelectorControl(parent), m_source(0), m_selectedDevice(0)
+    :QVideoDeviceSelectorControl(parent), m_factory(0), m_selectedDevice(0)
 {
-    update();
 }
 
-QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(GstElement *source, QObject *parent)
-    :QVideoDeviceSelectorControl(parent), m_source(source), m_selectedDevice(0)
+QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(
+        GstElementFactory *factory, QObject *parent)
+    : QVideoDeviceSelectorControl(parent), m_factory(factory), m_selectedDevice(0)
 {
-    if (m_source)
-        gst_object_ref(GST_OBJECT(m_source));
-
-    update();
+    if (m_factory)
+        gst_object_ref(GST_OBJECT(m_factory));
 }
 
 QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl()
 {
-    if (m_source)
-        gst_object_unref(GST_OBJECT(m_source));
+    if (m_factory)
+        gst_object_unref(GST_OBJECT(m_factory));
 }
 
 int QGstreamerVideoInputDeviceControl::deviceCount() const
 {
-    return m_names.size();
+    return QGstUtils::enumerateCameras(m_factory).count();
 }
 
 QString QGstreamerVideoInputDeviceControl::deviceName(int index) const
 {
-    return m_names[index];
+    return QGstUtils::enumerateCameras(m_factory).value(index).name;
 }
 
 QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const
 {
-    return m_descriptions[index];
+    return QGstUtils::enumerateCameras(m_factory).value(index).description;
 }
 
 int QGstreamerVideoInputDeviceControl::defaultDevice() const
@@ -93,7 +90,6 @@ int QGstreamerVideoInputDeviceControl::selectedDevice() const
     return m_selectedDevice;
 }
 
-
 void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index)
 {
     if (index != m_selectedDevice) {
@@ -102,60 +98,3 @@ void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index)
         emit selectedDeviceChanged(deviceName(index));
     }
 }
-
-
-void QGstreamerVideoInputDeviceControl::update()
-{
-    m_names.clear();
-    m_descriptions.clear();
-
-    // subdevsrc and the like have a camera-device property that takes an enumeration
-    // identifying a primary or secondary camera, so return identifiers that map to those
-    // instead of a list of actual devices.
-    if (m_source && g_object_class_find_property(G_OBJECT_GET_CLASS(m_source), "camera-device")) {
-        m_names << QLatin1String("primary") << QLatin1String("secondary");
-        m_descriptions << tr("Main camera") << tr("Front camera");
-        return;
-    }
-
-    QDir devDir("/dev");
-    devDir.setFilter(QDir::System);
-
-    QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*");
-
-    foreach( const QFileInfo &entryInfo, entries ) {
-        //qDebug() << "Try" << entryInfo.filePath();
-
-        int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
-        if (fd == -1)
-            continue;
-
-        bool isCamera = false;
-
-        v4l2_input input;
-        memset(&input, 0, sizeof(input));
-        for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
-            if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
-                isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
-                break;
-            }
-        }
-
-        if (isCamera) {
-            // find out its driver "name"
-            QString name;
-            struct v4l2_capability vcap;
-            memset(&vcap, 0, sizeof(struct v4l2_capability));
-
-            if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
-                name = entryInfo.fileName();
-            else
-                name = QString((const char*)vcap.card);
-            //qDebug() << "found camera: " << name;
-
-            m_names.append(entryInfo.filePath());
-            m_descriptions.append(name);
-        }
-        qt_safe_close(fd);
-    }
-}
index 41bd005..9d94cb6 100644 (file)
@@ -42,6 +42,7 @@
 #include "qgstutils_p.h"
 
 #include <QtCore/qdatetime.h>
+#include <QtCore/qdir.h>
 #include <QtCore/qbytearray.h>
 #include <QtCore/qvariant.h>
 #include <QtCore/qsize.h>
 #include <QtCore/qstringlist.h>
 #include <qaudioformat.h>
 
+#include <private/qcore_unix_p.h>
+#include <linux/videodev2.h>
+
+#include "qgstreamervideoinputdevicecontrol_p.h"
+
 QT_BEGIN_NAMESPACE
 
 //internal
@@ -401,6 +407,165 @@ QMultimedia::SupportEstimate QGstUtils::hasSupport(const QString &mimeType,
     return QMultimedia::MaybeSupported;
 }
 
+namespace {
+
+typedef QHash<GstElementFactory *, QVector<QGstUtils::CameraInfo> > FactoryCameraInfoMap;
+
+Q_GLOBAL_STATIC(FactoryCameraInfoMap, qt_camera_device_info);
+
+}
+
+QVector<QGstUtils::CameraInfo> QGstUtils::enumerateCameras(GstElementFactory *factory)
+{
+    FactoryCameraInfoMap::const_iterator it = qt_camera_device_info()->constFind(factory);
+    if (it != qt_camera_device_info()->constEnd())
+        return *it;
+
+    QVector<CameraInfo> &devices = (*qt_camera_device_info())[factory];
+
+    if (factory) {
+        bool hasVideoSource = false;
+
+        const GType type = gst_element_factory_get_element_type(factory);
+        GObjectClass * const objectClass = type
+                ? static_cast<GObjectClass *>(g_type_class_ref(type))
+                : 0;
+        if (objectClass) {
+            if (g_object_class_find_property(objectClass, "camera-device")) {
+                const CameraInfo primary = {
+                    QStringLiteral("primary"),
+                    QGstreamerVideoInputDeviceControl::primaryCamera(),
+                    0,
+                    QCamera::BackFace
+                };
+                const CameraInfo secondary = {
+                    QStringLiteral("secondary"),
+                    QGstreamerVideoInputDeviceControl::secondaryCamera(),
+                    0,
+                    QCamera::FrontFace
+                };
+
+                devices.append(primary);
+                devices.append(secondary);
+
+                GstElement *camera = g_object_class_find_property(objectClass, "sensor-mount-angle")
+                        ? gst_element_factory_create(factory, 0)
+                        : 0;
+                if (camera) {
+                    if (gst_element_set_state(camera, GST_STATE_READY) != GST_STATE_CHANGE_SUCCESS) {
+                        // no-op
+                    } else for (int i = 0; i < 2; ++i) {
+                        gint orientation = 0;
+                        g_object_set(G_OBJECT(camera), "camera-device", i, NULL);
+                        g_object_get(G_OBJECT(camera), "sensor-mount-angle", &orientation, NULL);
+
+                        devices[i].orientation = (720 - orientation) % 360;
+                    }
+                    gst_element_set_state(camera, GST_STATE_NULL);
+                    gst_object_unref(GST_OBJECT(camera));
+
+                }
+            } else if (g_object_class_find_property(objectClass, "video-source")) {
+                hasVideoSource = true;
+            }
+
+            g_type_class_unref(objectClass);
+        }
+
+        if (!devices.isEmpty() || !hasVideoSource) {
+            return devices;
+        }
+    }
+
+    QDir devDir(QStringLiteral("/dev"));
+    devDir.setFilter(QDir::System);
+
+    QFileInfoList entries = devDir.entryInfoList(QStringList()
+                << QStringLiteral("video*"));
+
+    foreach (const QFileInfo &entryInfo, entries) {
+        //qDebug() << "Try" << entryInfo.filePath();
+
+        int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
+        if (fd == -1)
+            continue;
+
+        bool isCamera = false;
+
+        v4l2_input input;
+        memset(&input, 0, sizeof(input));
+        for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
+            if (input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
+                isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
+                break;
+            }
+        }
+
+        if (isCamera) {
+            // find out its driver "name"
+            QString name;
+            struct v4l2_capability vcap;
+            memset(&vcap, 0, sizeof(struct v4l2_capability));
+
+            if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
+                name = entryInfo.fileName();
+            else
+                name = QString::fromUtf8((const char*)vcap.card);
+            //qDebug() << "found camera: " << name;
+
+
+            CameraInfo device = {
+                entryInfo.absoluteFilePath(),
+                name,
+                0,
+                QCamera::UnspecifiedPosition
+            };
+            devices.append(device);
+        }
+        qt_safe_close(fd);
+    }
+
+    return devices;
+}
+
+QList<QByteArray> QGstUtils::cameraDevices(GstElementFactory * factory)
+{
+    QList<QByteArray> devices;
+
+    foreach (const CameraInfo &camera, enumerateCameras(factory))
+        devices.append(camera.name.toUtf8());
+
+    return devices;
+}
+
+QString QGstUtils::cameraDescription(const QString &device, GstElementFactory * factory)
+{
+    foreach (const CameraInfo &camera, enumerateCameras(factory)) {
+        if (camera.name == device)
+            return camera.description;
+    }
+    return QString();
+}
+
+QCamera::Position QGstUtils::cameraPosition(const QString &device, GstElementFactory * factory)
+{
+    foreach (const CameraInfo &camera, enumerateCameras(factory)) {
+        if (camera.name == device)
+            return camera.position;
+    }
+    return QCamera::UnspecifiedPosition;
+}
+
+int QGstUtils::cameraOrientation(const QString &device, GstElementFactory * factory)
+{
+    foreach (const CameraInfo &camera, enumerateCameras(factory)) {
+        if (camera.name == device)
+            return camera.orientation;
+    }
+    return 0;
+}
+
+
 void qt_gst_object_ref_sink(gpointer object)
 {
 #if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 24)
index eeb576e..c4fe83f 100644 (file)
@@ -46,6 +46,7 @@
 #include <QtCore/qstringlist.h>
 
 #include <gst/gst.h>
+#include <qcamera.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -54,7 +55,7 @@ class QGstreamerVideoInputDeviceControl : public QVideoDeviceSelectorControl
 Q_OBJECT
 public:
     QGstreamerVideoInputDeviceControl(QObject *parent);
-    QGstreamerVideoInputDeviceControl(GstElement *source, QObject *parent);
+    QGstreamerVideoInputDeviceControl(GstElementFactory *factory, QObject *parent);
     ~QGstreamerVideoInputDeviceControl();
 
     int deviceCount() const;
@@ -65,17 +66,16 @@ public:
     int defaultDevice() const;
     int selectedDevice() const;
 
+    static QString primaryCamera() { return tr("Main camera"); }
+    static QString secondaryCamera() { return tr("Front camera"); }
+
 public Q_SLOTS:
     void setSelectedDevice(int index);
 
 private:
-    void update();
-
-    GstElement *m_source;
+    GstElementFactory *m_factory;
 
     int m_selectedDevice;
-    QStringList m_names;
-    QStringList m_descriptions;
 };
 
 QT_END_NAMESPACE
index eea1e15..701de59 100644 (file)
 
 #include <QtCore/qmap.h>
 #include <QtCore/qset.h>
+#include <QtCore/qvector.h>
 #include <gst/gst.h>
 #include <qaudioformat.h>
+#include <qcamera.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -65,6 +67,14 @@ class QVariant;
 class QByteArray;
 
 namespace QGstUtils {
+    struct CameraInfo
+    {
+        QString name;
+        QString description;
+        int orientation;
+        QCamera::Position position;
+    };
+
     QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list);
 
     QSize capsResolution(const GstCaps *caps);
@@ -76,6 +86,12 @@ namespace QGstUtils {
     QMultimedia::SupportEstimate hasSupport(const QString &mimeType,
                                              const QStringList &codecs,
                                              const QSet<QString> &supportedMimeTypeSet);
+
+    QVector<CameraInfo> enumerateCameras(GstElementFactory *factory = 0);
+    QList<QByteArray> cameraDevices(GstElementFactory * factory = 0);
+    QString cameraDescription(const QString &device, GstElementFactory * factory = 0);
+    QCamera::Position cameraPosition(const QString &device, GstElementFactory * factory = 0);
+    int cameraOrientation(const QString &device, GstElementFactory * factory = 0);
 }
 
 void qt_gst_object_ref_sink(gpointer object);
index 9efa081..bba797f 100644 (file)
@@ -30,7 +30,8 @@ HEADERS += \
     $$PWD/camerabinresourcepolicy.h \
     $$PWD/camerabincapturedestination.h \
     $$PWD/camerabincapturebufferformat.h \
-    $$PWD/camerabinviewfindersettings.h
+    $$PWD/camerabinviewfindersettings.h \
+    $$PWD/camerabininfocontrol.h
 
 SOURCES += \
     $$PWD/camerabinserviceplugin.cpp \
@@ -48,7 +49,8 @@ SOURCES += \
     $$PWD/camerabinresourcepolicy.cpp \
     $$PWD/camerabincapturedestination.cpp \
     $$PWD/camerabinviewfindersettings.cpp \
-    $$PWD/camerabincapturebufferformat.cpp
+    $$PWD/camerabincapturebufferformat.cpp \
+    $$PWD/camerabininfocontrol.cpp
 
 maemo6 {
     HEADERS += \
diff --git a/src/plugins/gstreamer/camerabin/camerabininfocontrol.cpp b/src/plugins/gstreamer/camerabin/camerabininfocontrol.cpp
new file mode 100644 (file)
index 0000000..a3ee369
--- /dev/null
@@ -0,0 +1,71 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+
+#include "camerabininfocontrol.h"
+
+#include <private/qgstutils_p.h>
+
+QT_BEGIN_NAMESPACE
+
+CameraBinInfoControl::CameraBinInfoControl(GstElementFactory *sourceFactory, QObject *parent)
+    : QCameraInfoControl(parent)
+    , m_sourceFactory(sourceFactory)
+{
+    gst_object_ref(GST_OBJECT(m_sourceFactory));
+}
+
+CameraBinInfoControl::~CameraBinInfoControl()
+{
+    gst_object_unref(GST_OBJECT(m_sourceFactory));
+}
+
+QCamera::Position CameraBinInfoControl::cameraPosition(const QString &device) const
+{
+    return QGstUtils::cameraPosition(device, m_sourceFactory);
+}
+
+int CameraBinInfoControl::cameraOrientation(const QString &device) const
+{
+    return QGstUtils::cameraOrientation(device, m_sourceFactory);
+}
+
+QT_END_NAMESPACE
diff --git a/src/plugins/gstreamer/camerabin/camerabininfocontrol.h b/src/plugins/gstreamer/camerabin/camerabininfocontrol.h
new file mode 100644 (file)
index 0000000..577eb3f
--- /dev/null
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2014 Jolla Ltd.
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:LGPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and Digia.  For licensing terms and
+** conditions see http://qt.digia.com/licensing.  For further information
+** use the contact form at http://qt.digia.com/contact-us.
+**
+** GNU Lesser General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU Lesser
+** General Public License version 2.1 as published by the Free Software
+** Foundation and appearing in the file LICENSE.LGPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU Lesser General Public License version 2.1 requirements
+** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
+**
+** In addition, as a special exception, Digia gives you certain additional
+** rights.  These rights are described in the Digia Qt LGPL Exception
+** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3.0 as published by the Free Software
+** Foundation and appearing in the file LICENSE.GPL included in the
+** packaging of this file.  Please review the following information to
+** ensure the GNU General Public License version 3.0 requirements will be
+** met: http://www.gnu.org/copyleft/gpl.html.
+**
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef CAMERABININFOCONTROL_H
+#define CAMERABININFOCONTROL_H
+
+#include <qcamerainfocontrol.h>
+
+#include <gst/gst.h>
+
+QT_BEGIN_NAMESPACE
+
+class CameraBinInfoControl : public QCameraInfoControl
+{
+    Q_OBJECT
+public:
+    CameraBinInfoControl(GstElementFactory *sourceFactory, QObject *parent);
+    ~CameraBinInfoControl();
+
+    QCamera::Position cameraPosition(const QString &deviceName) const;
+    int cameraOrientation(const QString &deviceName) const;
+
+private:
+    GstElementFactory * const m_sourceFactory;
+};
+
+QT_END_NAMESPACE
+
+#endif
index df02a9e..5db7236 100644 (file)
@@ -48,6 +48,7 @@
 #include "camerabinimageencoder.h"
 #include "camerabincontrol.h"
 #include "camerabinmetadata.h"
+#include "camerabininfocontrol.h"
 
 #ifdef HAVE_GST_PHOTOGRAPHY
 #include "camerabinexposure.h"
@@ -89,8 +90,9 @@
 
 QT_BEGIN_NAMESPACE
 
-CameraBinService::CameraBinService(const QString &service, QObject *parent):
-    QMediaService(parent)
+CameraBinService::CameraBinService(GstElementFactory *sourceFactory, QObject *parent):
+    QMediaService(parent),
+    m_cameraInfoControl(0)
 {
     m_captureSession = 0;
     m_metaDataControl = 0;
@@ -106,40 +108,32 @@ CameraBinService::CameraBinService(const QString &service, QObject *parent):
 #endif
     m_imageCaptureControl = 0;
 
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        m_captureSession = new CameraBinSession(this);
-        m_videoInputDevice = new QGstreamerVideoInputDeviceControl(
-                    m_captureSession->buildCameraSource(), m_captureSession);
-        m_imageCaptureControl = new CameraBinImageCapture(m_captureSession);
+    m_captureSession = new CameraBinSession(sourceFactory, this);
+    m_videoInputDevice = new QGstreamerVideoInputDeviceControl(sourceFactory, m_captureSession);
+    m_imageCaptureControl = new CameraBinImageCapture(m_captureSession);
 
-        connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)),
-                m_captureSession, SLOT(setDevice(QString)));
+    connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)),
+            m_captureSession, SLOT(setDevice(QString)));
 
-        if (m_videoInputDevice->deviceCount())
-            m_captureSession->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice()));
+    if (m_videoInputDevice->deviceCount())
+        m_captureSession->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice()));
 
 #if defined(Q_WS_MAEMO_6) && defined(__arm__) && defined(HAVE_WIDGETS)
-        m_videoRenderer = new QGstreamerGLTextureRenderer(this);
+    m_videoRenderer = new QGstreamerGLTextureRenderer(this);
 #else
-        m_videoRenderer = new QGstreamerVideoRenderer(this);
+    m_videoRenderer = new QGstreamerVideoRenderer(this);
 #endif
 
 #ifdef Q_WS_MAEMO_6
-        m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink");
+    m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink");
 #else
-        m_videoWindow = new QGstreamerVideoWindow(this);
+    m_videoWindow = new QGstreamerVideoWindow(this);
 #endif
 
 #if defined(HAVE_WIDGETS)
-        m_videoWidgetControl = new QGstreamerVideoWidgetControl(this);
+    m_videoWidgetControl = new QGstreamerVideoWidgetControl(this);
 #endif
 
-    }
-    if (!m_captureSession) {
-        qWarning() << Q_FUNC_INFO << "Service type is not supported:" << service;
-        return;
-    }
-
     m_audioInputSelector = new QGstreamerAudioInputSelector(this);
     connect(m_audioInputSelector, SIGNAL(activeInputChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString)));
 
@@ -244,6 +238,12 @@ QMediaControl *CameraBinService::requestControl(const char *name)
     if (qstrcmp(name, QCameraViewfinderSettingsControl_iid) == 0)
         return m_captureSession->viewfinderSettingsControl();
 
+    if (qstrcmp(name, QCameraInfoControl_iid) == 0) {
+        if (!m_cameraInfoControl)
+            m_cameraInfoControl = new CameraBinInfoControl(m_captureSession->sourceFactory(), this);
+        return m_cameraInfoControl;
+    }
+
     return 0;
 }
 
index 7d3b3df..4dc0f40 100644 (file)
@@ -67,7 +67,7 @@ class CameraBinService : public QMediaService
     Q_OBJECT
 
 public:
-    CameraBinService(const QString &service, QObject *parent = 0);
+    CameraBinService(GstElementFactory *sourceFactory, QObject *parent = 0);
     virtual ~CameraBinService();
 
     QMediaControl *requestControl(const char *name);
@@ -92,6 +92,7 @@ private:
     QGstreamerVideoWidgetControl *m_videoWidgetControl;
 #endif
     CameraBinImageCapture *m_imageCaptureControl;
+    QMediaControl *m_cameraInfoControl;
 };
 
 QT_END_NAMESPACE
index 3decd60..bfb0c49 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
+template <typename T, int N> static int lengthOf(const T(&)[N]) { return N; }
+
+CameraBinServicePlugin::CameraBinServicePlugin()
+    : m_sourceFactory(0)
+{
+}
+
+CameraBinServicePlugin::~CameraBinServicePlugin()
+{
+    if (m_sourceFactory)
+        gst_object_unref(GST_OBJECT(m_sourceFactory));
+}
+
 QMediaService* CameraBinServicePlugin::create(const QString &key)
 {
     QGstUtils::initializeGst();
 
     if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
-        return new CameraBinService(key);
+        return new CameraBinService(sourceFactory());
 
     qWarning() << "Gstreamer camerabin service plugin: unsupported key:" << key;
     return 0;
@@ -82,40 +95,24 @@ QMediaServiceProviderHint::Features CameraBinServicePlugin::supportedFeatures(
 
 QByteArray CameraBinServicePlugin::defaultDevice(const QByteArray &service) const
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
-
-        return m_defaultCameraDevice;
-    }
-
-    return QByteArray();
+    return service == Q_MEDIASERVICE_CAMERA
+            ? QGstUtils::enumerateCameras(sourceFactory()).value(0).name.toUtf8()
+            : QByteArray();
 }
 
 QList<QByteArray> CameraBinServicePlugin::devices(const QByteArray &service) const
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
 
-        return m_cameraDevices;
-    }
-
-    return QList<QByteArray>();
+    return service == Q_MEDIASERVICE_CAMERA
+            ? QGstUtils::cameraDevices(m_sourceFactory)
+            : QList<QByteArray>();
 }
 
-QString CameraBinServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
+QString CameraBinServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &deviceName)
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
-
-        for (int i=0; i<m_cameraDevices.count(); i++)
-            if (m_cameraDevices[i] == device)
-                return m_cameraDescriptions[i];
-    }
-
-    return QString();
+    return service == Q_MEDIASERVICE_CAMERA
+            ? QGstUtils::cameraDescription(deviceName, m_sourceFactory)
+            : QString();
 }
 
 QVariant CameraBinServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property)
@@ -126,53 +123,36 @@ QVariant CameraBinServicePlugin::deviceProperty(const QByteArray &service, const
     return QVariant();
 }
 
-void CameraBinServicePlugin::updateDevices() const
+QCamera::Position CameraBinServicePlugin::cameraPosition(const QByteArray &deviceName) const
 {
-    m_defaultCameraDevice.clear();
-    m_cameraDevices.clear();
-    m_cameraDescriptions.clear();
-
-    QDir devDir("/dev");
-    devDir.setFilter(QDir::System);
-
-    QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*");
-
-    foreach (const QFileInfo &entryInfo, entries) {
-        int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
-        if (fd == -1)
-            continue;
-
-        bool isCamera = false;
-
-        v4l2_input input;
-        memset(&input, 0, sizeof(input));
-        for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
-            if (input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
-                isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
-                break;
-            }
-        }
-
-        if (isCamera) {
-            // find out its driver "name"
-            QString name;
-            struct v4l2_capability vcap;
-            memset(&vcap, 0, sizeof(struct v4l2_capability));
+    return QGstUtils::cameraPosition(deviceName, m_sourceFactory);
+}
 
-            if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
-                name = entryInfo.fileName();
-            else
-                name = QString((const char*)vcap.card);
-            //qDebug() << "found camera: " << name;
+int CameraBinServicePlugin::cameraOrientation(const QByteArray &deviceName) const
+{
+    return QGstUtils::cameraOrientation(deviceName, m_sourceFactory);
+}
 
-            m_cameraDevices.append(entryInfo.filePath().toLocal8Bit());
-            m_cameraDescriptions.append(name);
+GstElementFactory *CameraBinServicePlugin::sourceFactory() const
+{
+    if (!m_sourceFactory) {
+        GstElementFactory *factory = 0;
+        const QByteArray envCandidate = qgetenv("QT_GSTREAMER_CAMERABIN_SRC");
+        if (!envCandidate.isEmpty())
+            factory = gst_element_factory_find(envCandidate.constData());
+
+        static const char *candidates[] = { "subdevsrc", "wrappercamerabinsrc" };
+        for (int i = 0; !factory && i < lengthOf(candidates); ++i)
+            factory = gst_element_factory_find(candidates[i]);
+
+        if (factory) {
+            m_sourceFactory = GST_ELEMENT_FACTORY(gst_plugin_feature_load(
+                    GST_PLUGIN_FEATURE(factory)));
+            gst_object_unref((GST_OBJECT(factory)));
         }
-        qt_safe_close(fd);
     }
 
-    if (!m_cameraDevices.isEmpty())
-        m_defaultCameraDevice = m_cameraDevices.first();
+    return m_sourceFactory;
 }
 
 QT_END_NAMESPACE
index 50ffc59..6b192d8 100644 (file)
@@ -44,7 +44,9 @@
 #define CAMERABINSERVICEPLUGIN_H
 
 #include <qmediaserviceproviderplugin.h>
-#include <QtCore/QObject>
+#include <private/qgstreamervideoinputdevicecontrol_p.h>
+
+#include <gst/gst.h>
 
 QT_BEGIN_NAMESPACE
 
@@ -53,13 +55,18 @@ class CameraBinServicePlugin
     , public QMediaServiceSupportedDevicesInterface
     , public QMediaServiceDefaultDeviceInterface
     , public QMediaServiceFeaturesInterface
+    , public QMediaServiceCameraInfoInterface
 {
     Q_OBJECT
     Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
     Q_INTERFACES(QMediaServiceDefaultDeviceInterface)
     Q_INTERFACES(QMediaServiceFeaturesInterface)
+    Q_INTERFACES(QMediaServiceCameraInfoInterface)
     Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0" FILE "camerabin.json")
 public:
+    CameraBinServicePlugin();
+    ~CameraBinServicePlugin();
+
     QMediaService* create(QString const& key);
     void release(QMediaService *service);
 
@@ -70,12 +77,13 @@ public:
     QString deviceDescription(const QByteArray &service, const QByteArray &device);
     QVariant deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property);
 
+    QCamera::Position cameraPosition(const QByteArray &device) const;
+    int cameraOrientation(const QByteArray &device) const;
+
 private:
-    void updateDevices() const;
+    GstElementFactory *sourceFactory() const;
 
-    mutable QByteArray m_defaultCameraDevice;
-    mutable QList<QByteArray> m_cameraDevices;
-    mutable QStringList m_cameraDescriptions;
+    mutable GstElementFactory *m_sourceFactory;
 };
 
 QT_END_NAMESPACE
index a835b1c..b18e9c9 100644 (file)
 
 QT_BEGIN_NAMESPACE
 
-CameraBinSession::CameraBinSession(QObject *parent)
+CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *parent)
     :QObject(parent),
      m_recordingActive(false),
      m_state(QCamera::UnloadedState),
@@ -133,6 +133,7 @@ CameraBinSession::CameraBinSession(QObject *parent)
      m_viewfinderInterface(0),
      m_videoSrc(0),
      m_viewfinderElement(0),
+     m_sourceFactory(sourceFactory),
      m_viewfinderHasChanged(true),
      m_videoInputHasChanged(true),
      m_audioSrc(0),
@@ -142,6 +143,9 @@ CameraBinSession::CameraBinSession(QObject *parent)
      m_audioEncoder(0),
      m_muxer(0)
 {
+    if (m_sourceFactory)
+        gst_object_ref(GST_OBJECT(m_sourceFactory));
+
     m_camerabin = gst_element_factory_make("camerabin2", "camerabin2");
     g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this);
     qt_gst_object_ref_sink(m_camerabin);
@@ -195,6 +199,9 @@ CameraBinSession::~CameraBinSession()
     }
     if (m_viewfinderElement)
         gst_object_unref(GST_OBJECT(m_viewfinderElement));
+
+    if (m_sourceFactory)
+        gst_object_unref(GST_OBJECT(m_sourceFactory));
 }
 
 #ifdef HAVE_GST_PHOTOGRAPHY
@@ -383,32 +390,17 @@ GstElement *CameraBinSession::buildCameraSource()
     m_videoInputHasChanged = false;
 
     GstElement *videoSrc = 0;
+
+    if (!videoSrc)
     g_object_get(G_OBJECT(m_camerabin), CAMERA_SOURCE_PROPERTY, &videoSrc, NULL);
 
-    // If the QT_GSTREAMER_CAMERABIN_SRC environment variable has been set use the source
-    // it recommends.
-    const QByteArray envCandidate = qgetenv("QT_GSTREAMER_CAMERABIN_SRC");
-    if (!m_videoSrc && !envCandidate.isEmpty()) {
-        m_videoSrc = gst_element_factory_make(envCandidate.constData(), "camera_source");
-    }
+    if (m_sourceFactory)
+        m_videoSrc = gst_element_factory_create(m_sourceFactory, "camera_source");
 
     // If gstreamer has set a default source use it.
     if (!m_videoSrc)
         m_videoSrc = videoSrc;
 
-    // If there's no better guidance try the names of some known camera source elements.
-    if (!m_videoSrc) {
-        const QList<QByteArray> candidates = QList<QByteArray>()
-                << "subdevsrc"
-                << "wrappercamerabinsrc";
-
-        foreach (const QByteArray &sourceElementName, candidates) {
-            m_videoSrc = gst_element_factory_make(sourceElementName.constData(), "camera_source");
-            if (m_videoSrc)
-                break;
-        }
-    }
-
     if (m_videoSrc && !m_inputDevice.isEmpty()) {
 #if CAMERABIN_DEBUG
         qDebug() << "set camera device" << m_inputDevice;
index 54800e9..836c086 100644 (file)
@@ -96,7 +96,7 @@ public:
        BackCamera // Main photo camera
     };
 
-    CameraBinSession(QObject *parent);
+    CameraBinSession(GstElementFactory *sourceFactory, QObject *parent);
     ~CameraBinSession();
 
 #ifdef HAVE_GST_PHOTOGRAPHY
@@ -121,6 +121,7 @@ public:
     QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const;
 
     GstElement *buildCameraSource();
+    GstElementFactory *sourceFactory() const { return m_sourceFactory; }
 
     CameraBinControl *cameraControl() const { return m_cameraControl; }
     CameraBinAudioEncoder *audioEncodeControl() const { return m_audioEncodeControl; }
@@ -239,6 +240,7 @@ private:
     GstElement *m_camerabin;
     GstElement *m_videoSrc;
     GstElement *m_viewfinderElement;
+    GstElementFactory *m_sourceFactory;
     bool m_viewfinderHasChanged;
     bool m_videoInputHasChanged;
 
index 8b88fbb..6763c68 100644 (file)
@@ -51,9 +51,6 @@
 #include "qgstreamercaptureservice.h"
 #include <private/qgstutils_p.h>
 
-#include <private/qcore_unix_p.h>
-#include <linux/videodev2.h>
-
 QMediaService* QGstreamerCaptureServicePlugin::create(const QString &key)
 {
     QGstUtils::initializeGst();
@@ -87,40 +84,19 @@ QMediaServiceProviderHint::Features QGstreamerCaptureServicePlugin::supportedFea
 
 QByteArray QGstreamerCaptureServicePlugin::defaultDevice(const QByteArray &service) const
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
-
-        return m_defaultCameraDevice;
-    }
-
-    return QByteArray();
+    return service == Q_MEDIASERVICE_CAMERA
+            ? QGstUtils::enumerateCameras().value(0).name.toUtf8()
+            : QByteArray();
 }
 
 QList<QByteArray> QGstreamerCaptureServicePlugin::devices(const QByteArray &service) const
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
-
-        return m_cameraDevices;
-    }
-
-    return QList<QByteArray>();
+    return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDevices() : QList<QByteArray>();
 }
 
 QString QGstreamerCaptureServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
 {
-    if (service == Q_MEDIASERVICE_CAMERA) {
-        if (m_cameraDevices.isEmpty())
-            updateDevices();
-
-        for (int i=0; i<m_cameraDevices.count(); i++)
-            if (m_cameraDevices[i] == device)
-                return m_cameraDescriptions[i];
-    }
-
-    return QString();
+    return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDescription(deviceName) : QString();
 }
 
 QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property)
@@ -131,56 +107,6 @@ QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &servic
     return QVariant();
 }
 
-void QGstreamerCaptureServicePlugin::updateDevices() const
-{
-    m_defaultCameraDevice.clear();
-    m_cameraDevices.clear();
-    m_cameraDescriptions.clear();
-
-    QDir devDir("/dev");
-    devDir.setFilter(QDir::System);
-
-    QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*");
-
-    foreach( const QFileInfo &entryInfo, entries ) {
-        //qDebug() << "Try" << entryInfo.filePath();
-
-        int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR );
-        if (fd == -1)
-            continue;
-
-        bool isCamera = false;
-
-        v4l2_input input;
-        memset(&input, 0, sizeof(input));
-        for (; ::ioctl(fd, VIDIOC_ENUMINPUT, &input) >= 0; ++input.index) {
-            if(input.type == V4L2_INPUT_TYPE_CAMERA || input.type == 0) {
-                isCamera = ::ioctl(fd, VIDIOC_S_INPUT, input.index) != 0;
-                break;
-            }
-        }
-
-        if (isCamera) {
-            // find out its driver "name"
-            QString name;
-            struct v4l2_capability vcap;
-            memset(&vcap, 0, sizeof(struct v4l2_capability));
-
-            if (ioctl(fd, VIDIOC_QUERYCAP, &vcap) != 0)
-                name = entryInfo.fileName();
-            else
-                name = QString((const char*)vcap.card);
-            //qDebug() << "found camera: " << name;
-
-            m_cameraDevices.append(entryInfo.filePath().toLocal8Bit());
-            m_cameraDescriptions.append(name);
-        }
-        qt_safe_close(fd);
-    }
-
-    if (!m_cameraDevices.isEmpty())
-        m_defaultCameraDevice = m_cameraDevices.first();
-}
 #endif
 
 QMultimedia::SupportEstimate QGstreamerCaptureServicePlugin::hasSupport(const QString &mimeType,
index a1141d3..a46be9e 100644 (file)
@@ -87,13 +87,6 @@ public:
     QStringList supportedMimeTypes() const;
 
 private:
-#if defined(USE_GSTREAMER_CAMERA)
-    void updateDevices() const;
-
-    mutable QByteArray m_defaultCameraDevice;
-    mutable QList<QByteArray> m_cameraDevices;
-    mutable QStringList m_cameraDescriptions;
-#endif
     void updateSupportedMimeTypes() const;
 
     mutable QSet<QString> m_supportedMimeTypeSet; //for fast access