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) \
200 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_warning ("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);
1012 gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args)
1014 while (first_name) {
1015 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1018 if (!entry) return FALSE;
1019 GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
1020 if (!result) return FALSE;
1022 first_name = va_arg (var_args, gchar *);
1029 * @props: the props to query
1030 * @first_name: the first key
1031 * @...: a pointer to a datastructure that can hold the value.
1033 * Gets the contents of the props into given key/value pairs.
1035 * Returns: TRUE is the props entry could be fetched.
1038 gst_props_get (GstProps *props, gchar *first_name, ...)
1043 va_start (var_args, first_name);
1044 ret = gst_props_getv (props, FALSE, first_name, var_args);
1051 * gst_props_get_safe:
1052 * @props: the props to query
1053 * @first_name: the first key
1054 * @...: a pointer to a datastructure that can hold the value.
1056 * Gets the contents of the props into given key/value pairs.
1058 * Returns: TRUE is the props entry could be fetched.
1061 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
1066 va_start (var_args, first_name);
1067 ret = gst_props_getv (props, TRUE, first_name, var_args);
1074 * gst_props_entry_get_int:
1075 * @entry: the props entry to query
1076 * @val: a pointer to a gint to hold the value.
1078 * Get the contents of the entry into the given gint.
1080 * Returns: TRUE is the value could be fetched. FALSE if the
1081 * entry is not of given type.
1084 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1086 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1090 * gst_props_entry_get_float:
1091 * @entry: the props entry to query
1092 * @val: a pointer to a gfloat to hold the value.
1094 * Get the contents of the entry into the given gfloat.
1096 * Returns: TRUE is the value could be fetched. FALSE if the
1097 * entry is not of given type.
1100 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1102 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1106 * gst_props_entry_get_fourcc_int:
1107 * @entry: the props entry to query
1108 * @val: a pointer to a guint32 to hold the value.
1110 * Get the contents of the entry into the given guint32.
1112 * Returns: TRUE is the value could be fetched. FALSE if the
1113 * entry is not of given type.
1116 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1118 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1122 * gst_props_entry_get_boolean:
1123 * @entry: the props entry to query
1124 * @val: a pointer to a gboolean to hold the value.
1126 * Get the contents of the entry into the given gboolean.
1128 * Returns: TRUE is the value could be fetched. FALSE if the
1129 * entry is not of given type.
1132 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1134 return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val);
1138 * gst_props_entry_get_string:
1139 * @entry: the props entry to query
1140 * @val: a pointer to a gchar* to hold the value.
1142 * Get the contents of the entry into the given gchar*.
1144 * Returns: TRUE is the value could be fetched. FALSE if the
1145 * entry is not of given type.
1148 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1150 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1154 * gst_props_entry_get_int_range:
1155 * @entry: the props entry to query
1156 * @min: a pointer to a gint to hold the minimun value.
1157 * @max: a pointer to a gint to hold the maximum value.
1159 * Get the contents of the entry into the given gints.
1161 * Returns: TRUE is the value could be fetched. FALSE if the
1162 * entry is not of given type.
1165 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1167 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1171 * gst_props_entry_get_float_range:
1172 * @entry: the props entry to query
1173 * @min: a pointer to a gfloat to hold the minimun value.
1174 * @max: a pointer to a gfloat to hold the maximum value.
1176 * Get the contents of the entry into the given gfloats.
1178 * Returns: TRUE is the value could be fetched. FALSE if the
1179 * entry is not of given type.
1182 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1184 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1188 * gst_props_entry_get_list:
1189 * @entry: the props entry to query
1190 * @val: a pointer to a GList to hold the value.
1192 * Get the contents of the entry into the given GList.
1194 * Returns: TRUE is the value could be fetched. FALSE if the
1195 * entry is not of given type.
1198 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1200 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1205 * @props: the property to merge into
1206 * @tomerge: the property to merge
1208 * Merge the properties of tomerge into props.
1210 * Returns: the new merged property
1213 gst_props_merge (GstProps *props, GstProps *tomerge)
1217 g_return_val_if_fail (props != NULL, NULL);
1218 g_return_val_if_fail (tomerge != NULL, NULL);
1220 merge_props = tomerge->properties;
1222 /* FIXME do proper merging here... */
1223 while (merge_props) {
1224 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1226 gst_props_add_entry (props, entry);
1228 merge_props = g_list_next (merge_props);
1235 /* entry2 is always a list, entry1 never is */
1237 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1239 GList *entrylist = entry2->data.list_data.entries;
1240 gboolean found = FALSE;
1242 while (entrylist && !found) {
1243 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1245 found |= gst_props_entry_check_compatibility (entry1, entry);
1247 entrylist = g_list_next (entrylist);
1254 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1256 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1257 g_quark_to_string (entry2->propid));
1259 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1260 return gst_props_entry_check_list_compatibility (entry1, entry2);
1263 switch (entry1->propstype) {
1264 case GST_PROPS_LIST_TYPE:
1266 GList *entrylist = entry1->data.list_data.entries;
1267 gboolean valid = TRUE; /* innocent until proven guilty */
1269 while (entrylist && valid) {
1270 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1272 valid &= gst_props_entry_check_compatibility (entry, entry2);
1274 entrylist = g_list_next (entrylist);
1279 case GST_PROPS_INT_RANGE_TYPE:
1280 switch (entry2->propstype) {
1281 /* a - b <---> a - c */
1282 case GST_PROPS_INT_RANGE_TYPE:
1283 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1284 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1289 case GST_PROPS_FLOAT_RANGE_TYPE:
1290 switch (entry2->propstype) {
1291 /* a - b <---> a - c */
1292 case GST_PROPS_FLOAT_RANGE_TYPE:
1293 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1294 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1299 case GST_PROPS_FOURCC_TYPE:
1300 switch (entry2->propstype) {
1302 case GST_PROPS_FOURCC_TYPE:
1303 GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?",
1304 (char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data);
1305 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1310 case GST_PROPS_INT_TYPE:
1311 switch (entry2->propstype) {
1313 case GST_PROPS_INT_RANGE_TYPE:
1314 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1315 entry1->data.int_data,entry2->data.int_range_data.max);
1316 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1317 entry2->data.int_range_data.max >= entry1->data.int_data);
1319 case GST_PROPS_INT_TYPE:
1320 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1321 return (entry2->data.int_data == entry1->data.int_data);
1326 case GST_PROPS_FLOAT_TYPE:
1327 switch (entry2->propstype) {
1329 case GST_PROPS_FLOAT_RANGE_TYPE:
1330 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1331 entry2->data.float_range_data.max >= entry1->data.float_data);
1333 case GST_PROPS_FLOAT_TYPE:
1334 return (entry2->data.float_data == entry1->data.float_data);
1339 case GST_PROPS_BOOL_TYPE:
1340 switch (entry2->propstype) {
1342 case GST_PROPS_BOOL_TYPE:
1343 return (entry2->data.bool_data == entry1->data.bool_data);
1347 case GST_PROPS_STRING_TYPE:
1348 switch (entry2->propstype) {
1350 case GST_PROPS_STRING_TYPE:
1351 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1352 entry2->data.string_data.string, entry1->data.string_data.string);
1353 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1365 * gst_props_check_compatibility:
1366 * @fromprops: a property
1367 * @toprops: a property
1369 * Checks whether two capabilities are compatible.
1371 * Returns: TRUE if compatible, FALSE otherwise
1374 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1380 gboolean compatible = TRUE;
1382 g_return_val_if_fail (fromprops != NULL, FALSE);
1383 g_return_val_if_fail (toprops != NULL, FALSE);
1385 sourcelist = fromprops->properties;
1386 sinklist = toprops->properties;
1388 while (sourcelist && sinklist && compatible) {
1389 GstPropsEntry *entry1;
1390 GstPropsEntry *entry2;
1392 entry1 = (GstPropsEntry *)sourcelist->data;
1393 entry2 = (GstPropsEntry *)sinklist->data;
1395 while (entry1->propid < entry2->propid) {
1397 sourcelist = g_list_next (sourcelist);
1398 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1401 while (entry1->propid > entry2->propid) {
1403 sinklist = g_list_next (sinklist);
1404 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1408 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1410 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1411 g_quark_to_string (entry1->propid));
1414 sourcelist = g_list_next (sourcelist);
1415 sinklist = g_list_next (sinklist);
1417 if (sinklist && compatible) {
1418 GstPropsEntry *entry2;
1419 entry2 = (GstPropsEntry *)sinklist->data;
1430 static GstPropsEntry*
1431 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1433 GstPropsEntry *result = NULL;
1435 /* try to move the ranges and lists first */
1436 switch (entry2->propstype) {
1437 case GST_PROPS_INT_RANGE_TYPE:
1438 case GST_PROPS_FLOAT_RANGE_TYPE:
1439 case GST_PROPS_LIST_TYPE:
1441 GstPropsEntry *temp;
1451 switch (entry1->propstype) {
1452 case GST_PROPS_LIST_TYPE:
1454 GList *entrylist = entry1->data.list_data.entries;
1455 GList *intersection = NULL;
1458 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1459 GstPropsEntry *intersectentry;
1461 intersectentry = gst_props_entry_intersect (entry2, entry);
1463 if (intersectentry) {
1464 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1465 intersection = g_list_concat (intersection,
1466 g_list_copy (intersectentry->data.list_data.entries));
1467 /* set the list to NULL because the entries are concatenated to the above
1468 * list and we don't want to free them */
1469 intersectentry->data.list_data.entries = NULL;
1470 gst_props_entry_destroy (intersectentry);
1473 intersection = g_list_prepend (intersection, intersectentry);
1476 entrylist = g_list_next (entrylist);
1479 /* check if the list only contains 1 element, if so, we can just copy it */
1480 if (g_list_next (intersection) == NULL) {
1481 result = (GstPropsEntry *) (intersection->data);
1482 g_list_free (intersection);
1484 /* else we need to create a new entry to hold the list */
1486 result = gst_props_alloc_entry ();
1487 result->propid = entry1->propid;
1488 result->propstype = GST_PROPS_LIST_TYPE;
1489 result->data.list_data.entries = g_list_reverse (intersection);
1494 case GST_PROPS_INT_RANGE_TYPE:
1495 switch (entry2->propstype) {
1496 /* a - b <---> a - c */
1497 case GST_PROPS_INT_RANGE_TYPE:
1499 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1500 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1502 if (lower <= upper) {
1503 result = gst_props_alloc_entry ();
1504 result->propid = entry1->propid;
1506 if (lower == upper) {
1507 result->propstype = GST_PROPS_INT_TYPE;
1508 result->data.int_data = lower;
1511 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1512 result->data.int_range_data.min = lower;
1513 result->data.int_range_data.max = upper;
1518 case GST_PROPS_LIST_TYPE:
1520 GList *entries = entry2->data.list_data.entries;
1521 result = gst_props_alloc_entry ();
1522 result->propid = entry1->propid;
1523 result->propstype = GST_PROPS_LIST_TYPE;
1524 result->data.list_data.entries = NULL;
1526 GstPropsEntry * this = (GstPropsEntry *)entries->data;
1527 if (this->propstype != GST_PROPS_INT_TYPE) {
1528 /* no hope, this list doesn't even contain ints! */
1529 gst_props_entry_destroy (result);
1533 if (this->data.int_data >= entry1->data.int_range_data.min &&
1534 this->data.int_data <= entry1->data.int_range_data.max) {
1535 result->data.list_data.entries = g_list_append (result->data.list_data.entries,
1536 gst_props_entry_copy (this));
1538 entries = g_list_next (entries);
1542 case GST_PROPS_INT_TYPE:
1544 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1545 entry1->data.int_range_data.max >= entry2->data.int_data) {
1546 result = gst_props_entry_copy (entry2);
1554 case GST_PROPS_FLOAT_RANGE_TYPE:
1555 switch (entry2->propstype) {
1556 /* a - b <---> a - c */
1557 case GST_PROPS_FLOAT_RANGE_TYPE:
1559 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1560 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1562 if (lower <= upper) {
1563 result = gst_props_alloc_entry ();
1564 result->propid = entry1->propid;
1566 if (lower == upper) {
1567 result->propstype = GST_PROPS_FLOAT_TYPE;
1568 result->data.float_data = lower;
1571 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1572 result->data.float_range_data.min = lower;
1573 result->data.float_range_data.max = upper;
1578 case GST_PROPS_FLOAT_TYPE:
1579 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1580 entry1->data.float_range_data.max >= entry2->data.float_data) {
1581 result = gst_props_entry_copy (entry2);
1587 case GST_PROPS_FOURCC_TYPE:
1588 switch (entry2->propstype) {
1590 case GST_PROPS_FOURCC_TYPE:
1591 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1592 result = gst_props_entry_copy (entry1);
1597 case GST_PROPS_INT_TYPE:
1598 switch (entry2->propstype) {
1600 case GST_PROPS_INT_TYPE:
1601 if (entry1->data.int_data == entry2->data.int_data)
1602 result = gst_props_entry_copy (entry1);
1607 case GST_PROPS_FLOAT_TYPE:
1608 switch (entry2->propstype) {
1610 case GST_PROPS_FLOAT_TYPE:
1611 if (entry1->data.float_data == entry2->data.float_data)
1612 result = gst_props_entry_copy (entry1);
1617 case GST_PROPS_BOOL_TYPE:
1618 switch (entry2->propstype) {
1620 case GST_PROPS_BOOL_TYPE:
1621 if (entry1->data.bool_data == entry2->data.bool_data)
1622 result = gst_props_entry_copy (entry1);
1626 case GST_PROPS_STRING_TYPE:
1627 switch (entry2->propstype) {
1629 case GST_PROPS_STRING_TYPE:
1630 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1631 result = gst_props_entry_copy (entry1);
1643 * gst_props_intersect:
1644 * @props1: a property
1645 * @props2: another property
1647 * Calculates the intersection bewteen two GstProps.
1649 * Returns: a GstProps with the intersection or NULL if the
1650 * intersection is empty.
1653 gst_props_intersect (GstProps *props1, GstProps *props2)
1657 GstProps *intersection;
1659 GstPropsEntry *iprops = NULL;
1661 intersection = gst_props_empty_new ();
1662 intersection->fixed = TRUE;
1664 g_return_val_if_fail (props1 != NULL, NULL);
1665 g_return_val_if_fail (props2 != NULL, NULL);
1667 props1list = props1->properties;
1668 props2list = props2->properties;
1670 while (props1list && props2list) {
1671 GstPropsEntry *entry1;
1672 GstPropsEntry *entry2;
1674 entry1 = (GstPropsEntry *)props1list->data;
1675 entry2 = (GstPropsEntry *)props2list->data;
1677 while (entry1->propid < entry2->propid) {
1678 GstPropsEntry *toadd;
1680 GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"", g_quark_to_string (entry1->propid));
1682 toadd = gst_props_entry_copy (entry1);
1683 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1684 intersection->fixed = FALSE;
1686 intersection->properties = g_list_prepend (intersection->properties, toadd);
1688 props1list = g_list_next (props1list);
1690 entry1 = (GstPropsEntry *)props1list->data;
1694 while (entry1->propid > entry2->propid) {
1695 GstPropsEntry *toadd;
1697 toadd = gst_props_entry_copy (entry2);
1698 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1699 intersection->fixed = FALSE;
1701 intersection->properties = g_list_prepend (intersection->properties, toadd);
1703 props2list = g_list_next (props2list);
1705 entry2 = (GstPropsEntry *)props2list->data;
1709 /* at this point we are talking about the same property */
1710 iprops = gst_props_entry_intersect (entry1, entry2);
1713 if (GST_PROPS_ENTRY_IS_VARIABLE (iprops))
1714 intersection->fixed = FALSE;
1715 intersection->properties = g_list_prepend (intersection->properties, iprops);
1718 gst_props_unref (intersection);
1722 props1list = g_list_next (props1list);
1723 props2list = g_list_next (props2list);
1727 /* at this point one of the lists could contain leftover properties */
1729 leftovers = props1list;
1730 else if (props2list)
1731 leftovers = props2list;
1736 GstPropsEntry *entry;
1738 entry = (GstPropsEntry *) leftovers->data;
1739 if (GST_PROPS_ENTRY_IS_VARIABLE (entry))
1740 intersection->fixed = FALSE;
1741 intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry));
1743 leftovers = g_list_next (leftovers);
1746 intersection->properties = g_list_reverse (intersection->properties);
1748 return intersection;
1752 * gst_props_normalize:
1753 * @props: a property
1755 * Unrolls all lists in the given GstProps. This is usefull if you
1756 * want to loop over the props.
1758 * Returns: A GList with the unrolled props entries.
1761 gst_props_normalize (GstProps *props)
1764 GList *result = NULL;
1769 entries = props->properties;
1772 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1774 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1775 GList *list_entries = entry->data.list_data.entries;
1777 while (list_entries) {
1778 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1779 GstPropsEntry *new_entry;
1783 newprops = gst_props_empty_new ();
1784 newprops->properties = gst_props_list_copy (props->properties);
1785 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
1787 GList *new_list = NULL;
1789 new_entry = (GstPropsEntry *) lentry->data;
1790 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
1792 new_list = gst_props_normalize (newprops);
1793 result = g_list_concat (new_list, result);
1796 result = g_list_append (result, newprops);
1799 list_entries = g_list_next (list_entries);
1801 /* we break out of the loop because the other lists are
1802 * unrolled in the recursive call */
1805 entries = g_list_next (entries);
1808 result = g_list_prepend (result, props);
1811 result = g_list_reverse (result);
1812 gst_props_unref (props);
1817 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
1819 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
1824 switch (entry->propstype) {
1825 case GST_PROPS_INT_TYPE:
1826 subtree = xmlNewChild (parent, NULL, "int", NULL);
1827 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1828 str = g_strdup_printf ("%d", entry->data.int_data);
1829 xmlNewProp (subtree, "value", str);
1832 case GST_PROPS_INT_RANGE_TYPE:
1833 subtree = xmlNewChild (parent, NULL, "range", NULL);
1834 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1835 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
1836 xmlNewProp (subtree, "min", str);
1838 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
1839 xmlNewProp (subtree, "max", str);
1842 case GST_PROPS_FLOAT_TYPE:
1843 subtree = xmlNewChild (parent, NULL, "float", NULL);
1844 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1845 str = g_strdup_printf ("%f", entry->data.float_data);
1846 xmlNewProp (subtree, "value", str);
1849 case GST_PROPS_FLOAT_RANGE_TYPE:
1850 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
1851 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1852 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
1853 xmlNewProp (subtree, "min", str);
1855 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
1856 xmlNewProp (subtree, "max", str);
1859 case GST_PROPS_FOURCC_TYPE:
1860 str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
1861 xmlAddChild (parent, xmlNewComment (str));
1863 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
1864 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1865 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
1866 xmlNewProp (subtree, "hexvalue", str);
1869 case GST_PROPS_BOOL_TYPE:
1870 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
1871 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1872 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
1874 case GST_PROPS_STRING_TYPE:
1875 subtree = xmlNewChild (parent, NULL, "string", NULL);
1876 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1877 xmlNewProp (subtree, "value", entry->data.string_data.string);
1880 g_warning ("trying to save unknown property type %d", entry->propstype);
1888 * gst_props_save_thyself:
1889 * @props: a property to save
1890 * @parent: the parent XML tree
1892 * Saves the property into an XML representation.
1894 * Returns: the new XML tree
1897 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
1902 g_return_val_if_fail (props != NULL, NULL);
1904 proplist = props->properties;
1907 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
1909 switch (entry->propstype) {
1910 case GST_PROPS_LIST_TYPE:
1911 subtree = xmlNewChild (parent, NULL, "list", NULL);
1912 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1913 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
1916 gst_props_save_thyself_func (entry, parent);
1919 proplist = g_list_next (proplist);
1925 static GstPropsEntry*
1926 gst_props_load_thyself_func (xmlNodePtr field)
1928 GstPropsEntry *entry;
1931 entry = gst_props_alloc_entry ();
1933 if (!strcmp(field->name, "int")) {
1934 entry->propstype = GST_PROPS_INT_TYPE;
1935 prop = xmlGetProp(field, "name");
1936 entry->propid = g_quark_from_string (prop);
1938 prop = xmlGetProp(field, "value");
1939 sscanf (prop, "%d", &entry->data.int_data);
1942 else if (!strcmp(field->name, "range")) {
1943 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
1944 prop = xmlGetProp(field, "name");
1945 entry->propid = g_quark_from_string (prop);
1947 prop = xmlGetProp (field, "min");
1948 sscanf (prop, "%d", &entry->data.int_range_data.min);
1950 prop = xmlGetProp (field, "max");
1951 sscanf (prop, "%d", &entry->data.int_range_data.max);
1954 else if (!strcmp(field->name, "float")) {
1955 entry->propstype = GST_PROPS_FLOAT_TYPE;
1956 prop = xmlGetProp(field, "name");
1957 entry->propid = g_quark_from_string (prop);
1959 prop = xmlGetProp(field, "value");
1960 sscanf (prop, "%f", &entry->data.float_data);
1963 else if (!strcmp(field->name, "floatrange")) {
1964 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1965 prop = xmlGetProp(field, "name");
1966 entry->propid = g_quark_from_string (prop);
1968 prop = xmlGetProp (field, "min");
1969 sscanf (prop, "%f", &entry->data.float_range_data.min);
1971 prop = xmlGetProp (field, "max");
1972 sscanf (prop, "%f", &entry->data.float_range_data.max);
1975 else if (!strcmp(field->name, "boolean")) {
1976 entry->propstype = GST_PROPS_BOOL_TYPE;
1977 prop = xmlGetProp(field, "name");
1978 entry->propid = g_quark_from_string (prop);
1980 prop = xmlGetProp (field, "value");
1981 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
1982 else entry->data.bool_data = 1;
1985 else if (!strcmp(field->name, "fourcc")) {
1986 entry->propstype = GST_PROPS_FOURCC_TYPE;
1987 prop = xmlGetProp(field, "name");
1988 entry->propid = g_quark_from_string (prop);
1990 prop = xmlGetProp (field, "hexvalue");
1991 sscanf (prop, "%08x", &entry->data.fourcc_data);
1994 else if (!strcmp(field->name, "string")) {
1995 entry->propstype = GST_PROPS_STRING_TYPE;
1996 prop = xmlGetProp(field, "name");
1997 entry->propid = g_quark_from_string (prop);
1999 entry->data.string_data.string = xmlGetProp (field, "value");
2002 g_mutex_lock (_gst_props_entries_chunk_lock);
2003 g_mem_chunk_free (_gst_props_entries_chunk, entry);
2004 g_mutex_unlock (_gst_props_entries_chunk_lock);
2012 * gst_props_load_thyself:
2013 * @parent: the XML tree to load from
2015 * Creates a new property out of an XML tree.
2017 * Returns: the new property
2020 gst_props_load_thyself (xmlNodePtr parent)
2023 xmlNodePtr field = parent->xmlChildrenNode;
2026 props = gst_props_empty_new ();
2029 if (!strcmp (field->name, "list")) {
2030 GstPropsEntry *entry;
2031 xmlNodePtr subfield = field->xmlChildrenNode;
2033 entry = gst_props_alloc_entry ();
2034 prop = xmlGetProp (field, "name");
2035 entry->propid = g_quark_from_string (prop);
2037 entry->propstype = GST_PROPS_LIST_TYPE;
2038 entry->data.list_data.entries = NULL;
2041 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2044 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2046 subfield = subfield->next;
2048 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2049 gst_props_add_entry (props, entry);
2052 GstPropsEntry *entry;
2054 entry = gst_props_load_thyself_func (field);
2057 gst_props_add_entry (props, entry);
2059 field = field->next;
2064 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */