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);
72 transform_func (const GValue *src_value,
75 GstProps *props = g_value_peek_pointer (src_value);
76 GString *result = g_string_new ("");
77 GList *propslist = props->properties;
80 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
81 const gchar *name = g_quark_to_string (entry->propid);
83 switch (entry->propstype) {
84 case GST_PROPS_STRING_TYPE:
85 g_string_append_printf (result, "%s='%s'", name, entry->data.string_data.string);
90 propslist = g_list_next (propslist);
92 g_string_append (result, "; ");
95 dest_value->data[0].v_pointer = result->str;
100 _gst_props_initialize (void)
102 _gst_props_entries_chunk = g_mem_chunk_new ("GstPropsEntries",
103 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 256,
105 _gst_props_entries_chunk_lock = g_mutex_new ();
107 _gst_props_chunk = g_mem_chunk_new ("GstProps",
108 sizeof (GstProps), sizeof (GstProps) * 256,
110 _gst_props_chunk_lock = g_mutex_new ();
112 _gst_props_type = g_boxed_type_register_static ("GstProps",
113 (GBoxedCopyFunc) gst_props_ref,
114 (GBoxedFreeFunc) gst_props_unref);
116 g_value_register_transform_func (_gst_props_type,
122 gst_props_debug_entry (GstPropsEntry *entry)
124 const gchar *name = g_quark_to_string (entry->propid);
126 switch (entry->propstype) {
127 case GST_PROPS_INT_TYPE:
128 GST_DEBUG (GST_CAT_PROPERTIES, "%s: int %d", name, entry->data.int_data);
130 case GST_PROPS_FLOAT_TYPE:
131 GST_DEBUG (GST_CAT_PROPERTIES, "%s: float %f", name, entry->data.float_data);
133 case GST_PROPS_FOURCC_TYPE:
134 GST_DEBUG (GST_CAT_PROPERTIES, "%s: fourcc %4.4s", name, (gchar*)&entry->data.fourcc_data);
136 case GST_PROPS_BOOL_TYPE:
137 GST_DEBUG (GST_CAT_PROPERTIES, "%s: bool %d", name, entry->data.bool_data);
139 case GST_PROPS_STRING_TYPE:
140 GST_DEBUG (GST_CAT_PROPERTIES, "%s: string \"%s\"", name, entry->data.string_data.string);
142 case GST_PROPS_INT_RANGE_TYPE:
143 GST_DEBUG (GST_CAT_PROPERTIES, "%s: int range %d-%d", name, entry->data.int_range_data.min,
144 entry->data.int_range_data.max);
146 case GST_PROPS_FLOAT_RANGE_TYPE:
147 GST_DEBUG (GST_CAT_PROPERTIES, "%s: float range %f-%f", name, entry->data.float_range_data.min,
148 entry->data.float_range_data.max);
150 case GST_PROPS_LIST_TYPE:
151 GST_DEBUG (GST_CAT_PROPERTIES, "[list]");
153 GList *entries = entry->data.list_data.entries;
156 gst_props_debug_entry ((GstPropsEntry *)entries->data);
157 entries = g_list_next (entries);
162 g_warning ("unknown property type %d", entry->propstype);
168 props_compare_func (gconstpointer a,
171 GstPropsEntry *entry1 = (GstPropsEntry *)a;
172 GstPropsEntry *entry2 = (GstPropsEntry *)b;
174 return (entry1->propid - entry2->propid);
178 props_find_func (gconstpointer a,
181 GstPropsEntry *entry2 = (GstPropsEntry *)a;
182 GQuark quark = (GQuark) GPOINTER_TO_INT (b);
184 return (quark - entry2->propid);
187 /* This is implemented as a huge macro because we cannot pass
188 * va_list variables by reference on some architectures.
190 #define GST_PROPS_ENTRY_FILL(entry, var_args) \
192 entry->propstype = va_arg (var_args, GstPropsType); \
194 switch (entry->propstype) { \
195 case GST_PROPS_INT_TYPE: \
196 entry->data.int_data = va_arg (var_args, gint); \
198 case GST_PROPS_INT_RANGE_TYPE: \
199 entry->data.int_range_data.min = va_arg (var_args, gint); \
200 entry->data.int_range_data.max = va_arg (var_args, gint); \
202 case GST_PROPS_FLOAT_TYPE: \
203 entry->data.float_data = va_arg (var_args, gdouble); \
205 case GST_PROPS_FLOAT_RANGE_TYPE: \
206 entry->data.float_range_data.min = va_arg (var_args, gdouble); \
207 entry->data.float_range_data.max = va_arg (var_args, gdouble); \
209 case GST_PROPS_FOURCC_TYPE: \
210 entry->data.fourcc_data = va_arg (var_args, gulong); \
212 case GST_PROPS_BOOL_TYPE: \
213 entry->data.bool_data = va_arg (var_args, gboolean); \
215 case GST_PROPS_STRING_TYPE: \
216 entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
218 case GST_PROPS_GLIST_TYPE: \
219 entry->propstype = GST_PROPS_LIST_TYPE; \
220 entry->data.list_data.entries = g_list_copy (va_arg (var_args, GList*)); \
228 #define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
234 GstPropsType propstype = va_arg (var_args, GstPropsType); \
235 if (propstype != entry->propstype) { \
240 switch (entry->propstype) { \
241 case GST_PROPS_INT_TYPE: \
242 *(va_arg (var_args, gint*)) = entry->data.int_data; \
244 case GST_PROPS_INT_RANGE_TYPE: \
245 *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
246 *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
248 case GST_PROPS_FLOAT_TYPE: \
249 *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
251 case GST_PROPS_FLOAT_RANGE_TYPE: \
252 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
253 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
255 case GST_PROPS_FOURCC_TYPE: \
256 *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
258 case GST_PROPS_BOOL_TYPE: \
259 *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
261 case GST_PROPS_STRING_TYPE: \
262 *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
264 case GST_PROPS_LIST_TYPE: \
265 *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
274 static GstPropsEntry*
275 gst_props_alloc_entry (void)
277 GstPropsEntry *entry;
279 g_mutex_lock (_gst_props_entries_chunk_lock);
280 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
281 g_mutex_unlock (_gst_props_entries_chunk_lock);
287 gst_props_entry_destroy (GstPropsEntry *entry)
289 switch (entry->propstype) {
290 case GST_PROPS_STRING_TYPE:
291 g_free (entry->data.string_data.string);
293 case GST_PROPS_LIST_TYPE:
295 GList *entries = entry->data.list_data.entries;
298 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
299 entries = g_list_next (entries);
301 g_list_free (entry->data.list_data.entries);
307 g_mutex_lock (_gst_props_entries_chunk_lock);
308 g_mem_chunk_free (_gst_props_entries_chunk, entry);
309 g_mutex_unlock (_gst_props_entries_chunk_lock);
313 * gst_props_empty_new:
315 * Create a new empty property.
317 * Returns: the new property
320 gst_props_empty_new (void)
324 g_mutex_lock (_gst_props_chunk_lock);
325 props = g_mem_chunk_alloc (_gst_props_chunk);
326 g_mutex_unlock (_gst_props_chunk_lock);
328 props->properties = NULL;
336 * gst_props_add_entry:
337 * @props: the property to add the entry to
338 * @entry: the entry to add
340 * Addes the given propsentry to the props
343 gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
345 g_return_if_fail (props);
346 g_return_if_fail (entry);
348 if (props->fixed && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
349 props->fixed = FALSE;
351 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
356 * @firstname: the first property name
357 * @...: the property values
359 * Create a new property from the given key/value pairs
361 * Returns: the new property
364 gst_props_new (const gchar *firstname, ...)
369 va_start (var_args, firstname);
371 props = gst_props_newv (firstname, var_args);
381 * @props: the props to debug
383 * Dump the contents of the given properties into the DEBUG log.
386 gst_props_debug (GstProps *props)
388 GList *propslist = props->properties;
391 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
393 gst_props_debug_entry (entry);
395 propslist = g_list_next (propslist);
400 * gst_props_merge_int_entries:
401 * @newentry: the new entry
402 * @oldentry: an old entry
404 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
406 * Assumes that the entries are either ints or int ranges.
408 * Returns: TRUE if the entries were merged, FALSE otherwise.
411 gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
413 gint new_min, new_max, old_min, old_max;
414 gboolean can_merge = FALSE;
416 if (newentry->propstype == GST_PROPS_INT_TYPE) {
417 new_min = newentry->data.int_data;
418 new_max = newentry->data.int_data;
420 new_min = newentry->data.int_range_data.min;
421 new_max = newentry->data.int_range_data.max;
424 if (oldentry->propstype == GST_PROPS_INT_TYPE) {
425 old_min = oldentry->data.int_data;
426 old_max = oldentry->data.int_data;
428 old_min = oldentry->data.int_range_data.min;
429 old_max = oldentry->data.int_range_data.max;
432 /* Put range which starts lower into (new_min, new_max) */
433 if (old_min < new_min) {
443 /* new_min is min of either entry - second half of the following conditional */
444 /* is to avoid overflow problems. */
445 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
446 /* ranges overlap, or are adjacent. Pick biggest maximum. */
448 if (old_max > new_max) new_max = old_max;
452 if (new_min == new_max) {
453 newentry->propstype = GST_PROPS_INT_TYPE;
454 newentry->data.int_data = new_min;
456 newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
457 newentry->data.int_range_data.min = new_min;
458 newentry->data.int_range_data.max = new_max;
465 * gst_props_add_to_int_list:
466 * @entries: the existing list of entries
467 * @entry: the new entry to add to the list
469 * Add an integer property to a list of properties, removing duplicates
470 * and merging ranges.
472 * Assumes that the existing list is in simplest form, contains
473 * only ints and int ranges, and that the new entry is an int or
476 * Returns: a pointer to a list with the new entry added.
479 gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
485 GstPropsEntry * oldentry = (GstPropsEntry *)(i->data);
486 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
489 /* replace the existing one with the merged one */
490 g_mutex_lock (_gst_props_entries_chunk_lock);
491 g_mem_chunk_free (_gst_props_entries_chunk, oldentry);
492 g_mutex_unlock (_gst_props_entries_chunk_lock);
493 entries = g_list_remove_link (entries, i);
496 /* start again: it's possible that this change made an earlier entry */
497 /* mergeable, and the pointer is now invalid anyway. */
504 return g_list_prepend (entries, newentry);
507 static GstPropsEntry*
508 gst_props_entry_newv (const gchar *name, va_list var_args)
510 GstPropsEntry *entry;
512 entry = gst_props_alloc_entry ();
513 entry->propid = g_quark_from_string (name);
514 GST_PROPS_ENTRY_FILL (entry, var_args);
520 * gst_props_entry_new:
521 * @name: the name of the props entry
522 * @...: the value of the entry
524 * Create a new property entry with the given key/value.
526 * Returns: the new entry.
529 gst_props_entry_new (const gchar *name, ...)
532 GstPropsEntry *entry;
534 va_start (var_args, name);
535 entry = gst_props_entry_newv (name, var_args);
543 * @firstname: the first property name
544 * @var_args: the property values
546 * Create a new property from the list of entries.
548 * Returns: the new property created from the list of entries
551 gst_props_newv (const gchar *firstname, va_list var_args)
554 gboolean inlist = FALSE;
555 const gchar *prop_name;
556 GstPropsEntry *list_entry = NULL;
559 GST_PROPS_LIST_T_UNSET,
560 GST_PROPS_LIST_T_INTS,
561 GST_PROPS_LIST_T_FLOATS,
562 GST_PROPS_LIST_T_MISC,
565 /* type of the list */
566 list_types list_type = GST_PROPS_LIST_T_UNSET;
567 /* type of current item */
568 list_types entry_type = GST_PROPS_LIST_T_UNSET;
570 if (firstname == NULL)
573 props = gst_props_empty_new ();
575 prop_name = firstname;
579 GstPropsEntry *entry;
581 entry = gst_props_alloc_entry ();
582 entry->propid = g_quark_from_string (prop_name);
583 GST_PROPS_ENTRY_FILL (entry, var_args);
585 switch (entry->propstype) {
586 case GST_PROPS_INT_TYPE:
587 case GST_PROPS_INT_RANGE_TYPE:
588 entry_type = GST_PROPS_LIST_T_INTS;
590 case GST_PROPS_FLOAT_TYPE:
591 case GST_PROPS_FLOAT_RANGE_TYPE:
592 entry_type = GST_PROPS_LIST_T_FLOATS;
594 case GST_PROPS_FOURCC_TYPE:
595 case GST_PROPS_BOOL_TYPE:
596 case GST_PROPS_STRING_TYPE:
597 entry_type = GST_PROPS_LIST_T_MISC;
599 case GST_PROPS_LIST_TYPE:
600 g_return_val_if_fail (inlist == FALSE, NULL);
603 list_type = GST_PROPS_LIST_T_UNSET;
604 list_entry->data.list_data.entries = NULL;
606 case GST_PROPS_END_TYPE:
607 g_return_val_if_fail (inlist == TRUE, NULL);
609 /* if list was of size 1, replace the list by a the item it contains */
610 if (g_list_length(list_entry->data.list_data.entries) == 1) {
611 GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
612 list_entry->propstype = subentry->propstype;
613 list_entry->data = subentry->data;
614 g_mutex_lock (_gst_props_entries_chunk_lock);
615 g_mem_chunk_free (_gst_props_entries_chunk, subentry);
616 g_mutex_unlock (_gst_props_entries_chunk_lock);
619 list_entry->data.list_data.entries =
620 g_list_reverse (list_entry->data.list_data.entries);
623 g_mutex_lock (_gst_props_entries_chunk_lock);
624 g_mem_chunk_free (_gst_props_entries_chunk, entry);
625 g_mutex_unlock (_gst_props_entries_chunk_lock);
628 prop_name = va_arg (var_args, gchar*);
631 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
632 g_mutex_lock (_gst_props_entries_chunk_lock);
633 g_mem_chunk_free (_gst_props_entries_chunk, entry);
634 g_mutex_unlock (_gst_props_entries_chunk_lock);
638 if (inlist && (list_entry != entry)) {
639 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
640 if (list_type != entry_type) {
641 g_warning ("property list contained incompatible entry types\n");
644 case GST_PROPS_LIST_T_INTS:
645 list_entry->data.list_data.entries =
646 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
649 list_entry->data.list_data.entries =
650 g_list_prepend (list_entry->data.list_data.entries, entry);
656 gst_props_add_entry (props, entry);
659 prop_name = va_arg (var_args, gchar*);
667 * @props: the props to modify
668 * @name: the name of the entry to modify
669 * @...: The prop entry.
671 * Modifies the value of the given entry in the props struct.
672 * For the optional args, use GST_PROPS_FOO, where FOO is INT,
673 * STRING, etc. This macro expands to a variable number of arguments,
674 * hence the lack of precision in the function prototype. No
675 * terminating NULL is necessary as only one property can be changed.
677 * Returns: the new modified property structure.
680 gst_props_set (GstProps *props, const gchar *name, ...)
686 g_return_val_if_fail (props != NULL, NULL);
688 quark = g_quark_from_string (name);
690 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
693 GstPropsEntry *entry;
695 entry = (GstPropsEntry *)lentry->data;
697 va_start (var_args, name);
699 GST_PROPS_ENTRY_FILL (entry, var_args);
704 g_warning ("gstprops: no property '%s' to change\n", name);
713 * @props: the props to unref
715 * Decrease the refcount of the property structure, destroying
716 * the property if the refcount is 0.
719 gst_props_unref (GstProps *props)
726 if (props->refcount == 0)
727 gst_props_destroy (props);
732 * @props: the props to ref
734 * Increase the refcount of the property structure.
737 gst_props_ref (GstProps *props)
739 g_return_if_fail (props != NULL);
747 * @props: the props to destroy
749 * Destroy the property, freeing all the memory that
753 gst_props_destroy (GstProps *props)
760 entries = props->properties;
763 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
764 entries = g_list_next (entries);
766 g_list_free (props->properties);
768 g_mutex_lock (_gst_props_chunk_lock);
769 g_mem_chunk_free (_gst_props_chunk, props);
770 g_mutex_unlock (_gst_props_chunk_lock);
776 static GstPropsEntry*
777 gst_props_entry_copy (GstPropsEntry *entry)
779 GstPropsEntry *newentry;
781 newentry = gst_props_alloc_entry ();
782 memcpy (newentry, entry, sizeof (GstPropsEntry));
783 if (entry->propstype == GST_PROPS_LIST_TYPE) {
784 newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
786 else if (entry->propstype == GST_PROPS_STRING_TYPE) {
787 newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
794 gst_props_list_copy (GList *propslist)
799 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
801 new = g_list_prepend (new, gst_props_entry_copy (entry));
803 propslist = g_list_next (propslist);
805 new = g_list_reverse (new);
812 * @props: the props to copy
814 * Copy the property structure.
816 * Returns: the new property that is a copy of the original
820 gst_props_copy (GstProps *props)
827 new = gst_props_empty_new ();
828 new->properties = gst_props_list_copy (props->properties);
829 new->fixed = props->fixed;
835 * gst_props_copy_on_write:
836 * @props: the props to copy on write
838 * Copy the property structure if the refcount is >1.
840 * Returns: A new props that can be safely written to.
843 gst_props_copy_on_write (GstProps *props)
845 GstProps *new = props;;
847 g_return_val_if_fail (props != NULL, NULL);
849 if (props->refcount > 1) {
850 new = gst_props_copy (props);
851 gst_props_unref (props);
858 * gst_props_get_entry:
859 * @props: the props to query
860 * @name: the name of the entry to get
862 * Get the props entry with the geven name
864 * Returns: The props entry with the geven name or NULL when
865 * the entry was not found.
868 gst_props_get_entry (GstProps *props, const gchar *name)
873 g_return_val_if_fail (props != NULL, NULL);
874 g_return_val_if_fail (name != NULL, NULL);
876 quark = g_quark_from_string (name);
878 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
881 GstPropsEntry *thisentry;
882 thisentry = (GstPropsEntry *)lentry->data;
889 * gst_props_has_property:
890 * @props: the props to check
891 * @name: the name of the key to find
893 * Checks if a given props has a property with the given name.
895 * Returns: TRUE if the property was found, FALSE otherwise.
898 gst_props_has_property (GstProps *props, const gchar *name)
900 return (gst_props_get_entry (props, name) != NULL);
904 * gst_props_has_property_typed:
905 * @props: the props to check
906 * @name: the name of the key to find
907 * @type: the type of the required property
909 * Checks if a given props has a property with the given name and the given type.
911 * Returns: TRUE if the property was found, FALSE otherwise.
914 gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
916 const GstPropsEntry *entry;
918 entry = gst_props_get_entry (props, name);
922 return (entry->propstype == type);
926 * gst_props_has_fixed_property:
927 * @props: the props to check
928 * @name: the name of the key to find
930 * Checks if a given props has a property with the given name that
931 * is also fixed, ie. is not a list or a range.
933 * Returns: TRUE if the property was found, FALSE otherwise.
936 gst_props_has_fixed_property (GstProps *props, const gchar *name)
938 const GstPropsEntry *entry;
940 entry = gst_props_get_entry (props, name);
944 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
948 * gst_props_entry_get_type:
949 * @entry: the props entry to query
951 * Get the type of the given props entry.
953 * Returns: The type of the props entry.
956 gst_props_entry_get_type (const GstPropsEntry *entry)
958 g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
960 return entry->propstype;
964 * gst_props_entry_get_name:
965 * @entry: the props entry to query
967 * Get the name of the given props entry.
969 * Returns: The name of the props entry.
972 gst_props_entry_get_name (const GstPropsEntry *entry)
974 g_return_val_if_fail (entry != NULL, NULL);
976 return g_quark_to_string (entry->propid);
980 * gst_props_entry_is_fixed:
981 * @entry: the props entry to query
983 * Checks if the props entry is fixe, ie. is not a list
986 * Returns: TRUE is the props entry is fixed.
989 gst_props_entry_is_fixed (const GstPropsEntry *entry)
991 g_return_val_if_fail (entry != NULL, FALSE);
993 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
997 gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
1001 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1007 * gst_props_entry_get:
1008 * @entry: the props entry to query
1009 * @...: a pointer to a type that can hold the value.
1011 * Gets the contents of the entry.
1013 * Returns: TRUE is the props entry could be fetched.
1016 gst_props_entry_get (const GstPropsEntry *entry, ...)
1021 g_return_val_if_fail (entry != NULL, FALSE);
1023 va_start (var_args, entry);
1024 result = gst_props_entry_getv (entry, FALSE, var_args);
1031 gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
1036 g_return_val_if_fail (entry != NULL, FALSE);
1038 va_start (var_args, entry);
1039 result = gst_props_entry_getv (entry, TRUE, var_args);
1046 gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args)
1048 while (first_name) {
1049 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1052 if (!entry) return FALSE;
1053 GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
1054 if (!result) return FALSE;
1056 first_name = va_arg (var_args, gchar *);
1063 * @props: the props to query
1064 * @first_name: the first key
1065 * @...: a pointer to a datastructure that can hold the value.
1067 * Gets the contents of the props into given key/value pairs.
1069 * Returns: TRUE is the props entry could be fetched.
1072 gst_props_get (GstProps *props, gchar *first_name, ...)
1077 va_start (var_args, first_name);
1078 ret = gst_props_getv (props, FALSE, first_name, var_args);
1085 * gst_props_get_safe:
1086 * @props: the props to query
1087 * @first_name: the first key
1088 * @...: a pointer to a datastructure that can hold the value.
1090 * Gets the contents of the props into given key/value pairs.
1092 * Returns: TRUE is the props entry could be fetched.
1095 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
1100 va_start (var_args, first_name);
1101 ret = gst_props_getv (props, TRUE, first_name, var_args);
1108 * gst_props_entry_get_int:
1109 * @entry: the props entry to query
1110 * @val: a pointer to a gint to hold the value.
1112 * Get the contents of the entry into the given gint.
1114 * Returns: TRUE is the value could be fetched. FALSE if the
1115 * entry is not of given type.
1118 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1120 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1124 * gst_props_entry_get_float:
1125 * @entry: the props entry to query
1126 * @val: a pointer to a gfloat to hold the value.
1128 * Get the contents of the entry into the given gfloat.
1130 * Returns: TRUE is the value could be fetched. FALSE if the
1131 * entry is not of given type.
1134 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1136 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1140 * gst_props_entry_get_fourcc_int:
1141 * @entry: the props entry to query
1142 * @val: a pointer to a guint32 to hold the value.
1144 * Get the contents of the entry into the given guint32.
1146 * Returns: TRUE is the value could be fetched. FALSE if the
1147 * entry is not of given type.
1150 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1152 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1156 * gst_props_entry_get_boolean:
1157 * @entry: the props entry to query
1158 * @val: a pointer to a gboolean to hold the value.
1160 * Get the contents of the entry into the given gboolean.
1162 * Returns: TRUE is the value could be fetched. FALSE if the
1163 * entry is not of given type.
1166 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1168 return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val);
1172 * gst_props_entry_get_string:
1173 * @entry: the props entry to query
1174 * @val: a pointer to a gchar* to hold the value.
1176 * Get the contents of the entry into the given gchar*.
1178 * Returns: TRUE is the value could be fetched. FALSE if the
1179 * entry is not of given type.
1182 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1184 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1188 * gst_props_entry_get_int_range:
1189 * @entry: the props entry to query
1190 * @min: a pointer to a gint to hold the minimun value.
1191 * @max: a pointer to a gint to hold the maximum value.
1193 * Get the contents of the entry into the given gints.
1195 * Returns: TRUE is the value could be fetched. FALSE if the
1196 * entry is not of given type.
1199 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1201 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1205 * gst_props_entry_get_float_range:
1206 * @entry: the props entry to query
1207 * @min: a pointer to a gfloat to hold the minimun value.
1208 * @max: a pointer to a gfloat to hold the maximum value.
1210 * Get the contents of the entry into the given gfloats.
1212 * Returns: TRUE is the value could be fetched. FALSE if the
1213 * entry is not of given type.
1216 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1218 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1222 * gst_props_entry_get_list:
1223 * @entry: the props entry to query
1224 * @val: a pointer to a GList to hold the value.
1226 * Get the contents of the entry into the given GList.
1228 * Returns: TRUE is the value could be fetched. FALSE if the
1229 * entry is not of given type.
1232 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1234 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1239 * @props: the property to merge into
1240 * @tomerge: the property to merge
1242 * Merge the properties of tomerge into props.
1244 * Returns: the new merged property
1247 gst_props_merge (GstProps *props, GstProps *tomerge)
1251 g_return_val_if_fail (props != NULL, NULL);
1252 g_return_val_if_fail (tomerge != NULL, NULL);
1254 merge_props = tomerge->properties;
1256 /* FIXME do proper merging here... */
1257 while (merge_props) {
1258 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1260 gst_props_add_entry (props, entry);
1262 merge_props = g_list_next (merge_props);
1269 /* entry2 is always a list, entry1 never is */
1271 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1273 GList *entrylist = entry2->data.list_data.entries;
1274 gboolean found = FALSE;
1276 while (entrylist && !found) {
1277 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1279 found |= gst_props_entry_check_compatibility (entry1, entry);
1281 entrylist = g_list_next (entrylist);
1288 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1290 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1291 g_quark_to_string (entry2->propid));
1293 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1294 return gst_props_entry_check_list_compatibility (entry1, entry2);
1297 switch (entry1->propstype) {
1298 case GST_PROPS_LIST_TYPE:
1300 GList *entrylist = entry1->data.list_data.entries;
1301 gboolean valid = TRUE; /* innocent until proven guilty */
1303 while (entrylist && valid) {
1304 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1306 valid &= gst_props_entry_check_compatibility (entry, entry2);
1308 entrylist = g_list_next (entrylist);
1313 case GST_PROPS_INT_RANGE_TYPE:
1314 switch (entry2->propstype) {
1315 /* a - b <---> a - c */
1316 case GST_PROPS_INT_RANGE_TYPE:
1317 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1318 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1323 case GST_PROPS_FLOAT_RANGE_TYPE:
1324 switch (entry2->propstype) {
1325 /* a - b <---> a - c */
1326 case GST_PROPS_FLOAT_RANGE_TYPE:
1327 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1328 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1333 case GST_PROPS_FOURCC_TYPE:
1334 switch (entry2->propstype) {
1336 case GST_PROPS_FOURCC_TYPE:
1337 GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?",
1338 (char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data);
1339 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1344 case GST_PROPS_INT_TYPE:
1345 switch (entry2->propstype) {
1347 case GST_PROPS_INT_RANGE_TYPE:
1348 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1349 entry1->data.int_data,entry2->data.int_range_data.max);
1350 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1351 entry2->data.int_range_data.max >= entry1->data.int_data);
1353 case GST_PROPS_INT_TYPE:
1354 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1355 return (entry2->data.int_data == entry1->data.int_data);
1360 case GST_PROPS_FLOAT_TYPE:
1361 switch (entry2->propstype) {
1363 case GST_PROPS_FLOAT_RANGE_TYPE:
1364 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1365 entry2->data.float_range_data.max >= entry1->data.float_data);
1367 case GST_PROPS_FLOAT_TYPE:
1368 return (entry2->data.float_data == entry1->data.float_data);
1373 case GST_PROPS_BOOL_TYPE:
1374 switch (entry2->propstype) {
1376 case GST_PROPS_BOOL_TYPE:
1377 return (entry2->data.bool_data == entry1->data.bool_data);
1381 case GST_PROPS_STRING_TYPE:
1382 switch (entry2->propstype) {
1384 case GST_PROPS_STRING_TYPE:
1385 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1386 entry2->data.string_data.string, entry1->data.string_data.string);
1387 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1399 * gst_props_check_compatibility:
1400 * @fromprops: a property
1401 * @toprops: a property
1403 * Checks whether two capabilities are compatible.
1405 * Returns: TRUE if compatible, FALSE otherwise
1408 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1414 gboolean compatible = TRUE;
1416 g_return_val_if_fail (fromprops != NULL, FALSE);
1417 g_return_val_if_fail (toprops != NULL, FALSE);
1419 sourcelist = fromprops->properties;
1420 sinklist = toprops->properties;
1422 while (sourcelist && sinklist && compatible) {
1423 GstPropsEntry *entry1;
1424 GstPropsEntry *entry2;
1426 entry1 = (GstPropsEntry *)sourcelist->data;
1427 entry2 = (GstPropsEntry *)sinklist->data;
1429 while (entry1->propid < entry2->propid) {
1431 sourcelist = g_list_next (sourcelist);
1432 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1435 while (entry1->propid > entry2->propid) {
1437 sinklist = g_list_next (sinklist);
1438 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1442 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1444 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1445 g_quark_to_string (entry1->propid));
1448 sourcelist = g_list_next (sourcelist);
1449 sinklist = g_list_next (sinklist);
1451 if (sinklist && compatible) {
1452 GstPropsEntry *entry2;
1453 entry2 = (GstPropsEntry *)sinklist->data;
1464 static GstPropsEntry*
1465 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1467 GstPropsEntry *result = NULL;
1469 /* try to move the ranges and lists first */
1470 switch (entry2->propstype) {
1471 case GST_PROPS_INT_RANGE_TYPE:
1472 case GST_PROPS_FLOAT_RANGE_TYPE:
1473 case GST_PROPS_LIST_TYPE:
1475 GstPropsEntry *temp;
1485 switch (entry1->propstype) {
1486 case GST_PROPS_LIST_TYPE:
1488 GList *entrylist = entry1->data.list_data.entries;
1489 GList *intersection = NULL;
1492 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1493 GstPropsEntry *intersectentry;
1495 intersectentry = gst_props_entry_intersect (entry2, entry);
1497 if (intersectentry) {
1498 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1499 intersection = g_list_concat (intersection,
1500 g_list_copy (intersectentry->data.list_data.entries));
1501 /* set the list to NULL because the entries are concatenated to the above
1502 * list and we don't want to free them */
1503 intersectentry->data.list_data.entries = NULL;
1504 gst_props_entry_destroy (intersectentry);
1507 intersection = g_list_prepend (intersection, intersectentry);
1510 entrylist = g_list_next (entrylist);
1513 /* check if the list only contains 1 element, if so, we can just copy it */
1514 if (g_list_next (intersection) == NULL) {
1515 result = (GstPropsEntry *) (intersection->data);
1516 g_list_free (intersection);
1518 /* else we need to create a new entry to hold the list */
1520 result = gst_props_alloc_entry ();
1521 result->propid = entry1->propid;
1522 result->propstype = GST_PROPS_LIST_TYPE;
1523 result->data.list_data.entries = g_list_reverse (intersection);
1528 case GST_PROPS_INT_RANGE_TYPE:
1529 switch (entry2->propstype) {
1530 /* a - b <---> a - c */
1531 case GST_PROPS_INT_RANGE_TYPE:
1533 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1534 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1536 if (lower <= upper) {
1537 result = gst_props_alloc_entry ();
1538 result->propid = entry1->propid;
1540 if (lower == upper) {
1541 result->propstype = GST_PROPS_INT_TYPE;
1542 result->data.int_data = lower;
1545 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1546 result->data.int_range_data.min = lower;
1547 result->data.int_range_data.max = upper;
1552 case GST_PROPS_LIST_TYPE:
1554 GList *entries = entry2->data.list_data.entries;
1555 result = gst_props_alloc_entry ();
1556 result->propid = entry1->propid;
1557 result->propstype = GST_PROPS_LIST_TYPE;
1558 result->data.list_data.entries = NULL;
1560 GstPropsEntry * this = (GstPropsEntry *)entries->data;
1561 if (this->propstype != GST_PROPS_INT_TYPE) {
1562 /* no hope, this list doesn't even contain ints! */
1563 gst_props_entry_destroy (result);
1567 if (this->data.int_data >= entry1->data.int_range_data.min &&
1568 this->data.int_data <= entry1->data.int_range_data.max) {
1569 result->data.list_data.entries = g_list_append (result->data.list_data.entries,
1570 gst_props_entry_copy (this));
1572 entries = g_list_next (entries);
1576 case GST_PROPS_INT_TYPE:
1578 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1579 entry1->data.int_range_data.max >= entry2->data.int_data) {
1580 result = gst_props_entry_copy (entry2);
1588 case GST_PROPS_FLOAT_RANGE_TYPE:
1589 switch (entry2->propstype) {
1590 /* a - b <---> a - c */
1591 case GST_PROPS_FLOAT_RANGE_TYPE:
1593 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1594 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1596 if (lower <= upper) {
1597 result = gst_props_alloc_entry ();
1598 result->propid = entry1->propid;
1600 if (lower == upper) {
1601 result->propstype = GST_PROPS_FLOAT_TYPE;
1602 result->data.float_data = lower;
1605 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1606 result->data.float_range_data.min = lower;
1607 result->data.float_range_data.max = upper;
1612 case GST_PROPS_FLOAT_TYPE:
1613 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1614 entry1->data.float_range_data.max >= entry2->data.float_data) {
1615 result = gst_props_entry_copy (entry2);
1621 case GST_PROPS_FOURCC_TYPE:
1622 switch (entry2->propstype) {
1624 case GST_PROPS_FOURCC_TYPE:
1625 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1626 result = gst_props_entry_copy (entry1);
1631 case GST_PROPS_INT_TYPE:
1632 switch (entry2->propstype) {
1634 case GST_PROPS_INT_TYPE:
1635 if (entry1->data.int_data == entry2->data.int_data)
1636 result = gst_props_entry_copy (entry1);
1641 case GST_PROPS_FLOAT_TYPE:
1642 switch (entry2->propstype) {
1644 case GST_PROPS_FLOAT_TYPE:
1645 if (entry1->data.float_data == entry2->data.float_data)
1646 result = gst_props_entry_copy (entry1);
1651 case GST_PROPS_BOOL_TYPE:
1652 switch (entry2->propstype) {
1654 case GST_PROPS_BOOL_TYPE:
1655 if (entry1->data.bool_data == entry2->data.bool_data)
1656 result = gst_props_entry_copy (entry1);
1660 case GST_PROPS_STRING_TYPE:
1661 switch (entry2->propstype) {
1663 case GST_PROPS_STRING_TYPE:
1664 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1665 result = gst_props_entry_copy (entry1);
1677 * gst_props_intersect:
1678 * @props1: a property
1679 * @props2: another property
1681 * Calculates the intersection bewteen two GstProps.
1683 * Returns: a GstProps with the intersection or NULL if the
1684 * intersection is empty.
1687 gst_props_intersect (GstProps *props1, GstProps *props2)
1691 GstProps *intersection;
1693 GstPropsEntry *iprops = NULL;
1695 intersection = gst_props_empty_new ();
1696 intersection->fixed = TRUE;
1698 g_return_val_if_fail (props1 != NULL, NULL);
1699 g_return_val_if_fail (props2 != NULL, NULL);
1701 props1list = props1->properties;
1702 props2list = props2->properties;
1704 while (props1list && props2list) {
1705 GstPropsEntry *entry1;
1706 GstPropsEntry *entry2;
1708 entry1 = (GstPropsEntry *)props1list->data;
1709 entry2 = (GstPropsEntry *)props2list->data;
1711 while (entry1->propid < entry2->propid) {
1712 GstPropsEntry *toadd;
1714 GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"", g_quark_to_string (entry1->propid));
1716 toadd = gst_props_entry_copy (entry1);
1717 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1718 intersection->fixed = FALSE;
1720 intersection->properties = g_list_prepend (intersection->properties, toadd);
1722 props1list = g_list_next (props1list);
1724 entry1 = (GstPropsEntry *)props1list->data;
1728 while (entry1->propid > entry2->propid) {
1729 GstPropsEntry *toadd;
1731 toadd = gst_props_entry_copy (entry2);
1732 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1733 intersection->fixed = FALSE;
1735 intersection->properties = g_list_prepend (intersection->properties, toadd);
1737 props2list = g_list_next (props2list);
1739 entry2 = (GstPropsEntry *)props2list->data;
1743 /* at this point we are talking about the same property */
1744 iprops = gst_props_entry_intersect (entry1, entry2);
1747 if (GST_PROPS_ENTRY_IS_VARIABLE (iprops))
1748 intersection->fixed = FALSE;
1749 intersection->properties = g_list_prepend (intersection->properties, iprops);
1752 gst_props_unref (intersection);
1756 props1list = g_list_next (props1list);
1757 props2list = g_list_next (props2list);
1761 /* at this point one of the lists could contain leftover properties */
1763 leftovers = props1list;
1764 else if (props2list)
1765 leftovers = props2list;
1770 GstPropsEntry *entry;
1772 entry = (GstPropsEntry *) leftovers->data;
1773 if (GST_PROPS_ENTRY_IS_VARIABLE (entry))
1774 intersection->fixed = FALSE;
1775 intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry));
1777 leftovers = g_list_next (leftovers);
1780 intersection->properties = g_list_reverse (intersection->properties);
1782 return intersection;
1786 * gst_props_normalize:
1787 * @props: a property
1789 * Unrolls all lists in the given GstProps. This is usefull if you
1790 * want to loop over the props.
1792 * Returns: A GList with the unrolled props entries.
1795 gst_props_normalize (GstProps *props)
1798 GList *result = NULL;
1803 entries = props->properties;
1806 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1808 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1809 GList *list_entries = entry->data.list_data.entries;
1811 while (list_entries) {
1812 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1813 GstPropsEntry *new_entry;
1817 newprops = gst_props_empty_new ();
1818 newprops->properties = gst_props_list_copy (props->properties);
1819 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
1821 GList *new_list = NULL;
1823 new_entry = (GstPropsEntry *) lentry->data;
1824 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
1826 new_list = gst_props_normalize (newprops);
1827 result = g_list_concat (new_list, result);
1830 result = g_list_append (result, newprops);
1833 list_entries = g_list_next (list_entries);
1835 /* we break out of the loop because the other lists are
1836 * unrolled in the recursive call */
1839 entries = g_list_next (entries);
1842 result = g_list_prepend (result, props);
1845 result = g_list_reverse (result);
1846 gst_props_unref (props);
1851 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
1853 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
1858 switch (entry->propstype) {
1859 case GST_PROPS_INT_TYPE:
1860 subtree = xmlNewChild (parent, NULL, "int", NULL);
1861 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1862 str = g_strdup_printf ("%d", entry->data.int_data);
1863 xmlNewProp (subtree, "value", str);
1866 case GST_PROPS_INT_RANGE_TYPE:
1867 subtree = xmlNewChild (parent, NULL, "range", NULL);
1868 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1869 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
1870 xmlNewProp (subtree, "min", str);
1872 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
1873 xmlNewProp (subtree, "max", str);
1876 case GST_PROPS_FLOAT_TYPE:
1877 subtree = xmlNewChild (parent, NULL, "float", NULL);
1878 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1879 str = g_strdup_printf ("%f", entry->data.float_data);
1880 xmlNewProp (subtree, "value", str);
1883 case GST_PROPS_FLOAT_RANGE_TYPE:
1884 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
1885 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1886 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
1887 xmlNewProp (subtree, "min", str);
1889 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
1890 xmlNewProp (subtree, "max", str);
1893 case GST_PROPS_FOURCC_TYPE:
1894 str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
1895 xmlAddChild (parent, xmlNewComment (str));
1897 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
1898 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1899 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
1900 xmlNewProp (subtree, "hexvalue", str);
1903 case GST_PROPS_BOOL_TYPE:
1904 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
1905 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1906 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
1908 case GST_PROPS_STRING_TYPE:
1909 subtree = xmlNewChild (parent, NULL, "string", NULL);
1910 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1911 xmlNewProp (subtree, "value", entry->data.string_data.string);
1914 g_warning ("trying to save unknown property type %d", entry->propstype);
1922 * gst_props_save_thyself:
1923 * @props: a property to save
1924 * @parent: the parent XML tree
1926 * Saves the property into an XML representation.
1928 * Returns: the new XML tree
1931 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
1936 g_return_val_if_fail (props != NULL, NULL);
1938 proplist = props->properties;
1941 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
1943 switch (entry->propstype) {
1944 case GST_PROPS_LIST_TYPE:
1945 subtree = xmlNewChild (parent, NULL, "list", NULL);
1946 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1947 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
1950 gst_props_save_thyself_func (entry, parent);
1953 proplist = g_list_next (proplist);
1959 static GstPropsEntry*
1960 gst_props_load_thyself_func (xmlNodePtr field)
1962 GstPropsEntry *entry;
1965 entry = gst_props_alloc_entry ();
1967 if (!strcmp(field->name, "int")) {
1968 entry->propstype = GST_PROPS_INT_TYPE;
1969 prop = xmlGetProp(field, "name");
1970 entry->propid = g_quark_from_string (prop);
1972 prop = xmlGetProp(field, "value");
1973 sscanf (prop, "%d", &entry->data.int_data);
1976 else if (!strcmp(field->name, "range")) {
1977 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
1978 prop = xmlGetProp(field, "name");
1979 entry->propid = g_quark_from_string (prop);
1981 prop = xmlGetProp (field, "min");
1982 sscanf (prop, "%d", &entry->data.int_range_data.min);
1984 prop = xmlGetProp (field, "max");
1985 sscanf (prop, "%d", &entry->data.int_range_data.max);
1988 else if (!strcmp(field->name, "float")) {
1989 entry->propstype = GST_PROPS_FLOAT_TYPE;
1990 prop = xmlGetProp(field, "name");
1991 entry->propid = g_quark_from_string (prop);
1993 prop = xmlGetProp(field, "value");
1994 sscanf (prop, "%f", &entry->data.float_data);
1997 else if (!strcmp(field->name, "floatrange")) {
1998 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1999 prop = xmlGetProp(field, "name");
2000 entry->propid = g_quark_from_string (prop);
2002 prop = xmlGetProp (field, "min");
2003 sscanf (prop, "%f", &entry->data.float_range_data.min);
2005 prop = xmlGetProp (field, "max");
2006 sscanf (prop, "%f", &entry->data.float_range_data.max);
2009 else if (!strcmp(field->name, "boolean")) {
2010 entry->propstype = GST_PROPS_BOOL_TYPE;
2011 prop = xmlGetProp(field, "name");
2012 entry->propid = g_quark_from_string (prop);
2014 prop = xmlGetProp (field, "value");
2015 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
2016 else entry->data.bool_data = 1;
2019 else if (!strcmp(field->name, "fourcc")) {
2020 entry->propstype = GST_PROPS_FOURCC_TYPE;
2021 prop = xmlGetProp(field, "name");
2022 entry->propid = g_quark_from_string (prop);
2024 prop = xmlGetProp (field, "hexvalue");
2025 sscanf (prop, "%08x", &entry->data.fourcc_data);
2028 else if (!strcmp(field->name, "string")) {
2029 entry->propstype = GST_PROPS_STRING_TYPE;
2030 prop = xmlGetProp(field, "name");
2031 entry->propid = g_quark_from_string (prop);
2033 entry->data.string_data.string = xmlGetProp (field, "value");
2036 g_mutex_lock (_gst_props_entries_chunk_lock);
2037 g_mem_chunk_free (_gst_props_entries_chunk, entry);
2038 g_mutex_unlock (_gst_props_entries_chunk_lock);
2046 * gst_props_load_thyself:
2047 * @parent: the XML tree to load from
2049 * Creates a new property out of an XML tree.
2051 * Returns: the new property
2054 gst_props_load_thyself (xmlNodePtr parent)
2057 xmlNodePtr field = parent->xmlChildrenNode;
2060 props = gst_props_empty_new ();
2063 if (!strcmp (field->name, "list")) {
2064 GstPropsEntry *entry;
2065 xmlNodePtr subfield = field->xmlChildrenNode;
2067 entry = gst_props_alloc_entry ();
2068 prop = xmlGetProp (field, "name");
2069 entry->propid = g_quark_from_string (prop);
2071 entry->propstype = GST_PROPS_LIST_TYPE;
2072 entry->data.list_data.entries = NULL;
2075 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2078 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2080 subfield = subfield->next;
2082 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2083 gst_props_add_entry (props, entry);
2086 GstPropsEntry *entry;
2088 entry = gst_props_load_thyself_func (field);
2091 gst_props_add_entry (props, entry);
2093 field = field->next;
2098 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */