summaryrefslogtreecommitdiffstats
path: root/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/gstreamer/camerabin/camerabinfocus.cpp')
-rw-r--r--src/plugins/gstreamer/camerabin/camerabinfocus.cpp272
1 files changed, 229 insertions, 43 deletions
diff --git a/src/plugins/gstreamer/camerabin/camerabinfocus.cpp b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
index 665e20443..32b8d9454 100644
--- a/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
+++ b/src/plugins/gstreamer/camerabin/camerabinfocus.cpp
@@ -1,7 +1,7 @@
/****************************************************************************
**
-** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
-** Contact: http://www.qt-project.org/legal
+** Copyright (C) 2015 The Qt Company Ltd.
+** Contact: http://www.qt.io/licensing/
**
** This file is part of the Qt Toolkit.
**
@@ -10,9 +10,9 @@
** 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.
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see http://www.qt.io/terms-conditions. For further
+** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
@@ -23,8 +23,8 @@
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** 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
+** As a special exception, The Qt Company gives you certain additional
+** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
@@ -37,16 +37,26 @@
#include <gst/interfaces/photography.h>
#include <QDebug>
+#include <QtCore/qcoreevent.h>
#include <QtCore/qmetaobject.h>
+#include <private/qgstutils_p.h>
+
+#if !GST_CHECK_VERSION(1,0,0)
+typedef GstFocusMode GstPhotographyFocusMode;
+#endif
+
//#define CAMERABIN_DEBUG 1
QT_BEGIN_NAMESPACE
CameraBinFocus::CameraBinFocus(CameraBinSession *session)
:QCameraFocusControl(session),
+#if GST_CHECK_VERSION(1,0,0)
+ QGstreamerBufferProbe(ProbeBuffers),
+#endif
m_session(session),
- m_cameraState(QCamera::UnloadedState),
+ m_cameraStatus(QCamera::UnloadedStatus),
m_focusMode(QCameraFocus::AutoFocus),
m_focusPointMode(QCameraFocus::FocusPointAuto),
m_focusStatus(QCamera::Unlocked),
@@ -58,8 +68,8 @@ CameraBinFocus::CameraBinFocus(CameraBinSession *session)
gst_photography_set_focus_mode(m_session->photography(), GST_PHOTOGRAPHY_FOCUS_MODE_AUTO);
- connect(m_session, SIGNAL(stateChanged(QCamera::State)),
- this, SLOT(_q_handleCameraStateChange(QCamera::State)));
+ connect(m_session, SIGNAL(statusChanged(QCamera::Status)),
+ this, SLOT(_q_handleCameraStatusChange(QCamera::Status)));
}
CameraBinFocus::~CameraBinFocus()
@@ -73,7 +83,7 @@ QCameraFocus::FocusModes CameraBinFocus::focusMode() const
void CameraBinFocus::setFocusMode(QCameraFocus::FocusModes mode)
{
- GstFocusMode photographyMode;
+ GstPhotographyFocusMode photographyMode;
switch (mode) {
case QCameraFocus::AutoFocus:
@@ -125,22 +135,72 @@ QCameraFocus::FocusPointMode CameraBinFocus::focusPointMode() const
void CameraBinFocus::setFocusPointMode(QCameraFocus::FocusPointMode mode)
{
- Q_UNUSED(mode);
- if (m_focusPointMode != mode
- && (mode == QCameraFocus::FocusPointAuto || mode == QCameraFocus::FocusPointCustom)) {
- m_focusPointMode = mode;
+ GstElement *source = m_session->cameraSource();
+
+ if (m_focusPointMode == mode || !source)
+ return;
- if (m_focusPointMode == QCameraFocus::FocusPointAuto)
- resetFocusPoint();
+#if GST_CHECK_VERSION(1,0,0)
+ if (m_focusPointMode == QCameraFocus::FocusPointFaceDetection) {
+ g_object_set (G_OBJECT(source), "detect-faces", FALSE, NULL);
+
+ if (GstPad *pad = gst_element_get_static_pad(source, "vfsrc")) {
+ removeProbeFromPad(pad);
+ gst_object_unref(GST_OBJECT(pad));
+ }
+
+ m_faceResetTimer.stop();
+ m_faceFocusRects.clear();
+
+ QMutexLocker locker(&m_mutex);
+ m_faces.clear();
+ }
+#endif
- emit focusPointModeChanged(m_focusPointMode);
+ if (m_focusPointMode != QCameraFocus::FocusPointAuto)
+ resetFocusPoint();
+ switch (mode) {
+ case QCameraFocus::FocusPointAuto:
+ case QCameraFocus::FocusPointCustom:
+ break;
+#if GST_CHECK_VERSION(1,0,0)
+ case QCameraFocus::FocusPointFaceDetection:
+ if (g_object_class_find_property(G_OBJECT_GET_CLASS(source), "detect-faces")) {
+ if (GstPad *pad = gst_element_get_static_pad(source, "vfsrc")) {
+ addProbeToPad(pad);
+ g_object_set (G_OBJECT(source), "detect-faces", TRUE, NULL);
+ break;
+ }
+ }
+ return;
+#endif
+ default:
+ return;
}
+
+ m_focusPointMode = mode;
+ emit focusPointModeChanged(m_focusPointMode);
+ emit focusZonesChanged();
}
bool CameraBinFocus::isFocusPointModeSupported(QCameraFocus::FocusPointMode mode) const
{
return mode == QCameraFocus::FocusPointAuto || mode == QCameraFocus::FocusPointCustom;
+
+ switch (mode) {
+ case QCameraFocus::FocusPointAuto:
+ case QCameraFocus::FocusPointCustom:
+ return true;
+#if GST_CHECK_VERSION(1,0,0)
+ case QCameraFocus::FocusPointFaceDetection:
+ if (GstElement *source = m_session->cameraSource())
+ return g_object_class_find_property(G_OBJECT_GET_CLASS(source), "detect-faces");
+ return false;
+#endif
+ default:
+ return false;
+ }
}
QPointF CameraBinFocus::customFocusPoint() const
@@ -161,7 +221,7 @@ void CameraBinFocus::setCustomFocusPoint(const QPointF &point)
const QRectF focusRect = m_focusRect;
m_focusRect.moveCenter(m_focusPoint);
- updateRegionOfInterest(m_focusRect, 1);
+ updateRegionOfInterest(m_focusRect);
if (focusRect != m_focusRect) {
emit focusZonesChanged();
@@ -174,16 +234,30 @@ void CameraBinFocus::setCustomFocusPoint(const QPointF &point)
QCameraFocusZoneList CameraBinFocus::focusZones() const
{
- return QCameraFocusZoneList() << QCameraFocusZone(m_focusRect, m_focusZoneStatus);
+ QCameraFocusZoneList zones;
+
+ if (m_focusPointMode != QCameraFocus::FocusPointFaceDetection) {
+ zones.append(QCameraFocusZone(m_focusRect, m_focusZoneStatus));
+#if GST_CHECK_VERSION(1,0,0)
+ } else foreach (const QRect &face, m_faceFocusRects) {
+ const QRectF normalizedRect(
+ face.x() / qreal(m_viewfinderResolution.width()),
+ face.y() / qreal(m_viewfinderResolution.height()),
+ face.width() / qreal(m_viewfinderResolution.width()),
+ face.height() / qreal(m_viewfinderResolution.height()));
+ zones.append(QCameraFocusZone(normalizedRect, m_focusZoneStatus));
+#endif
+ }
+ return zones;
}
-
void CameraBinFocus::handleFocusMessage(GstMessage *gm)
{
//it's a sync message, so it's called from non main thread
- if (gst_structure_has_name(gm->structure, GST_PHOTOGRAPHY_AUTOFOCUS_DONE)) {
+ const GstStructure *structure = gst_message_get_structure(gm);
+ if (gst_structure_has_name(structure, GST_PHOTOGRAPHY_AUTOFOCUS_DONE)) {
gint status = GST_PHOTOGRAPHY_FOCUS_STATUS_NONE;
- gst_structure_get_int (gm->structure, "status", &status);
+ gst_structure_get_int (structure, "status", &status);
QCamera::LockStatus focusStatus = m_focusStatus;
QCamera::LockChangeReason reason = QCamera::UserRequest;
@@ -234,16 +308,23 @@ void CameraBinFocus::_q_setFocusStatus(QCamera::LockStatus status, QCamera::Lock
emit focusZonesChanged();
}
+#if GST_CHECK_VERSION(1,0,0)
+ if (m_focusPointMode == QCameraFocus::FocusPointFaceDetection
+ && m_focusStatus == QCamera::Unlocked) {
+ _q_updateFaces();
+ }
+#endif
+
emit _q_focusStatusChanged(m_focusStatus, reason);
}
}
-void CameraBinFocus::_q_handleCameraStateChange(QCamera::State state)
+void CameraBinFocus::_q_handleCameraStatusChange(QCamera::Status status)
{
- m_cameraState = state;
- if (state == QCamera::ActiveState) {
+ m_cameraStatus = status;
+ if (status == QCamera::ActiveStatus) {
if (GstPad *pad = gst_element_get_static_pad(m_session->cameraSource(), "vfsrc")) {
- if (GstCaps *caps = gst_pad_get_negotiated_caps(pad)) {
+ if (GstCaps *caps = qt_gst_pad_get_current_caps(pad)) {
if (GstStructure *structure = gst_caps_get_structure(caps, 0)) {
int width = 0;
int height = 0;
@@ -256,7 +337,7 @@ void CameraBinFocus::_q_handleCameraStateChange(QCamera::State state)
gst_object_unref(GST_OBJECT(pad));
}
if (m_focusPointMode == QCameraFocus::FocusPointCustom) {
- updateRegionOfInterest(m_focusRect, 1);
+ updateRegionOfInterest(m_focusRect);
}
} else {
_q_setFocusStatus(QCamera::Unlocked, QCamera::LockLost);
@@ -295,7 +376,7 @@ void CameraBinFocus::resetFocusPoint()
m_focusPoint = QPointF(0.5, 0.5);
m_focusRect.moveCenter(m_focusPoint);
- updateRegionOfInterest(QRectF(0, 0, 0, 0), 0);
+ updateRegionOfInterest(QVector<QRect>());
if (focusRect != m_focusRect) {
emit customFocusPointChanged(m_focusPoint);
@@ -303,21 +384,14 @@ void CameraBinFocus::resetFocusPoint()
}
}
-void CameraBinFocus::updateRegionOfInterest(const QRectF &focusRect, int priority)
+static void appendRegion(GValue *regions, int priority, const QRect &rectangle)
{
- if (m_cameraState != QCamera::ActiveState)
- return;
-
- GstElement * const cameraSource = m_session->cameraSource();
- if (!cameraSource)
- return;
-
GstStructure *region = gst_structure_new(
"region",
- "region-x" , G_TYPE_UINT , uint(m_viewfinderResolution.width() * focusRect.x()),
- "region-y" , G_TYPE_UINT, uint(m_viewfinderResolution.height() * focusRect.y()),
- "region-w" , G_TYPE_UINT , uint(m_viewfinderResolution.width() * focusRect.width()),
- "region-h" , G_TYPE_UINT, uint(m_viewfinderResolution.height() * focusRect.height()),
+ "region-x" , G_TYPE_UINT , rectangle.x(),
+ "region-y" , G_TYPE_UINT, rectangle.y(),
+ "region-w" , G_TYPE_UINT , rectangle.width(),
+ "region-h" , G_TYPE_UINT, rectangle.height(),
"region-priority" , G_TYPE_UINT, priority,
NULL);
@@ -326,10 +400,51 @@ void CameraBinFocus::updateRegionOfInterest(const QRectF &focusRect, int priorit
gst_value_set_structure(&regionValue, region);
gst_structure_free(region);
+ gst_value_list_append_value(regions, &regionValue);
+ g_value_unset(&regionValue);
+}
+
+void CameraBinFocus::updateRegionOfInterest(const QRectF &rectangle)
+{
+ updateRegionOfInterest(QVector<QRect>() << QRect(
+ rectangle.x() * m_viewfinderResolution.width(),
+ rectangle.y() * m_viewfinderResolution.height(),
+ rectangle.width() * m_viewfinderResolution.width(),
+ rectangle.height() * m_viewfinderResolution.height()));
+}
+
+void CameraBinFocus::updateRegionOfInterest(const QVector<QRect> &rectangles)
+{
+ if (m_cameraStatus != QCamera::ActiveStatus)
+ return;
+
+ GstElement * const cameraSource = m_session->cameraSource();
+ if (!cameraSource)
+ return;
+
GValue regions = G_VALUE_INIT;
g_value_init(&regions, GST_TYPE_LIST);
- gst_value_list_append_value(&regions, &regionValue);
- g_value_unset(&regionValue);
+
+ if (rectangles.isEmpty()) {
+ appendRegion(&regions, 0, QRect(0, 0, 0, 0));
+ } else {
+ // Add padding around small face rectangles so the auto focus has a reasonable amount
+ // of image to work with.
+ const int minimumDimension = qMin(
+ m_viewfinderResolution.width(), m_viewfinderResolution.height()) * 0.3;
+ const QRect viewfinderRectangle(QPoint(0, 0), m_viewfinderResolution);
+
+ foreach (const QRect &rectangle, rectangles) {
+ QRect paddedRectangle(
+ 0,
+ 0,
+ qMax(rectangle.width(), minimumDimension),
+ qMax(rectangle.height(), minimumDimension));
+ paddedRectangle.moveCenter(rectangle.center());
+
+ appendRegion(&regions, 1, viewfinderRectangle.intersected(paddedRectangle));
+ }
+ }
GstStructure *regionsOfInterest = gst_structure_new(
"regions-of-interest",
@@ -343,4 +458,75 @@ void CameraBinFocus::updateRegionOfInterest(const QRectF &focusRect, int priorit
gst_element_send_event(cameraSource, event);
}
+#if GST_CHECK_VERSION(1,0,0)
+
+void CameraBinFocus::_q_updateFaces()
+{
+ if (m_focusPointMode != QCameraFocus::FocusPointFaceDetection
+ || m_focusStatus != QCamera::Unlocked) {
+ return;
+ }
+
+ QVector<QRect> faces;
+
+ {
+ QMutexLocker locker(&m_mutex);
+ faces = m_faces;
+ }
+
+ if (!faces.isEmpty()) {
+ m_faceResetTimer.stop();
+ m_faceFocusRects = faces;
+ updateRegionOfInterest(m_faceFocusRects);
+ emit focusZonesChanged();
+ } else {
+ m_faceResetTimer.start(500, this);
+ }
+}
+
+void CameraBinFocus::timerEvent(QTimerEvent *event)
+{
+ if (event->timerId() == m_faceResetTimer.timerId()) {
+ m_faceResetTimer.stop();
+
+ if (m_focusStatus == QCamera::Unlocked) {
+ m_faceFocusRects.clear();
+ updateRegionOfInterest(m_faceFocusRects);
+ emit focusZonesChanged();
+ }
+ } else {
+ QCameraFocusControl::timerEvent(event);
+ }
+}
+
+bool CameraBinFocus::probeBuffer(GstBuffer *buffer)
+{
+ QVector<QRect> faces;
+
+ gpointer state = NULL;
+ const GstMetaInfo *info = GST_VIDEO_REGION_OF_INTEREST_META_INFO;
+
+ while (GstMeta *meta = gst_buffer_iterate_meta(buffer, &state)) {
+ if (meta->info->api != info->api)
+ continue;
+
+ GstVideoRegionOfInterestMeta *region = reinterpret_cast<GstVideoRegionOfInterestMeta *>(meta);
+
+ faces.append(QRect(region->x, region->y, region->w, region->h));
+ }
+
+ QMutexLocker locker(&m_mutex);
+
+ if (m_faces != faces) {
+ m_faces = faces;
+
+ static const int signalIndex = metaObject()->indexOfSlot("_q_updateFaces()");
+ metaObject()->method(signalIndex).invoke(this, Qt::QueuedConnection);
+ }
+
+ return true;
+}
+
+#endif
+
QT_END_NAMESPACE