f38e2c25d72d3c80d13adda8de314c74274ecc4f
[harmattan/cameraplus] / lib / qtcamanalysisbin.cpp
1 /*!
2  * This file is part of CameraPlus.
3  *
4  * Copyright (C) 2012 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
25 #define FACTORY_NAME(x) gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(gst_element_get_factory(x)))
26
27 static GstElement *qt_cam_analysis_bin_create(QList<GstElement *>& children,
28                                               const char *name, GstPad **queuePad);
29 static GstElement *qt_cam_analysis_bin_create(GstElement *child,
30                                               const char *name, GstPad **queuePad);
31
32 class QtCamAnalysisBinPrivate {
33 public:
34   QtCamAnalysisBinPrivate() :
35     bin(0),
36     probe(0),
37     queuePad(0) {
38
39   }
40
41   static gboolean block_buffers(GstPad *pad, GstMiniObject *o) {
42     Q_UNUSED(pad);
43     Q_UNUSED(o);
44
45     // Drop data
46     return FALSE;
47   }
48
49   GstElement *bin;
50   gulong probe;
51   GstPad *queuePad;
52 };
53
54 QtCamAnalysisBin::QtCamAnalysisBin(QtCamAnalysisBinPrivate *d) :
55   d_ptr(d) {
56   gst_object_ref(d_ptr->bin);
57 }
58
59 QtCamAnalysisBin::~QtCamAnalysisBin() {
60   setBlocked(false);
61   gst_object_unref(GST_OBJECT(d_ptr->queuePad));
62   gst_object_unref(d_ptr->bin);
63   delete d_ptr; d_ptr = 0;
64 }
65
66 void QtCamAnalysisBin::setBlocked(bool blocked) {
67   if (blocked == isBlocked()) {
68     return;
69   }
70
71   if (blocked) {
72     d_ptr->probe = gst_pad_add_buffer_probe(d_ptr->queuePad,
73                                             G_CALLBACK(QtCamAnalysisBinPrivate::block_buffers),
74                                             d_ptr);
75   }
76   else {
77     gst_pad_remove_data_probe(d_ptr->queuePad, d_ptr->probe);
78     d_ptr->probe = 0;
79   }
80 }
81
82 bool QtCamAnalysisBin::isBlocked() const {
83   return d_ptr->probe != 0;
84 }
85
86 GstElement *QtCamAnalysisBin::bin() {
87   return d_ptr->bin;
88 }
89
90 QtCamAnalysisBin *QtCamAnalysisBin::create(const QStringList& factories, const char *name) {
91   QList<GstElement *> elements;
92   if (factories.isEmpty()) {
93     return 0;
94   }
95
96   foreach (const QString& factory, factories) {
97     GstElement *element = gst_element_factory_make(factory.toUtf8().constData(), NULL);
98     if (!element) {
99       qWarning() << "Failed to create element" << factory;
100       continue;
101     }
102
103     elements << element;
104   }
105
106   GstPad *pad = 0;
107   GstElement *bin = qt_cam_analysis_bin_create(elements, name, &pad);
108   if (!bin) {
109     return 0;
110   }
111
112   QtCamAnalysisBinPrivate *d = new QtCamAnalysisBinPrivate;
113   d->bin = bin;
114   d->queuePad = pad;
115
116   return new QtCamAnalysisBin(d);
117 }
118
119 GstElement *qt_cam_analysis_bin_create(QList<GstElement *>& children,
120                                        const char *name, GstPad **queuePad) {
121   GstElement *bin = 0;
122
123   QList<GstElement *> added;
124
125   if (children.isEmpty()) {
126     return 0;
127   }
128
129   if (children.size() == 1) {
130     return qt_cam_analysis_bin_create(children.takeFirst(), name, queuePad);
131   }
132
133   bin = gst_bin_new("analysis-bin-bin");
134
135   while (!children.isEmpty()) {
136     GstElement *elem = children.takeFirst();
137
138     if (!gst_bin_add(GST_BIN(bin), elem)) {
139       qWarning() << "Failed to add element" << FACTORY_NAME(elem) << "to bin";
140       gst_object_unref(elem);
141     }
142     else {
143       added << elem;
144     }
145   }
146
147   for (int x = 1; x < added.count(); x++) {
148     GstElement *elem = added[x];
149     GstElement *prev = added[x - 1];
150
151     if (!gst_element_link(prev, elem)) {
152       qWarning() << "Failed to link" << FACTORY_NAME(prev) << "and" << FACTORY_NAME(elem);
153     }
154   }
155
156   GstPad *pad = gst_element_get_static_pad(added.first(), "sink");
157   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
158   gst_object_unref(GST_OBJECT(pad));
159
160   pad = gst_element_get_static_pad(added.last(), "src");
161   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
162   gst_object_unref(GST_OBJECT(pad));
163
164   return qt_cam_analysis_bin_create(bin, name, queuePad);
165 }
166
167 /*
168  *       -- identity -- ghost pad
169  * tee -
170  *       -- queue -- copy -- filters -- fakesink
171  */
172 GstElement *qt_cam_analysis_bin_create(GstElement *child, const char *name, GstPad **queuePad) {
173   GstPad *pad = 0;
174
175   GstElement *bin = gst_bin_new(name);
176
177   GstElement *tee = gst_element_factory_make("tee", "analysis-bin-tee");
178   GstElement *queue = gst_element_factory_make("queue", "analysis-bin-queue");
179   GstElement *fakesink = gst_element_factory_make("fakesink", "analysis-bin-fakesink");
180   GstElement *copy = gst_element_factory_make("copy", "analysis-bin-copy");
181   GstElement *identity = gst_element_factory_make("identity", "analysis-bin-identity");
182
183   if (!bin || !tee || !queue || !fakesink || !copy || !identity) {
184     qWarning() << "Failed to create some elements";
185     goto free_and_out;
186   }
187
188   gst_bin_add_many(GST_BIN(bin), tee, queue, copy, fakesink, child, identity, NULL);
189
190   g_object_set(tee, "silent", TRUE, NULL);
191   g_object_set(queue, "silent", TRUE, "leaky", 2, "max-size-buffers", 1, NULL);
192   g_object_set(fakesink, "silent", TRUE, "sync", FALSE, "async", FALSE, NULL);
193   g_object_set(identity, "silent", TRUE, "signal-handoffs", FALSE, NULL);
194
195   gst_element_link(tee, identity);
196   gst_element_link(tee, queue);
197   gst_element_link(queue, copy);
198   gst_element_link(copy, child);
199   gst_element_link(child, fakesink);
200
201   pad = gst_element_get_static_pad(tee, "sink");
202   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
203   gst_object_unref(GST_OBJECT(pad));
204
205   pad = gst_element_get_static_pad(identity, "src");
206   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
207   gst_object_unref(GST_OBJECT(pad));
208
209   pad = gst_element_get_static_pad(tee, "src0");
210   g_object_set(tee, "alloc-pad", pad, NULL);
211   gst_object_unref(GST_OBJECT(pad));
212
213   *queuePad = gst_element_get_static_pad(queue, "src");
214
215   return bin;
216
217  free_and_out:
218   if (bin) {
219     gst_object_unref(bin);
220   }
221   else {
222     gst_object_unref(child);
223   }
224
225   if (tee) {
226     gst_object_unref(tee);
227   }
228
229   if (queue) {
230     gst_object_unref(queue);
231   }
232
233   if (copy) {
234     gst_object_unref(copy);
235   }
236
237   if (identity) {
238     gst_object_unref(identity);
239   }
240
241   if (fakesink) {
242     gst_object_unref(fakesink);
243   }
244
245   return 0;
246 }