2 * Copyright (C) 1999,2000 Erik Walthinsen <omega@cse.ogi.edu>
3 * 2000 Wim Taymans <wim.taymans@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"
29 GType _gst_props_type;
31 #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE)
33 struct _GstPropsEntry {
35 GstPropsType propstype;
44 /* structured values */
62 static GMemChunk *_gst_props_entries_chunk;
63 static GMutex *_gst_props_entries_chunk_lock;
65 static GMemChunk *_gst_props_chunk;
66 static GMutex *_gst_props_chunk_lock;
68 static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2);
69 static GList* gst_props_list_copy (GList *propslist);
73 _gst_props_initialize (void)
75 _gst_props_entries_chunk = g_mem_chunk_new ("GstPropsEntries",
76 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 256,
78 _gst_props_entries_chunk_lock = g_mutex_new ();
80 _gst_props_chunk = g_mem_chunk_new ("GstProps",
81 sizeof (GstProps), sizeof (GstProps) * 256,
83 _gst_props_chunk_lock = g_mutex_new ();
85 _gst_props_type = g_boxed_type_register_static ("GstProps",
86 (GBoxedCopyFunc) gst_props_ref,
87 (GBoxedFreeFunc) gst_props_unref);
92 gst_props_debug_entry (GstPropsEntry *entry)
94 const gchar *name = g_quark_to_string (entry->propid);
96 switch (entry->propstype) {
97 case GST_PROPS_INT_TYPE:
98 GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data);
100 case GST_PROPS_FLOAT_TYPE:
101 GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data);
103 case GST_PROPS_FOURCC_TYPE:
104 GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s", name, (gchar*)&entry->data.fourcc_data);
106 case GST_PROPS_BOOL_TYPE:
107 GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data);
109 case GST_PROPS_STRING_TYPE:
110 GST_DEBUG (GST_CAT_PROPERTIES, "%s: string %s", name, entry->data.string_data.string);
112 case GST_PROPS_INT_RANGE_TYPE:
113 GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min,
114 entry->data.int_range_data.max);
116 case GST_PROPS_FLOAT_RANGE_TYPE:
117 GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min,
118 entry->data.float_range_data.max);
120 case GST_PROPS_LIST_TYPE:
121 GST_DEBUG (GST_CAT_PROPERTIES, "[list]");
123 GList *entries = entry->data.list_data.entries;
126 gst_props_debug_entry ((GstPropsEntry *)entries->data);
127 entries = g_list_next (entries);
132 g_warning ("unknown property type %d", entry->propstype);
138 props_compare_func (gconstpointer a,
141 GstPropsEntry *entry1 = (GstPropsEntry *)a;
142 GstPropsEntry *entry2 = (GstPropsEntry *)b;
144 return (entry1->propid - entry2->propid);
148 props_find_func (gconstpointer a,
151 GstPropsEntry *entry2 = (GstPropsEntry *)a;
152 GQuark quark = (GQuark) GPOINTER_TO_INT (b);
154 return (quark - entry2->propid);
157 /* This is implemented as a huge macro because we cannot pass
158 * va_list variables by reference on some architectures.
160 #define GST_PROPS_ENTRY_FILL(entry, var_args) \
162 entry->propstype = va_arg (var_args, GstPropsType); \
164 switch (entry->propstype) { \
165 case GST_PROPS_INT_TYPE: \
166 entry->data.int_data = va_arg (var_args, gint); \
168 case GST_PROPS_INT_RANGE_TYPE: \
169 entry->data.int_range_data.min = va_arg (var_args, gint); \
170 entry->data.int_range_data.max = va_arg (var_args, gint); \
172 case GST_PROPS_FLOAT_TYPE: \
173 entry->data.float_data = va_arg (var_args, gdouble); \
175 case GST_PROPS_FLOAT_RANGE_TYPE: \
176 entry->data.float_range_data.min = va_arg (var_args, gdouble); \
177 entry->data.float_range_data.max = va_arg (var_args, gdouble); \
179 case GST_PROPS_FOURCC_TYPE: \
180 entry->data.fourcc_data = va_arg (var_args, gulong); \
182 case GST_PROPS_BOOL_TYPE: \
183 entry->data.bool_data = va_arg (var_args, gboolean); \
185 case GST_PROPS_STRING_TYPE: \
186 entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
194 #define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
196 GstPropsType propstype = va_arg (var_args, GstPropsType); \
201 if (propstype != entry->propstype) { \
206 switch (entry->propstype) { \
207 case GST_PROPS_INT_TYPE: \
208 *(va_arg (var_args, gint*)) = entry->data.int_data; \
210 case GST_PROPS_INT_RANGE_TYPE: \
211 *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
212 *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
214 case GST_PROPS_FLOAT_TYPE: \
215 *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
217 case GST_PROPS_FLOAT_RANGE_TYPE: \
218 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
219 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
221 case GST_PROPS_FOURCC_TYPE: \
222 *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
224 case GST_PROPS_BOOL_TYPE: \
225 *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
227 case GST_PROPS_STRING_TYPE: \
228 *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
230 case GST_PROPS_LIST_TYPE: \
231 *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
240 static GstPropsEntry*
241 gst_props_alloc_entry (void)
243 GstPropsEntry *entry;
245 g_mutex_lock (_gst_props_entries_chunk_lock);
246 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
247 g_mutex_unlock (_gst_props_entries_chunk_lock);
253 gst_props_entry_destroy (GstPropsEntry *entry)
255 switch (entry->propstype) {
256 case GST_PROPS_STRING_TYPE:
257 g_free (entry->data.string_data.string);
259 case GST_PROPS_LIST_TYPE:
261 GList *entries = entry->data.list_data.entries;
264 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
265 entries = g_list_next (entries);
267 g_list_free (entry->data.list_data.entries);
273 g_mutex_lock (_gst_props_entries_chunk_lock);
274 g_mem_chunk_free (_gst_props_entries_chunk, entry);
275 g_mutex_unlock (_gst_props_entries_chunk_lock);
279 * gst_props_empty_new:
281 * Create a new empty property.
283 * Returns: the new property
286 gst_props_empty_new (void)
290 g_mutex_lock (_gst_props_chunk_lock);
291 props = g_mem_chunk_alloc (_gst_props_chunk);
292 g_mutex_unlock (_gst_props_chunk_lock);
294 props->properties = NULL;
302 * gst_props_add_entry:
303 * @props: the property to add the entry to
304 * @entry: the entry to add
306 * Addes the given propsentry to the props
309 gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
311 g_return_if_fail (props);
312 g_return_if_fail (entry);
314 if (props->fixed && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
315 props->fixed = FALSE;
317 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
322 * @firstname: the first property name
323 * @...: the property values
325 * Create a new property from the given key/value pairs
327 * Returns: the new property
330 gst_props_new (const gchar *firstname, ...)
335 va_start (var_args, firstname);
337 props = gst_props_newv (firstname, var_args);
347 * @props: the props to debug
349 * Dump the contents of the given properties into the DEBUG log.
352 gst_props_debug (GstProps *props)
354 GList *propslist = props->properties;
357 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
359 gst_props_debug_entry (entry);
361 propslist = g_list_next (propslist);
366 * gst_props_merge_int_entries:
367 * @newentry: the new entry
368 * @oldentry: an old entry
370 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
372 * Assumes that the entries are either ints or int ranges.
374 * Returns: TRUE if the entries were merged, FALSE otherwise.
377 gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
379 gint new_min, new_max, old_min, old_max;
380 gboolean can_merge = FALSE;
382 if (newentry->propstype == GST_PROPS_INT_TYPE) {
383 new_min = newentry->data.int_data;
384 new_max = newentry->data.int_data;
386 new_min = newentry->data.int_range_data.min;
387 new_max = newentry->data.int_range_data.max;
390 if (oldentry->propstype == GST_PROPS_INT_TYPE) {
391 old_min = oldentry->data.int_data;
392 old_max = oldentry->data.int_data;
394 old_min = oldentry->data.int_range_data.min;
395 old_max = oldentry->data.int_range_data.max;
398 /* Put range which starts lower into (new_min, new_max) */
399 if (old_min < new_min) {
409 /* new_min is min of either entry - second half of the following conditional */
410 /* is to avoid overflow problems. */
411 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
412 /* ranges overlap, or are adjacent. Pick biggest maximum. */
414 if (old_max > new_max) new_max = old_max;
418 if (new_min == new_max) {
419 newentry->propstype = GST_PROPS_INT_TYPE;
420 newentry->data.int_data = new_min;
422 newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
423 newentry->data.int_range_data.min = new_min;
424 newentry->data.int_range_data.max = new_max;
431 * gst_props_add_to_int_list:
432 * @entries: the existing list of entries
433 * @entry: the new entry to add to the list
435 * Add an integer property to a list of properties, removing duplicates
436 * and merging ranges.
438 * Assumes that the existing list is in simplest form, contains
439 * only ints and int ranges, and that the new entry is an int or
442 * Returns: a pointer to a list with the new entry added.
445 gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
451 GstPropsEntry * oldentry = (GstPropsEntry *)(i->data);
452 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
455 /* replace the existing one with the merged one */
456 g_mutex_lock (_gst_props_entries_chunk_lock);
457 g_mem_chunk_free (_gst_props_entries_chunk, oldentry);
458 g_mutex_unlock (_gst_props_entries_chunk_lock);
459 entries = g_list_remove_link (entries, i);
462 /* start again: it's possible that this change made an earlier entry */
463 /* mergeable, and the pointer is now invalid anyway. */
470 return g_list_prepend (entries, newentry);
473 static GstPropsEntry*
474 gst_props_entry_newv (const gchar *name, va_list var_args)
476 GstPropsEntry *entry;
478 entry = gst_props_alloc_entry ();
479 entry->propid = g_quark_from_string (name);
480 GST_PROPS_ENTRY_FILL (entry, var_args);
486 * gst_props_entry_new:
487 * @name: the name of the props entry
488 * @...: the value of the entry
490 * Create a new property entry with the given key/value.
492 * Returns: the new entry.
495 gst_props_entry_new (const gchar *name, ...)
498 GstPropsEntry *entry;
500 va_start (var_args, name);
501 entry = gst_props_entry_newv (name, var_args);
509 * @firstname: the first property name
510 * @var_args: the property values
512 * Create a new property from the list of entries.
514 * Returns: the new property created from the list of entries
517 gst_props_newv (const gchar *firstname, va_list var_args)
520 gboolean inlist = FALSE;
521 const gchar *prop_name;
522 GstPropsEntry *list_entry = NULL;
525 GST_PROPS_LIST_T_UNSET,
526 GST_PROPS_LIST_T_INTS,
527 GST_PROPS_LIST_T_FLOATS,
528 GST_PROPS_LIST_T_MISC,
531 /* type of the list */
532 list_types list_type = GST_PROPS_LIST_T_UNSET;
533 /* type of current item */
534 list_types entry_type = GST_PROPS_LIST_T_UNSET;
536 if (firstname == NULL)
539 props = gst_props_empty_new ();
541 prop_name = firstname;
545 GstPropsEntry *entry;
547 entry = gst_props_alloc_entry ();
548 entry->propid = g_quark_from_string (prop_name);
549 GST_PROPS_ENTRY_FILL (entry, var_args);
551 switch (entry->propstype) {
552 case GST_PROPS_INT_TYPE:
553 case GST_PROPS_INT_RANGE_TYPE:
554 entry_type = GST_PROPS_LIST_T_INTS;
556 case GST_PROPS_FLOAT_TYPE:
557 case GST_PROPS_FLOAT_RANGE_TYPE:
558 entry_type = GST_PROPS_LIST_T_FLOATS;
560 case GST_PROPS_FOURCC_TYPE:
561 case GST_PROPS_BOOL_TYPE:
562 case GST_PROPS_STRING_TYPE:
563 entry_type = GST_PROPS_LIST_T_MISC;
565 case GST_PROPS_LIST_TYPE:
566 g_return_val_if_fail (inlist == FALSE, NULL);
569 list_type = GST_PROPS_LIST_T_UNSET;
570 list_entry->data.list_data.entries = NULL;
572 case GST_PROPS_END_TYPE:
573 g_return_val_if_fail (inlist == TRUE, NULL);
575 /* if list was of size 1, replace the list by a the item it contains */
576 if (g_list_length(list_entry->data.list_data.entries) == 1) {
577 GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
578 list_entry->propstype = subentry->propstype;
579 list_entry->data = subentry->data;
580 g_mutex_lock (_gst_props_entries_chunk_lock);
581 g_mem_chunk_free (_gst_props_entries_chunk, subentry);
582 g_mutex_unlock (_gst_props_entries_chunk_lock);
585 list_entry->data.list_data.entries =
586 g_list_reverse (list_entry->data.list_data.entries);
589 g_mutex_lock (_gst_props_entries_chunk_lock);
590 g_mem_chunk_free (_gst_props_entries_chunk, entry);
591 g_mutex_unlock (_gst_props_entries_chunk_lock);
594 prop_name = va_arg (var_args, gchar*);
597 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
598 g_mutex_lock (_gst_props_entries_chunk_lock);
599 g_mem_chunk_free (_gst_props_entries_chunk, entry);
600 g_mutex_unlock (_gst_props_entries_chunk_lock);
604 if (inlist && (list_entry != entry)) {
605 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
606 if (list_type != entry_type) {
607 g_warning ("property list contained incompatible entry types\n");
610 case GST_PROPS_LIST_T_INTS:
611 list_entry->data.list_data.entries =
612 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
615 list_entry->data.list_data.entries =
616 g_list_prepend (list_entry->data.list_data.entries, entry);
622 gst_props_add_entry (props, entry);
625 prop_name = va_arg (var_args, gchar*);
633 * @props: the props to modify
634 * @name: the name of the entry to modify
635 * @...: The prop entry.
637 * Modifies the value of the given entry in the props struct.
638 * For the optional args, use GST_PROPS_FOO, where FOO is INT,
639 * STRING, etc. This macro expands to a variable number of arguments,
640 * hence the lack of precision in the function prototype. No
641 * terminating NULL is necessary as only one property can be changed.
643 * Returns: the new modified property structure.
646 gst_props_set (GstProps *props, const gchar *name, ...)
652 g_return_val_if_fail (props != NULL, NULL);
654 quark = g_quark_from_string (name);
656 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
659 GstPropsEntry *entry;
661 entry = (GstPropsEntry *)lentry->data;
663 va_start (var_args, name);
665 GST_PROPS_ENTRY_FILL (entry, var_args);
670 g_print("gstprops: no property '%s' to change\n", name);
679 * @props: the props to unref
681 * Decrease the refcount of the property structure, destroying
682 * the property if the refcount is 0.
685 gst_props_unref (GstProps *props)
692 if (props->refcount == 0)
693 gst_props_destroy (props);
698 * @props: the props to ref
700 * Increase the refcount of the property structure.
703 gst_props_ref (GstProps *props)
705 g_return_if_fail (props != NULL);
713 * @props: the props to destroy
715 * Destroy the property, freeing all the memory that
719 gst_props_destroy (GstProps *props)
726 entries = props->properties;
729 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
730 entries = g_list_next (entries);
732 g_list_free (props->properties);
734 g_mutex_lock (_gst_props_chunk_lock);
735 g_mem_chunk_free (_gst_props_chunk, props);
736 g_mutex_unlock (_gst_props_chunk_lock);
742 static GstPropsEntry*
743 gst_props_entry_copy (GstPropsEntry *entry)
745 GstPropsEntry *newentry;
747 newentry = gst_props_alloc_entry ();
748 memcpy (newentry, entry, sizeof (GstPropsEntry));
749 if (entry->propstype == GST_PROPS_LIST_TYPE) {
750 newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
752 else if (entry->propstype == GST_PROPS_STRING_TYPE) {
753 newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
760 gst_props_list_copy (GList *propslist)
765 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
767 new = g_list_prepend (new, gst_props_entry_copy (entry));
769 propslist = g_list_next (propslist);
771 new = g_list_reverse (new);
778 * @props: the props to copy
780 * Copy the property structure.
782 * Returns: the new property that is a copy of the original
786 gst_props_copy (GstProps *props)
793 new = gst_props_empty_new ();
794 new->properties = gst_props_list_copy (props->properties);
795 new->fixed = props->fixed;
801 * gst_props_copy_on_write:
802 * @props: the props to copy on write
804 * Copy the property structure if the refcount is >1.
806 * Returns: A new props that can be safely written to.
809 gst_props_copy_on_write (GstProps *props)
811 GstProps *new = props;;
813 g_return_val_if_fail (props != NULL, NULL);
815 if (props->refcount > 1) {
816 new = gst_props_copy (props);
817 gst_props_unref (props);
824 * gst_props_get_entry:
825 * @props: the props to query
826 * @name: the name of the entry to get
828 * Get the props entry with the geven name
830 * Returns: The props entry with the geven name or NULL when
831 * the entry was not found.
834 gst_props_get_entry (GstProps *props, const gchar *name)
839 g_return_val_if_fail (props != NULL, NULL);
840 g_return_val_if_fail (name != NULL, NULL);
842 quark = g_quark_from_string (name);
844 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
847 GstPropsEntry *thisentry;
848 thisentry = (GstPropsEntry *)lentry->data;
855 * gst_props_has_property:
856 * @props: the props to check
857 * @name: the name of the key to find
859 * Checks if a given props has a property with the given name.
861 * Returns: TRUE if the property was found, FALSE otherwise.
864 gst_props_has_property (GstProps *props, const gchar *name)
866 return (gst_props_get_entry (props, name) != NULL);
870 * gst_props_has_property_typed:
871 * @props: the props to check
872 * @name: the name of the key to find
873 * @type: the type of the required property
875 * Checks if a given props has a property with the given name and the given type.
877 * Returns: TRUE if the property was found, FALSE otherwise.
880 gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
882 const GstPropsEntry *entry;
884 entry = gst_props_get_entry (props, name);
888 return (entry->propstype == type);
892 * gst_props_has_fixed_property:
893 * @props: the props to check
894 * @name: the name of the key to find
896 * Checks if a given props has a property with the given name that
897 * is also fixed, ie. is not a list or a range.
899 * Returns: TRUE if the property was found, FALSE otherwise.
902 gst_props_has_fixed_property (GstProps *props, const gchar *name)
904 const GstPropsEntry *entry;
906 entry = gst_props_get_entry (props, name);
910 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
914 * gst_props_entry_get_type:
915 * @entry: the props entry to query
917 * Get the type of the given props entry.
919 * Returns: The type of the props entry.
922 gst_props_entry_get_type (const GstPropsEntry *entry)
924 g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
926 return entry->propstype;
930 * gst_props_entry_get_name:
931 * @entry: the props entry to query
933 * Get the name of the given props entry.
935 * Returns: The name of the props entry.
938 gst_props_entry_get_name (const GstPropsEntry *entry)
940 g_return_val_if_fail (entry != NULL, NULL);
942 return g_quark_to_string (entry->propid);
946 * gst_props_entry_is_fixed:
947 * @entry: the props entry to query
949 * Checks if the props entry is fixe, ie. is not a list
952 * Returns: TRUE is the props entry is fixed.
955 gst_props_entry_is_fixed (const GstPropsEntry *entry)
957 g_return_val_if_fail (entry != NULL, FALSE);
959 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
963 gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
967 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
973 * gst_props_entry_get:
974 * @entry: the props entry to query
975 * @...: a pointer to a type that can hold the value.
977 * Gets the contents of the entry.
979 * Returns: TRUE is the props entry could be fetched.
982 gst_props_entry_get (const GstPropsEntry *entry, ...)
987 g_return_val_if_fail (entry != NULL, FALSE);
989 va_start (var_args, entry);
990 result = gst_props_entry_getv (entry, FALSE, var_args);
997 gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
1002 g_return_val_if_fail (entry != NULL, FALSE);
1004 va_start (var_args, entry);
1005 result = gst_props_entry_getv (entry, TRUE, var_args);
1013 * @props: the props to query
1014 * @first_name: the first key
1015 * @...: a pointer to a datastructure that can hold the value.
1017 * Gets the contents of the props into given key/value pairs.
1019 * Returns: TRUE is the props entry could be fetched.
1022 gst_props_get (GstProps *props, gchar *first_name, ...)
1026 va_start (var_args, first_name);
1028 while (first_name) {
1029 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1032 if (!entry) return FALSE;
1033 GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
1034 if (!result) return FALSE;
1036 first_name = va_arg (var_args, gchar *);
1044 * gst_props_entry_get_int:
1045 * @entry: the props entry to query
1046 * @val: a pointer to a gint to hold the value.
1048 * Get the contents of the entry into the given gint.
1050 * Returns: TRUE is the value could be fetched. FALSE if the
1051 * entry is not of given type.
1054 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1056 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1060 * gst_props_entry_get_float:
1061 * @entry: the props entry to query
1062 * @val: a pointer to a gfloat to hold the value.
1064 * Get the contents of the entry into the given gfloat.
1066 * Returns: TRUE is the value could be fetched. FALSE if the
1067 * entry is not of given type.
1070 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1072 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1076 * gst_props_entry_get_fourcc_int:
1077 * @entry: the props entry to query
1078 * @val: a pointer to a guint32 to hold the value.
1080 * Get the contents of the entry into the given guint32.
1082 * Returns: TRUE is the value could be fetched. FALSE if the
1083 * entry is not of given type.
1086 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1088 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1092 * gst_props_entry_get_boolean:
1093 * @entry: the props entry to query
1094 * @val: a pointer to a gboolean to hold the value.
1096 * Get the contents of the entry into the given gboolean.
1098 * Returns: TRUE is the value could be fetched. FALSE if the
1099 * entry is not of given type.
1102 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1104 return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val);
1108 * gst_props_entry_get_string:
1109 * @entry: the props entry to query
1110 * @val: a pointer to a gchar* to hold the value.
1112 * Get the contents of the entry into the given gchar*.
1114 * Returns: TRUE is the value could be fetched. FALSE if the
1115 * entry is not of given type.
1118 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1120 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1124 * gst_props_entry_get_int_range:
1125 * @entry: the props entry to query
1126 * @min: a pointer to a gint to hold the minimun value.
1127 * @max: a pointer to a gint to hold the maximum value.
1129 * Get the contents of the entry into the given gints.
1131 * Returns: TRUE is the value could be fetched. FALSE if the
1132 * entry is not of given type.
1135 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1137 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1141 * gst_props_entry_get_float_range:
1142 * @entry: the props entry to query
1143 * @min: a pointer to a gfloat to hold the minimun value.
1144 * @max: a pointer to a gfloat to hold the maximum value.
1146 * Get the contents of the entry into the given gfloats.
1148 * Returns: TRUE is the value could be fetched. FALSE if the
1149 * entry is not of given type.
1152 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1154 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1158 * gst_props_entry_get_list:
1159 * @entry: the props entry to query
1160 * @val: a pointer to a GList to hold the value.
1162 * Get the contents of the entry into the given GList.
1164 * Returns: TRUE is the value could be fetched. FALSE if the
1165 * entry is not of given type.
1168 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1170 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1175 * @props: the property to merge into
1176 * @tomerge: the property to merge
1178 * Merge the properties of tomerge into props.
1180 * Returns: the new merged property
1183 gst_props_merge (GstProps *props, GstProps *tomerge)
1187 g_return_val_if_fail (props != NULL, NULL);
1188 g_return_val_if_fail (tomerge != NULL, NULL);
1190 merge_props = tomerge->properties;
1192 /* FIXME do proper merging here... */
1193 while (merge_props) {
1194 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1196 gst_props_add_entry (props, entry);
1198 merge_props = g_list_next (merge_props);
1205 /* entry2 is always a list, entry1 never is */
1207 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1209 GList *entrylist = entry2->data.list_data.entries;
1210 gboolean found = FALSE;
1212 while (entrylist && !found) {
1213 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1215 found |= gst_props_entry_check_compatibility (entry1, entry);
1217 entrylist = g_list_next (entrylist);
1224 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1226 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1227 g_quark_to_string (entry2->propid));
1229 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1230 return gst_props_entry_check_list_compatibility (entry1, entry2);
1233 switch (entry1->propstype) {
1234 case GST_PROPS_LIST_TYPE:
1236 GList *entrylist = entry1->data.list_data.entries;
1237 gboolean valid = TRUE; /* innocent until proven guilty */
1239 while (entrylist && valid) {
1240 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1242 valid &= gst_props_entry_check_compatibility (entry, entry2);
1244 entrylist = g_list_next (entrylist);
1249 case GST_PROPS_INT_RANGE_TYPE:
1250 switch (entry2->propstype) {
1251 /* a - b <---> a - c */
1252 case GST_PROPS_INT_RANGE_TYPE:
1253 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1254 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1259 case GST_PROPS_FLOAT_RANGE_TYPE:
1260 switch (entry2->propstype) {
1261 /* a - b <---> a - c */
1262 case GST_PROPS_FLOAT_RANGE_TYPE:
1263 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1264 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1269 case GST_PROPS_FOURCC_TYPE:
1270 switch (entry2->propstype) {
1272 case GST_PROPS_FOURCC_TYPE:
1273 GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?",
1274 (char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data);
1275 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1280 case GST_PROPS_INT_TYPE:
1281 switch (entry2->propstype) {
1283 case GST_PROPS_INT_RANGE_TYPE:
1284 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1285 entry1->data.int_data,entry2->data.int_range_data.max);
1286 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1287 entry2->data.int_range_data.max >= entry1->data.int_data);
1289 case GST_PROPS_INT_TYPE:
1290 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1291 return (entry2->data.int_data == entry1->data.int_data);
1296 case GST_PROPS_FLOAT_TYPE:
1297 switch (entry2->propstype) {
1299 case GST_PROPS_FLOAT_RANGE_TYPE:
1300 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1301 entry2->data.float_range_data.max >= entry1->data.float_data);
1303 case GST_PROPS_FLOAT_TYPE:
1304 return (entry2->data.float_data == entry1->data.float_data);
1309 case GST_PROPS_BOOL_TYPE:
1310 switch (entry2->propstype) {
1312 case GST_PROPS_BOOL_TYPE:
1313 return (entry2->data.bool_data == entry1->data.bool_data);
1317 case GST_PROPS_STRING_TYPE:
1318 switch (entry2->propstype) {
1320 case GST_PROPS_STRING_TYPE:
1321 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1322 entry2->data.string_data.string, entry1->data.string_data.string);
1323 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1335 * gst_props_check_compatibility:
1336 * @fromprops: a property
1337 * @toprops: a property
1339 * Checks whether two capabilities are compatible.
1341 * Returns: TRUE if compatible, FALSE otherwise
1344 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1350 gboolean compatible = TRUE;
1352 g_return_val_if_fail (fromprops != NULL, FALSE);
1353 g_return_val_if_fail (toprops != NULL, FALSE);
1355 sourcelist = fromprops->properties;
1356 sinklist = toprops->properties;
1358 while (sourcelist && sinklist && compatible) {
1359 GstPropsEntry *entry1;
1360 GstPropsEntry *entry2;
1362 entry1 = (GstPropsEntry *)sourcelist->data;
1363 entry2 = (GstPropsEntry *)sinklist->data;
1365 while (entry1->propid < entry2->propid) {
1367 sourcelist = g_list_next (sourcelist);
1368 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1371 while (entry1->propid > entry2->propid) {
1373 sinklist = g_list_next (sinklist);
1374 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1378 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1380 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1381 g_quark_to_string (entry1->propid));
1384 sourcelist = g_list_next (sourcelist);
1385 sinklist = g_list_next (sinklist);
1387 if (sinklist && compatible) {
1388 GstPropsEntry *entry2;
1389 entry2 = (GstPropsEntry *)sinklist->data;
1400 static GstPropsEntry*
1401 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1403 GstPropsEntry *result = NULL;
1405 /* try to move the ranges and lists first */
1406 switch (entry2->propstype) {
1407 case GST_PROPS_INT_RANGE_TYPE:
1408 case GST_PROPS_FLOAT_RANGE_TYPE:
1409 case GST_PROPS_LIST_TYPE:
1411 GstPropsEntry *temp;
1421 switch (entry1->propstype) {
1422 case GST_PROPS_LIST_TYPE:
1424 GList *entrylist = entry1->data.list_data.entries;
1425 GList *intersection = NULL;
1428 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1429 GstPropsEntry *intersectentry;
1431 intersectentry = gst_props_entry_intersect (entry2, entry);
1433 if (intersectentry) {
1434 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1435 intersection = g_list_concat (intersection, intersectentry->data.list_data.entries);
1436 /* set the list to NULL because the entries are concatenated to the above
1437 * list and we don't want to free them */
1438 intersectentry->data.list_data.entries = NULL;
1439 gst_props_entry_destroy (intersectentry);
1442 intersection = g_list_prepend (intersection, intersectentry);
1445 entrylist = g_list_next (entrylist);
1448 /* check if the list only contains 1 element, if so, we can just copy it */
1449 if (g_list_next (intersection) == NULL) {
1450 result = (GstPropsEntry *) (intersection->data);
1451 g_list_free (intersection);
1453 /* else we need to create a new entry to hold the list */
1455 result = gst_props_alloc_entry ();
1456 result->propid = entry1->propid;
1457 result->propstype = GST_PROPS_LIST_TYPE;
1458 result->data.list_data.entries = g_list_reverse (intersection);
1463 case GST_PROPS_INT_RANGE_TYPE:
1464 switch (entry2->propstype) {
1465 /* a - b <---> a - c */
1466 case GST_PROPS_INT_RANGE_TYPE:
1468 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1469 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1471 if (lower <= upper) {
1472 result = gst_props_alloc_entry ();
1473 result->propid = entry1->propid;
1475 if (lower == upper) {
1476 result->propstype = GST_PROPS_INT_TYPE;
1477 result->data.int_data = lower;
1480 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1481 result->data.int_range_data.min = lower;
1482 result->data.int_range_data.max = upper;
1487 case GST_PROPS_LIST_TYPE:
1489 GList *entries = entry2->data.list_data.entries;
1490 result = gst_props_alloc_entry ();
1491 result->propid = entry1->propid;
1492 result->propstype = GST_PROPS_LIST_TYPE;
1493 result->data.list_data.entries = NULL;
1495 GstPropsEntry * this = (GstPropsEntry *)entries->data;
1496 if (this->propstype != GST_PROPS_INT_TYPE) {
1497 /* no hope, this list doesn't even contain ints! */
1498 gst_props_entry_destroy (result);
1502 if (this->data.int_data >= entry1->data.int_range_data.min &&
1503 this->data.int_data <= entry1->data.int_range_data.max) {
1504 result->data.list_data.entries = g_list_append (result->data.list_data.entries,
1505 gst_props_entry_copy (this));
1507 entries = g_list_next (entries);
1511 case GST_PROPS_INT_TYPE:
1513 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1514 entry1->data.int_range_data.max >= entry2->data.int_data) {
1515 result = gst_props_entry_copy (entry2);
1523 case GST_PROPS_FLOAT_RANGE_TYPE:
1524 switch (entry2->propstype) {
1525 /* a - b <---> a - c */
1526 case GST_PROPS_FLOAT_RANGE_TYPE:
1528 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1529 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1531 if (lower <= upper) {
1532 result = gst_props_alloc_entry ();
1533 result->propid = entry1->propid;
1535 if (lower == upper) {
1536 result->propstype = GST_PROPS_FLOAT_TYPE;
1537 result->data.float_data = lower;
1540 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1541 result->data.float_range_data.min = lower;
1542 result->data.float_range_data.max = upper;
1547 case GST_PROPS_FLOAT_TYPE:
1548 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1549 entry1->data.float_range_data.max >= entry2->data.float_data) {
1550 result = gst_props_entry_copy (entry2);
1556 case GST_PROPS_FOURCC_TYPE:
1557 switch (entry2->propstype) {
1559 case GST_PROPS_FOURCC_TYPE:
1560 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1561 result = gst_props_entry_copy (entry1);
1566 case GST_PROPS_INT_TYPE:
1567 switch (entry2->propstype) {
1569 case GST_PROPS_INT_TYPE:
1570 if (entry1->data.int_data == entry2->data.int_data)
1571 result = gst_props_entry_copy (entry1);
1576 case GST_PROPS_FLOAT_TYPE:
1577 switch (entry2->propstype) {
1579 case GST_PROPS_FLOAT_TYPE:
1580 if (entry1->data.float_data == entry2->data.float_data)
1581 result = gst_props_entry_copy (entry1);
1586 case GST_PROPS_BOOL_TYPE:
1587 switch (entry2->propstype) {
1589 case GST_PROPS_BOOL_TYPE:
1590 if (entry1->data.bool_data == entry2->data.bool_data)
1591 result = gst_props_entry_copy (entry1);
1595 case GST_PROPS_STRING_TYPE:
1596 switch (entry2->propstype) {
1598 case GST_PROPS_STRING_TYPE:
1599 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1600 result = gst_props_entry_copy (entry1);
1612 * gst_props_intersect:
1613 * @props1: a property
1614 * @props2: another property
1616 * Calculates the intersection bewteen two GstProps.
1618 * Returns: a GstProps with the intersection or NULL if the
1619 * intersection is empty.
1622 gst_props_intersect (GstProps *props1, GstProps *props2)
1626 GstProps *intersection;
1628 GstPropsEntry *iprops = NULL;
1630 intersection = gst_props_empty_new ();
1631 intersection->fixed = TRUE;
1633 g_return_val_if_fail (props1 != NULL, NULL);
1634 g_return_val_if_fail (props2 != NULL, NULL);
1636 props1list = props1->properties;
1637 props2list = props2->properties;
1639 while (props1list && props2list) {
1640 GstPropsEntry *entry1;
1641 GstPropsEntry *entry2;
1643 entry1 = (GstPropsEntry *)props1list->data;
1644 entry2 = (GstPropsEntry *)props2list->data;
1646 while (entry1->propid < entry2->propid) {
1647 GstPropsEntry *toadd;
1649 GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"", g_quark_to_string (entry1->propid));
1651 toadd = gst_props_entry_copy (entry1);
1652 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1653 intersection->fixed = FALSE;
1655 intersection->properties = g_list_prepend (intersection->properties, toadd);
1657 props1list = g_list_next (props1list);
1659 entry1 = (GstPropsEntry *)props1list->data;
1663 while (entry1->propid > entry2->propid) {
1664 GstPropsEntry *toadd;
1666 toadd = gst_props_entry_copy (entry2);
1667 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1668 intersection->fixed = FALSE;
1670 intersection->properties = g_list_prepend (intersection->properties, toadd);
1672 props2list = g_list_next (props2list);
1674 entry2 = (GstPropsEntry *)props2list->data;
1678 /* at this point we are talking about the same property */
1679 iprops = gst_props_entry_intersect (entry1, entry2);
1682 if (GST_PROPS_ENTRY_IS_VARIABLE (iprops))
1683 intersection->fixed = FALSE;
1684 intersection->properties = g_list_prepend (intersection->properties, iprops);
1687 gst_props_unref (intersection);
1691 props1list = g_list_next (props1list);
1692 props2list = g_list_next (props2list);
1696 /* at this point one of the lists could contain leftover properties */
1698 leftovers = props1list;
1699 else if (props2list)
1700 leftovers = props2list;
1705 GstPropsEntry *entry;
1707 entry = (GstPropsEntry *) leftovers->data;
1708 if (GST_PROPS_ENTRY_IS_VARIABLE (entry))
1709 intersection->fixed = FALSE;
1710 intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry));
1712 leftovers = g_list_next (leftovers);
1715 intersection->properties = g_list_reverse (intersection->properties);
1717 return intersection;
1721 * gst_props_normalize:
1722 * @props: a property
1724 * Unrolls all lists in the given GstProps. This is usefull if you
1725 * want to loop over the props.
1727 * Returns: A GList with the unrolled props entries.
1730 gst_props_normalize (GstProps *props)
1733 GList *result = NULL;
1738 entries = props->properties;
1741 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1743 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1744 GList *list_entries = entry->data.list_data.entries;
1746 while (list_entries) {
1747 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1748 GstPropsEntry *new_entry;
1752 newprops = gst_props_empty_new ();
1753 newprops->properties = gst_props_list_copy (props->properties);
1754 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
1756 GList *new_list = NULL;
1758 new_entry = (GstPropsEntry *) lentry->data;
1759 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
1761 new_list = gst_props_normalize (newprops);
1762 result = g_list_concat (new_list, result);
1765 result = g_list_append (result, newprops);
1768 list_entries = g_list_next (list_entries);
1770 /* we break out of the loop because the other lists are
1771 * unrolled in the recursive call */
1774 entries = g_list_next (entries);
1777 result = g_list_prepend (result, props);
1780 result = g_list_reverse (result);
1781 gst_props_unref (props);
1786 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
1788 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
1793 switch (entry->propstype) {
1794 case GST_PROPS_INT_TYPE:
1795 subtree = xmlNewChild (parent, NULL, "int", NULL);
1796 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1797 str = g_strdup_printf ("%d", entry->data.int_data);
1798 xmlNewProp (subtree, "value", str);
1801 case GST_PROPS_INT_RANGE_TYPE:
1802 subtree = xmlNewChild (parent, NULL, "range", NULL);
1803 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1804 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
1805 xmlNewProp (subtree, "min", str);
1807 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
1808 xmlNewProp (subtree, "max", str);
1811 case GST_PROPS_FLOAT_TYPE:
1812 subtree = xmlNewChild (parent, NULL, "float", NULL);
1813 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1814 str = g_strdup_printf ("%f", entry->data.float_data);
1815 xmlNewProp (subtree, "value", str);
1818 case GST_PROPS_FLOAT_RANGE_TYPE:
1819 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
1820 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1821 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
1822 xmlNewProp (subtree, "min", str);
1824 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
1825 xmlNewProp (subtree, "max", str);
1828 case GST_PROPS_FOURCC_TYPE:
1829 str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
1830 xmlAddChild (parent, xmlNewComment (str));
1832 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
1833 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1834 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
1835 xmlNewProp (subtree, "hexvalue", str);
1838 case GST_PROPS_BOOL_TYPE:
1839 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
1840 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1841 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
1843 case GST_PROPS_STRING_TYPE:
1844 subtree = xmlNewChild (parent, NULL, "string", NULL);
1845 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1846 xmlNewProp (subtree, "value", entry->data.string_data.string);
1849 g_warning ("trying to save unknown property type %d", entry->propstype);
1857 * gst_props_save_thyself:
1858 * @props: a property to save
1859 * @parent: the parent XML tree
1861 * Saves the property into an XML representation.
1863 * Returns: the new XML tree
1866 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
1871 g_return_val_if_fail (props != NULL, NULL);
1873 proplist = props->properties;
1876 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
1878 switch (entry->propstype) {
1879 case GST_PROPS_LIST_TYPE:
1880 subtree = xmlNewChild (parent, NULL, "list", NULL);
1881 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1882 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
1885 gst_props_save_thyself_func (entry, parent);
1888 proplist = g_list_next (proplist);
1894 static GstPropsEntry*
1895 gst_props_load_thyself_func (xmlNodePtr field)
1897 GstPropsEntry *entry;
1900 entry = gst_props_alloc_entry ();
1902 if (!strcmp(field->name, "int")) {
1903 entry->propstype = GST_PROPS_INT_TYPE;
1904 prop = xmlGetProp(field, "name");
1905 entry->propid = g_quark_from_string (prop);
1907 prop = xmlGetProp(field, "value");
1908 sscanf (prop, "%d", &entry->data.int_data);
1911 else if (!strcmp(field->name, "range")) {
1912 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
1913 prop = xmlGetProp(field, "name");
1914 entry->propid = g_quark_from_string (prop);
1916 prop = xmlGetProp (field, "min");
1917 sscanf (prop, "%d", &entry->data.int_range_data.min);
1919 prop = xmlGetProp (field, "max");
1920 sscanf (prop, "%d", &entry->data.int_range_data.max);
1923 else if (!strcmp(field->name, "float")) {
1924 entry->propstype = GST_PROPS_FLOAT_TYPE;
1925 prop = xmlGetProp(field, "name");
1926 entry->propid = g_quark_from_string (prop);
1928 prop = xmlGetProp(field, "value");
1929 sscanf (prop, "%f", &entry->data.float_data);
1932 else if (!strcmp(field->name, "floatrange")) {
1933 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1934 prop = xmlGetProp(field, "name");
1935 entry->propid = g_quark_from_string (prop);
1937 prop = xmlGetProp (field, "min");
1938 sscanf (prop, "%f", &entry->data.float_range_data.min);
1940 prop = xmlGetProp (field, "max");
1941 sscanf (prop, "%f", &entry->data.float_range_data.max);
1944 else if (!strcmp(field->name, "boolean")) {
1945 entry->propstype = GST_PROPS_BOOL_TYPE;
1946 prop = xmlGetProp(field, "name");
1947 entry->propid = g_quark_from_string (prop);
1949 prop = xmlGetProp (field, "value");
1950 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
1951 else entry->data.bool_data = 1;
1954 else if (!strcmp(field->name, "fourcc")) {
1955 entry->propstype = GST_PROPS_FOURCC_TYPE;
1956 prop = xmlGetProp(field, "name");
1957 entry->propid = g_quark_from_string (prop);
1959 prop = xmlGetProp (field, "hexvalue");
1960 sscanf (prop, "%08x", &entry->data.fourcc_data);
1963 else if (!strcmp(field->name, "string")) {
1964 entry->propstype = GST_PROPS_STRING_TYPE;
1965 prop = xmlGetProp(field, "name");
1966 entry->propid = g_quark_from_string (prop);
1968 entry->data.string_data.string = xmlGetProp (field, "value");
1971 g_mutex_lock (_gst_props_entries_chunk_lock);
1972 g_mem_chunk_free (_gst_props_entries_chunk, entry);
1973 g_mutex_unlock (_gst_props_entries_chunk_lock);
1981 * gst_props_load_thyself:
1982 * @parent: the XML tree to load from
1984 * Creates a new property out of an XML tree.
1986 * Returns: the new property
1989 gst_props_load_thyself (xmlNodePtr parent)
1992 xmlNodePtr field = parent->xmlChildrenNode;
1995 props = gst_props_empty_new ();
1998 if (!strcmp (field->name, "list")) {
1999 GstPropsEntry *entry;
2000 xmlNodePtr subfield = field->xmlChildrenNode;
2002 entry = gst_props_alloc_entry ();
2003 prop = xmlGetProp (field, "name");
2004 entry->propid = g_quark_from_string (prop);
2006 entry->propstype = GST_PROPS_LIST_TYPE;
2007 entry->data.list_data.entries = NULL;
2010 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2013 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2015 subfield = subfield->next;
2017 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2018 gst_props_add_entry (props, entry);
2021 GstPropsEntry *entry;
2023 entry = gst_props_load_thyself_func (field);
2026 gst_props_add_entry (props, entry);
2028 field = field->next;
2033 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */