Merge branch '0.10'
[platform/upstream/gstreamer.git] / ges / ges-track-effect.c
1 /* GStreamer Editing Services
2  * Copyright (C) 2010 Thibault Saunier <tsaunier@gnome.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the
16  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17  * Boston, MA 02111-1307, USA.
18  */
19
20 /**
21  * SECTION:ges-track-effect
22  * @short_description: adds an effect to a stream in a #GESTimelineSource or a
23  * #GESTimelineLayer
24  *
25  * @Since: 0.10.2
26  */
27
28 #include <glib/gprintf.h>
29 #include <string.h>
30
31 #include "ges-internal.h"
32 #include "ges-track-object.h"
33 #include "ges-track-effect.h"
34
35 G_DEFINE_ABSTRACT_TYPE (GESTrackEffect, ges_track_effect,
36     GES_TYPE_TRACK_OPERATION);
37
38 static GHashTable *ges_track_effect_get_props_hashtable (GESTrackObject * self);
39 guint pspec_hash (gconstpointer key_spec);
40 static gboolean pspec_equal (gconstpointer key_spec_1,
41     gconstpointer key_spec_2);
42
43 struct _GESTrackEffectPrivate
44 {
45   void *nothing;
46 };
47
48 static void
49 ges_track_effect_class_init (GESTrackEffectClass * klass)
50 {
51   GESTrackObjectClass *obj_bg_class = GES_TRACK_OBJECT_CLASS (klass);
52
53   g_type_class_add_private (klass, sizeof (GESTrackEffectPrivate));
54
55   obj_bg_class->get_props_hastable = ges_track_effect_get_props_hashtable;
56 }
57
58 static void
59 ges_track_effect_init (GESTrackEffect * self)
60 {
61   self->priv =
62       G_TYPE_INSTANCE_GET_PRIVATE (self, GES_TYPE_TRACK_EFFECT,
63       GESTrackEffectPrivate);
64 }
65
66 static gboolean
67 pspec_equal (gconstpointer key_spec_1, gconstpointer key_spec_2)
68 {
69   const GParamSpec *key1 = key_spec_1;
70   const GParamSpec *key2 = key_spec_2;
71
72   return (key1->owner_type == key2->owner_type &&
73       strcmp (key1->name, key2->name) == 0);
74 }
75
76 guint
77 pspec_hash (gconstpointer key_spec)
78 {
79   const GParamSpec *key = key_spec;
80   const gchar *p;
81   guint h = key->owner_type;
82
83   for (p = key->name; *p; p++)
84     h = (h << 5) - h + *p;
85
86   return h;
87 }
88
89 /*  Virtual methods */
90 static GHashTable *
91 ges_track_effect_get_props_hashtable (GESTrackObject * self)
92 {
93   GValue item = { 0, };
94   GstIterator *it;
95   GParamSpec **parray;
96   GObjectClass *class;
97   const gchar *klass;
98   GstElementFactory *factory;
99   GstElement *element;
100   gboolean done = FALSE;
101   GHashTable *ret = NULL;
102
103   element = ges_track_object_get_element (self);
104   if (!element) {
105     GST_DEBUG
106         ("Can't build the property hashtable until the gnlobject is created");
107     return NULL;
108   }
109
110   ret = g_hash_table_new_full ((GHashFunc) pspec_hash, pspec_equal,
111       (GDestroyNotify) g_param_spec_unref, gst_object_unref);
112
113   /*  We go over child elements recursivly, and add writable properties to the
114    *  hashtable
115    *  FIXME: Add a blacklist of properties */
116   it = gst_bin_iterate_recurse (GST_BIN (element));
117
118   while (!done) {
119     switch (gst_iterator_next (it, &item)) {
120       case GST_ITERATOR_OK:
121       {
122         gchar **categories;
123         guint category;
124         GstElement *child = g_value_get_object (&item);
125
126         factory = gst_element_get_factory (child);
127         klass = gst_element_factory_get_klass (factory);
128
129         GST_DEBUG ("Looking at element '%s' of klass '%s'",
130             GST_ELEMENT_NAME (child), klass);
131
132         categories = g_strsplit (klass, "/", 0);
133
134         for (category = 0; categories[category]; category++) {
135           if (g_strcmp0 (categories[category], "Effect") == 0) {
136             guint i, nb_specs;
137
138             class = G_OBJECT_GET_CLASS (child);
139             parray = g_object_class_list_properties (class, &nb_specs);
140             for (i = 0; i < nb_specs; i++) {
141               if (parray[i]->flags & G_PARAM_WRITABLE) {
142                 g_hash_table_insert (ret, g_param_spec_ref (parray[i]),
143                     gst_object_ref (child));
144               }
145             }
146             g_free (parray);
147
148             GST_DEBUG
149                 ("%d configurable properties of '%s' added to property hashtable",
150                 nb_specs, GST_ELEMENT_NAME (child));
151             break;
152           }
153         }
154
155         g_strfreev (categories);
156         g_value_reset (&item);
157         break;
158       }
159       case GST_ITERATOR_RESYNC:
160         /* FIXME, properly restart the process */
161         GST_DEBUG ("iterator resync");
162         gst_iterator_resync (it);
163         break;
164
165       case GST_ITERATOR_DONE:
166         GST_DEBUG ("iterator done");
167         done = TRUE;
168         break;
169
170       default:
171         break;
172     }
173   }
174   g_value_unset (&item);
175   gst_iterator_free (it);
176
177   return ret;
178 }