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_LIST_TYPE: \
219 entry->data.list_data.entries = g_list_copy (va_arg (var_args, GList*)); \
227 #define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
233 GstPropsType propstype = va_arg (var_args, GstPropsType); \
234 if (propstype != entry->propstype) { \
239 switch (entry->propstype) { \
240 case GST_PROPS_INT_TYPE: \
241 *(va_arg (var_args, gint*)) = entry->data.int_data; \
243 case GST_PROPS_INT_RANGE_TYPE: \
244 *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
245 *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
247 case GST_PROPS_FLOAT_TYPE: \
248 *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
250 case GST_PROPS_FLOAT_RANGE_TYPE: \
251 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
252 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
254 case GST_PROPS_FOURCC_TYPE: \
255 *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
257 case GST_PROPS_BOOL_TYPE: \
258 *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
260 case GST_PROPS_STRING_TYPE: \
261 *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
263 case GST_PROPS_LIST_TYPE: \
264 *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
273 static GstPropsEntry*
274 gst_props_alloc_entry (void)
276 GstPropsEntry *entry;
278 g_mutex_lock (_gst_props_entries_chunk_lock);
279 entry = g_mem_chunk_alloc (_gst_props_entries_chunk);
280 g_mutex_unlock (_gst_props_entries_chunk_lock);
286 gst_props_entry_destroy (GstPropsEntry *entry)
288 switch (entry->propstype) {
289 case GST_PROPS_STRING_TYPE:
290 g_free (entry->data.string_data.string);
292 case GST_PROPS_LIST_TYPE:
294 GList *entries = entry->data.list_data.entries;
297 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
298 entries = g_list_next (entries);
300 g_list_free (entry->data.list_data.entries);
306 g_mutex_lock (_gst_props_entries_chunk_lock);
307 g_mem_chunk_free (_gst_props_entries_chunk, entry);
308 g_mutex_unlock (_gst_props_entries_chunk_lock);
312 * gst_props_empty_new:
314 * Create a new empty property.
316 * Returns: the new property
319 gst_props_empty_new (void)
323 g_mutex_lock (_gst_props_chunk_lock);
324 props = g_mem_chunk_alloc (_gst_props_chunk);
325 g_mutex_unlock (_gst_props_chunk_lock);
327 props->properties = NULL;
335 * gst_props_add_entry:
336 * @props: the property to add the entry to
337 * @entry: the entry to add
339 * Addes the given propsentry to the props
342 gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
344 g_return_if_fail (props);
345 g_return_if_fail (entry);
347 if (props->fixed && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
348 props->fixed = FALSE;
350 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
355 * @firstname: the first property name
356 * @...: the property values
358 * Create a new property from the given key/value pairs
360 * Returns: the new property
363 gst_props_new (const gchar *firstname, ...)
368 va_start (var_args, firstname);
370 props = gst_props_newv (firstname, var_args);
380 * @props: the props to debug
382 * Dump the contents of the given properties into the DEBUG log.
385 gst_props_debug (GstProps *props)
387 GList *propslist = props->properties;
390 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
392 gst_props_debug_entry (entry);
394 propslist = g_list_next (propslist);
399 * gst_props_merge_int_entries:
400 * @newentry: the new entry
401 * @oldentry: an old entry
403 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
405 * Assumes that the entries are either ints or int ranges.
407 * Returns: TRUE if the entries were merged, FALSE otherwise.
410 gst_props_merge_int_entries(GstPropsEntry * newentry, GstPropsEntry * oldentry)
412 gint new_min, new_max, old_min, old_max;
413 gboolean can_merge = FALSE;
415 if (newentry->propstype == GST_PROPS_INT_TYPE) {
416 new_min = newentry->data.int_data;
417 new_max = newentry->data.int_data;
419 new_min = newentry->data.int_range_data.min;
420 new_max = newentry->data.int_range_data.max;
423 if (oldentry->propstype == GST_PROPS_INT_TYPE) {
424 old_min = oldentry->data.int_data;
425 old_max = oldentry->data.int_data;
427 old_min = oldentry->data.int_range_data.min;
428 old_max = oldentry->data.int_range_data.max;
431 /* Put range which starts lower into (new_min, new_max) */
432 if (old_min < new_min) {
442 /* new_min is min of either entry - second half of the following conditional */
443 /* is to avoid overflow problems. */
444 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
445 /* ranges overlap, or are adjacent. Pick biggest maximum. */
447 if (old_max > new_max) new_max = old_max;
451 if (new_min == new_max) {
452 newentry->propstype = GST_PROPS_INT_TYPE;
453 newentry->data.int_data = new_min;
455 newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
456 newentry->data.int_range_data.min = new_min;
457 newentry->data.int_range_data.max = new_max;
464 * gst_props_add_to_int_list:
465 * @entries: the existing list of entries
466 * @entry: the new entry to add to the list
468 * Add an integer property to a list of properties, removing duplicates
469 * and merging ranges.
471 * Assumes that the existing list is in simplest form, contains
472 * only ints and int ranges, and that the new entry is an int or
475 * Returns: a pointer to a list with the new entry added.
478 gst_props_add_to_int_list (GList * entries, GstPropsEntry * newentry)
484 GstPropsEntry * oldentry = (GstPropsEntry *)(i->data);
485 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
488 /* replace the existing one with the merged one */
489 g_mutex_lock (_gst_props_entries_chunk_lock);
490 g_mem_chunk_free (_gst_props_entries_chunk, oldentry);
491 g_mutex_unlock (_gst_props_entries_chunk_lock);
492 entries = g_list_remove_link (entries, i);
495 /* start again: it's possible that this change made an earlier entry */
496 /* mergeable, and the pointer is now invalid anyway. */
503 return g_list_prepend (entries, newentry);
506 static GstPropsEntry*
507 gst_props_entry_newv (const gchar *name, va_list var_args)
509 GstPropsEntry *entry;
511 entry = gst_props_alloc_entry ();
512 entry->propid = g_quark_from_string (name);
513 GST_PROPS_ENTRY_FILL (entry, var_args);
519 * gst_props_entry_new:
520 * @name: the name of the props entry
521 * @...: the value of the entry
523 * Create a new property entry with the given key/value.
525 * Returns: the new entry.
528 gst_props_entry_new (const gchar *name, ...)
531 GstPropsEntry *entry;
533 va_start (var_args, name);
534 entry = gst_props_entry_newv (name, var_args);
542 * @firstname: the first property name
543 * @var_args: the property values
545 * Create a new property from the list of entries.
547 * Returns: the new property created from the list of entries
550 gst_props_newv (const gchar *firstname, va_list var_args)
553 gboolean inlist = FALSE;
554 const gchar *prop_name;
555 GstPropsEntry *list_entry = NULL;
558 GST_PROPS_LIST_T_UNSET,
559 GST_PROPS_LIST_T_INTS,
560 GST_PROPS_LIST_T_FLOATS,
561 GST_PROPS_LIST_T_MISC,
564 /* type of the list */
565 list_types list_type = GST_PROPS_LIST_T_UNSET;
566 /* type of current item */
567 list_types entry_type = GST_PROPS_LIST_T_UNSET;
569 if (firstname == NULL)
572 props = gst_props_empty_new ();
574 prop_name = firstname;
578 GstPropsEntry *entry;
580 entry = gst_props_alloc_entry ();
581 entry->propid = g_quark_from_string (prop_name);
582 GST_PROPS_ENTRY_FILL (entry, var_args);
584 switch (entry->propstype) {
585 case GST_PROPS_INT_TYPE:
586 case GST_PROPS_INT_RANGE_TYPE:
587 entry_type = GST_PROPS_LIST_T_INTS;
589 case GST_PROPS_FLOAT_TYPE:
590 case GST_PROPS_FLOAT_RANGE_TYPE:
591 entry_type = GST_PROPS_LIST_T_FLOATS;
593 case GST_PROPS_FOURCC_TYPE:
594 case GST_PROPS_BOOL_TYPE:
595 case GST_PROPS_STRING_TYPE:
596 entry_type = GST_PROPS_LIST_T_MISC;
598 case GST_PROPS_LIST_TYPE:
599 g_return_val_if_fail (inlist == FALSE, NULL);
602 list_type = GST_PROPS_LIST_T_UNSET;
603 list_entry->data.list_data.entries = NULL;
605 case GST_PROPS_END_TYPE:
606 g_return_val_if_fail (inlist == TRUE, NULL);
608 /* if list was of size 1, replace the list by a the item it contains */
609 if (g_list_length(list_entry->data.list_data.entries) == 1) {
610 GstPropsEntry * subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
611 list_entry->propstype = subentry->propstype;
612 list_entry->data = subentry->data;
613 g_mutex_lock (_gst_props_entries_chunk_lock);
614 g_mem_chunk_free (_gst_props_entries_chunk, subentry);
615 g_mutex_unlock (_gst_props_entries_chunk_lock);
618 list_entry->data.list_data.entries =
619 g_list_reverse (list_entry->data.list_data.entries);
622 g_mutex_lock (_gst_props_entries_chunk_lock);
623 g_mem_chunk_free (_gst_props_entries_chunk, entry);
624 g_mutex_unlock (_gst_props_entries_chunk_lock);
627 prop_name = va_arg (var_args, gchar*);
630 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
631 g_mutex_lock (_gst_props_entries_chunk_lock);
632 g_mem_chunk_free (_gst_props_entries_chunk, entry);
633 g_mutex_unlock (_gst_props_entries_chunk_lock);
637 if (inlist && (list_entry != entry)) {
638 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
639 if (list_type != entry_type) {
640 g_warning ("property list contained incompatible entry types\n");
643 case GST_PROPS_LIST_T_INTS:
644 list_entry->data.list_data.entries =
645 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
648 list_entry->data.list_data.entries =
649 g_list_prepend (list_entry->data.list_data.entries, entry);
655 gst_props_add_entry (props, entry);
658 prop_name = va_arg (var_args, gchar*);
666 * @props: the props to modify
667 * @name: the name of the entry to modify
668 * @...: The prop entry.
670 * Modifies the value of the given entry in the props struct.
671 * For the optional args, use GST_PROPS_FOO, where FOO is INT,
672 * STRING, etc. This macro expands to a variable number of arguments,
673 * hence the lack of precision in the function prototype. No
674 * terminating NULL is necessary as only one property can be changed.
676 * Returns: the new modified property structure.
679 gst_props_set (GstProps *props, const gchar *name, ...)
685 g_return_val_if_fail (props != NULL, NULL);
687 quark = g_quark_from_string (name);
689 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
692 GstPropsEntry *entry;
694 entry = (GstPropsEntry *)lentry->data;
696 va_start (var_args, name);
698 GST_PROPS_ENTRY_FILL (entry, var_args);
703 g_warning ("gstprops: no property '%s' to change\n", name);
712 * @props: the props to unref
714 * Decrease the refcount of the property structure, destroying
715 * the property if the refcount is 0.
718 gst_props_unref (GstProps *props)
725 if (props->refcount == 0)
726 gst_props_destroy (props);
731 * @props: the props to ref
733 * Increase the refcount of the property structure.
736 gst_props_ref (GstProps *props)
738 g_return_if_fail (props != NULL);
746 * @props: the props to destroy
748 * Destroy the property, freeing all the memory that
752 gst_props_destroy (GstProps *props)
759 entries = props->properties;
762 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
763 entries = g_list_next (entries);
765 g_list_free (props->properties);
767 g_mutex_lock (_gst_props_chunk_lock);
768 g_mem_chunk_free (_gst_props_chunk, props);
769 g_mutex_unlock (_gst_props_chunk_lock);
775 static GstPropsEntry*
776 gst_props_entry_copy (GstPropsEntry *entry)
778 GstPropsEntry *newentry;
780 newentry = gst_props_alloc_entry ();
781 memcpy (newentry, entry, sizeof (GstPropsEntry));
782 if (entry->propstype == GST_PROPS_LIST_TYPE) {
783 newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
785 else if (entry->propstype == GST_PROPS_STRING_TYPE) {
786 newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
793 gst_props_list_copy (GList *propslist)
798 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
800 new = g_list_prepend (new, gst_props_entry_copy (entry));
802 propslist = g_list_next (propslist);
804 new = g_list_reverse (new);
811 * @props: the props to copy
813 * Copy the property structure.
815 * Returns: the new property that is a copy of the original
819 gst_props_copy (GstProps *props)
826 new = gst_props_empty_new ();
827 new->properties = gst_props_list_copy (props->properties);
828 new->fixed = props->fixed;
834 * gst_props_copy_on_write:
835 * @props: the props to copy on write
837 * Copy the property structure if the refcount is >1.
839 * Returns: A new props that can be safely written to.
842 gst_props_copy_on_write (GstProps *props)
844 GstProps *new = props;;
846 g_return_val_if_fail (props != NULL, NULL);
848 if (props->refcount > 1) {
849 new = gst_props_copy (props);
850 gst_props_unref (props);
857 * gst_props_get_entry:
858 * @props: the props to query
859 * @name: the name of the entry to get
861 * Get the props entry with the geven name
863 * Returns: The props entry with the geven name or NULL when
864 * the entry was not found.
867 gst_props_get_entry (GstProps *props, const gchar *name)
872 g_return_val_if_fail (props != NULL, NULL);
873 g_return_val_if_fail (name != NULL, NULL);
875 quark = g_quark_from_string (name);
877 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
880 GstPropsEntry *thisentry;
881 thisentry = (GstPropsEntry *)lentry->data;
888 * gst_props_has_property:
889 * @props: the props to check
890 * @name: the name of the key to find
892 * Checks if a given props has a property with the given name.
894 * Returns: TRUE if the property was found, FALSE otherwise.
897 gst_props_has_property (GstProps *props, const gchar *name)
899 return (gst_props_get_entry (props, name) != NULL);
903 * gst_props_has_property_typed:
904 * @props: the props to check
905 * @name: the name of the key to find
906 * @type: the type of the required property
908 * Checks if a given props has a property with the given name and the given type.
910 * Returns: TRUE if the property was found, FALSE otherwise.
913 gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
915 const GstPropsEntry *entry;
917 entry = gst_props_get_entry (props, name);
921 return (entry->propstype == type);
925 * gst_props_has_fixed_property:
926 * @props: the props to check
927 * @name: the name of the key to find
929 * Checks if a given props has a property with the given name that
930 * is also fixed, ie. is not a list or a range.
932 * Returns: TRUE if the property was found, FALSE otherwise.
935 gst_props_has_fixed_property (GstProps *props, const gchar *name)
937 const GstPropsEntry *entry;
939 entry = gst_props_get_entry (props, name);
943 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
947 * gst_props_entry_get_type:
948 * @entry: the props entry to query
950 * Get the type of the given props entry.
952 * Returns: The type of the props entry.
955 gst_props_entry_get_type (const GstPropsEntry *entry)
957 g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
959 return entry->propstype;
963 * gst_props_entry_get_name:
964 * @entry: the props entry to query
966 * Get the name of the given props entry.
968 * Returns: The name of the props entry.
971 gst_props_entry_get_name (const GstPropsEntry *entry)
973 g_return_val_if_fail (entry != NULL, NULL);
975 return g_quark_to_string (entry->propid);
979 * gst_props_entry_is_fixed:
980 * @entry: the props entry to query
982 * Checks if the props entry is fixe, ie. is not a list
985 * Returns: TRUE is the props entry is fixed.
988 gst_props_entry_is_fixed (const GstPropsEntry *entry)
990 g_return_val_if_fail (entry != NULL, FALSE);
992 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
996 gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
1000 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1006 * gst_props_entry_get:
1007 * @entry: the props entry to query
1008 * @...: a pointer to a type that can hold the value.
1010 * Gets the contents of the entry.
1012 * Returns: TRUE is the props entry could be fetched.
1015 gst_props_entry_get (const GstPropsEntry *entry, ...)
1020 g_return_val_if_fail (entry != NULL, FALSE);
1022 va_start (var_args, entry);
1023 result = gst_props_entry_getv (entry, FALSE, var_args);
1030 gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
1035 g_return_val_if_fail (entry != NULL, FALSE);
1037 va_start (var_args, entry);
1038 result = gst_props_entry_getv (entry, TRUE, var_args);
1045 gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args)
1047 while (first_name) {
1048 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1051 if (!entry) return FALSE;
1052 GST_PROPS_ENTRY_READ (entry, var_args, FALSE, &result);
1053 if (!result) return FALSE;
1055 first_name = va_arg (var_args, gchar *);
1062 * @props: the props to query
1063 * @first_name: the first key
1064 * @...: a pointer to a datastructure that can hold the value.
1066 * Gets the contents of the props into given key/value pairs.
1068 * Returns: TRUE is the props entry could be fetched.
1071 gst_props_get (GstProps *props, gchar *first_name, ...)
1076 va_start (var_args, first_name);
1077 ret = gst_props_getv (props, FALSE, first_name, var_args);
1084 * gst_props_get_safe:
1085 * @props: the props to query
1086 * @first_name: the first key
1087 * @...: a pointer to a datastructure that can hold the value.
1089 * Gets the contents of the props into given key/value pairs.
1091 * Returns: TRUE is the props entry could be fetched.
1094 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
1099 va_start (var_args, first_name);
1100 ret = gst_props_getv (props, TRUE, first_name, var_args);
1107 * gst_props_entry_get_int:
1108 * @entry: the props entry to query
1109 * @val: a pointer to a gint to hold the value.
1111 * Get the contents of the entry into the given gint.
1113 * Returns: TRUE is the value could be fetched. FALSE if the
1114 * entry is not of given type.
1117 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1119 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1123 * gst_props_entry_get_float:
1124 * @entry: the props entry to query
1125 * @val: a pointer to a gfloat to hold the value.
1127 * Get the contents of the entry into the given gfloat.
1129 * Returns: TRUE is the value could be fetched. FALSE if the
1130 * entry is not of given type.
1133 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1135 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1139 * gst_props_entry_get_fourcc_int:
1140 * @entry: the props entry to query
1141 * @val: a pointer to a guint32 to hold the value.
1143 * Get the contents of the entry into the given guint32.
1145 * Returns: TRUE is the value could be fetched. FALSE if the
1146 * entry is not of given type.
1149 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1151 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1155 * gst_props_entry_get_boolean:
1156 * @entry: the props entry to query
1157 * @val: a pointer to a gboolean to hold the value.
1159 * Get the contents of the entry into the given gboolean.
1161 * Returns: TRUE is the value could be fetched. FALSE if the
1162 * entry is not of given type.
1165 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1167 return gst_props_entry_get_safe (entry, GST_PROPS_BOOL_TYPE, val);
1171 * gst_props_entry_get_string:
1172 * @entry: the props entry to query
1173 * @val: a pointer to a gchar* to hold the value.
1175 * Get the contents of the entry into the given gchar*.
1177 * Returns: TRUE is the value could be fetched. FALSE if the
1178 * entry is not of given type.
1181 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1183 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1187 * gst_props_entry_get_int_range:
1188 * @entry: the props entry to query
1189 * @min: a pointer to a gint to hold the minimun value.
1190 * @max: a pointer to a gint to hold the maximum value.
1192 * Get the contents of the entry into the given gints.
1194 * Returns: TRUE is the value could be fetched. FALSE if the
1195 * entry is not of given type.
1198 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1200 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1204 * gst_props_entry_get_float_range:
1205 * @entry: the props entry to query
1206 * @min: a pointer to a gfloat to hold the minimun value.
1207 * @max: a pointer to a gfloat to hold the maximum value.
1209 * Get the contents of the entry into the given gfloats.
1211 * Returns: TRUE is the value could be fetched. FALSE if the
1212 * entry is not of given type.
1215 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1217 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1221 * gst_props_entry_get_list:
1222 * @entry: the props entry to query
1223 * @val: a pointer to a GList to hold the value.
1225 * Get the contents of the entry into the given GList.
1227 * Returns: TRUE is the value could be fetched. FALSE if the
1228 * entry is not of given type.
1231 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1233 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1238 * @props: the property to merge into
1239 * @tomerge: the property to merge
1241 * Merge the properties of tomerge into props.
1243 * Returns: the new merged property
1246 gst_props_merge (GstProps *props, GstProps *tomerge)
1250 g_return_val_if_fail (props != NULL, NULL);
1251 g_return_val_if_fail (tomerge != NULL, NULL);
1253 merge_props = tomerge->properties;
1255 /* FIXME do proper merging here... */
1256 while (merge_props) {
1257 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1259 gst_props_add_entry (props, entry);
1261 merge_props = g_list_next (merge_props);
1268 /* entry2 is always a list, entry1 never is */
1270 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1272 GList *entrylist = entry2->data.list_data.entries;
1273 gboolean found = FALSE;
1275 while (entrylist && !found) {
1276 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1278 found |= gst_props_entry_check_compatibility (entry1, entry);
1280 entrylist = g_list_next (entrylist);
1287 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1289 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1290 g_quark_to_string (entry2->propid));
1292 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1293 return gst_props_entry_check_list_compatibility (entry1, entry2);
1296 switch (entry1->propstype) {
1297 case GST_PROPS_LIST_TYPE:
1299 GList *entrylist = entry1->data.list_data.entries;
1300 gboolean valid = TRUE; /* innocent until proven guilty */
1302 while (entrylist && valid) {
1303 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1305 valid &= gst_props_entry_check_compatibility (entry, entry2);
1307 entrylist = g_list_next (entrylist);
1312 case GST_PROPS_INT_RANGE_TYPE:
1313 switch (entry2->propstype) {
1314 /* a - b <---> a - c */
1315 case GST_PROPS_INT_RANGE_TYPE:
1316 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1317 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1322 case GST_PROPS_FLOAT_RANGE_TYPE:
1323 switch (entry2->propstype) {
1324 /* a - b <---> a - c */
1325 case GST_PROPS_FLOAT_RANGE_TYPE:
1326 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1327 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1332 case GST_PROPS_FOURCC_TYPE:
1333 switch (entry2->propstype) {
1335 case GST_PROPS_FOURCC_TYPE:
1336 GST_DEBUG(GST_CAT_PROPERTIES,"\"%4.4s\" <--> \"%4.4s\" ?",
1337 (char*) &entry2->data.fourcc_data, (char*) &entry1->data.fourcc_data);
1338 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1343 case GST_PROPS_INT_TYPE:
1344 switch (entry2->propstype) {
1346 case GST_PROPS_INT_RANGE_TYPE:
1347 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1348 entry1->data.int_data,entry2->data.int_range_data.max);
1349 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1350 entry2->data.int_range_data.max >= entry1->data.int_data);
1352 case GST_PROPS_INT_TYPE:
1353 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1354 return (entry2->data.int_data == entry1->data.int_data);
1359 case GST_PROPS_FLOAT_TYPE:
1360 switch (entry2->propstype) {
1362 case GST_PROPS_FLOAT_RANGE_TYPE:
1363 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1364 entry2->data.float_range_data.max >= entry1->data.float_data);
1366 case GST_PROPS_FLOAT_TYPE:
1367 return (entry2->data.float_data == entry1->data.float_data);
1372 case GST_PROPS_BOOL_TYPE:
1373 switch (entry2->propstype) {
1375 case GST_PROPS_BOOL_TYPE:
1376 return (entry2->data.bool_data == entry1->data.bool_data);
1380 case GST_PROPS_STRING_TYPE:
1381 switch (entry2->propstype) {
1383 case GST_PROPS_STRING_TYPE:
1384 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1385 entry2->data.string_data.string, entry1->data.string_data.string);
1386 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1398 * gst_props_check_compatibility:
1399 * @fromprops: a property
1400 * @toprops: a property
1402 * Checks whether two capabilities are compatible.
1404 * Returns: TRUE if compatible, FALSE otherwise
1407 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1413 gboolean compatible = TRUE;
1415 g_return_val_if_fail (fromprops != NULL, FALSE);
1416 g_return_val_if_fail (toprops != NULL, FALSE);
1418 sourcelist = fromprops->properties;
1419 sinklist = toprops->properties;
1421 while (sourcelist && sinklist && compatible) {
1422 GstPropsEntry *entry1;
1423 GstPropsEntry *entry2;
1425 entry1 = (GstPropsEntry *)sourcelist->data;
1426 entry2 = (GstPropsEntry *)sinklist->data;
1428 while (entry1->propid < entry2->propid) {
1430 sourcelist = g_list_next (sourcelist);
1431 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1434 while (entry1->propid > entry2->propid) {
1436 sinklist = g_list_next (sinklist);
1437 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1441 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1443 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1444 g_quark_to_string (entry1->propid));
1447 sourcelist = g_list_next (sourcelist);
1448 sinklist = g_list_next (sinklist);
1450 if (sinklist && compatible) {
1451 GstPropsEntry *entry2;
1452 entry2 = (GstPropsEntry *)sinklist->data;
1463 static GstPropsEntry*
1464 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1466 GstPropsEntry *result = NULL;
1468 /* try to move the ranges and lists first */
1469 switch (entry2->propstype) {
1470 case GST_PROPS_INT_RANGE_TYPE:
1471 case GST_PROPS_FLOAT_RANGE_TYPE:
1472 case GST_PROPS_LIST_TYPE:
1474 GstPropsEntry *temp;
1484 switch (entry1->propstype) {
1485 case GST_PROPS_LIST_TYPE:
1487 GList *entrylist = entry1->data.list_data.entries;
1488 GList *intersection = NULL;
1491 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1492 GstPropsEntry *intersectentry;
1494 intersectentry = gst_props_entry_intersect (entry2, entry);
1496 if (intersectentry) {
1497 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1498 intersection = g_list_concat (intersection,
1499 g_list_copy (intersectentry->data.list_data.entries));
1500 /* set the list to NULL because the entries are concatenated to the above
1501 * list and we don't want to free them */
1502 intersectentry->data.list_data.entries = NULL;
1503 gst_props_entry_destroy (intersectentry);
1506 intersection = g_list_prepend (intersection, intersectentry);
1509 entrylist = g_list_next (entrylist);
1512 /* check if the list only contains 1 element, if so, we can just copy it */
1513 if (g_list_next (intersection) == NULL) {
1514 result = (GstPropsEntry *) (intersection->data);
1515 g_list_free (intersection);
1517 /* else we need to create a new entry to hold the list */
1519 result = gst_props_alloc_entry ();
1520 result->propid = entry1->propid;
1521 result->propstype = GST_PROPS_LIST_TYPE;
1522 result->data.list_data.entries = g_list_reverse (intersection);
1527 case GST_PROPS_INT_RANGE_TYPE:
1528 switch (entry2->propstype) {
1529 /* a - b <---> a - c */
1530 case GST_PROPS_INT_RANGE_TYPE:
1532 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1533 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1535 if (lower <= upper) {
1536 result = gst_props_alloc_entry ();
1537 result->propid = entry1->propid;
1539 if (lower == upper) {
1540 result->propstype = GST_PROPS_INT_TYPE;
1541 result->data.int_data = lower;
1544 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1545 result->data.int_range_data.min = lower;
1546 result->data.int_range_data.max = upper;
1551 case GST_PROPS_LIST_TYPE:
1553 GList *entries = entry2->data.list_data.entries;
1554 result = gst_props_alloc_entry ();
1555 result->propid = entry1->propid;
1556 result->propstype = GST_PROPS_LIST_TYPE;
1557 result->data.list_data.entries = NULL;
1559 GstPropsEntry * this = (GstPropsEntry *)entries->data;
1560 if (this->propstype != GST_PROPS_INT_TYPE) {
1561 /* no hope, this list doesn't even contain ints! */
1562 gst_props_entry_destroy (result);
1566 if (this->data.int_data >= entry1->data.int_range_data.min &&
1567 this->data.int_data <= entry1->data.int_range_data.max) {
1568 result->data.list_data.entries = g_list_append (result->data.list_data.entries,
1569 gst_props_entry_copy (this));
1571 entries = g_list_next (entries);
1575 case GST_PROPS_INT_TYPE:
1577 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1578 entry1->data.int_range_data.max >= entry2->data.int_data) {
1579 result = gst_props_entry_copy (entry2);
1587 case GST_PROPS_FLOAT_RANGE_TYPE:
1588 switch (entry2->propstype) {
1589 /* a - b <---> a - c */
1590 case GST_PROPS_FLOAT_RANGE_TYPE:
1592 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1593 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1595 if (lower <= upper) {
1596 result = gst_props_alloc_entry ();
1597 result->propid = entry1->propid;
1599 if (lower == upper) {
1600 result->propstype = GST_PROPS_FLOAT_TYPE;
1601 result->data.float_data = lower;
1604 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1605 result->data.float_range_data.min = lower;
1606 result->data.float_range_data.max = upper;
1611 case GST_PROPS_FLOAT_TYPE:
1612 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1613 entry1->data.float_range_data.max >= entry2->data.float_data) {
1614 result = gst_props_entry_copy (entry2);
1620 case GST_PROPS_FOURCC_TYPE:
1621 switch (entry2->propstype) {
1623 case GST_PROPS_FOURCC_TYPE:
1624 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1625 result = gst_props_entry_copy (entry1);
1630 case GST_PROPS_INT_TYPE:
1631 switch (entry2->propstype) {
1633 case GST_PROPS_INT_TYPE:
1634 if (entry1->data.int_data == entry2->data.int_data)
1635 result = gst_props_entry_copy (entry1);
1640 case GST_PROPS_FLOAT_TYPE:
1641 switch (entry2->propstype) {
1643 case GST_PROPS_FLOAT_TYPE:
1644 if (entry1->data.float_data == entry2->data.float_data)
1645 result = gst_props_entry_copy (entry1);
1650 case GST_PROPS_BOOL_TYPE:
1651 switch (entry2->propstype) {
1653 case GST_PROPS_BOOL_TYPE:
1654 if (entry1->data.bool_data == entry2->data.bool_data)
1655 result = gst_props_entry_copy (entry1);
1659 case GST_PROPS_STRING_TYPE:
1660 switch (entry2->propstype) {
1662 case GST_PROPS_STRING_TYPE:
1663 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1664 result = gst_props_entry_copy (entry1);
1676 * gst_props_intersect:
1677 * @props1: a property
1678 * @props2: another property
1680 * Calculates the intersection bewteen two GstProps.
1682 * Returns: a GstProps with the intersection or NULL if the
1683 * intersection is empty.
1686 gst_props_intersect (GstProps *props1, GstProps *props2)
1690 GstProps *intersection;
1692 GstPropsEntry *iprops = NULL;
1694 intersection = gst_props_empty_new ();
1695 intersection->fixed = TRUE;
1697 g_return_val_if_fail (props1 != NULL, NULL);
1698 g_return_val_if_fail (props2 != NULL, NULL);
1700 props1list = props1->properties;
1701 props2list = props2->properties;
1703 while (props1list && props2list) {
1704 GstPropsEntry *entry1;
1705 GstPropsEntry *entry2;
1707 entry1 = (GstPropsEntry *)props1list->data;
1708 entry2 = (GstPropsEntry *)props2list->data;
1710 while (entry1->propid < entry2->propid) {
1711 GstPropsEntry *toadd;
1713 GST_DEBUG (GST_CAT_PROPERTIES,"source is more specific in \"%s\"", g_quark_to_string (entry1->propid));
1715 toadd = gst_props_entry_copy (entry1);
1716 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1717 intersection->fixed = FALSE;
1719 intersection->properties = g_list_prepend (intersection->properties, toadd);
1721 props1list = g_list_next (props1list);
1723 entry1 = (GstPropsEntry *)props1list->data;
1727 while (entry1->propid > entry2->propid) {
1728 GstPropsEntry *toadd;
1730 toadd = gst_props_entry_copy (entry2);
1731 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd))
1732 intersection->fixed = FALSE;
1734 intersection->properties = g_list_prepend (intersection->properties, toadd);
1736 props2list = g_list_next (props2list);
1738 entry2 = (GstPropsEntry *)props2list->data;
1742 /* at this point we are talking about the same property */
1743 iprops = gst_props_entry_intersect (entry1, entry2);
1746 if (GST_PROPS_ENTRY_IS_VARIABLE (iprops))
1747 intersection->fixed = FALSE;
1748 intersection->properties = g_list_prepend (intersection->properties, iprops);
1751 gst_props_unref (intersection);
1755 props1list = g_list_next (props1list);
1756 props2list = g_list_next (props2list);
1760 /* at this point one of the lists could contain leftover properties */
1762 leftovers = props1list;
1763 else if (props2list)
1764 leftovers = props2list;
1769 GstPropsEntry *entry;
1771 entry = (GstPropsEntry *) leftovers->data;
1772 if (GST_PROPS_ENTRY_IS_VARIABLE (entry))
1773 intersection->fixed = FALSE;
1774 intersection->properties = g_list_prepend (intersection->properties, gst_props_entry_copy (entry));
1776 leftovers = g_list_next (leftovers);
1779 intersection->properties = g_list_reverse (intersection->properties);
1781 return intersection;
1785 * gst_props_normalize:
1786 * @props: a property
1788 * Unrolls all lists in the given GstProps. This is usefull if you
1789 * want to loop over the props.
1791 * Returns: A GList with the unrolled props entries.
1794 gst_props_normalize (GstProps *props)
1797 GList *result = NULL;
1802 entries = props->properties;
1805 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1807 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1808 GList *list_entries = entry->data.list_data.entries;
1810 while (list_entries) {
1811 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1812 GstPropsEntry *new_entry;
1816 newprops = gst_props_empty_new ();
1817 newprops->properties = gst_props_list_copy (props->properties);
1818 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
1820 GList *new_list = NULL;
1822 new_entry = (GstPropsEntry *) lentry->data;
1823 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
1825 new_list = gst_props_normalize (newprops);
1826 result = g_list_concat (new_list, result);
1829 result = g_list_append (result, newprops);
1832 list_entries = g_list_next (list_entries);
1834 /* we break out of the loop because the other lists are
1835 * unrolled in the recursive call */
1838 entries = g_list_next (entries);
1841 result = g_list_prepend (result, props);
1844 result = g_list_reverse (result);
1845 gst_props_unref (props);
1850 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
1852 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
1857 switch (entry->propstype) {
1858 case GST_PROPS_INT_TYPE:
1859 subtree = xmlNewChild (parent, NULL, "int", NULL);
1860 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1861 str = g_strdup_printf ("%d", entry->data.int_data);
1862 xmlNewProp (subtree, "value", str);
1865 case GST_PROPS_INT_RANGE_TYPE:
1866 subtree = xmlNewChild (parent, NULL, "range", NULL);
1867 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1868 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
1869 xmlNewProp (subtree, "min", str);
1871 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
1872 xmlNewProp (subtree, "max", str);
1875 case GST_PROPS_FLOAT_TYPE:
1876 subtree = xmlNewChild (parent, NULL, "float", NULL);
1877 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1878 str = g_strdup_printf ("%f", entry->data.float_data);
1879 xmlNewProp (subtree, "value", str);
1882 case GST_PROPS_FLOAT_RANGE_TYPE:
1883 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
1884 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1885 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
1886 xmlNewProp (subtree, "min", str);
1888 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
1889 xmlNewProp (subtree, "max", str);
1892 case GST_PROPS_FOURCC_TYPE:
1893 str = g_strdup_printf ("%4.4s", (gchar *)&entry->data.fourcc_data);
1894 xmlAddChild (parent, xmlNewComment (str));
1896 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
1897 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1898 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
1899 xmlNewProp (subtree, "hexvalue", str);
1902 case GST_PROPS_BOOL_TYPE:
1903 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
1904 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1905 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
1907 case GST_PROPS_STRING_TYPE:
1908 subtree = xmlNewChild (parent, NULL, "string", NULL);
1909 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1910 xmlNewProp (subtree, "value", entry->data.string_data.string);
1913 g_warning ("trying to save unknown property type %d", entry->propstype);
1921 * gst_props_save_thyself:
1922 * @props: a property to save
1923 * @parent: the parent XML tree
1925 * Saves the property into an XML representation.
1927 * Returns: the new XML tree
1930 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
1935 g_return_val_if_fail (props != NULL, NULL);
1937 proplist = props->properties;
1940 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
1942 switch (entry->propstype) {
1943 case GST_PROPS_LIST_TYPE:
1944 subtree = xmlNewChild (parent, NULL, "list", NULL);
1945 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
1946 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
1949 gst_props_save_thyself_func (entry, parent);
1952 proplist = g_list_next (proplist);
1958 static GstPropsEntry*
1959 gst_props_load_thyself_func (xmlNodePtr field)
1961 GstPropsEntry *entry;
1964 entry = gst_props_alloc_entry ();
1966 if (!strcmp(field->name, "int")) {
1967 entry->propstype = GST_PROPS_INT_TYPE;
1968 prop = xmlGetProp(field, "name");
1969 entry->propid = g_quark_from_string (prop);
1971 prop = xmlGetProp(field, "value");
1972 sscanf (prop, "%d", &entry->data.int_data);
1975 else if (!strcmp(field->name, "range")) {
1976 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
1977 prop = xmlGetProp(field, "name");
1978 entry->propid = g_quark_from_string (prop);
1980 prop = xmlGetProp (field, "min");
1981 sscanf (prop, "%d", &entry->data.int_range_data.min);
1983 prop = xmlGetProp (field, "max");
1984 sscanf (prop, "%d", &entry->data.int_range_data.max);
1987 else if (!strcmp(field->name, "float")) {
1988 entry->propstype = GST_PROPS_FLOAT_TYPE;
1989 prop = xmlGetProp(field, "name");
1990 entry->propid = g_quark_from_string (prop);
1992 prop = xmlGetProp(field, "value");
1993 sscanf (prop, "%f", &entry->data.float_data);
1996 else if (!strcmp(field->name, "floatrange")) {
1997 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1998 prop = xmlGetProp(field, "name");
1999 entry->propid = g_quark_from_string (prop);
2001 prop = xmlGetProp (field, "min");
2002 sscanf (prop, "%f", &entry->data.float_range_data.min);
2004 prop = xmlGetProp (field, "max");
2005 sscanf (prop, "%f", &entry->data.float_range_data.max);
2008 else if (!strcmp(field->name, "boolean")) {
2009 entry->propstype = GST_PROPS_BOOL_TYPE;
2010 prop = xmlGetProp(field, "name");
2011 entry->propid = g_quark_from_string (prop);
2013 prop = xmlGetProp (field, "value");
2014 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
2015 else entry->data.bool_data = 1;
2018 else if (!strcmp(field->name, "fourcc")) {
2019 entry->propstype = GST_PROPS_FOURCC_TYPE;
2020 prop = xmlGetProp(field, "name");
2021 entry->propid = g_quark_from_string (prop);
2023 prop = xmlGetProp (field, "hexvalue");
2024 sscanf (prop, "%08x", &entry->data.fourcc_data);
2027 else if (!strcmp(field->name, "string")) {
2028 entry->propstype = GST_PROPS_STRING_TYPE;
2029 prop = xmlGetProp(field, "name");
2030 entry->propid = g_quark_from_string (prop);
2032 entry->data.string_data.string = xmlGetProp (field, "value");
2035 g_mutex_lock (_gst_props_entries_chunk_lock);
2036 g_mem_chunk_free (_gst_props_entries_chunk, entry);
2037 g_mutex_unlock (_gst_props_entries_chunk_lock);
2045 * gst_props_load_thyself:
2046 * @parent: the XML tree to load from
2048 * Creates a new property out of an XML tree.
2050 * Returns: the new property
2053 gst_props_load_thyself (xmlNodePtr parent)
2056 xmlNodePtr field = parent->xmlChildrenNode;
2059 props = gst_props_empty_new ();
2062 if (!strcmp (field->name, "list")) {
2063 GstPropsEntry *entry;
2064 xmlNodePtr subfield = field->xmlChildrenNode;
2066 entry = gst_props_alloc_entry ();
2067 prop = xmlGetProp (field, "name");
2068 entry->propid = g_quark_from_string (prop);
2070 entry->propstype = GST_PROPS_LIST_TYPE;
2071 entry->data.list_data.entries = NULL;
2074 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2077 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2079 subfield = subfield->next;
2081 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2082 gst_props_add_entry (props, entry);
2085 GstPropsEntry *entry;
2087 entry = gst_props_load_thyself_func (field);
2090 gst_props_add_entry (props, entry);
2092 field = field->next;
2097 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */