Provide face and orientation info from gstreamer camera backend.

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>
This commit is contained in:
Andrew den Exter
2014-07-08 15:56:05 +10:00
committed by Andrew den Exter
parent 074bd6ab37
commit cddbe8736d
15 changed files with 445 additions and 283 deletions

View File

@@ -44,43 +44,40 @@
#include <QtCore/QDir> #include <QtCore/QDir>
#include <QtCore/QDebug> #include <QtCore/QDebug>
#include <private/qcore_unix_p.h> #include <private/qgstutils_p.h>
#include <linux/videodev2.h>
QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(QObject *parent) 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) QGstreamerVideoInputDeviceControl::QGstreamerVideoInputDeviceControl(
:QVideoDeviceSelectorControl(parent), m_source(source), m_selectedDevice(0) GstElementFactory *factory, QObject *parent)
: QVideoDeviceSelectorControl(parent), m_factory(factory), m_selectedDevice(0)
{ {
if (m_source) if (m_factory)
gst_object_ref(GST_OBJECT(m_source)); gst_object_ref(GST_OBJECT(m_factory));
update();
} }
QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl() QGstreamerVideoInputDeviceControl::~QGstreamerVideoInputDeviceControl()
{ {
if (m_source) if (m_factory)
gst_object_unref(GST_OBJECT(m_source)); gst_object_unref(GST_OBJECT(m_factory));
} }
int QGstreamerVideoInputDeviceControl::deviceCount() const int QGstreamerVideoInputDeviceControl::deviceCount() const
{ {
return m_names.size(); return QGstUtils::enumerateCameras(m_factory).count();
} }
QString QGstreamerVideoInputDeviceControl::deviceName(int index) const QString QGstreamerVideoInputDeviceControl::deviceName(int index) const
{ {
return m_names[index]; return QGstUtils::enumerateCameras(m_factory).value(index).name;
} }
QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const QString QGstreamerVideoInputDeviceControl::deviceDescription(int index) const
{ {
return m_descriptions[index]; return QGstUtils::enumerateCameras(m_factory).value(index).description;
} }
int QGstreamerVideoInputDeviceControl::defaultDevice() const int QGstreamerVideoInputDeviceControl::defaultDevice() const
@@ -93,7 +90,6 @@ int QGstreamerVideoInputDeviceControl::selectedDevice() const
return m_selectedDevice; return m_selectedDevice;
} }
void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index) void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index)
{ {
if (index != m_selectedDevice) { if (index != m_selectedDevice) {
@@ -102,60 +98,3 @@ void QGstreamerVideoInputDeviceControl::setSelectedDevice(int index)
emit selectedDeviceChanged(deviceName(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);
}
}

View File

@@ -42,6 +42,7 @@
#include "qgstutils_p.h" #include "qgstutils_p.h"
#include <QtCore/qdatetime.h> #include <QtCore/qdatetime.h>
#include <QtCore/qdir.h>
#include <QtCore/qbytearray.h> #include <QtCore/qbytearray.h>
#include <QtCore/qvariant.h> #include <QtCore/qvariant.h>
#include <QtCore/qsize.h> #include <QtCore/qsize.h>
@@ -49,6 +50,11 @@
#include <QtCore/qstringlist.h> #include <QtCore/qstringlist.h>
#include <qaudioformat.h> #include <qaudioformat.h>
#include <private/qcore_unix_p.h>
#include <linux/videodev2.h>
#include "qgstreamervideoinputdevicecontrol_p.h"
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
//internal //internal
@@ -401,6 +407,165 @@ QMultimedia::SupportEstimate QGstUtils::hasSupport(const QString &mimeType,
return QMultimedia::MaybeSupported; 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) void qt_gst_object_ref_sink(gpointer object)
{ {
#if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 24) #if (GST_VERSION_MAJOR >= 0) && (GST_VERSION_MINOR >= 10) && (GST_VERSION_MICRO >= 24)

View File

@@ -46,6 +46,7 @@
#include <QtCore/qstringlist.h> #include <QtCore/qstringlist.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <qcamera.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -54,7 +55,7 @@ class QGstreamerVideoInputDeviceControl : public QVideoDeviceSelectorControl
Q_OBJECT Q_OBJECT
public: public:
QGstreamerVideoInputDeviceControl(QObject *parent); QGstreamerVideoInputDeviceControl(QObject *parent);
QGstreamerVideoInputDeviceControl(GstElement *source, QObject *parent); QGstreamerVideoInputDeviceControl(GstElementFactory *factory, QObject *parent);
~QGstreamerVideoInputDeviceControl(); ~QGstreamerVideoInputDeviceControl();
int deviceCount() const; int deviceCount() const;
@@ -65,17 +66,16 @@ public:
int defaultDevice() const; int defaultDevice() const;
int selectedDevice() const; int selectedDevice() const;
static QString primaryCamera() { return tr("Main camera"); }
static QString secondaryCamera() { return tr("Front camera"); }
public Q_SLOTS: public Q_SLOTS:
void setSelectedDevice(int index); void setSelectedDevice(int index);
private: private:
void update(); GstElementFactory *m_factory;
GstElement *m_source;
int m_selectedDevice; int m_selectedDevice;
QStringList m_names;
QStringList m_descriptions;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -55,8 +55,10 @@
#include <QtCore/qmap.h> #include <QtCore/qmap.h>
#include <QtCore/qset.h> #include <QtCore/qset.h>
#include <QtCore/qvector.h>
#include <gst/gst.h> #include <gst/gst.h>
#include <qaudioformat.h> #include <qaudioformat.h>
#include <qcamera.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -65,6 +67,14 @@ class QVariant;
class QByteArray; class QByteArray;
namespace QGstUtils { namespace QGstUtils {
struct CameraInfo
{
QString name;
QString description;
int orientation;
QCamera::Position position;
};
QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list); QMap<QByteArray, QVariant> gstTagListToMap(const GstTagList *list);
QSize capsResolution(const GstCaps *caps); QSize capsResolution(const GstCaps *caps);
@@ -76,6 +86,12 @@ namespace QGstUtils {
QMultimedia::SupportEstimate hasSupport(const QString &mimeType, QMultimedia::SupportEstimate hasSupport(const QString &mimeType,
const QStringList &codecs, const QStringList &codecs,
const QSet<QString> &supportedMimeTypeSet); 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); void qt_gst_object_ref_sink(gpointer object);

View File

@@ -30,7 +30,8 @@ HEADERS += \
$$PWD/camerabinresourcepolicy.h \ $$PWD/camerabinresourcepolicy.h \
$$PWD/camerabincapturedestination.h \ $$PWD/camerabincapturedestination.h \
$$PWD/camerabincapturebufferformat.h \ $$PWD/camerabincapturebufferformat.h \
$$PWD/camerabinviewfindersettings.h $$PWD/camerabinviewfindersettings.h \
$$PWD/camerabininfocontrol.h
SOURCES += \ SOURCES += \
$$PWD/camerabinserviceplugin.cpp \ $$PWD/camerabinserviceplugin.cpp \
@@ -48,7 +49,8 @@ SOURCES += \
$$PWD/camerabinresourcepolicy.cpp \ $$PWD/camerabinresourcepolicy.cpp \
$$PWD/camerabincapturedestination.cpp \ $$PWD/camerabincapturedestination.cpp \
$$PWD/camerabinviewfindersettings.cpp \ $$PWD/camerabinviewfindersettings.cpp \
$$PWD/camerabincapturebufferformat.cpp $$PWD/camerabincapturebufferformat.cpp \
$$PWD/camerabininfocontrol.cpp
maemo6 { maemo6 {
HEADERS += \ HEADERS += \

View File

@@ -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

View File

@@ -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

View File

@@ -48,6 +48,7 @@
#include "camerabinimageencoder.h" #include "camerabinimageencoder.h"
#include "camerabincontrol.h" #include "camerabincontrol.h"
#include "camerabinmetadata.h" #include "camerabinmetadata.h"
#include "camerabininfocontrol.h"
#ifdef HAVE_GST_PHOTOGRAPHY #ifdef HAVE_GST_PHOTOGRAPHY
#include "camerabinexposure.h" #include "camerabinexposure.h"
@@ -89,8 +90,9 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
CameraBinService::CameraBinService(const QString &service, QObject *parent): CameraBinService::CameraBinService(GstElementFactory *sourceFactory, QObject *parent):
QMediaService(parent) QMediaService(parent),
m_cameraInfoControl(0)
{ {
m_captureSession = 0; m_captureSession = 0;
m_metaDataControl = 0; m_metaDataControl = 0;
@@ -106,40 +108,32 @@ CameraBinService::CameraBinService(const QString &service, QObject *parent):
#endif #endif
m_imageCaptureControl = 0; m_imageCaptureControl = 0;
if (service == Q_MEDIASERVICE_CAMERA) { m_captureSession = new CameraBinSession(sourceFactory, this);
m_captureSession = new CameraBinSession(this); m_videoInputDevice = new QGstreamerVideoInputDeviceControl(sourceFactory, m_captureSession);
m_videoInputDevice = new QGstreamerVideoInputDeviceControl( m_imageCaptureControl = new CameraBinImageCapture(m_captureSession);
m_captureSession->buildCameraSource(), m_captureSession);
m_imageCaptureControl = new CameraBinImageCapture(m_captureSession);
connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)), connect(m_videoInputDevice, SIGNAL(selectedDeviceChanged(QString)),
m_captureSession, SLOT(setDevice(QString))); m_captureSession, SLOT(setDevice(QString)));
if (m_videoInputDevice->deviceCount()) if (m_videoInputDevice->deviceCount())
m_captureSession->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice())); m_captureSession->setDevice(m_videoInputDevice->deviceName(m_videoInputDevice->selectedDevice()));
#if defined(Q_WS_MAEMO_6) && defined(__arm__) && defined(HAVE_WIDGETS) #if defined(Q_WS_MAEMO_6) && defined(__arm__) && defined(HAVE_WIDGETS)
m_videoRenderer = new QGstreamerGLTextureRenderer(this); m_videoRenderer = new QGstreamerGLTextureRenderer(this);
#else #else
m_videoRenderer = new QGstreamerVideoRenderer(this); m_videoRenderer = new QGstreamerVideoRenderer(this);
#endif #endif
#ifdef Q_WS_MAEMO_6 #ifdef Q_WS_MAEMO_6
m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink"); m_videoWindow = new QGstreamerVideoWindow(this, "omapxvsink");
#else #else
m_videoWindow = new QGstreamerVideoWindow(this); m_videoWindow = new QGstreamerVideoWindow(this);
#endif #endif
#if defined(HAVE_WIDGETS) #if defined(HAVE_WIDGETS)
m_videoWidgetControl = new QGstreamerVideoWidgetControl(this); m_videoWidgetControl = new QGstreamerVideoWidgetControl(this);
#endif #endif
}
if (!m_captureSession) {
qWarning() << Q_FUNC_INFO << "Service type is not supported:" << service;
return;
}
m_audioInputSelector = new QGstreamerAudioInputSelector(this); m_audioInputSelector = new QGstreamerAudioInputSelector(this);
connect(m_audioInputSelector, SIGNAL(activeInputChanged(QString)), m_captureSession, SLOT(setCaptureDevice(QString))); 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) if (qstrcmp(name, QCameraViewfinderSettingsControl_iid) == 0)
return m_captureSession->viewfinderSettingsControl(); 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; return 0;
} }

View File

@@ -67,7 +67,7 @@ class CameraBinService : public QMediaService
Q_OBJECT Q_OBJECT
public: public:
CameraBinService(const QString &service, QObject *parent = 0); CameraBinService(GstElementFactory *sourceFactory, QObject *parent = 0);
virtual ~CameraBinService(); virtual ~CameraBinService();
QMediaControl *requestControl(const char *name); QMediaControl *requestControl(const char *name);
@@ -92,6 +92,7 @@ private:
QGstreamerVideoWidgetControl *m_videoWidgetControl; QGstreamerVideoWidgetControl *m_videoWidgetControl;
#endif #endif
CameraBinImageCapture *m_imageCaptureControl; CameraBinImageCapture *m_imageCaptureControl;
QMediaControl *m_cameraInfoControl;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -55,12 +55,25 @@
QT_BEGIN_NAMESPACE 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) QMediaService* CameraBinServicePlugin::create(const QString &key)
{ {
QGstUtils::initializeGst(); QGstUtils::initializeGst();
if (key == QLatin1String(Q_MEDIASERVICE_CAMERA)) if (key == QLatin1String(Q_MEDIASERVICE_CAMERA))
return new CameraBinService(key); return new CameraBinService(sourceFactory());
qWarning() << "Gstreamer camerabin service plugin: unsupported key:" << key; qWarning() << "Gstreamer camerabin service plugin: unsupported key:" << key;
return 0; return 0;
@@ -82,40 +95,24 @@ QMediaServiceProviderHint::Features CameraBinServicePlugin::supportedFeatures(
QByteArray CameraBinServicePlugin::defaultDevice(const QByteArray &service) const QByteArray CameraBinServicePlugin::defaultDevice(const QByteArray &service) const
{ {
if (service == Q_MEDIASERVICE_CAMERA) { return service == Q_MEDIASERVICE_CAMERA
if (m_cameraDevices.isEmpty()) ? QGstUtils::enumerateCameras(sourceFactory()).value(0).name.toUtf8()
updateDevices(); : QByteArray();
return m_defaultCameraDevice;
}
return QByteArray();
} }
QList<QByteArray> CameraBinServicePlugin::devices(const QByteArray &service) const QList<QByteArray> CameraBinServicePlugin::devices(const QByteArray &service) const
{ {
if (service == Q_MEDIASERVICE_CAMERA) {
if (m_cameraDevices.isEmpty())
updateDevices();
return m_cameraDevices; return service == Q_MEDIASERVICE_CAMERA
} ? QGstUtils::cameraDevices(m_sourceFactory)
: QList<QByteArray>();
return 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) { return service == Q_MEDIASERVICE_CAMERA
if (m_cameraDevices.isEmpty()) ? QGstUtils::cameraDescription(deviceName, m_sourceFactory)
updateDevices(); : QString();
for (int i=0; i<m_cameraDevices.count(); i++)
if (m_cameraDevices[i] == device)
return m_cameraDescriptions[i];
}
return QString();
} }
QVariant CameraBinServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property) 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(); return QVariant();
} }
void CameraBinServicePlugin::updateDevices() const QCamera::Position CameraBinServicePlugin::cameraPosition(const QByteArray &deviceName) const
{ {
m_defaultCameraDevice.clear(); return QGstUtils::cameraPosition(deviceName, m_sourceFactory);
m_cameraDevices.clear(); }
m_cameraDescriptions.clear();
QDir devDir("/dev"); int CameraBinServicePlugin::cameraOrientation(const QByteArray &deviceName) const
devDir.setFilter(QDir::System); {
return QGstUtils::cameraOrientation(deviceName, m_sourceFactory);
}
QFileInfoList entries = devDir.entryInfoList(QStringList() << "video*"); 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());
foreach (const QFileInfo &entryInfo, entries) { static const char *candidates[] = { "subdevsrc", "wrappercamerabinsrc" };
int fd = qt_safe_open(entryInfo.filePath().toLatin1().constData(), O_RDWR ); for (int i = 0; !factory && i < lengthOf(candidates); ++i)
if (fd == -1) factory = gst_element_factory_find(candidates[i]);
continue;
bool isCamera = false; if (factory) {
m_sourceFactory = GST_ELEMENT_FACTORY(gst_plugin_feature_load(
v4l2_input input; GST_PLUGIN_FEATURE(factory)));
memset(&input, 0, sizeof(input)); gst_object_unref((GST_OBJECT(factory)));
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()) return m_sourceFactory;
m_defaultCameraDevice = m_cameraDevices.first();
} }
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -44,7 +44,9 @@
#define CAMERABINSERVICEPLUGIN_H #define CAMERABINSERVICEPLUGIN_H
#include <qmediaserviceproviderplugin.h> #include <qmediaserviceproviderplugin.h>
#include <QtCore/QObject> #include <private/qgstreamervideoinputdevicecontrol_p.h>
#include <gst/gst.h>
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
@@ -53,13 +55,18 @@ class CameraBinServicePlugin
, public QMediaServiceSupportedDevicesInterface , public QMediaServiceSupportedDevicesInterface
, public QMediaServiceDefaultDeviceInterface , public QMediaServiceDefaultDeviceInterface
, public QMediaServiceFeaturesInterface , public QMediaServiceFeaturesInterface
, public QMediaServiceCameraInfoInterface
{ {
Q_OBJECT Q_OBJECT
Q_INTERFACES(QMediaServiceSupportedDevicesInterface) Q_INTERFACES(QMediaServiceSupportedDevicesInterface)
Q_INTERFACES(QMediaServiceDefaultDeviceInterface) Q_INTERFACES(QMediaServiceDefaultDeviceInterface)
Q_INTERFACES(QMediaServiceFeaturesInterface) Q_INTERFACES(QMediaServiceFeaturesInterface)
Q_INTERFACES(QMediaServiceCameraInfoInterface)
Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0" FILE "camerabin.json") Q_PLUGIN_METADATA(IID "org.qt-project.qt.mediaserviceproviderfactory/5.0" FILE "camerabin.json")
public: public:
CameraBinServicePlugin();
~CameraBinServicePlugin();
QMediaService* create(QString const& key); QMediaService* create(QString const& key);
void release(QMediaService *service); void release(QMediaService *service);
@@ -70,12 +77,13 @@ public:
QString deviceDescription(const QByteArray &service, const QByteArray &device); QString deviceDescription(const QByteArray &service, const QByteArray &device);
QVariant deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property); QVariant deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property);
private: QCamera::Position cameraPosition(const QByteArray &device) const;
void updateDevices() const; int cameraOrientation(const QByteArray &device) const;
mutable QByteArray m_defaultCameraDevice; private:
mutable QList<QByteArray> m_cameraDevices; GstElementFactory *sourceFactory() const;
mutable QStringList m_cameraDescriptions;
mutable GstElementFactory *m_sourceFactory;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@@ -119,7 +119,7 @@
QT_BEGIN_NAMESPACE QT_BEGIN_NAMESPACE
CameraBinSession::CameraBinSession(QObject *parent) CameraBinSession::CameraBinSession(GstElementFactory *sourceFactory, QObject *parent)
:QObject(parent), :QObject(parent),
m_recordingActive(false), m_recordingActive(false),
m_state(QCamera::UnloadedState), m_state(QCamera::UnloadedState),
@@ -133,6 +133,7 @@ CameraBinSession::CameraBinSession(QObject *parent)
m_viewfinderInterface(0), m_viewfinderInterface(0),
m_videoSrc(0), m_videoSrc(0),
m_viewfinderElement(0), m_viewfinderElement(0),
m_sourceFactory(sourceFactory),
m_viewfinderHasChanged(true), m_viewfinderHasChanged(true),
m_videoInputHasChanged(true), m_videoInputHasChanged(true),
m_audioSrc(0), m_audioSrc(0),
@@ -142,6 +143,9 @@ CameraBinSession::CameraBinSession(QObject *parent)
m_audioEncoder(0), m_audioEncoder(0),
m_muxer(0) m_muxer(0)
{ {
if (m_sourceFactory)
gst_object_ref(GST_OBJECT(m_sourceFactory));
m_camerabin = gst_element_factory_make("camerabin2", "camerabin2"); m_camerabin = gst_element_factory_make("camerabin2", "camerabin2");
g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this); g_signal_connect(G_OBJECT(m_camerabin), "notify::idle", G_CALLBACK(updateBusyStatus), this);
qt_gst_object_ref_sink(m_camerabin); qt_gst_object_ref_sink(m_camerabin);
@@ -195,6 +199,9 @@ CameraBinSession::~CameraBinSession()
} }
if (m_viewfinderElement) if (m_viewfinderElement)
gst_object_unref(GST_OBJECT(m_viewfinderElement)); gst_object_unref(GST_OBJECT(m_viewfinderElement));
if (m_sourceFactory)
gst_object_unref(GST_OBJECT(m_sourceFactory));
} }
#ifdef HAVE_GST_PHOTOGRAPHY #ifdef HAVE_GST_PHOTOGRAPHY
@@ -383,32 +390,17 @@ GstElement *CameraBinSession::buildCameraSource()
m_videoInputHasChanged = false; m_videoInputHasChanged = false;
GstElement *videoSrc = 0; GstElement *videoSrc = 0;
if (!videoSrc)
g_object_get(G_OBJECT(m_camerabin), CAMERA_SOURCE_PROPERTY, &videoSrc, NULL); 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 if (m_sourceFactory)
// it recommends. m_videoSrc = gst_element_factory_create(m_sourceFactory, "camera_source");
const QByteArray envCandidate = qgetenv("QT_GSTREAMER_CAMERABIN_SRC");
if (!m_videoSrc && !envCandidate.isEmpty()) {
m_videoSrc = gst_element_factory_make(envCandidate.constData(), "camera_source");
}
// If gstreamer has set a default source use it. // If gstreamer has set a default source use it.
if (!m_videoSrc) if (!m_videoSrc)
m_videoSrc = 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 (m_videoSrc && !m_inputDevice.isEmpty()) {
#if CAMERABIN_DEBUG #if CAMERABIN_DEBUG
qDebug() << "set camera device" << m_inputDevice; qDebug() << "set camera device" << m_inputDevice;

View File

@@ -96,7 +96,7 @@ public:
BackCamera // Main photo camera BackCamera // Main photo camera
}; };
CameraBinSession(QObject *parent); CameraBinSession(GstElementFactory *sourceFactory, QObject *parent);
~CameraBinSession(); ~CameraBinSession();
#ifdef HAVE_GST_PHOTOGRAPHY #ifdef HAVE_GST_PHOTOGRAPHY
@@ -121,6 +121,7 @@ public:
QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const; QString generateFileName(const QString &prefix, const QDir &dir, const QString &ext) const;
GstElement *buildCameraSource(); GstElement *buildCameraSource();
GstElementFactory *sourceFactory() const { return m_sourceFactory; }
CameraBinControl *cameraControl() const { return m_cameraControl; } CameraBinControl *cameraControl() const { return m_cameraControl; }
CameraBinAudioEncoder *audioEncodeControl() const { return m_audioEncodeControl; } CameraBinAudioEncoder *audioEncodeControl() const { return m_audioEncodeControl; }
@@ -239,6 +240,7 @@ private:
GstElement *m_camerabin; GstElement *m_camerabin;
GstElement *m_videoSrc; GstElement *m_videoSrc;
GstElement *m_viewfinderElement; GstElement *m_viewfinderElement;
GstElementFactory *m_sourceFactory;
bool m_viewfinderHasChanged; bool m_viewfinderHasChanged;
bool m_videoInputHasChanged; bool m_videoInputHasChanged;

