2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wtay@chello.be>
5 * gstprops.c: Properties subsystem for generic usage
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Library General Public
9 * License as published by the Free Software Foundation; either
10 * version 2 of the License, or (at your option) any later version.
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Library General Public License for more details.
17 * You should have received a copy of the GNU Library General Public
18 * License along with this library; if not, write to the
19 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 * Boston, MA 02111-1307, USA.
23 //#define GST_DEBUG_ENABLED
24 #include "gst_private.h"
27 #include "gstpropsprivate.h"
29 static GMemChunk *_gst_props_entries_chunk;
30 static GMutex *_gst_props_entries_chunk_lock;
32 static GMemChunk *_gst_props_chunk;
33 static GMutex *_gst_props_chunk_lock;
35 static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2);
38 _gst_props_initialize (void)
40 _gst_props_entries_chunk = g_mem_chunk_new ("GstPropsEntries",
41 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 256,
43 _gst_props_entries_chunk_lock = g_mutex_new ();
45 _gst_props_chunk = g_mem_chunk_new ("GstProps",
46 sizeof (GstProps), sizeof (GstProps) * 256,
48 _gst_props_chunk_lock = g_mutex_new ();
52 gst_props_debug_entry (GstPropsEntry *entry)
54 switch (entry->propstype) {
55 case GST_PROPS_INT_ID:
56 GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.int_data);
58 case GST_PROPS_FLOAT_ID:
59 GST_DEBUG (GST_CAT_PROPERTIES, "%f\n", entry->data.float_data);
61 case GST_PROPS_FOURCC_ID:
62 GST_DEBUG (GST_CAT_PROPERTIES, "%4.4s\n", (gchar*)&entry->data.fourcc_data);
64 case GST_PROPS_BOOL_ID:
65 GST_DEBUG (GST_CAT_PROPERTIES, "%d\n", entry->data.bool_data);
67 case GST_PROPS_STRING_ID:
68 GST_DEBUG (GST_CAT_PROPERTIES, "%s\n", entry->data.string_data.string);
70 case GST_PROPS_INT_RANGE_ID:
71 GST_DEBUG (GST_CAT_PROPERTIES, "%d-%d\n", entry->data.int_range_data.min,
72 entry->data.int_range_data.max);
74 case GST_PROPS_FLOAT_RANGE_ID:
75 GST_DEBUG (GST_CAT_PROPERTIES, "%f-%f\n", entry->data.float_range_data.min,
76 entry->data.float_range_data.max);
78 case GST_PROPS_LIST_ID:
79 GST_DEBUG (GST_CAT_PROPERTIES, "[list]\n");
86 props_compare_func (gconstpointer a,
89 GstPropsEntry *entry1 = (GstPropsEntry *)a;
90 GstPropsEntry *entry2 = (GstPropsEntry *)b;
92 return (entry1->propid - entry2->propid);
96 props_find_func (gconstpointer a,
99 GstPropsEntry *entry2 = (GstPropsEntry *)a;
100 GQuark entry1 = (GQuark) GPOINTER_TO_INT (b);
102 return (entry1 - entry2->propid);
105 /* This is implemented as a huge macro because we cannot pass
106 * va_list variables by reference on some architectures.
108 #define GST_PROPS_ENTRY_FILL(entry, var_args) \
110 entry->propstype = va_arg (var_args, GstPropsId); \
112 switch (entry->propstype) { \
113 case GST_PROPS_INT_ID: \
114 entry->data.int_data = va_arg (var_args, gint); \
116 case GST_PROPS_INT_RANGE_ID: \
117 entry->data.int_range_data.min = va_arg (var_args, gint); \
118 entry->data.int_range_data.max = va_arg (var_args, gint); \
120 case GST_PROPS_FLOAT_ID: \
121 entry->data.float_data = va_arg (var_args, gdouble); \
123 case GST_PROPS_FLOAT_RANGE_ID: \
124 entry->data.float_range_data.min = va_arg (var_args, gdouble); \
125 entry->data.float_range_data.max = va_arg (var_args, gdouble); \
127 case GST_PROPS_FOURCC_ID: \
128 entry->data.fourcc_data = va_arg (var_args, gulong); \
130 case GST_PROPS_BOOL_ID: \
131 entry->data.bool_data = va_arg (var_args, gboolean); \
133 case GST_PROPS_STRING_ID: \
134 entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
143 * @firstname: the first property name
144 * @...: the property values
146 * Create a new property from the given key/value pairs
148 * Returns: the new property
151 gst_props_new (const gchar *firstname, ...)
156 va_start (var_args, firstname);
158 props = gst_props_newv (firstname, var_args);
166 * gst_props_add_to_list:
167 * @entries: the existing list of entries
168 * @entry: the new entry to add to the list
170 * Add a property to a list of properties.
172 * Returns: a pointer to a list with the new entry added.
175 gst_props_add_to_list (GList * entries, GstPropsEntry *entry)
177 return g_list_prepend (entries, entry);
181 * gst_props_merge_int_entries:
182 * @newentry: the new entry
183 * @oldentry: an old entry
185 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
187 * Assumes that the entries are either ints or int ranges.
189 * Returns: TRUE if the entries were merged, FALSE otherwise.
192 gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
194 gint new_min, new_max, old_min, old_max;
195 gboolean can_merge = FALSE;
197 if (newentry->propstype == GST_PROPS_INT_ID) {
198 new_min = newentry->data.int_data;
199 new_max = newentry->data.int_data;
201 new_min = newentry->data.int_range_data.min;
202 new_max = newentry->data.int_range_data.max;
205 if (oldentry->propstype == GST_PROPS_INT_ID) {
206 old_min = oldentry->data.int_data;
207 old_max = oldentry->data.int_data;
209 old_min = oldentry->data.int_range_data.min;
210 old_max = oldentry->data.int_range_data.max;
213 // Put range which starts lower into (new_min, new_max)
214 if (old_min < new_min) {
224 // new_min is min of either entry - second half of the following conditional
225 // is to avoid overflow problems.
226 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
227 // ranges overlap, or are adjacent. Pick biggest maximum.
229 if (old_max > new_max) new_max = old_max;
233 if (new_min == new_max) {
234 newentry->propstype = GST_PROPS_INT_ID;
235 newentry->data.int_data = new_min;
237 newentry->propstype = GST_PROPS_INT_RANGE_ID;
238 newentry->data.int_range_data.min = new_min;
239 newentry->data.int_range_data.max = new_max;
246 * gst_props_add_to_int_list:
247 * @entries: the existing list of entries
248 * @entry: the new entry to add to the list
250 * Add an integer property to a list of properties, removing duplicates
251 * and merging ranges.
253 * Assumes that the existing list is in simplest form, contains
254 * only ints and int ranges, and that the new entry is an int or
257 * Returns: a pointer to a list with the new entry added.
260 gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
266 GstPropsEntry * oldentry = (GstPropsEntry *)(i->data);
267 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
270 // replace the existing one with the merged one
271 g_mutex_lock (_gst_props_entries_chunk_lock);
272 g_mem_chunk_free (_gst_props_entries_chunk, oldentry);
273 g_mutex_unlock (_gst_props_entries_chunk_lock);
274 entries = g_list_remove_link (entries, i);
277 // start again: it's possible that this change made an earlier entry
278 // mergeable, and the pointer is now invalid anyway.
285 return gst_props_add_to_list (entries, newentry);
290 * @firstname: the first property name
291 * @var_args: the property values
293 * Create a new property from the list of entries.
295 * Returns: the new property created from the list of entries
298 gst_props_newv (const gchar *firstname, va_list var_args)
301 gboolean inlist = FALSE;
302 const gchar *prop_name;
303 GstPropsEntry *list_entry = NULL;
306 GST_PROPS_LIST_T_UNSET,
307 GST_PROPS_LIST_T_INTS,
308 GST_PROPS_LIST_T_FLOATS,
309 GST_PROPS_LIST_T_MISC,
313 list_types list_type = GST_PROPS_LIST_T_UNSET;
314 // type of current item
315 list_types entry_type = GST_PROPS_LIST_T_UNSET;
317 if (firstname == NULL)
320 g_mutex_lock (_gst_props_chunk_lock);
321 props = g_mem_chunk_alloc (_gst_props_chunk);
322 g_mutex_unlock (_gst_props_chunk_lock);
324 props->properties = NULL;
327 prop_name = firstname;
331 GstPropsEntry *entry;
333 g_mutex_lock (_gst_props_entries_chunk_lock);
334 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
335 g_mutex_unlock (_gst_props_entries_chunk_lock);
337 entry->propid = g_quark_from_string (prop_name);
338 GST_PROPS_ENTRY_FILL (entry, var_args);
340 switch (entry->propstype) {
341 case GST_PROPS_INT_ID:
342 case GST_PROPS_INT_RANGE_ID:
343 entry_type = GST_PROPS_LIST_T_INTS;
345 case GST_PROPS_FLOAT_ID:
346 case GST_PROPS_FLOAT_RANGE_ID:
347 entry_type = GST_PROPS_LIST_T_FLOATS;
349 case GST_PROPS_FOURCC_ID:
350 case GST_PROPS_BOOL_ID:
351 case GST_PROPS_STRING_ID:
352 entry_type = GST_PROPS_LIST_T_MISC;
354 case GST_PROPS_LIST_ID:
355 g_return_val_if_fail (inlist == FALSE, NULL);
358 list_type = GST_PROPS_LIST_T_UNSET;
359 list_entry->data.list_data.entries = NULL;
361 case GST_PROPS_END_ID:
362 g_return_val_if_fail (inlist == TRUE, NULL);
364 // if list was of size 1, replace the list by a the item it contains
365 if (g_list_length(list_entry->data.list_data.entries) == 1) {
366 GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
367 list_entry->propstype = subentry->propstype;
368 list_entry->data = subentry->data;
369 g_mutex_lock (_gst_props_entries_chunk_lock);
370 g_mem_chunk_free (_gst_props_entries_chunk, subentry);
371 g_mutex_unlock (_gst_props_entries_chunk_lock);
374 g_mutex_lock (_gst_props_entries_chunk_lock);
375 g_mem_chunk_free (_gst_props_entries_chunk, entry);
376 g_mutex_unlock (_gst_props_entries_chunk_lock);
379 prop_name = va_arg (var_args, gchar*);
382 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
383 g_mutex_lock (_gst_props_entries_chunk_lock);
384 g_mem_chunk_free (_gst_props_entries_chunk, entry);
385 g_mutex_unlock (_gst_props_entries_chunk_lock);
389 if (inlist && (list_entry != entry)) {
390 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
391 if (list_type != entry_type) {
392 g_warning ("property list contained incompatible entry types\n");
395 case GST_PROPS_LIST_T_INTS:
396 list_entry->data.list_data.entries =
397 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
400 list_entry->data.list_data.entries =
401 gst_props_add_to_list (list_entry->data.list_data.entries, entry);
407 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
410 prop_name = va_arg (var_args, gchar*);
418 * @props: the props to modify
419 * @name: the name of the entry to modify
420 * @...: More property entries.
422 * Modifies the value of the given entry in the props struct.
424 * Returns: the new modified property structure.
427 gst_props_set (GstProps *props, const gchar *name, ...)
433 quark = g_quark_from_string (name);
435 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
438 GstPropsEntry *entry;
440 entry = (GstPropsEntry *)lentry->data;
442 va_start (var_args, name);
444 GST_PROPS_ENTRY_FILL (entry, var_args);
449 g_print("gstprops: no property '%s' to change\n", name);
457 * @props: the props to unref
459 * Decrease the refcount of the property structure, destroying
460 * the property if the refcount is 0.
463 gst_props_unref (GstProps *props)
465 g_return_if_fail (props != NULL);
469 if (props->refcount == 0)
470 gst_props_destroy (props);
475 * @props: the props to ref
477 * Increase the refcount of the property structure.
480 gst_props_ref (GstProps *props)
482 g_return_if_fail (props != NULL);
489 * @props: the props to destroy
491 * Destroy the property, freeing all the memory that
495 gst_props_destroy (GstProps *props)
499 g_return_if_fail (props != NULL);
501 entries = props->properties;
504 GstPropsEntry *entry = (GstPropsEntry *)entries->data;
506 // FIXME also free the lists
507 g_mutex_lock (_gst_props_entries_chunk_lock);
508 g_mem_chunk_free (_gst_props_entries_chunk, entry);
509 g_mutex_unlock (_gst_props_entries_chunk_lock);
511 entries = g_list_next (entries);
514 g_list_free (props->properties);
519 * @props: the props to copy
521 * Copy the property structure.
523 * Returns: the new property that is a copy of the original
527 gst_props_copy (GstProps *props)
532 g_return_val_if_fail (props != NULL, NULL);
534 g_mutex_lock (_gst_props_chunk_lock);
535 new = g_mem_chunk_alloc (_gst_props_chunk);
536 g_mutex_unlock (_gst_props_chunk_lock);
538 new->properties = NULL;
540 properties = props->properties;
543 GstPropsEntry *entry = (GstPropsEntry *)properties->data;
544 GstPropsEntry *newentry;
546 g_mutex_lock (_gst_props_entries_chunk_lock);
547 newentry = g_mem_chunk_alloc (_gst_props_entries_chunk);
548 g_mutex_unlock (_gst_props_entries_chunk_lock);
550 // FIXME copy lists too
551 memcpy (newentry, entry, sizeof (GstPropsEntry));
553 new->properties = g_list_prepend (new->properties, newentry);
555 properties = g_list_next (properties);
557 new->properties = g_list_reverse (new->properties);
563 * gst_props_copy_on_write:
564 * @props: the props to copy on write
566 * Copy the property structure if the refcount is >1.
568 * Returns: A new props that can be safely written to.
571 gst_props_copy_on_write (GstProps *props)
573 GstProps *new = props;;
575 g_return_val_if_fail (props != NULL, NULL);
577 if (props->refcount > 1) {
578 new = gst_props_copy (props);
579 gst_props_unref (props);
587 * @props: the props to get the int value from
588 * @name: the name of the props entry to get.
590 * Get the named entry as an integer.
592 * Returns: the integer value of the named entry, 0 if not found.
595 gst_props_get_int (GstProps *props, const gchar *name)
600 g_return_val_if_fail (props != NULL, 0);
601 g_return_val_if_fail (name != NULL, 0);
603 quark = g_quark_from_string (name);
605 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
608 GstPropsEntry *thisentry;
610 thisentry = (GstPropsEntry *)lentry->data;
612 return thisentry->data.int_data;
619 * gst_props_get_float:
620 * @props: the props to get the float value from
621 * @name: the name of the props entry to get.
623 * Get the named entry as a float.
625 * Returns: the float value of the named entry, 0.0 if not found.
628 gst_props_get_float (GstProps *props, const gchar *name)
633 quark = g_quark_from_string (name);
635 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
638 GstPropsEntry *thisentry;
640 thisentry = (GstPropsEntry *)lentry->data;
642 return thisentry->data.float_data;
649 * gst_props_get_fourcc_int:
650 * @props: the props to get the fourcc value from
651 * @name: the name of the props entry to get.
653 * Get the named entry as a gulong fourcc.
655 * Returns: the fourcc value of the named entry, 0 if not found.
658 gst_props_get_fourcc_int (GstProps *props, const gchar *name)
663 g_return_val_if_fail (props != NULL, 0);
664 g_return_val_if_fail (name != NULL, 0);
666 quark = g_quark_from_string (name);
668 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
671 GstPropsEntry *thisentry;
673 thisentry = (GstPropsEntry *)lentry->data;
675 return thisentry->data.fourcc_data;
682 * gst_props_get_boolean:
683 * @props: the props to get the fourcc value from
684 * @name: the name of the props entry to get.
686 * Get the named entry as a boolean value.
688 * Returns: the boolean value of the named entry, 0 if not found.
691 gst_props_get_boolean (GstProps *props, const gchar *name)
696 g_return_val_if_fail (props != NULL, FALSE);
697 g_return_val_if_fail (name != NULL, FALSE);
699 quark = g_quark_from_string (name);
701 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
704 GstPropsEntry *thisentry;
706 thisentry = (GstPropsEntry *)lentry->data;
708 return thisentry->data.bool_data;
715 * gst_props_get_string:
716 * @props: the props to get the fourcc value from
717 * @name: the name of the props entry to get.
719 * Get the named entry as a string value.
721 * Returns: the string value of the named entry, NULL if not found.
724 gst_props_get_string (GstProps *props, const gchar *name)
729 g_return_val_if_fail (props != NULL, NULL);
730 g_return_val_if_fail (name != NULL, NULL);
732 quark = g_quark_from_string (name);
734 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
737 GstPropsEntry *thisentry;
739 thisentry = (GstPropsEntry *)lentry->data;
741 return thisentry->data.string_data.string;
749 * @props: the property to merge into
750 * @tomerge: the property to merge
752 * Merge the properties of tomerge into props.
754 * Returns: the new merged property
757 gst_props_merge (GstProps *props, GstProps *tomerge)
761 g_return_val_if_fail (props != NULL, NULL);
762 g_return_val_if_fail (tomerge != NULL, NULL);
764 merge_props = tomerge->properties;
766 // FIXME do proper merging here...
767 while (merge_props) {
768 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
770 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
772 merge_props = g_list_next (merge_props);
779 /* entry2 is always a list, entry1 never is */
781 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
783 GList *entrylist = entry2->data.list_data.entries;
784 gboolean found = FALSE;
786 while (entrylist && !found) {
787 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
789 found |= gst_props_entry_check_compatibility (entry1, entry);
791 entrylist = g_list_next (entrylist);
798 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
800 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s\n", g_quark_to_string (entry1->propid),
801 g_quark_to_string (entry2->propid));
802 gst_props_debug_entry (entry1);
803 gst_props_debug_entry (entry2);
804 switch (entry1->propstype) {
805 case GST_PROPS_LIST_ID:
807 GList *entrylist = entry1->data.list_data.entries;
808 gboolean valid = TRUE; // innocent until proven guilty
810 while (entrylist && valid) {
811 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
813 valid &= gst_props_entry_check_compatibility (entry, entry2);
815 entrylist = g_list_next (entrylist);
820 case GST_PROPS_INT_RANGE_ID:
821 switch (entry2->propstype) {
823 case GST_PROPS_INT_RANGE_ID:
824 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
825 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
826 case GST_PROPS_LIST_ID:
827 return gst_props_entry_check_list_compatibility (entry1, entry2);
832 case GST_PROPS_FLOAT_RANGE_ID:
833 switch (entry2->propstype) {
835 case GST_PROPS_FLOAT_RANGE_ID:
836 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
837 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
838 case GST_PROPS_LIST_ID:
839 return gst_props_entry_check_list_compatibility (entry1, entry2);
844 case GST_PROPS_FOURCC_ID:
845 switch (entry2->propstype) {
847 case GST_PROPS_FOURCC_ID:
848 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
850 case GST_PROPS_LIST_ID:
851 return gst_props_entry_check_list_compatibility (entry1, entry2);
856 case GST_PROPS_INT_ID:
857 switch (entry2->propstype) {
859 case GST_PROPS_INT_RANGE_ID:
860 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?\n",entry2->data.int_range_data.min,
861 entry1->data.int_data,entry2->data.int_range_data.max);
862 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
863 entry2->data.int_range_data.max >= entry1->data.int_data);
865 case GST_PROPS_INT_ID:
866 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?\n",entry1->data.int_data,entry2->data.int_data);
867 return (entry2->data.int_data == entry1->data.int_data);
869 case GST_PROPS_LIST_ID:
870 return gst_props_entry_check_list_compatibility (entry1, entry2);
875 case GST_PROPS_FLOAT_ID:
876 switch (entry2->propstype) {
878 case GST_PROPS_FLOAT_RANGE_ID:
879 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
880 entry2->data.float_range_data.max >= entry1->data.float_data);
882 case GST_PROPS_FLOAT_ID:
883 return (entry2->data.float_data == entry1->data.float_data);
885 case GST_PROPS_LIST_ID:
886 return gst_props_entry_check_list_compatibility (entry1, entry2);
891 case GST_PROPS_BOOL_ID:
892 switch (entry2->propstype) {
894 case GST_PROPS_BOOL_ID:
895 return (entry2->data.bool_data == entry1->data.bool_data);
896 case GST_PROPS_LIST_ID:
897 return gst_props_entry_check_list_compatibility (entry1, entry2);
901 case GST_PROPS_STRING_ID:
902 switch (entry2->propstype) {
904 case GST_PROPS_STRING_ID:
905 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
906 case GST_PROPS_LIST_ID:
907 return gst_props_entry_check_list_compatibility (entry1, entry2);
919 * gst_props_check_compatibility:
920 * @fromprops: a property
921 * @toprops: a property
923 * Checks whether two capabilities are compatible.
925 * Returns: TRUE if compatible, FALSE otherwise
928 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
934 gboolean compatible = TRUE;
936 g_return_val_if_fail (fromprops != NULL, FALSE);
937 g_return_val_if_fail (toprops != NULL, FALSE);
939 sourcelist = fromprops->properties;
940 sinklist = toprops->properties;
942 while (sourcelist && sinklist && compatible) {
943 GstPropsEntry *entry1;
944 GstPropsEntry *entry2;
946 entry1 = (GstPropsEntry *)sourcelist->data;
947 entry2 = (GstPropsEntry *)sinklist->data;
949 while (entry1->propid < entry2->propid) {
950 GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"\n", g_quark_to_string (entry1->propid));
952 sourcelist = g_list_next (sourcelist);
953 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
956 while (entry1->propid > entry2->propid) {
957 GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
959 sinklist = g_list_next (sinklist);
960 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
964 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
966 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: \n",
967 g_quark_to_string (entry1->propid));
968 gst_props_debug_entry (entry1);
969 gst_props_debug_entry (entry2);
972 sourcelist = g_list_next (sourcelist);
973 sinklist = g_list_next (sinklist);
975 if (sinklist && compatible) {
976 GstPropsEntry *entry2;
977 entry2 = (GstPropsEntry *)sinklist->data;
979 GST_DEBUG (GST_CAT_PROPERTIES,"source has missing property \"%s\"\n", g_quark_to_string (entry2->propid));
989 #if (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) )
991 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
996 switch (entry->propstype) {
997 case GST_PROPS_INT_ID:
998 subtree = xmlNewChild (parent, NULL, "int", NULL);
999 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1000 str = g_strdup_printf ("%d", entry->data.int_data);
1001 xmlNewProp (subtree, "value", str);
1004 case GST_PROPS_INT_RANGE_ID:
1005 subtree = xmlNewChild (parent, NULL, "range", NULL);
1006 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1007 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
1008 xmlNewProp (subtree, "min", str);
1010 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
1011 xmlNewProp (subtree, "max", str);
1014 case GST_PROPS_FLOAT_ID:
1015 subtree = xmlNewChild (parent, NULL, "float", NULL);
1016 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1017 str = g_strdup_printf ("%f", entry->data.float_data);
1018 xmlNewProp (subtree, "value", str);
1021 case GST_PROPS_FLOAT_RANGE_ID:
1022 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
1023 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1024 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
1025 xmlNewProp (subtree, "min", str);
1027 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
1028 xmlNewProp (subtree, "max", str);
1031 case GST_PROPS_FOURCC_ID:
1032 str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
1033 xmlAddChild (parent, xmlNewComment (str));
1035 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
1036 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1037 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
1038 xmlNewProp (subtree, "hexvalue", str);
1041 case GST_PROPS_BOOL_ID:
1042 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
1043 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1044 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
1046 case GST_PROPS_STRING_ID:
1047 subtree = xmlNewChild (parent, NULL, "string", NULL);
1048 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1049 xmlNewProp (subtree, "value", entry->data.string_data.string);
1059 * gst_props_save_thyself:
1060 * @props: a property to save
1061 * @parent: the parent XML tree
1063 * Saves the property into an XML representation.
1065 * Returns: the new XML tree
1068 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
1073 g_return_val_if_fail (props != NULL, NULL);
1075 proplist = props->properties;
1078 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
1080 switch (entry->propstype) {
1081 case GST_PROPS_LIST_ID:
1082 subtree = xmlNewChild (parent, NULL, "list", NULL);
1083 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1084 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
1086 gst_props_save_thyself_func (entry, parent);
1089 proplist = g_list_next (proplist);
1095 static GstPropsEntry*
1096 gst_props_load_thyself_func (xmlNodePtr field)
1098 GstPropsEntry *entry;
1101 g_mutex_lock (_gst_props_entries_chunk_lock);
1102 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
1103 g_mutex_unlock (_gst_props_entries_chunk_lock);
1105 if (!strcmp(field->name, "int")) {
1106 entry->propstype = GST_PROPS_INT_ID;
1107 prop = xmlGetProp(field, "name");
1108 entry->propid = g_quark_from_string (prop);
1110 prop = xmlGetProp(field, "value");
1111 sscanf (prop, "%d", &entry->data.int_data);
1114 else if (!strcmp(field->name, "range")) {
1115 entry->propstype = GST_PROPS_INT_RANGE_ID;
1116 prop = xmlGetProp(field, "name");
1117 entry->propid = g_quark_from_string (prop);
1119 prop = xmlGetProp (field, "min");
1120 sscanf (prop, "%d", &entry->data.int_range_data.min);
1122 prop = xmlGetProp (field, "max");
1123 sscanf (prop, "%d", &entry->data.int_range_data.max);
1126 else if (!strcmp(field->name, "float")) {
1127 entry->propstype = GST_PROPS_FLOAT_ID;
1128 prop = xmlGetProp(field, "name");
1129 entry->propid = g_quark_from_string (prop);
1131 prop = xmlGetProp(field, "value");
1132 sscanf (prop, "%f", &entry->data.float_data);
1135 else if (!strcmp(field->name, "floatrange")) {
1136 entry->propstype = GST_PROPS_FLOAT_RANGE_ID;
1137 prop = xmlGetProp(field, "name");
1138 entry->propid = g_quark_from_string (prop);
1140 prop = xmlGetProp (field, "min");
1141 sscanf (prop, "%f", &entry->data.float_range_data.min);
1143 prop = xmlGetProp (field, "max");
1144 sscanf (prop, "%f", &entry->data.float_range_data.max);
1147 else if (!strcmp(field->name, "boolean")) {
1148 entry->propstype = GST_PROPS_BOOL_ID;
1149 prop = xmlGetProp(field, "name");
1150 entry->propid = g_quark_from_string (prop);
1152 prop = xmlGetProp (field, "value");
1153 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
1154 else entry->data.bool_data = 1;
1157 else if (!strcmp(field->name, "fourcc")) {
1158 entry->propstype = GST_PROPS_FOURCC_ID;
1159 prop = xmlGetProp(field, "name");
1160 entry->propid = g_quark_from_string (prop);
1162 prop = xmlGetProp (field, "hexvalue");
1163 sscanf (prop, "%08x", &entry->data.fourcc_data);
1166 else if (!strcmp(field->name, "string")) {
1167 entry->propstype = GST_PROPS_STRING_ID;
1168 prop = xmlGetProp(field, "name");
1169 entry->propid = g_quark_from_string (prop);
1171 entry->data.string_data.string = xmlGetProp (field, "value");
1174 g_mutex_lock (_gst_props_entries_chunk_lock);
1175 g_mem_chunk_free (_gst_props_entries_chunk, entry);
1176 g_mutex_unlock (_gst_props_entries_chunk_lock);
1184 * gst_props_load_thyself:
1185 * @parent: the XML tree to load from
1187 * Creates a new property out of an XML tree.
1189 * Returns: the new property
1192 gst_props_load_thyself (xmlNodePtr parent)
1195 xmlNodePtr field = parent->xmlChildrenNode;
1198 g_mutex_lock (_gst_props_chunk_lock);
1199 props = g_mem_chunk_alloc (_gst_props_chunk);
1200 g_mutex_unlock (_gst_props_chunk_lock);
1202 props->properties = NULL;
1203 props->refcount = 1;
1206 if (!strcmp (field->name, "list")) {
1207 GstPropsEntry *entry;
1208 xmlNodePtr subfield = field->xmlChildrenNode;
1210 g_mutex_lock (_gst_props_entries_chunk_lock);
1211 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
1212 g_mutex_unlock (_gst_props_entries_chunk_lock);
1214 entry->propstype = GST_PROPS_LIST_ID;
1215 entry->data.list_data.entries = NULL;
1216 prop = xmlGetProp (field, "name");
1217 entry->propid = g_quark_from_string (prop);
1221 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
1224 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
1226 subfield = subfield->next;
1228 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
1229 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
1232 GstPropsEntry *entry;
1234 entry = gst_props_load_thyself_func (field);
1237 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
1239 field = field->next;
1244 #endif /* (! (defined(GST_DISABLE_LOADSAVE) && defined(GST_DISABLE_REGISTRY)) ) */