Move qt_cam_copy_register to QtCamera
[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.isEmpty()) {
138     gst_object_unref (bin);
139
140     return 0;
141   }
142
143   if (added.size() > 1) {
144     for (int x = 1; x < added.count(); x++) {
145       GstElement *elem = added[x];
146       GstElement *prev = added[x - 1];
147
148       if (!gst_element_link(prev, elem)) {
149         qWarning() << "Failed to link" << FACTORY_NAME(prev) << "and" << FACTORY_NAME(elem);
150       }
151     }
152   }
153
154   GstPad *pad = gst_element_get_static_pad(added.first(), "sink");
155   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
156   gst_object_unref(GST_OBJECT(pad));
157
158   pad = gst_element_get_static_pad(added.last(), "src");
159   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
160   gst_object_unref(GST_OBJECT(pad));
161
162   QtCamAnalysisBinPrivate *d = qt_cam_analysis_bin_create(bin, name);
163   if (!d) {
164     return 0;
165   }
166
167   d->elements = elements;
168
169   return d;
170 }
171
172 /*
173  *       -- identity -- ghost pad
174  * tee -
175  *       -- queue -- copy -- filters -- fakesink
176  */
177 QtCamAnalysisBinPrivate *qt_cam_analysis_bin_create(GstElement *child, const char *name) {
178   GstPad *pad = 0;
179   GstPad *queuePad = 0;
180   QtCamAnalysisBinPrivate *d = 0;
181
182   GstElement *bin = gst_bin_new(name);
183
184   GstElement *tee = gst_element_factory_make("tee", "analysis-bin-tee");
185   GstElement *queue = gst_element_factory_make("queue", "analysis-bin-queue");
186   GstElement *fakesink = gst_element_factory_make("fakesink", "analysis-bin-fakesink");
187   GstElement *copy = gst_element_factory_make("copy", "analysis-bin-copy");
188   GstElement *identity = gst_element_factory_make("identity", "analysis-bin-identity");
189
190   if (!bin || !tee || !queue || !fakesink || !copy || !identity) {
191     qWarning() << "Failed to create some elements";
192     goto free_and_out;
193   }
194
195   gst_bin_add_many(GST_BIN(bin), tee, queue, copy, fakesink, child, identity, NULL);
196
197   g_object_set(tee, "silent", TRUE, NULL);
198   g_object_set(queue, "silent", TRUE, "leaky", 2, "max-size-buffers", 1, NULL);
199   g_object_set(fakesink, "silent", TRUE, "sync", FALSE, "async", FALSE, NULL);
200   g_object_set(identity, "silent", TRUE, "signal-handoffs", FALSE, NULL);
201
202   gst_element_link(tee, identity);
203   gst_element_link(tee, queue);
204   gst_element_link(queue, copy);
205   gst_element_link(copy, child);
206   gst_element_link(child, fakesink);
207
208   pad = gst_element_get_static_pad(tee, "sink");
209   gst_element_add_pad(bin, gst_ghost_pad_new("sink", pad));
210   gst_object_unref(GST_OBJECT(pad));
211
212   pad = gst_element_get_static_pad(identity, "src");
213   gst_element_add_pad(bin, gst_ghost_pad_new("src", pad));
214   gst_object_unref(GST_OBJECT(pad));
215
216   pad = gst_element_get_static_pad(tee, "src0");
217   g_object_set(tee, "alloc-pad", pad, NULL);
218   gst_object_unref(GST_OBJECT(pad));
219
220   queuePad = gst_element_get_static_pad(queue, "src");
221
222   d = new QtCamAnalysisBinPrivate;
223   d->queuePad = queuePad;
224   d->bin = bin;
225   return d;
226
227  free_and_out:
228   if (bin) {
229     gst_object_unref(bin);
230   }
231   else {
232     gst_object_unref(child);
233   }
234
235   if (tee) {
236     gst_object_unref(tee);
237   }
238
239   if (queue) {
240     gst_object_unref(queue);
241   }
242
243   if (copy) {
244     gst_object_unref(copy);
245   }
246
247   if (identity) {
248     gst_object_unref(identity);
249   }
250
251   if (fakesink) {
252     gst_object_unref(fakesink);
253   }
254
255   return 0;
256 }
257
258 QList<GstElement *> QtCamAnalysisBin::lookup(const QString& factory) {
259   if (d_ptr->elements.contains(factory)) {
260     return d_ptr->elements.values(factory);
261   }
262
263   return QList<GstElement *>();
264 }