2 * Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
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.
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.
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.
24 #include "gstpropsprivate.h"
26 static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2);
30 _gst_props_initialize (void)
34 static GstPropsEntry *
35 gst_props_create_entry (GstPropsFactory factory, gint *skipped)
37 GstPropsFactoryEntry tag;
41 entry = g_new0 (GstPropsEntry, 1);
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++]);
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++]);
54 case GST_PROPS_FOURCC_ID:
55 entry->propstype = GST_PROPS_FOURCC_ID_NUM;
56 entry->data.fourcc_data = GPOINTER_TO_INT (factory[i++]);
58 case GST_PROPS_LIST_ID:
59 g_print("gstprops: list not allowed in list\n");
61 case GST_PROPS_BOOL_ID:
62 entry->propstype = GST_PROPS_BOOL_ID_NUM;
63 entry->data.bool_data = GPOINTER_TO_INT (factory[i++]);
66 g_print("gstprops: unknown props id found\n");
79 props_compare_func (gconstpointer a,
82 GstPropsEntry *entry1 = (GstPropsEntry *)a;
83 GstPropsEntry *entry2 = (GstPropsEntry *)b;
85 return (entry1->propid - entry2->propid);
90 * @factory: the factory to register
92 * Register the factory.
94 * Returns: The registered capability
97 gst_props_register (GstPropsFactory factory)
99 GstPropsFactoryEntry tag;
104 g_return_val_if_fail (factory != NULL, NULL);
108 if (!tag) return NULL;
110 props = g_new0 (GstProps, 1);
111 g_return_val_if_fail (props != NULL, NULL);
113 props->properties = NULL;
117 GstPropsEntry *entry;
119 quark = g_quark_from_string ((gchar *)tag);
122 switch (GPOINTER_TO_INT (tag)) {
123 case GST_PROPS_LIST_ID:
125 GstPropsEntry *list_entry;
127 entry = g_new0 (GstPropsEntry, 1);
128 entry->propid = quark;
129 entry->propstype = GST_PROPS_LIST_ID_NUM;
130 entry->data.list_data.entries = NULL;
132 i++; // skip list tag
135 list_entry = gst_props_create_entry (&factory[i], &skipped);
136 list_entry->propid = quark;
139 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, list_entry);
141 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
142 i++; //skip NULL (list end)
147 entry = gst_props_create_entry (&factory[i], &skipped);
148 entry->propid = quark;
153 props->properties = g_slist_insert_sorted (props->properties, entry, props_compare_func);
161 /* entry2 is always a list, entry1 never is */
163 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
165 GList *entrylist = entry2->data.list_data.entries;
166 gboolean found = FALSE;
168 while (entrylist && !found) {
169 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
171 found |= gst_props_entry_check_compatibility (entry1, entry);
173 entrylist = g_list_next (entrylist);
180 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
182 DEBUG ("compare: %s %s\n", g_quark_to_string (entry1->propid),
183 g_quark_to_string (entry2->propid));
184 switch (entry1->propstype) {
185 case GST_PROPS_LIST_ID_NUM:
187 GList *entrylist = entry1->data.list_data.entries;
188 gboolean valid = TRUE; // innocent until proven guilty
190 while (entrylist && valid) {
191 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
193 valid &= gst_props_entry_check_compatibility (entry, entry2);
195 entrylist = g_list_next (entrylist);
200 case GST_PROPS_INT_RANGE_ID_NUM:
201 switch (entry2->propstype) {
203 case GST_PROPS_INT_RANGE_ID_NUM:
204 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
205 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
206 case GST_PROPS_LIST_ID_NUM:
207 return gst_props_entry_check_list_compatibility (entry1, entry2);
212 case GST_PROPS_FOURCC_ID_NUM:
213 switch (entry2->propstype) {
215 case GST_PROPS_FOURCC_ID_NUM:
216 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
218 case GST_PROPS_LIST_ID_NUM:
219 return gst_props_entry_check_list_compatibility (entry1, entry2);
224 case GST_PROPS_INT_ID_NUM:
225 switch (entry2->propstype) {
227 case GST_PROPS_INT_RANGE_ID_NUM:
228 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
229 entry2->data.int_range_data.max >= entry1->data.int_data);
231 case GST_PROPS_INT_ID_NUM:
232 return (entry2->data.int_data == entry1->data.int_data);
234 case GST_PROPS_LIST_ID_NUM:
235 return gst_props_entry_check_list_compatibility (entry1, entry2);
240 case GST_PROPS_BOOL_ID_NUM:
241 switch (entry2->propstype) {
243 case GST_PROPS_BOOL_ID_NUM:
244 return (entry2->data.bool_data == entry1->data.bool_data);
245 case GST_PROPS_LIST_ID_NUM:
246 return gst_props_entry_check_list_compatibility (entry1, entry2);
258 * gst_props_check_compatibility:
259 * @fromprops: a capabilty
260 * @toprops: a capabilty
262 * Checks whether two capabilities are compatible
264 * Returns: true if compatible, false otherwise
267 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
273 gboolean compatible = TRUE;
275 g_return_val_if_fail (fromprops != NULL, FALSE);
276 g_return_val_if_fail (toprops != NULL, FALSE);
278 sourcelist = fromprops->properties;
279 sinklist = toprops->properties;
281 while (sourcelist && sinklist && compatible) {
282 GstPropsEntry *entry1;
283 GstPropsEntry *entry2;
285 entry1 = (GstPropsEntry *)sourcelist->data;
286 entry2 = (GstPropsEntry *)sinklist->data;
288 while (entry1->propid < entry2->propid) {
289 DEBUG ("source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
291 sourcelist = g_slist_next (sourcelist);
292 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
295 while (entry1->propid > entry2->propid) {
296 DEBUG ("source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
298 sinklist = g_slist_next (sinklist);
299 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
303 compatible &= gst_props_entry_check_compatibility (entry1, entry2);
305 sourcelist = g_slist_next (sourcelist);
306 sinklist = g_slist_next (sinklist);
309 GstPropsEntry *entry2;
310 entry2 = (GstPropsEntry *)sinklist->data;
312 DEBUG ("source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
323 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
327 switch (entry->propstype) {
328 case GST_PROPS_INT_ID_NUM:
329 subtree = xmlNewChild (parent, NULL, "int", NULL);
330 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
331 xmlNewProp (subtree, "value", g_strdup_printf ("%d", entry->data.int_data));
333 case GST_PROPS_INT_RANGE_ID_NUM:
334 subtree = xmlNewChild (parent, NULL, "range", NULL);
335 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
336 xmlNewProp (subtree, "min", g_strdup_printf ("%d", entry->data.int_range_data.min));
337 xmlNewProp (subtree, "max", g_strdup_printf ("%d", entry->data.int_range_data.max));
339 case GST_PROPS_FOURCC_ID_NUM:
340 xmlAddChild (parent, xmlNewComment (g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data)));
341 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
342 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
343 xmlNewProp (subtree, "hexvalue", g_strdup_printf ("%08x", entry->data.fourcc_data));
345 case GST_PROPS_BOOL_ID_NUM:
346 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
347 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
348 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
358 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
363 g_return_val_if_fail (props != NULL, NULL);
365 proplist = props->properties;
368 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
370 switch (entry->propstype) {
371 case GST_PROPS_LIST_ID_NUM:
372 subtree = xmlNewChild (parent, NULL, "list", NULL);
373 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
374 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
376 gst_props_save_thyself_func (entry, parent);
379 proplist = g_slist_next (proplist);
385 static GstPropsEntry*
386 gst_props_load_thyself_func (xmlNodePtr field)
388 GstPropsEntry *entry;
390 entry = g_new0 (GstPropsEntry, 1);
392 if (!strcmp(field->name, "int")) {
393 entry->propstype = GST_PROPS_INT_ID_NUM;
394 entry->propid = g_quark_from_string (xmlGetProp(field, "name"));
395 sscanf (xmlGetProp(field, "value"), "%d", &entry->data.int_data);
397 else if (!strcmp(field->name, "range")) {
398 entry->propstype = GST_PROPS_INT_RANGE_ID_NUM;
399 entry->propid = g_quark_from_string (xmlGetProp(field, "name"));
400 sscanf (xmlGetProp(field, "min"), "%d", &entry->data.int_range_data.min);
401 sscanf (xmlGetProp(field, "max"), "%d", &entry->data.int_range_data.max);
403 else if (!strcmp(field->name, "boolean")) {
404 entry->propstype = GST_PROPS_BOOL_ID_NUM;
405 entry->propid = g_quark_from_string (xmlGetProp(field, "name"));
406 if (!strcmp (xmlGetProp(field, "value"), "false")) entry->data.bool_data = 0;
407 else entry->data.bool_data = 1;
409 else if (!strcmp(field->name, "fourcc")) {
410 entry->propstype = GST_PROPS_FOURCC_ID_NUM;
411 entry->propid = g_quark_from_string (xmlGetProp(field, "name"));
412 sscanf (xmlGetProp(field, "hexvalue"), "%08x", &entry->data.fourcc_data);
419 gst_props_load_thyself (xmlNodePtr parent)
421 GstProps *props = g_new0 (GstProps, 1);
422 xmlNodePtr field = parent->childs;
425 if (!strcmp (field->name, "list")) {
426 GstPropsEntry *entry;
427 xmlNodePtr subfield = field->childs;
429 entry = g_new0 (GstPropsEntry, 1);
430 entry->propstype = GST_PROPS_LIST_ID_NUM;
431 entry->propid = g_quark_from_string (xmlGetProp(field, "name"));
434 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
436 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
438 subfield = subfield->next;
440 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
441 props->properties = g_slist_insert_sorted (props->properties, entry, props_compare_func);
444 GstPropsEntry *entry;
446 entry = gst_props_load_thyself_func (field);
448 props->properties = g_slist_insert_sorted (props->properties, entry, props_compare_func);