Set media.name to '*'.
[harmattan/cameraplus] / lib / qtcamroi_p.h
1 // -*- c++ -*-
2
3 /*!
4  * This file is part of CameraPlus.
5  *
6  * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
21  */
22
23 #ifndef QT_CAM_ROI_P_H
24 #define QT_CAM_ROI_P_H
25
26 #include "qtcamdevice.h"
27 #include "qtcamdevice_p.h"
28 #include "qtcamanalysisbin.h"
29 #include "qtcamgstreamermessagehandler.h"
30 #include "qtcamgstreamermessagelistener.h"
31 #include "qtcamroi.h"
32 #include <QDebug>
33 #include <QPointer>
34 #include <cmath>
35
36 class QtCamRoiPrivate : public QObject {
37   Q_OBJECT
38
39 public:
40   QtCamRoiPrivate(QtCamDevice *device, QtCamRoi *q, QObject *parent = 0) :
41     QObject(parent),
42     q_ptr(q),
43     dev(device),
44     roi(0),
45     msg(0) {
46
47   }
48
49   ~QtCamRoiPrivate() {
50     if (roi) {
51       gst_object_unref(roi);
52     }
53
54     if (handler) {
55       dev->listener()->removeSyncHandler(handler);
56
57       delete handler.data();
58     }
59
60     GstMessage *message = msg.fetchAndStoreOrdered(0);
61     if (message) {
62       gst_message_unref(message);
63       message = 0;
64     }
65   }
66
67   bool sendEventToSource(GstEvent *event) {
68     if (!dev->d_ptr->videoSource) {
69       qWarning() << "No video source";
70       gst_event_unref(event);
71       return false;
72     }
73
74     return gst_element_send_event(dev->d_ptr->videoSource, event) == TRUE ? true : false;
75   }
76
77   void init() {
78     if (!dev->d_ptr->viewfinderFilters) {
79       return;
80     }
81
82     QList<GstElement *> elements =
83       dev->d_ptr->viewfinderFilters->lookup(dev->config()->roiElement());
84     if (elements.isEmpty()) {
85       qWarning() << "Cannot find element" << dev->config()->roiElement();
86     }
87     else if (elements.size() > 1) {
88       qWarning() << "Found multiple element of" << dev->config()->roiElement();
89     }
90     else {
91       roi = GST_ELEMENT(gst_object_ref(elements.at(0)));
92     }
93   }
94
95   void installHandler() {
96
97     if (dev->listener()) {
98       handler = new QtCamGStreamerMessageHandler(dev->config()->roiMessage(), this);
99       dev->listener()->addSyncHandler(handler);
100       QObject::connect(handler, SIGNAL(messageSent(GstMessage *)),
101                        this, SLOT(handleMessage(GstMessage *)), Qt::DirectConnection);
102     }
103   }
104
105   int primaryRegion(const QRectF& area, const QList<QRectF>& rects) {
106     int index = -1;
107     qreal distance = 0.0;
108     QPointF center = area.center();
109
110     for (int x = 0; x < rects.size(); x++) {
111       const QRectF& rect = rects.at(x);
112
113       QPointF val = rect.center() - center;
114
115       qreal newDistance = sqrt(pow(val.x(), 2) + pow(val.y(), 2));
116       if (index == -1 || newDistance < distance) {
117         index = x;
118         distance = newDistance;
119       }
120     }
121
122     return index;
123   }
124
125 public slots:
126   void handleMessage(GstMessage *message) {
127     gst_message_ref(message);
128
129     GstMessage *oldMessage = msg.fetchAndStoreOrdered(message);
130
131     if (oldMessage) {
132       gst_message_unref(oldMessage);
133     }
134
135     QMetaObject::invokeMethod(this, "processMessage", Qt::QueuedConnection);
136   }
137
138 private slots:
139   void processMessage() {
140     GstMessage *message = msg.fetchAndStoreOrdered(0);
141     if (!message) {
142       return;
143     }
144
145     QList<QRectF> rects;
146     unsigned width = 0, height = 0;
147
148     const GstStructure *s = gst_message_get_structure(message);
149     if (!gst_structure_get_uint(s, "frame-width", &width) ||
150         !gst_structure_get_uint(s, "frame-height", &height)) {
151
152       qWarning() << "Failed to obtain frame dimensions for ROI message";
153       gst_message_unref(message);
154       return;
155     }
156
157     const GValue *regions = gst_structure_get_value(s, "regions");
158     if (!regions) {
159       qWarning() << "No regions in ROI message";
160       gst_message_unref(message);
161       return;
162     }
163
164     guint size = gst_value_list_get_size(regions);
165     for (unsigned i = 0; i < size; i++) {
166       const GValue *region = gst_value_list_get_value(regions, i);
167       const GstStructure *structure = gst_value_get_structure(region);
168
169       unsigned x = 0, y = 0, w = 0, h = 0;
170
171       gst_structure_get_uint(structure, "region-x", &x);
172       gst_structure_get_uint(structure, "region-y", &y);
173       gst_structure_get_uint(structure, "region-w", &w);
174       gst_structure_get_uint(structure, "region-h", &h);
175
176       QRectF rect((qreal)x/width, (qreal)y/height, (qreal)w/width, (qreal)h/height);
177
178       rects << rect;
179     }
180
181     int index = primaryRegion(QRectF(0, 0, 1, 1), rects);
182
183     QList<QRectF> rest(rects);
184     QRectF primary = index == -1 ? QRectF() : rest.takeAt(index);
185
186     emit q_ptr->regionsOfInterestUpdated(rects, primary, rest);
187
188     gst_message_unref(message);
189   }
190
191 public:
192   QtCamRoi *q_ptr;
193   QtCamDevice *dev;
194   GstElement *roi;
195   QPointer<QtCamGStreamerMessageHandler> handler;
196   QAtomicPointer<GstMessage> msg;
197 };
198
199 #endif /* QT_CAM_ROI_P_H */