Header cleanup: try to include as little as possible; this will probably speed up...
[platform/upstream/gstreamer.git] / gst / gstprops.c
1 /* Gnome-Streamer
2  * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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 //#define DEBUG_ENABLED
21
22 #include "gstdebug.h"
23 #include "gstprops.h"
24 #include "gstpropsprivate.h"
25
26 static gboolean         gst_props_entry_check_compatibility     (GstPropsEntry *entry1, GstPropsEntry *entry2);
27         
28
29 void 
30 _gst_props_initialize (void) 
31 {
32 }
33
34 static GstPropsEntry *
35 gst_props_create_entry (GstPropsFactory factory, gint *skipped)
36 {
37   GstPropsFactoryEntry tag;
38   GstPropsEntry *entry;
39   guint i=0;
40
41   entry = g_new0 (GstPropsEntry, 1);
42
43   tag = factory[i++];
44   switch (GPOINTER_TO_INT (tag)) {
45     case GST_PROPS_INT_ID:
46       entry->propstype = GST_PROPS_INT_ID_NUM;
47       entry->data.int_data = GPOINTER_TO_INT (factory[i++]);
48       break;
49     case GST_PROPS_INT_RANGE_ID:
50       entry->propstype = GST_PROPS_INT_RANGE_ID_NUM;
51       entry->data.int_range_data.min = GPOINTER_TO_INT (factory[i++]);
52       entry->data.int_range_data.max = GPOINTER_TO_INT (factory[i++]);
53       break;
54     case GST_PROPS_FOURCC_ID:
55       entry->propstype = GST_PROPS_FOURCC_ID_NUM;
56       entry->data.fourcc_data = GPOINTER_TO_INT (factory[i++]);
57       break;
58     case GST_PROPS_LIST_ID:
59       g_print("gstprops: list not allowed in list\n");
60       break;
61     case GST_PROPS_BOOL_ID:
62       entry->propstype = GST_PROPS_BOOL_ID_NUM;
63       entry->data.bool_data = GPOINTER_TO_INT (factory[i++]);
64       break;
65     default:
66       g_print("gstprops: unknown props id found\n");
67       g_free (entry);
68       entry = NULL;
69       break;
70   }
71
72   *skipped = i;
73
74   return entry;
75 }
76
77
78 static gint 
79 props_compare_func (gconstpointer a,
80                    gconstpointer b) 
81 {
82   GstPropsEntry *entry1 = (GstPropsEntry *)a;
83   GstPropsEntry *entry2 = (GstPropsEntry *)b;
84
85   return (entry1->propid - entry2->propid);
86 }
87
88 /**
89  * gst_props_register:
90  * @factory: the factory to register
91  *
92  * Register the factory. 
93  *
94  * Returns: The registered capability
95  */
96 GstProps *
97 gst_props_register (GstPropsFactory factory)
98 {
99   GstPropsFactoryEntry tag;
100   gint i = 0;
101   GstProps *props;
102   gint skipped;
103   
104   g_return_val_if_fail (factory != NULL, NULL);
105
106   props = g_new0 (GstProps, 1);
107   g_return_val_if_fail (props != NULL, NULL);
108
109   props->properties = NULL;
110
111   tag = factory[i++];
112   
113   while (tag) {
114     GQuark quark;
115     GstPropsEntry *entry;
116     
117     quark = g_quark_from_string ((gchar *)tag);
118
119     tag = factory[i];
120     switch (GPOINTER_TO_INT (tag)) {
121       case GST_PROPS_LIST_ID: 
122       {
123         GstPropsEntry *list_entry;
124
125         entry = g_new0 (GstPropsEntry, 1);
126         entry->propid = quark;
127         entry->propstype = GST_PROPS_LIST_ID_NUM;
128         entry->data.list_data.entries = NULL;
129
130         i++; // skip list tag
131         tag = factory[i];
132         while (tag) {
133           list_entry = gst_props_create_entry (&factory[i], &skipped);
134           list_entry->propid = quark;
135           i += skipped;
136           tag = factory[i];
137           entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, list_entry);
138         }
139         entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
140         i++; //skip NULL (list end)
141         break;
142       }
143       default:
144       {
145         entry = gst_props_create_entry (&factory[i], &skipped);
146         entry->propid = quark;
147         i += skipped;
148         break;
149       }
150     }
151     props->properties = g_slist_insert_sorted (props->properties, entry, props_compare_func);
152      
153     tag = factory[i++];
154   }
155
156   return props;
157 }
158
159 /* entry2 is always a list, entry1 never is */
160 static gboolean
161 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
162 {
163   GList *entrylist = entry2->data.list_data.entries;
164   gboolean found = FALSE;
165
166   while (entrylist && !found) {
167     GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
168
169     found |= gst_props_entry_check_compatibility (entry1, entry);
170
171     entrylist = g_list_next (entrylist);
172   }
173
174   return found;
175 }
176
177 static gboolean
178 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
179 {
180   DEBUG ("compare: %s %s\n", g_quark_to_string (entry1->propid),
181                              g_quark_to_string (entry2->propid));
182   switch (entry1->propstype) {
183     case GST_PROPS_LIST_ID_NUM:
184     {
185       GList *entrylist = entry1->data.list_data.entries;
186       gboolean valid = TRUE;    // innocent until proven guilty
187
188       while (entrylist && valid) {
189         GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
190
191         valid &= gst_props_entry_check_compatibility (entry, entry2);
192         
193         entrylist = g_list_next (entrylist);
194       }
195       
196       return valid;
197     }
198     case GST_PROPS_INT_RANGE_ID_NUM:
199       switch (entry2->propstype) {
200         // a - b   <--->   a - c
201         case GST_PROPS_INT_RANGE_ID_NUM:
202           return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
203                   entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
204         case GST_PROPS_LIST_ID_NUM:
205           return gst_props_entry_check_list_compatibility (entry1, entry2);
206         default:
207           return FALSE;
208       }
209       break;
210     case GST_PROPS_FOURCC_ID_NUM:
211       switch (entry2->propstype) {
212         // b   <--->   a
213         case GST_PROPS_FOURCC_ID_NUM:
214           return (entry2->data.fourcc_data == entry1->data.fourcc_data);
215         // b   <--->   a,b,c
216         case GST_PROPS_LIST_ID_NUM:
217           return gst_props_entry_check_list_compatibility (entry1, entry2);
218         default:
219           return FALSE;
220       }
221       break;
222     case GST_PROPS_INT_ID_NUM:
223       switch (entry2->propstype) {
224         // b   <--->   a - d
225         case GST_PROPS_INT_RANGE_ID_NUM:
226           return (entry2->data.int_range_data.min <= entry1->data.int_data &&
227                   entry2->data.int_range_data.max >= entry1->data.int_data);
228         // b   <--->   a
229         case GST_PROPS_INT_ID_NUM:
230           return (entry2->data.int_data == entry1->data.int_data);
231         // b   <--->   a,b,c
232         case GST_PROPS_LIST_ID_NUM:
233           return gst_props_entry_check_list_compatibility (entry1, entry2);
234         default:
235           return FALSE;
236       }
237       break;
238     case GST_PROPS_BOOL_ID_NUM:
239       switch (entry2->propstype) {
240         // t   <--->   t
241         case GST_PROPS_BOOL_ID_NUM:
242           return (entry2->data.bool_data == entry1->data.bool_data);
243         case GST_PROPS_LIST_ID_NUM:
244           return gst_props_entry_check_list_compatibility (entry1, entry2);
245         default:
246           return FALSE;
247       }
248     default:
249       break;
250   }
251
252   return FALSE;
253 }
254
255 /**
256  * gst_props_check_compatibility:
257  * @fromprops: a capabilty
258  * @toprops: a capabilty
259  *
260  * Checks whether two capabilities are compatible
261  *
262  * Returns: true if compatible, false otherwise
263  */
264 gboolean
265 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
266 {
267   GSList *sourcelist;
268   GSList *sinklist;
269   gint missing = 0;
270   gint more = 0;
271   gboolean compatible = TRUE;
272
273   g_return_val_if_fail (fromprops != NULL, FALSE);
274   g_return_val_if_fail (toprops != NULL, FALSE);
275         
276   sourcelist = fromprops->properties;
277   sinklist   = toprops->properties;
278
279   while (sourcelist && sinklist && compatible) {
280     GstPropsEntry *entry1;
281     GstPropsEntry *entry2;
282
283     entry1 = (GstPropsEntry *)sourcelist->data;
284     entry2 = (GstPropsEntry *)sinklist->data;
285
286     while (entry1->propid < entry2->propid) {
287       DEBUG ("source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
288       more++;
289       sourcelist = g_slist_next (sourcelist);
290       if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
291       else goto end;
292     }
293     while (entry1->propid > entry2->propid) {
294       DEBUG ("source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
295       missing++;
296       sinklist = g_slist_next (sinklist);
297       if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
298       else goto end;
299     }
300
301     compatible &= gst_props_entry_check_compatibility (entry1, entry2);
302
303     sourcelist = g_slist_next (sourcelist);
304     sinklist = g_slist_next (sinklist);
305   }
306 end:
307
308   if (missing)
309     return FALSE;
310
311   return compatible;
312 }
313
314 static xmlNodePtr
315 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
316 {
317   xmlNodePtr subtree;
318
319   switch (entry->propstype) {
320     case GST_PROPS_INT_ID_NUM: 
321       subtree = xmlNewChild (parent, NULL, "int", NULL);
322       xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
323       xmlNewProp (subtree, "value", g_strdup_printf ("%d", entry->data.int_data));
324       break;
325     case GST_PROPS_INT_RANGE_ID_NUM: 
326       subtree = xmlNewChild (parent, NULL, "range", NULL);
327       xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
328       xmlNewProp (subtree, "min", g_strdup_printf ("%d", entry->data.int_range_data.min));
329       xmlNewProp (subtree, "max", g_strdup_printf ("%d", entry->data.int_range_data.max));
330       break;
331     case GST_PROPS_FOURCC_ID_NUM: 
332       xmlAddChild (parent, xmlNewComment (g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data)));
333       subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
334       xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
335       xmlNewProp (subtree, "hexvalue", g_strdup_printf ("%08x", entry->data.fourcc_data));
336       break;
337     case GST_PROPS_BOOL_ID_NUM: 
338       subtree = xmlNewChild (parent, NULL, "boolean", NULL);
339       xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
340       xmlNewProp (subtree, "value", (entry->data.bool_data ?  "true" : "false"));
341       break;
342     default:
343       break;
344   }
345
346   return parent;
347 }
348
349 xmlNodePtr
350 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
351 {
352   GSList *proplist;
353   xmlNodePtr subtree;
354
355   g_return_val_if_fail (props != NULL, NULL);
356
357   proplist = props->properties;
358
359   while (proplist) {
360     GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
361
362     switch (entry->propstype) {
363       case GST_PROPS_LIST_ID_NUM: 
364         subtree = xmlNewChild (parent, NULL, "list", NULL);
365         g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
366       default:
367         gst_props_save_thyself_func (entry, parent);
368     }
369
370     proplist = g_slist_next (proplist);
371   }
372   
373   return parent;
374 }
375
376 GstProps*
377 gst_props_load_thyself (xmlNodePtr parent)
378 {
379   return NULL;
380 }
381