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"
28 #include "gstmemchunk.h"
30 #ifndef GST_DISABLE_TRACE
31 /* #define GST_WITH_ALLOC_TRACE */
33 static GstAllocTrace *_props_trace;
34 static GstAllocTrace *_entries_trace;
37 GType _gst_props_type;
38 GType _gst_props_entry_type;
40 #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE)
42 struct _GstPropsEntry {
44 GstPropsType propstype;
53 /* structured values */
71 static GstMemChunk *_gst_props_entries_chunk;
72 static GstMemChunk *_gst_props_chunk;
74 static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2);
75 static GList* gst_props_list_copy (GList *propslist);
78 transform_func (const GValue *src_value,
81 GstProps *props = g_value_peek_pointer (src_value);
82 GString *result = g_string_new ("");
85 GList *propslist = props->properties;
88 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
89 const gchar *name = g_quark_to_string (entry->propid);
91 switch (entry->propstype) {
92 case GST_PROPS_INT_TYPE:
93 g_string_append_printf (result, "%s=(int) %d", name, entry->data.int_data);
95 case GST_PROPS_FLOAT_TYPE:
96 g_string_append_printf (result, "%s=(float) %f", name, entry->data.float_data);
98 case GST_PROPS_FOURCC_TYPE:
99 g_string_append_printf (result, "%s=(fourcc) '%4.4s'", name, (gchar *)&entry->data.fourcc_data);
101 case GST_PROPS_BOOLEAN_TYPE:
102 g_string_append_printf (result, "%s=(boolean) %s", name,
103 (entry->data.bool_data ? "TRUE" : "FALSE"));
105 case GST_PROPS_STRING_TYPE:
106 g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string);
112 propslist = g_list_next (propslist);
114 g_string_append (result, "; ");
118 dest_value->data[0].v_pointer = result->str;
119 g_string_free (result, FALSE);
124 _gst_props_initialize (void)
126 _gst_props_entries_chunk = gst_mem_chunk_new ("GstPropsEntries",
127 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 1024,
130 _gst_props_chunk = gst_mem_chunk_new ("GstProps",
131 sizeof (GstProps), sizeof (GstProps) * 256,
134 _gst_props_type = g_boxed_type_register_static ("GstProps",
135 (GBoxedCopyFunc) gst_props_ref,
136 (GBoxedFreeFunc) gst_props_unref);
138 g_value_register_transform_func (_gst_props_type,
142 _gst_props_entry_type = g_boxed_type_register_static ("GstPropsEntry",
143 (GBoxedCopyFunc) gst_props_entry_copy,
144 (GBoxedFreeFunc) gst_props_entry_destroy);
146 #ifndef GST_DISABLE_TRACE
147 _props_trace = gst_alloc_trace_register (GST_PROPS_TRACE_NAME);
148 _entries_trace = gst_alloc_trace_register (GST_PROPS_ENTRY_TRACE_NAME);
153 gst_props_debug_entry (GstPropsEntry *entry)
155 const gchar *name = g_quark_to_string (entry->propid);
157 switch (entry->propstype) {
158 case GST_PROPS_INT_TYPE:
159 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int %d", entry, name, entry->data.int_data);
161 case GST_PROPS_FLOAT_TYPE:
162 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float %f", entry, name, entry->data.float_data);
164 case GST_PROPS_FOURCC_TYPE:
165 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: fourcc %c%c%c%c", entry, name,
166 (entry->data.fourcc_data>>0)&0xff,
167 (entry->data.fourcc_data>>8)&0xff,
168 (entry->data.fourcc_data>>16)&0xff,
169 (entry->data.fourcc_data>>24)&0xff);
171 case GST_PROPS_BOOLEAN_TYPE:
172 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: bool %d", entry, name, entry->data.bool_data);
174 case GST_PROPS_STRING_TYPE:
175 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: string \"%s\"", entry, name, entry->data.string_data.string);
177 case GST_PROPS_INT_RANGE_TYPE:
178 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int range %d-%d", entry, name, entry->data.int_range_data.min,
179 entry->data.int_range_data.max);
181 case GST_PROPS_FLOAT_RANGE_TYPE:
182 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float range %f-%f", entry, name, entry->data.float_range_data.min,
183 entry->data.float_range_data.max);
185 case GST_PROPS_LIST_TYPE:
186 GST_DEBUG (GST_CAT_PROPERTIES, "%p: [list]", entry);
188 GList *entries = entry->data.list_data.entries;
191 gst_props_debug_entry ((GstPropsEntry *)entries->data);
192 entries = g_list_next (entries);
197 g_warning ("unknown property type %d at %p", entry->propstype, entry);
203 props_compare_func (gconstpointer a,
206 GstPropsEntry *entry1 = (GstPropsEntry *)a;
207 GstPropsEntry *entry2 = (GstPropsEntry *)b;
209 return (entry1->propid - entry2->propid);
213 props_find_func (gconstpointer a,
216 GstPropsEntry *entry2 = (GstPropsEntry *)a;
217 GQuark quark = (GQuark) GPOINTER_TO_INT (b);
219 return (quark - entry2->propid);
222 /* This is implemented as a huge macro because we cannot pass
223 * va_list variables by reference on some architectures.
225 #define GST_PROPS_ENTRY_FILL(entry, var_args) \
227 entry->propstype = va_arg (var_args, GstPropsType); \
229 switch (entry->propstype) { \
230 case GST_PROPS_INT_TYPE: \
231 entry->data.int_data = va_arg (var_args, gint); \
233 case GST_PROPS_INT_RANGE_TYPE: \
234 entry->data.int_range_data.min = va_arg (var_args, gint); \
235 entry->data.int_range_data.max = va_arg (var_args, gint); \
237 case GST_PROPS_FLOAT_TYPE: \
238 entry->data.float_data = va_arg (var_args, gdouble); \
240 case GST_PROPS_FLOAT_RANGE_TYPE: \
241 entry->data.float_range_data.min = va_arg (var_args, gdouble); \
242 entry->data.float_range_data.max = va_arg (var_args, gdouble); \
244 case GST_PROPS_FOURCC_TYPE: \
245 entry->data.fourcc_data = va_arg (var_args, gulong); \
247 case GST_PROPS_BOOLEAN_TYPE: \
248 entry->data.bool_data = va_arg (var_args, gboolean); \
250 case GST_PROPS_STRING_TYPE: \
251 entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
253 case GST_PROPS_GLIST_TYPE: \
254 entry->propstype = GST_PROPS_LIST_TYPE; \
255 entry->data.list_data.entries = g_list_copy (va_arg (var_args, GList*)); \
263 #define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
269 GstPropsType propstype = va_arg (var_args, GstPropsType); \
270 if (propstype != entry->propstype) { \
275 switch (entry->propstype) { \
276 case GST_PROPS_INT_TYPE: \
277 *(va_arg (var_args, gint*)) = entry->data.int_data; \
279 case GST_PROPS_INT_RANGE_TYPE: \
280 *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
281 *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
283 case GST_PROPS_FLOAT_TYPE: \
284 *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
286 case GST_PROPS_FLOAT_RANGE_TYPE: \
287 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
288 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
290 case GST_PROPS_FOURCC_TYPE: \
291 *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
293 case GST_PROPS_BOOLEAN_TYPE: \
294 *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
296 case GST_PROPS_STRING_TYPE: \
297 *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
299 case GST_PROPS_LIST_TYPE: \
300 *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
309 static GstPropsEntry*
310 gst_props_alloc_entry (void)
312 GstPropsEntry *entry;
314 entry = gst_mem_chunk_alloc (_gst_props_entries_chunk);
315 #ifndef GST_DISABLE_TRACE
316 gst_alloc_trace_new (_entries_trace, entry);
319 GST_DEBUG (GST_CAT_PROPERTIES, "new entry %p", entry);
325 gst_props_entry_clean (GstPropsEntry *entry)
327 switch (entry->propstype) {
328 case GST_PROPS_STRING_TYPE:
329 g_free (entry->data.string_data.string);
331 case GST_PROPS_LIST_TYPE:
333 GList *entries = entry->data.list_data.entries;
336 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
337 entries = g_list_next (entries);
339 g_list_free (entry->data.list_data.entries);
348 * gst_props_entry_destroy:
349 * @entry: the entry to destroy
351 * Free the given propsentry
354 gst_props_entry_destroy (GstPropsEntry *entry)
356 GST_DEBUG (GST_CAT_PROPERTIES, "destroy entry %p", entry);
358 gst_props_entry_clean (entry);
360 gst_mem_chunk_free (_gst_props_entries_chunk, entry);
361 #ifndef GST_DISABLE_TRACE
362 gst_alloc_trace_free (_entries_trace, entry);
367 * gst_props_empty_new:
369 * Create a new empty property.
371 * Returns: the new property
374 gst_props_empty_new (void)
378 props = gst_mem_chunk_alloc (_gst_props_chunk);
379 #ifndef GST_DISABLE_TRACE
380 gst_alloc_trace_new (_props_trace, props);
383 GST_DEBUG (GST_CAT_PROPERTIES, "new %p", props);
385 props->properties = NULL;
387 GST_PROPS_FLAG_SET (props, GST_PROPS_FLOATING);
388 GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED);
395 * @oldprops: the props to take replace
396 * @newprops: the props to take replace
398 * Replace the pointer to the props, doing proper
402 gst_props_replace (GstProps **oldprops, GstProps *newprops)
404 if (*oldprops != newprops) {
405 if (newprops) gst_props_ref (newprops);
406 if (*oldprops) gst_props_unref (*oldprops);
408 *oldprops = newprops;
413 * gst_props_replace_sink:
414 * @oldprops: the props to take replace
415 * @newprops: the props to take replace
417 * Replace the pointer to the props and take ownership.
420 gst_props_replace_sink (GstProps **oldprops, GstProps *newprops)
422 gst_props_replace (oldprops, newprops);
423 gst_props_sink (newprops);
427 * gst_props_add_entry:
428 * @props: the property to add the entry to
429 * @entry: the entry to add
431 * Addes the given propsentry to the props
434 gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
436 g_return_if_fail (props);
437 g_return_if_fail (entry);
439 if (GST_PROPS_IS_FIXED (props) && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
440 GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED);
442 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
446 * gst_props_remove_entry:
447 * @props: the property to remove the entry from
448 * @entry: the entry to remove
450 * Removes the given propsentry from the props.
453 gst_props_remove_entry (GstProps *props, GstPropsEntry *entry)
455 g_return_if_fail (props != NULL);
456 g_return_if_fail (entry != NULL);
458 props->properties = g_list_remove (props->properties, entry);
462 * gst_props_remove_entry_by_name:
463 * @props: the property to remove the entry from
464 * @name: the name of the entry to remove
466 * Removes the propsentry with the given name from the props.
469 gst_props_remove_entry_by_name (GstProps *props, const gchar *name)
474 g_return_if_fail (props != NULL);
475 g_return_if_fail (name != NULL);
477 quark = g_quark_from_string (name);
479 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
481 gst_props_remove_entry (props, (GstPropsEntry *)lentry->data);
487 * @firstname: the first property name
488 * @...: the property values
490 * Create a new property from the given key/value pairs
492 * Returns: the new property
495 gst_props_new (const gchar *firstname, ...)
500 va_start (var_args, firstname);
502 props = gst_props_newv (firstname, var_args);
512 * @props: the props to debug
514 * Dump the contents of the given properties into the DEBUG log.
517 gst_props_debug (GstProps *props)
519 GList *propslist = props->properties;
521 GST_DEBUG (GST_CAT_PROPERTIES, "props %p, refcount %d, flags %d", props, props->refcount, props->flags);
524 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
526 gst_props_debug_entry (entry);
528 propslist = g_list_next (propslist);
533 * gst_props_merge_int_entries:
534 * @newentry: the new entry
535 * @oldentry: an old entry
537 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
539 * Assumes that the entries are either ints or int ranges.
541 * Returns: TRUE if the entries were merged, FALSE otherwise.
544 gst_props_merge_int_entries(GstPropsEntry *newentry, GstPropsEntry *oldentry)
546 gint new_min, new_max, old_min, old_max;
547 gboolean can_merge = FALSE;
549 if (newentry->propstype == GST_PROPS_INT_TYPE) {
550 new_min = newentry->data.int_data;
551 new_max = newentry->data.int_data;
553 new_min = newentry->data.int_range_data.min;
554 new_max = newentry->data.int_range_data.max;
557 if (oldentry->propstype == GST_PROPS_INT_TYPE) {
558 old_min = oldentry->data.int_data;
559 old_max = oldentry->data.int_data;
561 old_min = oldentry->data.int_range_data.min;
562 old_max = oldentry->data.int_range_data.max;
565 /* Put range which starts lower into (new_min, new_max) */
566 if (old_min < new_min) {
576 /* new_min is min of either entry - second half of the following conditional */
577 /* is to avoid overflow problems. */
578 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
579 /* ranges overlap, or are adjacent. Pick biggest maximum. */
581 if (old_max > new_max) new_max = old_max;
585 if (new_min == new_max) {
586 newentry->propstype = GST_PROPS_INT_TYPE;
587 newentry->data.int_data = new_min;
589 newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
590 newentry->data.int_range_data.min = new_min;
591 newentry->data.int_range_data.max = new_max;
598 * gst_props_add_to_int_list:
599 * @entries: the existing list of entries
600 * @entry: the new entry to add to the list
602 * Add an integer property to a list of properties, removing duplicates
603 * and merging ranges.
605 * Assumes that the existing list is in simplest form, contains
606 * only ints and int ranges, and that the new entry is an int or
609 * Returns: a pointer to a list with the new entry added.
612 gst_props_add_to_int_list (GList *entries, GstPropsEntry *newentry)
618 GstPropsEntry *oldentry = (GstPropsEntry *)(i->data);
619 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
622 /* replace the existing one with the merged one */
623 gst_props_entry_destroy (oldentry);
625 entries = g_list_remove_link (entries, i);
628 /* start again: it's possible that this change made an earlier entry */
629 /* mergeable, and the pointer is now invalid anyway. */
636 return g_list_prepend (entries, newentry);
639 static GstPropsEntry*
640 gst_props_entry_newv (const gchar *name, va_list var_args)
642 GstPropsEntry *entry;
644 entry = gst_props_alloc_entry ();
645 entry->propid = g_quark_from_string (name);
646 GST_PROPS_ENTRY_FILL (entry, var_args);
652 * gst_props_entry_new:
653 * @name: the name of the props entry
654 * @...: the value of the entry
656 * Create a new property entry with the given key/value.
658 * Returns: the new entry.
661 gst_props_entry_new (const gchar *name, ...)
664 GstPropsEntry *entry;
666 va_start (var_args, name);
667 entry = gst_props_entry_newv (name, var_args);
675 * @firstname: the first property name
676 * @var_args: the property values
678 * Create a new property from the list of entries.
680 * Returns: the new property created from the list of entries
683 gst_props_newv (const gchar *firstname, va_list var_args)
686 gboolean inlist = FALSE;
687 const gchar *prop_name;
688 GstPropsEntry *list_entry = NULL;
691 GST_PROPS_LIST_T_UNSET,
692 GST_PROPS_LIST_T_INTS,
693 GST_PROPS_LIST_T_FLOATS,
694 GST_PROPS_LIST_T_MISC,
697 /* type of the list */
698 list_types list_type = GST_PROPS_LIST_T_UNSET;
699 /* type of current item */
700 list_types entry_type = GST_PROPS_LIST_T_UNSET;
702 if (firstname == NULL)
705 props = gst_props_empty_new ();
707 prop_name = firstname;
711 GstPropsEntry *entry;
713 entry = gst_props_alloc_entry ();
714 entry->propid = g_quark_from_string (prop_name);
715 GST_PROPS_ENTRY_FILL (entry, var_args);
717 switch (entry->propstype) {
718 case GST_PROPS_INT_TYPE:
719 case GST_PROPS_INT_RANGE_TYPE:
720 entry_type = GST_PROPS_LIST_T_INTS;
722 case GST_PROPS_FLOAT_TYPE:
723 case GST_PROPS_FLOAT_RANGE_TYPE:
724 entry_type = GST_PROPS_LIST_T_FLOATS;
726 case GST_PROPS_FOURCC_TYPE:
727 case GST_PROPS_BOOLEAN_TYPE:
728 case GST_PROPS_STRING_TYPE:
729 entry_type = GST_PROPS_LIST_T_MISC;
731 case GST_PROPS_LIST_TYPE:
732 g_return_val_if_fail (inlist == FALSE, NULL);
735 list_type = GST_PROPS_LIST_T_UNSET;
736 list_entry->data.list_data.entries = NULL;
738 case GST_PROPS_END_TYPE:
739 g_return_val_if_fail (inlist == TRUE, NULL);
741 /* if list was of size 1, replace the list by a the item it contains */
742 if (g_list_length(list_entry->data.list_data.entries) == 1) {
743 GstPropsEntry *subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
744 list_entry->propstype = subentry->propstype;
745 list_entry->data = subentry->data;
746 gst_props_entry_destroy (subentry);
749 list_entry->data.list_data.entries =
750 g_list_reverse (list_entry->data.list_data.entries);
753 gst_props_entry_destroy (entry);
756 prop_name = va_arg (var_args, gchar*);
759 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
760 gst_props_entry_destroy (entry);
764 if (inlist && (list_entry != entry)) {
765 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
766 if (list_type != entry_type) {
767 g_warning ("property list contained incompatible entry types\n");
770 case GST_PROPS_LIST_T_INTS:
771 list_entry->data.list_data.entries =
772 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
775 list_entry->data.list_data.entries =
776 g_list_prepend (list_entry->data.list_data.entries, entry);
782 gst_props_add_entry (props, entry);
785 prop_name = va_arg (var_args, gchar*);
793 * @props: the props to modify
794 * @name: the name of the entry to modify
795 * @...: The prop entry.
797 * Modifies the value of the given entry in the props struct.
798 * For the optional args, use GST_PROPS_FOO, where FOO is INT,
799 * STRING, etc. This macro expands to a variable number of arguments,
800 * hence the lack of precision in the function prototype. No
801 * terminating NULL is necessary as only one property can be changed.
803 * Returns: the new modified property structure.
806 gst_props_set (GstProps *props, const gchar *name, ...)
812 g_return_val_if_fail (props != NULL, NULL);
814 quark = g_quark_from_string (name);
816 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
819 GstPropsEntry *entry;
821 entry = (GstPropsEntry *)lentry->data;
823 va_start (var_args, name);
824 gst_props_entry_clean (entry);
825 GST_PROPS_ENTRY_FILL (entry, var_args);
829 g_warning ("gstprops: no property '%s' to change\n", name);
838 * @props: the props to unref
840 * Decrease the refcount of the property structure, destroying
841 * the property if the refcount is 0.
843 * Returns: handle to unrefed props or NULL when it was
847 gst_props_unref (GstProps *props)
852 g_return_val_if_fail (props->refcount > 0, NULL);
854 GST_DEBUG (GST_CAT_PROPERTIES, "unref %p (%d->%d)", props, props->refcount, props->refcount-1);
857 if (props->refcount == 0) {
858 gst_props_destroy (props);
867 * @props: the props to ref
869 * Increase the refcount of the property structure.
871 * Returns: handle to refed props.
874 gst_props_ref (GstProps *props)
879 g_return_val_if_fail (props->refcount > 0, NULL);
881 GST_DEBUG (GST_CAT_PROPERTIES, "ref %p (%d->%d)", props, props->refcount, props->refcount+1);
890 * @props: the props to sink
892 * If the props if floating, decrease its refcount. Usually used
893 * with gst_props_ref() to take ownership of the props.
896 gst_props_sink (GstProps *props)
901 GST_DEBUG (GST_CAT_PROPERTIES, "sink %p", props);
903 if (GST_PROPS_IS_FLOATING (props)) {
904 GST_PROPS_FLAG_UNSET (props, GST_PROPS_FLOATING);
905 gst_props_unref (props);
911 * @props: the props to destroy
913 * Destroy the property, freeing all the memory that
917 gst_props_destroy (GstProps *props)
924 entries = props->properties;
927 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
928 entries = g_list_next (entries);
930 g_list_free (props->properties);
932 gst_mem_chunk_free (_gst_props_chunk, props);
933 #ifndef GST_DISABLE_TRACE
934 gst_alloc_trace_free (_props_trace, props);
939 * gst_props_entry_copy:
940 * @entry: the entry to copy
942 * Copy the propsentry.
944 * Returns: a new #GstPropsEntry that is a copy of the original
948 gst_props_entry_copy (const GstPropsEntry *entry)
950 GstPropsEntry *newentry;
952 newentry = gst_props_alloc_entry ();
953 memcpy (newentry, entry, sizeof (GstPropsEntry));
955 switch (entry->propstype) {
956 case GST_PROPS_LIST_TYPE:
957 newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
959 case GST_PROPS_STRING_TYPE:
960 newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
971 gst_props_list_copy (GList *propslist)
976 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
978 new = g_list_prepend (new, gst_props_entry_copy (entry));
980 propslist = g_list_next (propslist);
982 new = g_list_reverse (new);
989 * @props: the props to copy
991 * Copy the property structure.
993 * Returns: the new property that is a copy of the original
997 gst_props_copy (GstProps *props)
1004 new = gst_props_empty_new ();
1005 new->properties = gst_props_list_copy (props->properties);
1006 GST_PROPS_FLAGS (new) = GST_PROPS_FLAGS (props) | GST_PROPS_FLOATING;
1012 * gst_props_copy_on_write:
1013 * @props: the props to copy on write
1015 * Copy the property structure if the refcount is >1.
1017 * Returns: A new props that can be safely written to.
1020 gst_props_copy_on_write (GstProps *props)
1022 GstProps *new = props;;
1024 g_return_val_if_fail (props != NULL, NULL);
1026 if (props->refcount > 1) {
1027 new = gst_props_copy (props);
1028 gst_props_unref (props);
1035 * gst_props_get_entry:
1036 * @props: the props to query
1037 * @name: the name of the entry to get
1039 * Get the props entry with the geven name
1041 * Returns: The props entry with the geven name or NULL when
1042 * the entry was not found.
1044 const GstPropsEntry*
1045 gst_props_get_entry (GstProps *props, const gchar *name)
1050 g_return_val_if_fail (props != NULL, NULL);
1051 g_return_val_if_fail (name != NULL, NULL);
1053 quark = g_quark_from_string (name);
1055 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
1058 GstPropsEntry *thisentry;
1059 thisentry = (GstPropsEntry *)lentry->data;
1066 * gst_props_has_property:
1067 * @props: the props to check
1068 * @name: the name of the key to find
1070 * Checks if a given props has a property with the given name.
1072 * Returns: TRUE if the property was found, FALSE otherwise.
1075 gst_props_has_property (GstProps *props, const gchar *name)
1077 return (gst_props_get_entry (props, name) != NULL);
1081 * gst_props_has_property_typed:
1082 * @props: the props to check
1083 * @name: the name of the key to find
1084 * @type: the type of the required property
1086 * Checks if a given props has a property with the given name and the given type.
1088 * Returns: TRUE if the property was found, FALSE otherwise.
1091 gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
1093 const GstPropsEntry *entry;
1095 entry = gst_props_get_entry (props, name);
1099 return (entry->propstype == type);
1103 * gst_props_has_fixed_property:
1104 * @props: the props to check
1105 * @name: the name of the key to find
1107 * Checks if a given props has a property with the given name that
1108 * is also fixed, ie. is not a list or a range.
1110 * Returns: TRUE if the property was found, FALSE otherwise.
1113 gst_props_has_fixed_property (GstProps *props, const gchar *name)
1115 const GstPropsEntry *entry;
1117 entry = gst_props_get_entry (props, name);
1121 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
1125 * gst_props_entry_get_type:
1126 * @entry: the props entry to query
1128 * Get the type of the given props entry.
1130 * Returns: The type of the props entry.
1133 gst_props_entry_get_type (const GstPropsEntry *entry)
1135 g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
1137 return entry->propstype;
1141 * gst_props_entry_get_name:
1142 * @entry: the props entry to query
1144 * Get the name of the given props entry.
1146 * Returns: The name of the props entry.
1149 gst_props_entry_get_name (const GstPropsEntry *entry)
1151 g_return_val_if_fail (entry != NULL, NULL);
1153 return g_quark_to_string (entry->propid);
1157 * gst_props_entry_is_fixed:
1158 * @entry: the props entry to query
1160 * Checks if the props entry is fixe, ie. is not a list
1163 * Returns: TRUE is the props entry is fixed.
1166 gst_props_entry_is_fixed (const GstPropsEntry *entry)
1168 g_return_val_if_fail (entry != NULL, FALSE);
1170 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
1174 gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
1178 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1184 * gst_props_entry_get:
1185 * @entry: the props entry to query
1186 * @...: a pointer to a type that can hold the value.
1188 * Gets the contents of the entry.
1190 * Returns: TRUE is the props entry could be fetched.
1193 gst_props_entry_get (const GstPropsEntry *entry, ...)
1198 g_return_val_if_fail (entry != NULL, FALSE);
1200 va_start (var_args, entry);
1201 result = gst_props_entry_getv (entry, FALSE, var_args);
1208 gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
1213 g_return_val_if_fail (entry != NULL, FALSE);
1215 va_start (var_args, entry);
1216 result = gst_props_entry_getv (entry, TRUE, var_args);
1223 gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args)
1225 while (first_name) {
1226 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1229 if (!entry) return FALSE;
1230 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1231 if (!result) return FALSE;
1233 first_name = va_arg (var_args, gchar *);
1240 * @props: the props to query
1241 * @first_name: the first key
1242 * @...: a pointer to a datastructure that can hold the value.
1244 * Gets the contents of the props into given key/value pairs.
1245 * Make sure you pass a NULL terminated list.
1247 * Returns: TRUE if all of the props entries could be fetched.
1250 gst_props_get (GstProps *props, gchar *first_name, ...)
1255 va_start (var_args, first_name);
1256 ret = gst_props_getv (props, FALSE, first_name, var_args);
1263 * gst_props_get_safe:
1264 * @props: the props to query
1265 * @first_name: the first key
1266 * @...: a pointer to a datastructure that can hold the value.
1268 * Gets the contents of the props into given key/value pairs.
1270 * Returns: TRUE if all of the props entries could be fetched.
1273 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
1278 va_start (var_args, first_name);
1279 ret = gst_props_getv (props, TRUE, first_name, var_args);
1286 * gst_props_entry_get_int:
1287 * @entry: the props entry to query
1288 * @val: a pointer to a gint to hold the value.
1290 * Get the contents of the entry into the given gint.
1292 * Returns: TRUE is the value could be fetched. FALSE if the
1293 * entry is not of given type or did not exist.
1296 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1298 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1302 * gst_props_entry_get_float:
1303 * @entry: the props entry to query
1304 * @val: a pointer to a gfloat to hold the value.
1306 * Get the contents of the entry into the given gfloat.
1308 * Returns: TRUE is the value could be fetched. FALSE if the
1309 * entry is not of given type or did not exist.
1312 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1314 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1318 * gst_props_entry_get_fourcc_int:
1319 * @entry: the props entry to query
1320 * @val: a pointer to a guint32 to hold the value.
1322 * Get the contents of the entry into the given guint32.
1324 * Returns: TRUE is the value could be fetched. FALSE if the
1325 * entry is not of given type or did not exist.
1328 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1330 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1334 * gst_props_entry_get_boolean:
1335 * @entry: the props entry to query
1336 * @val: a pointer to a gboolean to hold the value.
1338 * Get the contents of the entry into the given gboolean.
1340 * Returns: TRUE is the value could be fetched. FALSE if the
1341 * entry is not of given type or did not exist.
1344 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1346 return gst_props_entry_get_safe (entry, GST_PROPS_BOOLEAN_TYPE, val);
1350 * gst_props_entry_get_string:
1351 * @entry: the props entry to query
1352 * @val: a pointer to a gchar* to hold the value.
1354 * Get the contents of the entry into the given gchar*.
1356 * Returns: TRUE is the value could be fetched. FALSE if the
1357 * entry is not of given type or did not exist.
1360 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1362 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1366 * gst_props_entry_get_int_range:
1367 * @entry: the props entry to query
1368 * @min: a pointer to a gint to hold the minimun value.
1369 * @max: a pointer to a gint to hold the maximum value.
1371 * Get the contents of the entry into the given gints.
1373 * Returns: TRUE is the value could be fetched. FALSE if the
1374 * entry is not of given type or did not exist.
1377 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1379 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1383 * gst_props_entry_get_float_range:
1384 * @entry: the props entry to query
1385 * @min: a pointer to a gfloat to hold the minimun value.
1386 * @max: a pointer to a gfloat to hold the maximum value.
1388 * Get the contents of the entry into the given gfloats.
1390 * Returns: TRUE is the value could be fetched. FALSE if the
1391 * entry is not of given type or did not exist.
1394 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1396 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1400 * gst_props_entry_get_list:
1401 * @entry: the props entry to query
1402 * @val: a pointer to a GList to hold the value.
1404 * Get the contents of the entry into the given GList.
1406 * Returns: TRUE is the value could be fetched. FALSE if the
1407 * entry is not of given type or did not exist.
1410 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1412 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1417 * @props: the property to merge into
1418 * @tomerge: the property to merge
1420 * Merge the properties of tomerge into props.
1422 * Returns: the new merged property
1425 gst_props_merge (GstProps *props, GstProps *tomerge)
1429 g_return_val_if_fail (props != NULL, NULL);
1430 g_return_val_if_fail (tomerge != NULL, NULL);
1432 merge_props = tomerge->properties;
1434 /* FIXME do proper merging here... */
1435 while (merge_props) {
1436 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1438 gst_props_add_entry (props, entry);
1440 merge_props = g_list_next (merge_props);
1447 /* entry2 is always a list, entry1 never is */
1449 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1451 GList *entrylist = entry2->data.list_data.entries;
1452 gboolean found = FALSE;
1454 while (entrylist && !found) {
1455 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1457 found |= gst_props_entry_check_compatibility (entry1, entry);
1459 entrylist = g_list_next (entrylist);
1466 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1468 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1469 g_quark_to_string (entry2->propid));
1471 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1472 return gst_props_entry_check_list_compatibility (entry1, entry2);
1475 switch (entry1->propstype) {
1476 case GST_PROPS_LIST_TYPE:
1478 GList *entrylist = entry1->data.list_data.entries;
1479 gboolean valid = TRUE; /* innocent until proven guilty */
1481 while (entrylist && valid) {
1482 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1484 valid &= gst_props_entry_check_compatibility (entry, entry2);
1486 entrylist = g_list_next (entrylist);
1491 case GST_PROPS_INT_RANGE_TYPE:
1492 switch (entry2->propstype) {
1493 /* a - b <---> a - c */
1494 case GST_PROPS_INT_RANGE_TYPE:
1495 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1496 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1501 case GST_PROPS_FLOAT_RANGE_TYPE:
1502 switch (entry2->propstype) {
1503 /* a - b <---> a - c */
1504 case GST_PROPS_FLOAT_RANGE_TYPE:
1505 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1506 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1511 case GST_PROPS_FOURCC_TYPE:
1512 switch (entry2->propstype) {
1514 case GST_PROPS_FOURCC_TYPE:
1515 GST_DEBUG(GST_CAT_PROPERTIES,"\"%c%c%c%c\" <--> \"%c%c%c%c\" ?",
1516 (entry2->data.fourcc_data>>0)&0xff,
1517 (entry2->data.fourcc_data>>8)&0xff,
1518 (entry2->data.fourcc_data>>16)&0xff,
1519 (entry2->data.fourcc_data>>24)&0xff,
1520 (entry1->data.fourcc_data>>0)&0xff,
1521 (entry1->data.fourcc_data>>8)&0xff,
1522 (entry1->data.fourcc_data>>16)&0xff,
1523 (entry1->data.fourcc_data>>24)&0xff);
1524 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1529 case GST_PROPS_INT_TYPE:
1530 switch (entry2->propstype) {
1532 case GST_PROPS_INT_RANGE_TYPE:
1533 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1534 entry1->data.int_data,entry2->data.int_range_data.max);
1535 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1536 entry2->data.int_range_data.max >= entry1->data.int_data);
1538 case GST_PROPS_INT_TYPE:
1539 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1540 return (entry2->data.int_data == entry1->data.int_data);
1545 case GST_PROPS_FLOAT_TYPE:
1546 switch (entry2->propstype) {
1548 case GST_PROPS_FLOAT_RANGE_TYPE:
1549 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1550 entry2->data.float_range_data.max >= entry1->data.float_data);
1552 case GST_PROPS_FLOAT_TYPE:
1553 return (entry2->data.float_data == entry1->data.float_data);
1558 case GST_PROPS_BOOLEAN_TYPE:
1559 switch (entry2->propstype) {
1561 case GST_PROPS_BOOLEAN_TYPE:
1562 return (entry2->data.bool_data == entry1->data.bool_data);
1566 case GST_PROPS_STRING_TYPE:
1567 switch (entry2->propstype) {
1569 case GST_PROPS_STRING_TYPE:
1570 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1571 entry2->data.string_data.string, entry1->data.string_data.string);
1572 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1584 * gst_props_check_compatibility:
1585 * @fromprops: a property
1586 * @toprops: a property
1588 * Checks whether two capabilities are compatible.
1590 * Returns: TRUE if compatible, FALSE otherwise
1593 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1599 gboolean compatible = TRUE;
1601 g_return_val_if_fail (fromprops != NULL, FALSE);
1602 g_return_val_if_fail (toprops != NULL, FALSE);
1604 sourcelist = fromprops->properties;
1605 sinklist = toprops->properties;
1607 while (sourcelist && sinklist && compatible) {
1608 GstPropsEntry *entry1;
1609 GstPropsEntry *entry2;
1611 entry1 = (GstPropsEntry *)sourcelist->data;
1612 entry2 = (GstPropsEntry *)sinklist->data;
1614 while (entry1->propid < entry2->propid) {
1616 sourcelist = g_list_next (sourcelist);
1617 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1620 while (entry1->propid > entry2->propid) {
1622 sinklist = g_list_next (sinklist);
1623 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1627 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1629 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1630 g_quark_to_string (entry1->propid));
1633 sourcelist = g_list_next (sourcelist);
1634 sinklist = g_list_next (sinklist);
1636 if (sinklist && compatible) {
1637 GstPropsEntry *entry2;
1638 entry2 = (GstPropsEntry *)sinklist->data;
1649 static GstPropsEntry*
1650 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1652 GstPropsEntry *result = NULL;
1654 /* try to move the ranges and lists first */
1655 switch (entry2->propstype) {
1656 case GST_PROPS_INT_RANGE_TYPE:
1657 case GST_PROPS_FLOAT_RANGE_TYPE:
1658 case GST_PROPS_LIST_TYPE:
1660 GstPropsEntry *temp;
1670 switch (entry1->propstype) {
1671 case GST_PROPS_LIST_TYPE:
1673 GList *entrylist = entry1->data.list_data.entries;
1674 GList *intersection = NULL;
1677 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1678 GstPropsEntry *intersectentry;
1680 intersectentry = gst_props_entry_intersect (entry2, entry);
1682 if (intersectentry) {
1683 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1684 intersection = g_list_concat (intersection,
1685 intersectentry->data.list_data.entries);
1686 /* set the list to NULL because the entries are concatenated to the above
1687 * list and we don't want to free them */
1688 intersectentry->data.list_data.entries = NULL;
1689 gst_props_entry_destroy (intersectentry);
1692 intersection = g_list_prepend (intersection, intersectentry);
1695 entrylist = g_list_next (entrylist);
1698 /* check if the list only contains 1 element, if so, we can just copy it */
1699 if (g_list_next (intersection) == NULL) {
1700 result = (GstPropsEntry *) (intersection->data);
1701 g_list_free (intersection);
1703 /* else we need to create a new entry to hold the list */
1705 result = gst_props_alloc_entry ();
1706 result->propid = entry1->propid;
1707 result->propstype = GST_PROPS_LIST_TYPE;
1708 result->data.list_data.entries = g_list_reverse (intersection);
1713 case GST_PROPS_INT_RANGE_TYPE:
1714 switch (entry2->propstype) {
1715 /* a - b <---> a - c */
1716 case GST_PROPS_INT_RANGE_TYPE:
1718 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1719 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1721 if (lower <= upper) {
1722 result = gst_props_alloc_entry ();
1723 result->propid = entry1->propid;
1725 if (lower == upper) {
1726 result->propstype = GST_PROPS_INT_TYPE;
1727 result->data.int_data = lower;
1730 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1731 result->data.int_range_data.min = lower;
1732 result->data.int_range_data.max = upper;
1737 case GST_PROPS_LIST_TYPE:
1739 GList *entries = entry2->data.list_data.entries;
1740 result = gst_props_alloc_entry ();
1741 result->propid = entry1->propid;
1742 result->propstype = GST_PROPS_LIST_TYPE;
1743 result->data.list_data.entries = NULL;
1745 GstPropsEntry *this = (GstPropsEntry *)entries->data;
1746 if (this->propstype != GST_PROPS_INT_TYPE) {
1747 /* no hope, this list doesn't even contain ints! */
1748 gst_props_entry_destroy (result);
1752 if (this->data.int_data >= entry1->data.int_range_data.min &&
1753 this->data.int_data <= entry1->data.int_range_data.max)
1755 /* prepend and reverse at the end */
1756 result->data.list_data.entries = g_list_prepend (result->data.list_data.entries,
1757 gst_props_entry_copy (this));
1759 entries = g_list_next (entries);
1762 result->data.list_data.entries = g_list_reverse (result->data.list_data.entries);
1766 case GST_PROPS_INT_TYPE:
1768 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1769 entry1->data.int_range_data.max >= entry2->data.int_data)
1771 result = gst_props_entry_copy (entry2);
1779 case GST_PROPS_FLOAT_RANGE_TYPE:
1780 switch (entry2->propstype) {
1781 /* a - b <---> a - c */
1782 case GST_PROPS_FLOAT_RANGE_TYPE:
1784 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1785 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1787 if (lower <= upper) {
1788 result = gst_props_alloc_entry ();
1789 result->propid = entry1->propid;
1791 if (lower == upper) {
1792 result->propstype = GST_PROPS_FLOAT_TYPE;
1793 result->data.float_data = lower;
1796 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1797 result->data.float_range_data.min = lower;
1798 result->data.float_range_data.max = upper;
1803 case GST_PROPS_FLOAT_TYPE:
1804 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1805 entry1->data.float_range_data.max >= entry2->data.float_data)
1807 result = gst_props_entry_copy (entry2);
1813 case GST_PROPS_FOURCC_TYPE:
1814 switch (entry2->propstype) {
1816 case GST_PROPS_FOURCC_TYPE:
1817 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1818 result = gst_props_entry_copy (entry1);
1823 case GST_PROPS_INT_TYPE:
1824 switch (entry2->propstype) {
1826 case GST_PROPS_INT_TYPE:
1827 if (entry1->data.int_data == entry2->data.int_data)
1828 result = gst_props_entry_copy (entry1);
1833 case GST_PROPS_FLOAT_TYPE:
1834 switch (entry2->propstype) {
1836 case GST_PROPS_FLOAT_TYPE:
1837 if (entry1->data.float_data == entry2->data.float_data)
1838 result = gst_props_entry_copy (entry1);
1843 case GST_PROPS_BOOLEAN_TYPE:
1844 switch (entry2->propstype) {
1846 case GST_PROPS_BOOLEAN_TYPE:
1847 if (entry1->data.bool_data == entry2->data.bool_data)
1848 result = gst_props_entry_copy (entry1);
1852 case GST_PROPS_STRING_TYPE:
1853 switch (entry2->propstype) {
1855 case GST_PROPS_STRING_TYPE:
1856 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1857 result = gst_props_entry_copy (entry1);
1868 /* when running over the entries in sorted order we can
1869 * optimize addition with _prepend and a reverse at the end */
1870 #define gst_props_entry_add_sorted_prepend(props, entry) \
1872 /* avoid double evaluation of input */ \
1873 GstPropsEntry *toadd = (entry); \
1874 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) \
1875 GST_PROPS_FLAG_UNSET ((props), GST_PROPS_FIXED); \
1876 props->properties = g_list_prepend ((props)->properties, toadd); \
1880 * gst_props_intersect:
1881 * @props1: a property
1882 * @props2: another property
1884 * Calculates the intersection bewteen two GstProps.
1886 * Returns: a GstProps with the intersection or NULL if the
1887 * intersection is empty. The new GstProps is floating and must
1888 * be unreffed afetr use.
1891 gst_props_intersect (GstProps *props1, GstProps *props2)
1895 GstProps *intersection;
1897 GstPropsEntry *iprops = NULL;
1899 g_return_val_if_fail (props1 != NULL, NULL);
1900 g_return_val_if_fail (props2 != NULL, NULL);
1902 intersection = gst_props_empty_new ();
1904 props1list = props1->properties;
1905 props2list = props2->properties;
1907 while (props1list && props2list) {
1908 GstPropsEntry *entry1;
1909 GstPropsEntry *entry2;
1911 entry1 = (GstPropsEntry *)props1list->data;
1912 entry2 = (GstPropsEntry *)props2list->data;
1914 while (entry1->propid < entry2->propid) {
1915 gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry1));
1917 props1list = g_list_next (props1list);
1921 entry1 = (GstPropsEntry *)props1list->data;
1923 while (entry1->propid > entry2->propid) {
1924 gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry2));
1926 props2list = g_list_next (props2list);
1930 entry2 = (GstPropsEntry *)props2list->data;
1932 /* at this point we are talking about the same property */
1933 iprops = gst_props_entry_intersect (entry1, entry2);
1935 /* common properties did not intersect, intersection is empty */
1936 gst_props_unref (intersection);
1940 gst_props_entry_add_sorted_prepend (intersection, iprops);
1942 props1list = g_list_next (props1list);
1943 props2list = g_list_next (props2list);
1947 /* at this point one of the lists could contain leftover properties, while
1948 * the other one is NULL */
1949 leftovers = props1list;
1951 leftovers = props2list;
1954 gst_props_entry_add_sorted_prepend (intersection,
1955 gst_props_entry_copy ((GstPropsEntry *) leftovers->data));
1956 leftovers = g_list_next (leftovers);
1959 intersection->properties = g_list_reverse (intersection->properties);
1961 return intersection;
1965 * gst_props_normalize:
1966 * @props: a property
1968 * Unrolls all lists in the given GstProps. This is usefull if you
1969 * want to loop over the props.
1971 * Returns: A GList with the unrolled props entries. g_list_free
1975 gst_props_normalize (GstProps *props)
1978 GList *result = NULL;
1983 entries = props->properties;
1986 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1988 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1989 GList *list_entries = entry->data.list_data.entries;
1991 while (list_entries) {
1992 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1993 GstPropsEntry *new_entry;
1997 /* FIXME fixed flags is probably messed up here */
1998 newprops = gst_props_copy (props);
1999 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
2003 new_entry = (GstPropsEntry *) lentry->data;
2004 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
2006 new_list = gst_props_normalize (newprops);
2007 result = g_list_concat (new_list, result);
2010 /* FIXME append or prepend */
2011 result = g_list_append (result, newprops);
2014 list_entries = g_list_next (list_entries);
2016 /* we break out of the loop because the other lists are
2017 * unrolled in the recursive call */
2020 entries = g_list_next (entries);
2023 /* no result, create list with input props */
2024 result = g_list_prepend (result, props);
2027 result = g_list_reverse (result);
2032 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
2034 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
2039 switch (entry->propstype) {
2040 case GST_PROPS_INT_TYPE:
2041 subtree = xmlNewChild (parent, NULL, "int", NULL);
2042 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2043 str = g_strdup_printf ("%d", entry->data.int_data);
2044 xmlNewProp (subtree, "value", str);
2047 case GST_PROPS_INT_RANGE_TYPE:
2048 subtree = xmlNewChild (parent, NULL, "range", NULL);
2049 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2050 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
2051 xmlNewProp (subtree, "min", str);
2053 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
2054 xmlNewProp (subtree, "max", str);
2057 case GST_PROPS_FLOAT_TYPE:
2058 subtree = xmlNewChild (parent, NULL, "float", NULL);
2059 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2060 str = g_strdup_printf ("%f", entry->data.float_data);
2061 xmlNewProp (subtree, "value", str);
2064 case GST_PROPS_FLOAT_RANGE_TYPE:
2065 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
2066 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2067 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
2068 xmlNewProp (subtree, "min", str);
2070 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
2071 xmlNewProp (subtree, "max", str);
2074 case GST_PROPS_FOURCC_TYPE:
2075 str = g_strdup_printf ("%c%c%c%c",
2076 (entry->data.fourcc_data>>0)&0xff,
2077 (entry->data.fourcc_data>>8)&0xff,
2078 (entry->data.fourcc_data>>16)&0xff,
2079 (entry->data.fourcc_data>>24)&0xff);
2080 xmlAddChild (parent, xmlNewComment (str));
2082 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
2083 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2084 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
2085 xmlNewProp (subtree, "hexvalue", str);
2088 case GST_PROPS_BOOLEAN_TYPE:
2089 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
2090 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2091 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
2093 case GST_PROPS_STRING_TYPE:
2094 subtree = xmlNewChild (parent, NULL, "string", NULL);
2095 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2096 xmlNewProp (subtree, "value", entry->data.string_data.string);
2099 g_warning ("trying to save unknown property type %d", entry->propstype);
2107 * gst_props_save_thyself:
2108 * @props: a property to save
2109 * @parent: the parent XML tree
2111 * Saves the property into an XML representation.
2113 * Returns: the new XML tree
2116 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
2121 g_return_val_if_fail (props != NULL, NULL);
2123 proplist = props->properties;
2126 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
2128 switch (entry->propstype) {
2129 case GST_PROPS_LIST_TYPE:
2130 subtree = xmlNewChild (parent, NULL, "list", NULL);
2131 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2132 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
2135 gst_props_save_thyself_func (entry, parent);
2138 proplist = g_list_next (proplist);
2144 static GstPropsEntry*
2145 gst_props_load_thyself_func (xmlNodePtr field)
2147 GstPropsEntry *entry;
2150 entry = gst_props_alloc_entry ();
2152 if (!strcmp(field->name, "int")) {
2153 entry->propstype = GST_PROPS_INT_TYPE;
2154 prop = xmlGetProp(field, "name");
2155 entry->propid = g_quark_from_string (prop);
2157 prop = xmlGetProp(field, "value");
2158 sscanf (prop, "%d", &entry->data.int_data);
2161 else if (!strcmp(field->name, "range")) {
2162 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
2163 prop = xmlGetProp(field, "name");
2164 entry->propid = g_quark_from_string (prop);
2166 prop = xmlGetProp (field, "min");
2167 sscanf (prop, "%d", &entry->data.int_range_data.min);
2169 prop = xmlGetProp (field, "max");
2170 sscanf (prop, "%d", &entry->data.int_range_data.max);
2173 else if (!strcmp(field->name, "float")) {
2174 entry->propstype = GST_PROPS_FLOAT_TYPE;
2175 prop = xmlGetProp(field, "name");
2176 entry->propid = g_quark_from_string (prop);
2178 prop = xmlGetProp(field, "value");
2179 sscanf (prop, "%f", &entry->data.float_data);
2182 else if (!strcmp(field->name, "floatrange")) {
2183 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
2184 prop = xmlGetProp(field, "name");
2185 entry->propid = g_quark_from_string (prop);
2187 prop = xmlGetProp (field, "min");
2188 sscanf (prop, "%f", &entry->data.float_range_data.min);
2190 prop = xmlGetProp (field, "max");
2191 sscanf (prop, "%f", &entry->data.float_range_data.max);
2194 else if (!strcmp(field->name, "boolean")) {
2195 entry->propstype = GST_PROPS_BOOLEAN_TYPE;
2196 prop = xmlGetProp(field, "name");
2197 entry->propid = g_quark_from_string (prop);
2199 prop = xmlGetProp (field, "value");
2200 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
2201 else entry->data.bool_data = 1;
2204 else if (!strcmp(field->name, "fourcc")) {
2205 entry->propstype = GST_PROPS_FOURCC_TYPE;
2206 prop = xmlGetProp(field, "name");
2207 entry->propid = g_quark_from_string (prop);
2209 prop = xmlGetProp (field, "hexvalue");
2210 sscanf (prop, "%08x", &entry->data.fourcc_data);
2213 else if (!strcmp(field->name, "string")) {
2214 entry->propstype = GST_PROPS_STRING_TYPE;
2215 prop = xmlGetProp(field, "name");
2216 entry->propid = g_quark_from_string (prop);
2218 entry->data.string_data.string = xmlGetProp (field, "value");
2221 gst_props_entry_destroy (entry);
2229 * gst_props_load_thyself:
2230 * @parent: the XML tree to load from
2232 * Creates a new property out of an XML tree.
2234 * Returns: the new property
2237 gst_props_load_thyself (xmlNodePtr parent)
2240 xmlNodePtr field = parent->xmlChildrenNode;
2243 props = gst_props_empty_new ();
2246 if (!strcmp (field->name, "list")) {
2247 GstPropsEntry *entry;
2248 xmlNodePtr subfield = field->xmlChildrenNode;
2250 entry = gst_props_alloc_entry ();
2251 prop = xmlGetProp (field, "name");
2252 entry->propid = g_quark_from_string (prop);
2254 entry->propstype = GST_PROPS_LIST_TYPE;
2255 entry->data.list_data.entries = NULL;
2258 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2261 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2263 subfield = subfield->next;
2265 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2266 gst_props_add_entry (props, entry);
2269 GstPropsEntry *entry;
2271 entry = gst_props_load_thyself_func (field);
2274 gst_props_add_entry (props, entry);
2276 field = field->next;
2281 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */