+// -*- c++ -*-
+
+/*!
+ * This file is part of CameraPlus.
+ *
+ * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifndef QT_CAM_ROI_P_H
+#define QT_CAM_ROI_P_H
+
+#include "qtcamdevice.h"
+#include "qtcamdevice_p.h"
+#include "qtcamanalysisbin.h"
+#include "qtcamgstreamermessagehandler.h"
+#include "qtcamgstreamermessagelistener.h"
+#include "qtcamroi.h"
+#include <QDebug>
+#include <QPointer>
+#include <cmath>
+
+class QtCamRoiPrivate : public QObject {
+ Q_OBJECT
+
+public:
+ QtCamRoiPrivate(QtCamDevice *device, QtCamRoi *q, QObject *parent = 0) :
+ QObject(parent),
+ q_ptr(q),
+ dev(device),
+ roi(0),
+ msg(0) {
+
+ }
+
+ ~QtCamRoiPrivate() {
+ if (roi) {
+ gst_object_unref(roi);
+ }
+
+ if (handler) {
+ dev->listener()->removeSyncHandler(handler);
+
+ delete handler.data();
+ }
+
+ GstMessage *message = msg.fetchAndStoreOrdered(0);
+ if (message) {
+ gst_message_unref(message);
+ message = 0;
+ }
+ }
+
+ bool sendEventToSource(GstEvent *event) {
+ if (!dev->d_ptr->videoSource) {
+ qWarning() << "No video source";
+ gst_event_unref(event);
+ return false;
+ }
+
+ return gst_element_send_event(dev->d_ptr->videoSource, event) == TRUE ? true : false;
+ }
+
+ void init() {
+ if (!dev->d_ptr->viewfinderFilters) {
+ return;
+ }
+
+ QList<GstElement *> elements =
+ dev->d_ptr->viewfinderFilters->lookup(dev->config()->roiElement());
+ if (elements.isEmpty()) {
+ qWarning() << "Cannot find element" << dev->config()->roiElement();
+ }
+ else if (elements.size() > 1) {
+ qWarning() << "Found multiple element of" << dev->config()->roiElement();
+ }
+ else {
+ roi = GST_ELEMENT(gst_object_ref(elements.at(0)));
+ }
+ }
+
+ void installHandler() {
+
+ if (dev->listener()) {
+ handler = new QtCamGStreamerMessageHandler(dev->config()->roiMessage(), this);
+ dev->listener()->addSyncHandler(handler);
+ QObject::connect(handler, SIGNAL(messageSent(GstMessage *)),
+ this, SLOT(handleMessage(GstMessage *)), Qt::DirectConnection);
+ }
+ }
+
+ int primaryRegion(const QRectF& area, const QList<QRectF>& rects) {
+ int index = -1;
+ qreal distance = 0.0;
+ QPointF center = area.center();
+
+ for (int x = 0; x < rects.size(); x++) {
+ const QRectF& rect = rects.at(x);
+
+ QPointF val = rect.center() - center;
+
+ qreal newDistance = sqrt(pow(val.x(), 2) + pow(val.y(), 2));
+ if (index == -1 || newDistance < distance) {
+ index = x;
+ distance = newDistance;
+ }
+ }
+
+ return -1;
+ }
+
+public slots:
+ void handleMessage(GstMessage *message) {
+ gst_message_ref(message);
+
+ GstMessage *oldMessage = msg.fetchAndStoreOrdered(message);
+
+ if (oldMessage) {
+ gst_message_unref(oldMessage);
+ }
+
+ QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection);
+ }
+
+private slots:
+ void processMessage() {
+ GstMessage *message = msg.fetchAndStoreOrdered(0);
+ if (!message) {
+ return;
+ }
+
+ QList<QRectF> rects;
+ unsigned width = 0, height = 0;
+
+ const GstStructure *s = gst_message_get_structure(message);
+ if (!gst_structure_get_uint(s, "frame-width", &width) ||
+ !gst_structure_get_uint(s, "frame-height", &height)) {
+
+ qWarning() << "Failed to obtain frame dimensions for ROI message";
+ gst_message_unref(message);
+ return;
+ }
+
+ const GValue *regions = gst_structure_get_value(s, "regions");
+ if (!regions) {
+ qWarning() << "No regions in ROI message";
+ gst_message_unref(message);
+ return;
+ }
+
+ guint size = gst_value_list_get_size(regions);
+ for (unsigned i = 0; i < size; i++) {
+ const GValue *region = gst_value_list_get_value(regions, i);
+ const GstStructure *structure = gst_value_get_structure(region);
+
+ unsigned x = 0, y = 0, w = 0, h = 0;
+
+ gst_structure_get_uint(structure, "region-x", &x);
+ gst_structure_get_uint(structure, "region-y", &y);
+ gst_structure_get_uint(structure, "region-w", &w);
+ gst_structure_get_uint(structure, "region-h", &h);
+
+ QRectF rect((qreal)x/width, (qreal)y/height, (qreal)w/width, (qreal)h/height);
+
+ rects << rect;
+ }
+
+ int index = primaryRegion(QRectF(0, 0, width, height), rects);
+
+ QList<QRectF> rest(rects);
+ QRectF primary = index == -1 ? QRectF() : rest.takeAt(index);
+
+ emit q_ptr->regionsOfInterestUpdated(rects, primary, rest);
+
+ gst_message_unref(message);
+ }
+
+public:
+ QtCamRoi *q_ptr;
+ QtCamDevice *dev;
+ GstElement *roi;
+ QPointer<QtCamGStreamerMessageHandler> handler;
+ QAtomicPointer<GstMessage> msg;
+};
+
+#endif /* QT_CAM_ROI_P_H */