Updated copyright year
[harmattan/cameraplus] / lib / qtcamanalysisbin.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012-2013 Mohammed Sameer <msameer@foolab.org>
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
19  */
20
21 #include "qtcamanalysisbin.h"
22 #include <QStringList>
23 #include <QDebug>
24 #include <QHash>
25
26 #define FACTORY_NAME(x) gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(x)))
27
28 static QtCamAnalysisBinPrivate *qt_cam_analysis_bin_create(const QStringList& factories,
29                                                            const char *name);
30 static QtCamAnalysisBinPrivate *qt_cam_analysis_bin_create(GstElement *child,
31                                                            const char *name);
32
33 class QtCamAnalysisBinPrivate {
34 public:
35   QtCamAnalysisBinPrivate() :
36     bin(0),
37     probe(0),
38     queuePad(0) {
39
40   }
41
42   static gboolean block_buffers(GstPad *pad, GstMiniObject *o) {
43     Q_UNUSED(pad);
44     Q_UNUSED(o);
45
46     // Drop data
47     return FALSE;
48   }
49
50   GstElement *bin;
51   gulong probe;
52   GstPad *queuePad;
53   QMultiHash<QString, GstElement *> elements;
54 };
55
56 QtCamAnalysisBin::QtCamAnalysisBin(QtCamAnalysisBinPrivate *d) :
57   d_ptr(d) {
58   gst_object_ref(d_ptr->bin);
59 }
60
61 QtCamAnalysisBin::~QtCamAnalysisBin() {
62   d_ptr->elements.clear();
63
64   setBlocked(false);
65   gst_object_unref(GST_OBJECT(d_ptr->queuePad));
66   gst_object_unref(d_ptr->bin);
67   delete d_ptr; d_ptr = 0;
68 }
69
70 void QtCamAnalysisBin::setBlocked(bool blocked) {
71   if (blocked == isBlocked()) {
72     return;
73   }
74
75   if (blocked) {
76     d_ptr->probe = gst_pad_add_buffer_probe(d_ptr->queuePad,
77                                             G_CALLBACK(QtCamAnalysisBinPrivate::block_buffers),
78                                             d_ptr);
79   }
80   else {
81     gst_pad_remove_data_probe(d_ptr->queuePad, d_ptr->probe);
82     d_ptr->probe = 0;
83   }
84 }
85
86 bool QtCamAnalysisBin::isBlocked() const {
87   return d_ptr->probe != 0;
88 }
89
90 GstElement *QtCamAnalysisBin::bin() {
91   return d_ptr->bin;
92 }
93
94 QtCamAnalysisBin *QtCamAnalysisBin::create(const QStringList& factories, const char *name) {
95   QList<GstElement *> elements;
96   if (factories.isEmpty()) {
97     return 0;
98   }
99
100   QtCamAnalysisBinPrivate *d = qt_cam_analysis_bin_create(factories, name);
101   if (!d) {
102     return 0;
103   }
104
105   return new QtCamAnalysisBin(d);
106 }
107
108 QtCamAnalysisBinPrivate *qt_cam_analysis_bin_create(const QStringList& factories,
109                                                     const char *name) {
110
111   if (factories.isEmpty()) {
112     return 0;
113   }
114
115   GstElement *bin = 0;
116   QHash<QString, GstElement *> elements;
117   QList<GstElement *> added;
118
119   bin = gst_bin_new("analysis-bin-bin");
120
121   foreach (const QString& factory, factories) {
122     GstElement *element = gst_element_factory_make(factory.toUtf8().constData(), NULL);
123     if (!element) {
124       qWarning() << "Failed to create element" << factory;
125       continue;
126     }
127
128     if (!gst_bin_add(GST_BIN(bin), element)) {
129       qWarning() << "Failed to add element" << factory << "to bin";
130       gst_object_unref(element);
131     }
132
133     elements.insert(factory, element);
134     added << element;
135   }
136
137   if (added.size() > 1) {
138     for (int x = 1; x < added.count(); x++) {
139       GstElement *elem = added[x];
140       GstElement *prev = added[x - 1];
141
142       if (!gst_element_link(prev, elem)) {
143         qWarning() << "Failed to link" << FACTORY_NAME(prev) << "and" << FACTORY_NAME(elem);
144       }
145     }
146   }
147
148   GstPad *pad = gst_element_get_static_pad(added.first(), "sink");
149   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
150   gst_object_unref(GST_OBJECT(pad));
151
152   pad = gst_element_get_static_pad(added.last(), "src");
153   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
154   gst_object_unref(GST_OBJECT(pad));
155
156   QtCamAnalysisBinPrivate *d = qt_cam_analysis_bin_create(bin, name);
157   if (!d) {
158     return 0;
159   }
160
161   d->elements = elements;
162
163   return d;
164 }
165
166 /*
167  *       -- identity -- ghost pad
168  * tee -
169  *       -- queue -- copy -- filters -- fakesink
170  */
171 QtCamAnalysisBinPrivate *qt_cam_analysis_bin_create(GstElement *child, const char *name) {
172   GstPad *pad = 0;
173   GstPad *queuePad = 0;
174   QtCamAnalysisBinPrivate *d = 0;
175
176   GstElement *bin = gst_bin_new(name);
177
178   GstElement *tee = gst_element_factory_make("tee", "analysis-bin-tee");
179   GstElement *queue = gst_element_factory_make("queue", "analysis-bin-queue");
180   GstElement *fakesink = gst_element_factory_make("fakesink", "analysis-bin-fakesink");
181   GstElement *copy = gst_element_factory_make("copy", "analysis-bin-copy");
182   GstElement *identity = gst_element_factory_make("identity", "analysis-bin-identity");
183
184   if (!bin || !tee || !queue || !fakesink || !copy || !identity) {
185     qWarning() << "Failed to create some elements";
186     goto free_and_out;
187   }
188
189   gst_bin_add_many(GST_BIN(bin), tee, queue, copy, fakesink, child, identity, NULL);
190
191   g_object_set(tee, "silent", TRUE, NULL);
192   g_object_set(queue, "silent", TRUE, "leaky", 2, "max-size-buffers", 1, NULL);
193   g_object_set(fakesink, "silent", TRUE, "sync", FALSE, "async", FALSE, NULL);
194   g_object_set(identity, "silent", TRUE, "signal-handoffs", FALSE, NULL);
195
196   gst_element_link(tee, identity);
197   gst_element_link(tee, queue);
198   gst_element_link(queue, copy);
199   gst_element_link(copy, child);
200   gst_element_link(child, fakesink);
201
202   pad = gst_element_get_static_pad(tee, "sink");
203   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
204   gst_object_unref(GST_OBJECT(pad));
205
206   pad = gst_element_get_static_pad(identity, "src");
207   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
208   gst_object_unref(GST_OBJECT(pad));
209
210   pad = gst_element_get_static_pad(tee, "src0");
211   g_object_set(tee, "alloc-pad", pad, NULL);
212   gst_object_unref(GST_OBJECT(pad));
213
214   queuePad = gst_element_get_static_pad(queue, "src");
215
216   d = new QtCamAnalysisBinPrivate;
217   d->queuePad = queuePad;
218   d->bin = bin;
219   return d;
220
221  free_and_out:
222   if (bin) {
223     gst_object_unref(bin);
224   }
225   else {
226     gst_object_unref(child);
227   }
228
229   if (tee) {
230     gst_object_unref(tee);
231   }
232
233   if (queue) {
234     gst_object_unref(queue);
235   }
236
237   if (copy) {
238     gst_object_unref(copy);
239   }
240
241   if (identity) {
242     gst_object_unref(identity);
243   }
244
245   if (fakesink) {
246     gst_object_unref(fakesink);
247   }
248
249   return 0;
250 }
251
252 QList<GstElement *> QtCamAnalysisBin::lookup(const QString& factory) {
253   if (d_ptr->elements.contains(factory)) {
254     return d_ptr->elements.values(factory);
255   }
256
257   return QList<GstElement *>();
258 }