View File

@@ -51,9 +51,6 @@
#include "qgstreamercaptureservice.h" #include "qgstreamercaptureservice.h"
#include <private/qgstutils_p.h> #include <private/qgstutils_p.h>
#include <private/qcore_unix_p.h>
#include <linux/videodev2.h>
QMediaService* QGstreamerCaptureServicePlugin::create(const QString &key) QMediaService* QGstreamerCaptureServicePlugin::create(const QString &key)
{ {
QGstUtils::initializeGst(); QGstUtils::initializeGst();
@@ -87,40 +84,19 @@ QMediaServiceProviderHint::Features QGstreamerCaptureServicePlugin::supportedFea
QByteArray QGstreamerCaptureServicePlugin::defaultDevice(const QByteArray &service) const QByteArray QGstreamerCaptureServicePlugin::defaultDevice(const QByteArray &service) const
{ {
if (service == Q_MEDIASERVICE_CAMERA) { return service == Q_MEDIASERVICE_CAMERA
if (m_cameraDevices.isEmpty()) ? QGstUtils::enumerateCameras().value(0).name.toUtf8()
updateDevices(); : QByteArray();
return m_defaultCameraDevice;
}
return QByteArray();
} }
QList<QByteArray> QGstreamerCaptureServicePlugin::devices(const QByteArray &service) const QList<QByteArray> QGstreamerCaptureServicePlugin::devices(const QByteArray &service) const
{ {
if (service == Q_MEDIASERVICE_CAMERA) { return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDevices() : QList<QByteArray>();
if (m_cameraDevices.isEmpty())
updateDevices();
return m_cameraDevices;
}
return QList<QByteArray>();
} }
QString QGstreamerCaptureServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device) QString QGstreamerCaptureServicePlugin::deviceDescription(const QByteArray &service, const QByteArray &device)
{ {
if (service == Q_MEDIASERVICE_CAMERA) { return service == Q_MEDIASERVICE_CAMERA ? QGstUtils::cameraDescription(deviceName) : QString();
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();
} }
QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property) QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &service, const QByteArray &device, const QByteArray &property)
@@ -131,56 +107,6 @@ QVariant QGstreamerCaptureServicePlugin::deviceProperty(const QByteArray &servic
return QVariant(); 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 #endif
QMultimedia::SupportEstimate QGstreamerCaptureServicePlugin::hasSupport(const QString &mimeType, QMultimedia::SupportEstimate QGstreamerCaptureServicePlugin::hasSupport(const QString &mimeType,

View File

@@ -87,13 +87,6 @@ public:
QStringList supportedMimeTypes() const; QStringList supportedMimeTypes() const;
private: 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; void updateSupportedMimeTypes() const;
mutable QSet<QString> m_supportedMimeTypeSet; //for fast access mutable QSet<QString> m_supportedMimeTypeSet; //for fast access