Added QtCamPropertySetter
[harmattan/cameraplus] / lib / qtcampropertysetter.cpp
diff --git a/lib/qtcampropertysetter.cpp b/lib/qtcampropertysetter.cpp
new file mode 100644 (file)
index 0000000..7d21e69
--- /dev/null
@@ -0,0 +1,245 @@
+/*!
+ * This file is part of CameraPlus.
+ *
+ * Copyright (C) 2012 Mohammed Sameer <msameer@foolab.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ */
+
+#include "qtcampropertysetter.h"
+#include "qtcamdevice_p.h"
+#include <QSettings>
+#include <QDebug>
+
+#define PROPERTIES_FILE                       "/etc/qtcamera/properties.ini"
+
+class QtCamPropertySetterPrivate {
+public:
+  void binAdded(GstElement *bin) {
+    g_signal_connect(bin, "element-added",
+                    G_CALLBACK(QtCamPropertySetterPrivate::element_added), this);
+
+    setProperties(bin);
+
+    // Let's traverse its children:
+    GstIterator *iter = gst_bin_iterate_elements(GST_BIN(bin));
+    if (!iter) {
+      return;
+    }
+
+    bool done = false;
+    GstElement *elem = 0;
+
+    while (!done) {
+      switch (gst_iterator_next(iter, (gpointer *)&elem)) {
+      case GST_ITERATOR_OK:
+       if (GST_IS_BIN(elem)) {
+         binAdded(elem);
+       }
+       else {
+         setProperties(elem);
+       }
+
+       gst_object_unref(elem);
+       break;
+      case GST_ITERATOR_RESYNC:
+       gst_iterator_resync(iter);
+       break;
+      case GST_ITERATOR_ERROR:
+       done = TRUE;
+       break;
+      case GST_ITERATOR_DONE:
+       done = TRUE;
+       break;
+      }
+    }
+  }
+
+  void setProperties(GstElement *element) {
+    QLatin1String name = elementName(element);
+    if (!name.latin1()) {
+      return;
+    }
+
+    QVariantMap map = properties(name);
+    if (map.isEmpty()) {
+      return;
+    }
+
+    QStringList keys = map.keys();
+    foreach (const QString& key, keys) {
+      QVariant value = map[key];
+      GParamSpec *pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(element),
+                                                      key.toUtf8().constData());
+      if (!pspec) {
+       qWarning() << "Property" << key << "not available for" << name;
+       continue;
+      }
+
+      GType type = getType(pspec->value_type);
+
+      switch (type) {
+      case G_TYPE_INT:
+      case G_TYPE_ENUM:
+       setInt(element, key, value);
+       break;
+      case G_TYPE_UINT:
+       setUnsignedInt(element, key, value);
+       break;
+      case G_TYPE_STRING:
+       setString(element, key, value);
+       break;
+      case G_TYPE_BOOLEAN:
+       setBoolean(element, key, value);
+       break;
+      default:
+       if (type == gstFraction) {
+         setFraction(element, key, value);
+         break;
+       }
+
+       qWarning() << "Unsupported property type"
+                  << g_type_name(pspec->value_type) << "of parent" << g_type_name(type)
+                  << "for" << key << "of element" << name;
+       break;
+      }
+    }
+  }
+
+  QVariantMap properties(const QLatin1String& name) {
+    QVariantMap map;
+
+    conf->beginGroup(name);
+
+    QStringList keys = conf->allKeys();
+    foreach (const QString& key, keys) {
+      map[key] = conf->value(key);
+    }
+
+    conf->endGroup();
+    return map;
+  }
+
+  QLatin1String elementName(GstElement *elem) {
+    GstElementFactory *factory = gst_element_get_factory(elem);
+    if (!factory) {
+      return QLatin1String(0);
+    }
+
+    const char *n = gst_plugin_feature_get_name(GST_PLUGIN_FEATURE(factory));
+    if (!n) {
+      return QLatin1String(0);
+    }
+
+    QLatin1String name(n);
+
+    return name;
+  }
+
+  void setInt(GstElement *elem, const QString& key, const QVariant& value) {
+    if (!value.canConvert(QVariant::Int)) {
+      qWarning() << "Cannot convert" << value << "to int";
+      return;
+    }
+
+    g_object_set(elem, key.toUtf8().constData(), value.toInt(), NULL);
+  }
+
+  void setUnsignedInt(GstElement *elem, const QString& key, const QVariant& value) {
+    if (!value.canConvert(QVariant::UInt)) {
+      qWarning() << "Cannot convert" << value << "to unsigned int";
+      return;
+    }
+
+    g_object_set(elem, key.toUtf8().constData(), value.toUInt(), NULL);
+  }
+
+  void setString(GstElement *elem, const QString& key, const QVariant& value) {
+    if (!value.canConvert(QVariant::String)) {
+      qWarning() << "Cannot convert" << value << "to string";
+      return;
+    }
+
+    g_object_set(elem, key.toUtf8().constData(), value.toString().toUtf8().constData(), NULL);
+  }
+
+  void setBoolean(GstElement *elem, const QString& key, const QVariant& value) {
+    if (!value.canConvert(QVariant::Bool)) {
+      qWarning() << "Cannot convert" << value << "to bool";
+      return;
+    }
+
+    g_object_set(elem, key.toUtf8().constData(), value.toBool() ? TRUE : FALSE, NULL);
+  }
+
+  void setFraction(GstElement *elem, const QString& key, const QVariant& value) {
+    if (!value.canConvert(QVariant::List)) {
+      qWarning() << "Cannot convert" << value << "to list";
+      return;
+    }
+
+    QList<QVariant> list = value.toList();
+    if (list.size() != 2) {
+      qWarning() << "fraction list must contain 2 items";
+      return;
+    }
+
+    if (!list[0].canConvert(QVariant::Int) || !list[1].canConvert(QVariant::Int)) {
+      qWarning() << "list items cannot be converted to int";
+      return;
+    }
+
+    int val1 = list[0].toInt();
+    int val2 = list[1].toInt();
+
+    g_object_set(elem, key.toUtf8().constData(), val1, val2, NULL);
+  }
+
+  GType getType(GType parent) {
+    if (G_TYPE_IS_FUNDAMENTAL(parent)) {
+      return parent;
+    }
+
+    return getType(g_type_parent(parent));
+  }
+
+  static void element_added(GstBin *bin, GstElement *child, gpointer user_data) {
+    Q_UNUSED(bin);
+
+    QtCamPropertySetterPrivate *d = static_cast<QtCamPropertySetterPrivate *>(user_data);
+
+    if (GST_IS_BIN(child)) {
+      d->binAdded(child);
+    }
+    else {
+      d->setProperties(child);
+    }
+  }
+
+  QSettings *conf;
+  GType gstFraction;
+};
+
+QtCamPropertySetter::QtCamPropertySetter(QtCamDevicePrivate *pvt) :
+  d_ptr(new QtCamPropertySetterPrivate) {
+  d_ptr->conf = new QSettings(PROPERTIES_FILE, QSettings::IniFormat);
+  d_ptr->gstFraction = GST_TYPE_FRACTION;
+  d_ptr->binAdded(pvt->cameraBin);
+}
+
+QtCamPropertySetter::~QtCamPropertySetter() {
+  delete d_ptr->conf; d_ptr->conf = 0;
+  delete d_ptr; d_ptr = 0;
+}