Free the iterator after iterating on bin elements.
[harmattan/cameraplus] / lib / qtcampropertysetter.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 "qtcampropertysetter.h"
22 #include "qtcamdevice_p.h"
23 #include <QSettings>
24 #include <QDebug>
25
26 #define PROPERTIES_FILE                       DATA_DIR"/properties.ini"
27
28 class QtCamPropertySetterPrivate {
29 public:
30   void binAdded(GstElement *bin) {
31     g_signal_connect(bin, "element-added",
32                      G_CALLBACK(QtCamPropertySetterPrivate::element_added), this);
33
34     setProperties(bin);
35
36     // Let's traverse its children:
37     GstIterator *iter = gst_bin_iterate_elements(GST_BIN(bin));
38     if (!iter) {
39       return;
40     }
41
42     bool done = false;
43     GstElement *elem = 0;
44
45     while (!done) {
46       switch (gst_iterator_next(iter, (gpointer *)&elem)) {
47       case GST_ITERATOR_OK:
48         if (GST_IS_BIN(elem)) {
49           binAdded(elem);
50         }
51         else {
52           setProperties(elem);
53         }
54
55         gst_object_unref(elem);
56         break;
57
58       case GST_ITERATOR_RESYNC:
59         gst_iterator_resync(iter);
60         break;
61
62       case GST_ITERATOR_ERROR:
63       case GST_ITERATOR_DONE:
64         done = true;
65         break;
66       }
67     }
68
69     gst_iterator_free(iter);
70   }
71
72   void setProperties(GstElement *element) {
73     QLatin1String name = elementName(element);
74     if (!name.latin1()) {
75       return;
76     }
77
78     QVariantMap map = properties(name);
79     if (map.isEmpty()) {
80       return;
81     }
82
83     QStringList keys = map.keys();
84     foreach (const QString& key, keys) {
85       QVariant value = map[key];
86       GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(element),
87                                                        key.toUtf8().constData());
88       if (!pspec) {
89         qWarning() << "Property" << key << "not available for" << name;
90         continue;
91       }
92
93       GType type = getType(pspec->value_type);
94
95       switch (type) {
96       case G_TYPE_INT:
97       case G_TYPE_ENUM:
98         setInt(element, key, value);
99         break;
100       case G_TYPE_UINT:
101         setUnsignedInt(element, key, value);
102         break;
103       case G_TYPE_STRING:
104         setString(element, key, value);
105         break;
106       case G_TYPE_BOOLEAN:
107         setBoolean(element, key, value);
108         break;
109       default:
110         if (type == gstFraction) {
111           setFraction(element, key, value);
112           break;
113         }
114
115         qWarning() << "Unsupported property type"
116                    << g_type_name(pspec->value_type) << "of parent" << g_type_name(type)
117                    << "for" << key << "of element" << name;
118         break;
119       }
120     }
121   }
122
123   QVariantMap properties(const QLatin1String& name) {
124     QVariantMap map;
125
126     conf->beginGroup(name);
127
128     QStringList keys = conf->allKeys();
129     foreach (const QString& key, keys) {
130       map[key] = conf->value(key);
131     }
132
133     conf->endGroup();
134     return map;
135   }
136
137   QLatin1String elementName(GstElement *elem) {
138     GstElementFactory *factory = gst_element_get_factory(elem);
139     if (!factory) {
140       return QLatin1String(0);
141     }
142
143     const char *n = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
144     if (!n) {
145       return QLatin1String(0);
146     }
147
148     QLatin1String name(n);
149
150     return name;
151   }
152
153   void setInt(GstElement *elem, const QString& key, const QVariant& value) {
154     if (!value.canConvert(QVariant::Int)) {
155       qWarning() << "Cannot convert" << value << "to int";
156       return;
157     }
158
159     g_object_set(elem, key.toUtf8().constData(), value.toInt(), NULL);
160   }
161
162   void setUnsignedInt(GstElement *elem, const QString& key, const QVariant& value) {
163     if (!value.canConvert(QVariant::UInt)) {
164       qWarning() << "Cannot convert" << value << "to unsigned int";
165       return;
166     }
167
168     g_object_set(elem, key.toUtf8().constData(), value.toUInt(), NULL);
169   }
170
171   void setString(GstElement *elem, const QString& key, const QVariant& value) {
172     if (!value.canConvert(QVariant::String)) {
173       qWarning() << "Cannot convert" << value << "to string";
174       return;
175     }
176
177     g_object_set(elem, key.toUtf8().constData(), value.toString().toUtf8().constData(), NULL);
178   }
179
180   void setBoolean(GstElement *elem, const QString& key, const QVariant& value) {
181     if (!value.canConvert(QVariant::Bool)) {
182       qWarning() << "Cannot convert" << value << "to bool";
183       return;
184     }
185
186     g_object_set(elem, key.toUtf8().constData(), value.toBool() ? TRUE : FALSE, NULL);
187   }
188
189   void setFraction(GstElement *elem, const QString& key, const QVariant& value) {
190     if (!value.canConvert(QVariant::List)) {
191       qWarning() << "Cannot convert" << value << "to list";
192       return;
193     }
194
195     QList<QVariant> list = value.toList();
196     if (list.size() != 2) {
197       qWarning() << "fraction list must contain 2 items";
198       return;
199     }
200
201     if (!list[0].canConvert(QVariant::Int) || !list[1].canConvert(QVariant::Int)) {
202       qWarning() << "list items cannot be converted to int";
203       return;
204     }
205
206     int val1 = list[0].toInt();
207     int val2 = list[1].toInt();
208
209     g_object_set(elem, key.toUtf8().constData(), val1, val2, NULL);
210   }
211
212   GType getType(GType parent) {
213     if (G_TYPE_IS_FUNDAMENTAL(parent)) {
214       return parent;
215     }
216
217     return getType(g_type_parent(parent));
218   }
219
220   static void element_added(GstBin *bin, GstElement *child, gpointer user_data) {
221     Q_UNUSED(bin);
222
223     QtCamPropertySetterPrivate *d = static_cast<QtCamPropertySetterPrivate *>(user_data);
224
225     if (GST_IS_BIN(child)) {
226       d->binAdded(child);
227     }
228     else {
229       d->setProperties(child);
230     }
231   }
232
233   QSettings *conf;
234   GType gstFraction;
235 };
236
237 QtCamPropertySetter::QtCamPropertySetter(QtCamDevicePrivate *pvt) :
238   d_ptr(new QtCamPropertySetterPrivate) {
239   d_ptr->conf = new QSettings(PROPERTIES_FILE, QSettings::IniFormat);
240   d_ptr->gstFraction = GST_TYPE_FRACTION;
241   d_ptr->binAdded(pvt->cameraBin);
242 }
243
244 QtCamPropertySetter::~QtCamPropertySetter() {
245   delete d_ptr->conf; d_ptr->conf = 0;
246   delete d_ptr; d_ptr = 0;
247 }