Updated copyright year
[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
70   void setProperties(GstElement *element) {
71     QLatin1String name = elementName(element);
72     if (!name.latin1()) {
73       return;
74     }
75
76     QVariantMap map = properties(name);
77     if (map.isEmpty()) {
78       return;
79     }
80
81     QStringList keys = map.keys();
82     foreach (const QString& key, keys) {
83       QVariant value = map[key];
84       GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(element),
85                                                        key.toUtf8().constData());
86       if (!pspec) {
87         qWarning() << "Property" << key << "not available for" << name;
88         continue;
89       }
90
91       GType type = getType(pspec->value_type);
92
93       switch (type) {
94       case G_TYPE_INT:
95       case G_TYPE_ENUM:
96         setInt(element, key, value);
97         break;
98       case G_TYPE_UINT:
99         setUnsignedInt(element, key, value);
100         break;
101       case G_TYPE_STRING:
102         setString(element, key, value);
103         break;
104       case G_TYPE_BOOLEAN:
105         setBoolean(element, key, value);
106         break;
107       default:
108         if (type == gstFraction) {
109           setFraction(element, key, value);
110           break;
111         }
112
113         qWarning() << "Unsupported property type"
114                    << g_type_name(pspec->value_type) << "of parent" << g_type_name(type)
115                    << "for" << key << "of element" << name;
116         break;
117       }
118     }
119   }
120
121   QVariantMap properties(const QLatin1String& name) {
122     QVariantMap map;
123
124     conf->beginGroup(name);
125
126     QStringList keys = conf->allKeys();
127     foreach (const QString& key, keys) {
128       map[key] = conf->value(key);
129     }
130
131     conf->endGroup();
132     return map;
133   }
134
135   QLatin1String elementName(GstElement *elem) {
136     GstElementFactory *factory = gst_element_get_factory(elem);
137     if (!factory) {
138       return QLatin1String(0);
139     }
140
141     const char *n = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
142     if (!n) {
143       return QLatin1String(0);
144     }
145
146     QLatin1String name(n);
147
148     return name;
149   }
150
151   void setInt(GstElement *elem, const QString& key, const QVariant& value) {
152     if (!value.canConvert(QVariant::Int)) {
153       qWarning() << "Cannot convert" << value << "to int";
154       return;
155     }
156
157     g_object_set(elem, key.toUtf8().constData(), value.toInt(), NULL);
158   }
159
160   void setUnsignedInt(GstElement *elem, const QString& key, const QVariant& value) {
161     if (!value.canConvert(QVariant::UInt)) {
162       qWarning() << "Cannot convert" << value << "to unsigned int";
163       return;
164     }
165
166     g_object_set(elem, key.toUtf8().constData(), value.toUInt(), NULL);
167   }
168
169   void setString(GstElement *elem, const QString& key, const QVariant& value) {
170     if (!value.canConvert(QVariant::String)) {
171       qWarning() << "Cannot convert" << value << "to string";
172       return;
173     }
174
175     g_object_set(elem, key.toUtf8().constData(), value.toString().toUtf8().constData(), NULL);
176   }
177
178   void setBoolean(GstElement *elem, const QString& key, const QVariant& value) {
179     if (!value.canConvert(QVariant::Bool)) {
180       qWarning() << "Cannot convert" << value << "to bool";
181       return;
182     }
183
184     g_object_set(elem, key.toUtf8().constData(), value.toBool() ? TRUE : FALSE, NULL);
185   }
186
187   void setFraction(GstElement *elem, const QString& key, const QVariant& value) {
188     if (!value.canConvert(QVariant::List)) {
189       qWarning() << "Cannot convert" << value << "to list";
190       return;
191     }
192
193     QList<QVariant> list = value.toList();
194     if (list.size() != 2) {
195       qWarning() << "fraction list must contain 2 items";
196       return;
197     }
198
199     if (!list[0].canConvert(QVariant::Int) || !list[1].canConvert(QVariant::Int)) {
200       qWarning() << "list items cannot be converted to int";
201       return;
202     }
203
204     int val1 = list[0].toInt();
205     int val2 = list[1].toInt();
206
207     g_object_set(elem, key.toUtf8().constData(), val1, val2, NULL);
208   }
209
210   GType getType(GType parent) {
211     if (G_TYPE_IS_FUNDAMENTAL(parent)) {
212       return parent;
213     }
214
215     return getType(g_type_parent(parent));
216   }
217
218   static void element_added(GstBin *bin, GstElement *child, gpointer user_data) {
219     Q_UNUSED(bin);
220
221     QtCamPropertySetterPrivate *d = static_cast<QtCamPropertySetterPrivate *>(user_data);
222
223     if (GST_IS_BIN(child)) {
224       d->binAdded(child);
225     }
226     else {
227       d->setProperties(child);
228     }
229   }
230
231   QSettings *conf;
232   GType gstFraction;
233 };
234
235 QtCamPropertySetter::QtCamPropertySetter(QtCamDevicePrivate *pvt) :
236   d_ptr(new QtCamPropertySetterPrivate) {
237   d_ptr->conf = new QSettings(PROPERTIES_FILE, QSettings::IniFormat);
238   d_ptr->gstFraction = GST_TYPE_FRACTION;
239   d_ptr->binAdded(pvt->cameraBin);
240 }
241
242 QtCamPropertySetter::~QtCamPropertySetter() {
243   delete d_ptr->conf; d_ptr->conf = 0;
244   delete d_ptr; d_ptr = 0;
245 }