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 /* #define GST_WITH_ALLOC_TRACE */
33 GType _gst_props_type;
34 GType _gst_props_entry_type;
36 static GstAllocTrace *_props_trace;
37 static GstAllocTrace *_entries_trace;
39 #define GST_PROPS_ENTRY_IS_VARIABLE(a) (((GstPropsEntry*)(a))->propstype > GST_PROPS_VAR_TYPE)
41 struct _GstPropsEntry {
43 GstPropsType propstype;
52 /* structured values */
70 static GstMemChunk *_gst_props_entries_chunk;
71 static GstMemChunk *_gst_props_chunk;
73 static gboolean gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2);
74 static GList* gst_props_list_copy (GList *propslist);
77 transform_func (const GValue *src_value,
80 GstProps *props = g_value_peek_pointer (src_value);
81 GString *result = g_string_new ("");
84 GList *propslist = props->properties;
87 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
88 const gchar *name = g_quark_to_string (entry->propid);
90 switch (entry->propstype) {
91 case GST_PROPS_INT_TYPE:
92 g_string_append_printf (result, "%s=(int) %d", name, entry->data.int_data);
94 case GST_PROPS_FLOAT_TYPE:
95 g_string_append_printf (result, "%s=(float) %f", name, entry->data.float_data);
97 case GST_PROPS_FOURCC_TYPE:
98 g_string_append_printf (result, "%s=(fourcc) '%4.4s'", name, (gchar *)&entry->data.fourcc_data);
100 case GST_PROPS_BOOLEAN_TYPE:
101 g_string_append_printf (result, "%s=(boolean) %s", name,
102 (entry->data.bool_data ? "TRUE" : "FALSE"));
104 case GST_PROPS_STRING_TYPE:
105 g_string_append_printf (result, "%s=(string) '%s'", name, entry->data.string_data.string);
111 propslist = g_list_next (propslist);
113 g_string_append (result, "; ");
117 dest_value->data[0].v_pointer = result->str;
118 g_string_free (result, FALSE);
123 _gst_props_initialize (void)
125 _gst_props_entries_chunk = gst_mem_chunk_new ("GstPropsEntries",
126 sizeof (GstPropsEntry), sizeof (GstPropsEntry) * 1024,
129 _gst_props_chunk = gst_mem_chunk_new ("GstProps",
130 sizeof (GstProps), sizeof (GstProps) * 256,
133 _gst_props_type = g_boxed_type_register_static ("GstProps",
134 (GBoxedCopyFunc) gst_props_ref,
135 (GBoxedFreeFunc) gst_props_unref);
137 g_value_register_transform_func (_gst_props_type,
141 _gst_props_entry_type = g_boxed_type_register_static ("GstPropsEntry",
142 (GBoxedCopyFunc) gst_props_entry_copy,
143 (GBoxedFreeFunc) gst_props_entry_destroy);
145 _props_trace = gst_alloc_trace_register (GST_PROPS_TRACE_NAME);
146 _entries_trace = gst_alloc_trace_register (GST_PROPS_ENTRY_TRACE_NAME);
150 gst_props_debug_entry (GstPropsEntry *entry)
152 const gchar *name = g_quark_to_string (entry->propid);
154 switch (entry->propstype) {
155 case GST_PROPS_INT_TYPE:
156 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int %d", entry, name, entry->data.int_data);
158 case GST_PROPS_FLOAT_TYPE:
159 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float %f", entry, name, entry->data.float_data);
161 case GST_PROPS_FOURCC_TYPE:
162 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: fourcc %c%c%c%c", entry, name,
163 (entry->data.fourcc_data>>0)&0xff,
164 (entry->data.fourcc_data>>8)&0xff,
165 (entry->data.fourcc_data>>16)&0xff,
166 (entry->data.fourcc_data>>24)&0xff);
168 case GST_PROPS_BOOLEAN_TYPE:
169 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: bool %d", entry, name, entry->data.bool_data);
171 case GST_PROPS_STRING_TYPE:
172 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: string \"%s\"", entry, name, entry->data.string_data.string);
174 case GST_PROPS_INT_RANGE_TYPE:
175 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: int range %d-%d", entry, name, entry->data.int_range_data.min,
176 entry->data.int_range_data.max);
178 case GST_PROPS_FLOAT_RANGE_TYPE:
179 GST_DEBUG (GST_CAT_PROPERTIES, "%p: %s: float range %f-%f", entry, name, entry->data.float_range_data.min,
180 entry->data.float_range_data.max);
182 case GST_PROPS_LIST_TYPE:
183 GST_DEBUG (GST_CAT_PROPERTIES, "%p: [list]", entry);
185 GList *entries = entry->data.list_data.entries;
188 gst_props_debug_entry ((GstPropsEntry *)entries->data);
189 entries = g_list_next (entries);
194 g_warning ("unknown property type %d at %p", entry->propstype, entry);
200 props_compare_func (gconstpointer a,
203 GstPropsEntry *entry1 = (GstPropsEntry *)a;
204 GstPropsEntry *entry2 = (GstPropsEntry *)b;
206 return (entry1->propid - entry2->propid);
210 props_find_func (gconstpointer a,
213 GstPropsEntry *entry2 = (GstPropsEntry *)a;
214 GQuark quark = (GQuark) GPOINTER_TO_INT (b);
216 return (quark - entry2->propid);
219 /* This is implemented as a huge macro because we cannot pass
220 * va_list variables by reference on some architectures.
222 #define GST_PROPS_ENTRY_FILL(entry, var_args) \
224 entry->propstype = va_arg (var_args, GstPropsType); \
226 switch (entry->propstype) { \
227 case GST_PROPS_INT_TYPE: \
228 entry->data.int_data = va_arg (var_args, gint); \
230 case GST_PROPS_INT_RANGE_TYPE: \
231 entry->data.int_range_data.min = va_arg (var_args, gint); \
232 entry->data.int_range_data.max = va_arg (var_args, gint); \
234 case GST_PROPS_FLOAT_TYPE: \
235 entry->data.float_data = va_arg (var_args, gdouble); \
237 case GST_PROPS_FLOAT_RANGE_TYPE: \
238 entry->data.float_range_data.min = va_arg (var_args, gdouble); \
239 entry->data.float_range_data.max = va_arg (var_args, gdouble); \
241 case GST_PROPS_FOURCC_TYPE: \
242 entry->data.fourcc_data = va_arg (var_args, gulong); \
244 case GST_PROPS_BOOLEAN_TYPE: \
245 entry->data.bool_data = va_arg (var_args, gboolean); \
247 case GST_PROPS_STRING_TYPE: \
248 entry->data.string_data.string = g_strdup (va_arg (var_args, gchar*)); \
250 case GST_PROPS_GLIST_TYPE: \
251 entry->propstype = GST_PROPS_LIST_TYPE; \
252 entry->data.list_data.entries = g_list_copy (va_arg (var_args, GList*)); \
260 #define GST_PROPS_ENTRY_READ(entry, var_args, safe, result) \
266 GstPropsType propstype = va_arg (var_args, GstPropsType); \
267 if (propstype != entry->propstype) { \
272 switch (entry->propstype) { \
273 case GST_PROPS_INT_TYPE: \
274 *(va_arg (var_args, gint*)) = entry->data.int_data; \
276 case GST_PROPS_INT_RANGE_TYPE: \
277 *(va_arg (var_args, gint*)) = entry->data.int_range_data.min; \
278 *(va_arg (var_args, gint*)) = entry->data.int_range_data.max; \
280 case GST_PROPS_FLOAT_TYPE: \
281 *(va_arg (var_args, gfloat*)) = entry->data.float_data; \
283 case GST_PROPS_FLOAT_RANGE_TYPE: \
284 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.min; \
285 *(va_arg (var_args, gfloat*)) = entry->data.float_range_data.max; \
287 case GST_PROPS_FOURCC_TYPE: \
288 *(va_arg (var_args, guint32*)) = entry->data.fourcc_data; \
290 case GST_PROPS_BOOLEAN_TYPE: \
291 *(va_arg (var_args, gboolean*)) = entry->data.bool_data; \
293 case GST_PROPS_STRING_TYPE: \
294 *(va_arg (var_args, gchar**)) = entry->data.string_data.string; \
296 case GST_PROPS_LIST_TYPE: \
297 *(va_arg (var_args, GList**)) = entry->data.list_data.entries; \
306 static GstPropsEntry*
307 gst_props_alloc_entry (void)
309 GstPropsEntry *entry;
311 entry = gst_mem_chunk_alloc (_gst_props_entries_chunk);
312 gst_alloc_trace_new (_entries_trace, entry);
314 GST_DEBUG (GST_CAT_PROPERTIES, "new entry %p", entry);
320 gst_props_entry_clean (GstPropsEntry *entry)
322 switch (entry->propstype) {
323 case GST_PROPS_STRING_TYPE:
324 g_free (entry->data.string_data.string);
326 case GST_PROPS_LIST_TYPE:
328 GList *entries = entry->data.list_data.entries;
331 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
332 entries = g_list_next (entries);
334 g_list_free (entry->data.list_data.entries);
343 gst_props_entry_destroy (GstPropsEntry *entry)
345 GST_DEBUG (GST_CAT_PROPERTIES, "destroy entry %p", entry);
347 gst_props_entry_clean (entry);
349 gst_mem_chunk_free (_gst_props_entries_chunk, entry);
350 gst_alloc_trace_free (_entries_trace, entry);
354 * gst_props_empty_new:
356 * Create a new empty property.
358 * Returns: the new property
361 gst_props_empty_new (void)
365 props = gst_mem_chunk_alloc (_gst_props_chunk);
366 gst_alloc_trace_new (_props_trace, props);
368 GST_DEBUG (GST_CAT_PROPERTIES, "new %p", props);
370 props->properties = NULL;
372 GST_PROPS_FLAG_SET (props, GST_PROPS_FLOATING);
373 GST_PROPS_FLAG_SET (props, GST_PROPS_FIXED);
380 * @oldprops: the props to take replace
381 * @newprops: the props to take replace
383 * Replace the pointer to the props, doing proper
387 gst_props_replace (GstProps **oldprops, GstProps *newprops)
389 if (*oldprops != newprops) {
390 if (newprops) gst_props_ref (newprops);
391 if (*oldprops) gst_props_unref (*oldprops);
393 *oldprops = newprops;
398 * gst_props_replace_sink:
399 * @oldprops: the props to take replace
400 * @newprops: the props to take replace
402 * Replace the pointer to the props and take ownership.
405 gst_props_replace_sink (GstProps **oldprops, GstProps *newprops)
407 gst_props_replace (oldprops, newprops);
408 gst_props_sink (newprops);
412 * gst_props_add_entry:
413 * @props: the property to add the entry to
414 * @entry: the entry to add
416 * Addes the given propsentry to the props
419 gst_props_add_entry (GstProps *props, GstPropsEntry *entry)
421 g_return_if_fail (props);
422 g_return_if_fail (entry);
424 if (GST_PROPS_IS_FIXED (props) && GST_PROPS_ENTRY_IS_VARIABLE (entry)) {
425 GST_PROPS_FLAG_UNSET (props, GST_PROPS_FIXED);
427 props->properties = g_list_insert_sorted (props->properties, entry, props_compare_func);
431 * gst_props_remove_entry:
432 * @props: the property to remove the entry from
433 * @entry: the entry to remove
435 * Removes the given propsentry from the props.
438 gst_props_remove_entry (GstProps *props, GstPropsEntry *entry)
440 g_return_if_fail (props != NULL);
441 g_return_if_fail (entry != NULL);
443 props->properties = g_list_remove (props->properties, entry);
447 * gst_props_remove_entry_by_name:
448 * @props: the property to remove the entry from
449 * @name: the name of the entry to remove
451 * Removes the propsentry with the given name from the props.
454 gst_props_remove_entry_by_name (GstProps *props, const gchar *name)
459 g_return_if_fail (props != NULL);
460 g_return_if_fail (name != NULL);
462 quark = g_quark_from_string (name);
464 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
466 gst_props_remove_entry (props, (GstPropsEntry *)lentry->data);
472 * @firstname: the first property name
473 * @...: the property values
475 * Create a new property from the given key/value pairs
477 * Returns: the new property
480 gst_props_new (const gchar *firstname, ...)
485 va_start (var_args, firstname);
487 props = gst_props_newv (firstname, var_args);
497 * @props: the props to debug
499 * Dump the contents of the given properties into the DEBUG log.
502 gst_props_debug (GstProps *props)
504 GList *propslist = props->properties;
506 GST_DEBUG (GST_CAT_PROPERTIES, "props %p, refcount %d, flags %d", props, props->refcount, props->flags);
509 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
511 gst_props_debug_entry (entry);
513 propslist = g_list_next (propslist);
518 * gst_props_merge_int_entries:
519 * @newentry: the new entry
520 * @oldentry: an old entry
522 * Tries to merge oldentry into newentry, if there is a simpler single entry which represents
524 * Assumes that the entries are either ints or int ranges.
526 * Returns: TRUE if the entries were merged, FALSE otherwise.
529 gst_props_merge_int_entries(GstPropsEntry *newentry, GstPropsEntry *oldentry)
531 gint new_min, new_max, old_min, old_max;
532 gboolean can_merge = FALSE;
534 if (newentry->propstype == GST_PROPS_INT_TYPE) {
535 new_min = newentry->data.int_data;
536 new_max = newentry->data.int_data;
538 new_min = newentry->data.int_range_data.min;
539 new_max = newentry->data.int_range_data.max;
542 if (oldentry->propstype == GST_PROPS_INT_TYPE) {
543 old_min = oldentry->data.int_data;
544 old_max = oldentry->data.int_data;
546 old_min = oldentry->data.int_range_data.min;
547 old_max = oldentry->data.int_range_data.max;
550 /* Put range which starts lower into (new_min, new_max) */
551 if (old_min < new_min) {
561 /* new_min is min of either entry - second half of the following conditional */
562 /* is to avoid overflow problems. */
563 if (new_max >= old_min - 1 && old_min - 1 < old_min) {
564 /* ranges overlap, or are adjacent. Pick biggest maximum. */
566 if (old_max > new_max) new_max = old_max;
570 if (new_min == new_max) {
571 newentry->propstype = GST_PROPS_INT_TYPE;
572 newentry->data.int_data = new_min;
574 newentry->propstype = GST_PROPS_INT_RANGE_TYPE;
575 newentry->data.int_range_data.min = new_min;
576 newentry->data.int_range_data.max = new_max;
583 * gst_props_add_to_int_list:
584 * @entries: the existing list of entries
585 * @entry: the new entry to add to the list
587 * Add an integer property to a list of properties, removing duplicates
588 * and merging ranges.
590 * Assumes that the existing list is in simplest form, contains
591 * only ints and int ranges, and that the new entry is an int or
594 * Returns: a pointer to a list with the new entry added.
597 gst_props_add_to_int_list (GList *entries, GstPropsEntry *newentry)
603 GstPropsEntry *oldentry = (GstPropsEntry *)(i->data);
604 gboolean merged = gst_props_merge_int_entries(newentry, oldentry);
607 /* replace the existing one with the merged one */
608 gst_props_entry_destroy (oldentry);
610 entries = g_list_remove_link (entries, i);
613 /* start again: it's possible that this change made an earlier entry */
614 /* mergeable, and the pointer is now invalid anyway. */
621 return g_list_prepend (entries, newentry);
624 static GstPropsEntry*
625 gst_props_entry_newv (const gchar *name, va_list var_args)
627 GstPropsEntry *entry;
629 entry = gst_props_alloc_entry ();
630 entry->propid = g_quark_from_string (name);
631 GST_PROPS_ENTRY_FILL (entry, var_args);
637 * gst_props_entry_new:
638 * @name: the name of the props entry
639 * @...: the value of the entry
641 * Create a new property entry with the given key/value.
643 * Returns: the new entry.
646 gst_props_entry_new (const gchar *name, ...)
649 GstPropsEntry *entry;
651 va_start (var_args, name);
652 entry = gst_props_entry_newv (name, var_args);
660 * @firstname: the first property name
661 * @var_args: the property values
663 * Create a new property from the list of entries.
665 * Returns: the new property created from the list of entries
668 gst_props_newv (const gchar *firstname, va_list var_args)
671 gboolean inlist = FALSE;
672 const gchar *prop_name;
673 GstPropsEntry *list_entry = NULL;
676 GST_PROPS_LIST_T_UNSET,
677 GST_PROPS_LIST_T_INTS,
678 GST_PROPS_LIST_T_FLOATS,
679 GST_PROPS_LIST_T_MISC,
682 /* type of the list */
683 list_types list_type = GST_PROPS_LIST_T_UNSET;
684 /* type of current item */
685 list_types entry_type = GST_PROPS_LIST_T_UNSET;
687 if (firstname == NULL)
690 props = gst_props_empty_new ();
692 prop_name = firstname;
696 GstPropsEntry *entry;
698 entry = gst_props_alloc_entry ();
699 entry->propid = g_quark_from_string (prop_name);
700 GST_PROPS_ENTRY_FILL (entry, var_args);
702 switch (entry->propstype) {
703 case GST_PROPS_INT_TYPE:
704 case GST_PROPS_INT_RANGE_TYPE:
705 entry_type = GST_PROPS_LIST_T_INTS;
707 case GST_PROPS_FLOAT_TYPE:
708 case GST_PROPS_FLOAT_RANGE_TYPE:
709 entry_type = GST_PROPS_LIST_T_FLOATS;
711 case GST_PROPS_FOURCC_TYPE:
712 case GST_PROPS_BOOLEAN_TYPE:
713 case GST_PROPS_STRING_TYPE:
714 entry_type = GST_PROPS_LIST_T_MISC;
716 case GST_PROPS_LIST_TYPE:
717 g_return_val_if_fail (inlist == FALSE, NULL);
720 list_type = GST_PROPS_LIST_T_UNSET;
721 list_entry->data.list_data.entries = NULL;
723 case GST_PROPS_END_TYPE:
724 g_return_val_if_fail (inlist == TRUE, NULL);
726 /* if list was of size 1, replace the list by a the item it contains */
727 if (g_list_length(list_entry->data.list_data.entries) == 1) {
728 GstPropsEntry *subentry = (GstPropsEntry *)(list_entry->data.list_data.entries->data);
729 list_entry->propstype = subentry->propstype;
730 list_entry->data = subentry->data;
731 gst_props_entry_destroy (subentry);
734 list_entry->data.list_data.entries =
735 g_list_reverse (list_entry->data.list_data.entries);
738 gst_props_entry_destroy (entry);
741 prop_name = va_arg (var_args, gchar*);
744 g_warning ("unknown property type found %d for '%s'\n", entry->propstype, prop_name);
745 gst_props_entry_destroy (entry);
749 if (inlist && (list_entry != entry)) {
750 if (list_type == GST_PROPS_LIST_T_UNSET) list_type = entry_type;
751 if (list_type != entry_type) {
752 g_warning ("property list contained incompatible entry types\n");
755 case GST_PROPS_LIST_T_INTS:
756 list_entry->data.list_data.entries =
757 gst_props_add_to_int_list (list_entry->data.list_data.entries, entry);
760 list_entry->data.list_data.entries =
761 g_list_prepend (list_entry->data.list_data.entries, entry);
767 gst_props_add_entry (props, entry);
770 prop_name = va_arg (var_args, gchar*);
778 * @props: the props to modify
779 * @name: the name of the entry to modify
780 * @...: The prop entry.
782 * Modifies the value of the given entry in the props struct.
783 * For the optional args, use GST_PROPS_FOO, where FOO is INT,
784 * STRING, etc. This macro expands to a variable number of arguments,
785 * hence the lack of precision in the function prototype. No
786 * terminating NULL is necessary as only one property can be changed.
788 * Returns: the new modified property structure.
791 gst_props_set (GstProps *props, const gchar *name, ...)
797 g_return_val_if_fail (props != NULL, NULL);
799 quark = g_quark_from_string (name);
801 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
804 GstPropsEntry *entry;
806 entry = (GstPropsEntry *)lentry->data;
808 va_start (var_args, name);
809 gst_props_entry_clean (entry);
810 GST_PROPS_ENTRY_FILL (entry, var_args);
814 g_warning ("gstprops: no property '%s' to change\n", name);
823 * @props: the props to unref
825 * Decrease the refcount of the property structure, destroying
826 * the property if the refcount is 0.
828 * Returns: handle to unrefed props or NULL when it was
832 gst_props_unref (GstProps *props)
837 g_return_val_if_fail (props->refcount > 0, NULL);
839 GST_DEBUG (GST_CAT_PROPERTIES, "unref %p (%d->%d)", props, props->refcount, props->refcount-1);
842 if (props->refcount == 0) {
843 gst_props_destroy (props);
852 * @props: the props to ref
854 * Increase the refcount of the property structure.
856 * Returns: handle to refed props.
859 gst_props_ref (GstProps *props)
864 g_return_val_if_fail (props->refcount > 0, NULL);
866 GST_DEBUG (GST_CAT_PROPERTIES, "ref %p (%d->%d)", props, props->refcount, props->refcount+1);
875 * @props: the props to sink
877 * If the props if floating, decrease its refcount. Usually used
878 * with gst_props_ref() to take ownership of the props.
881 gst_props_sink (GstProps *props)
886 GST_DEBUG (GST_CAT_PROPERTIES, "sink %p", props);
888 if (GST_PROPS_IS_FLOATING (props)) {
889 GST_PROPS_FLAG_UNSET (props, GST_PROPS_FLOATING);
890 gst_props_unref (props);
896 * @props: the props to destroy
898 * Destroy the property, freeing all the memory that
902 gst_props_destroy (GstProps *props)
909 entries = props->properties;
912 gst_props_entry_destroy ((GstPropsEntry *)entries->data);
913 entries = g_list_next (entries);
915 g_list_free (props->properties);
917 gst_mem_chunk_free (_gst_props_chunk, props);
918 gst_alloc_trace_free (_props_trace, props);
925 gst_props_entry_copy (const GstPropsEntry *entry)
927 GstPropsEntry *newentry;
929 newentry = gst_props_alloc_entry ();
930 memcpy (newentry, entry, sizeof (GstPropsEntry));
932 switch (entry->propstype) {
933 case GST_PROPS_LIST_TYPE:
934 newentry->data.list_data.entries = gst_props_list_copy (entry->data.list_data.entries);
936 case GST_PROPS_STRING_TYPE:
937 newentry->data.string_data.string = g_strdup (entry->data.string_data.string);
948 gst_props_list_copy (GList *propslist)
953 GstPropsEntry *entry = (GstPropsEntry *)propslist->data;
955 new = g_list_prepend (new, gst_props_entry_copy (entry));
957 propslist = g_list_next (propslist);
959 new = g_list_reverse (new);
966 * @props: the props to copy
968 * Copy the property structure.
970 * Returns: the new property that is a copy of the original
974 gst_props_copy (GstProps *props)
981 new = gst_props_empty_new ();
982 new->properties = gst_props_list_copy (props->properties);
983 GST_PROPS_FLAGS (new) = GST_PROPS_FLAGS (props) | GST_PROPS_FLOATING;
989 * gst_props_copy_on_write:
990 * @props: the props to copy on write
992 * Copy the property structure if the refcount is >1.
994 * Returns: A new props that can be safely written to.
997 gst_props_copy_on_write (GstProps *props)
999 GstProps *new = props;;
1001 g_return_val_if_fail (props != NULL, NULL);
1003 if (props->refcount > 1) {
1004 new = gst_props_copy (props);
1005 gst_props_unref (props);
1012 * gst_props_get_entry:
1013 * @props: the props to query
1014 * @name: the name of the entry to get
1016 * Get the props entry with the geven name
1018 * Returns: The props entry with the geven name or NULL when
1019 * the entry was not found.
1021 const GstPropsEntry*
1022 gst_props_get_entry (GstProps *props, const gchar *name)
1027 g_return_val_if_fail (props != NULL, NULL);
1028 g_return_val_if_fail (name != NULL, NULL);
1030 quark = g_quark_from_string (name);
1032 lentry = g_list_find_custom (props->properties, GINT_TO_POINTER (quark), props_find_func);
1035 GstPropsEntry *thisentry;
1036 thisentry = (GstPropsEntry *)lentry->data;
1043 * gst_props_has_property:
1044 * @props: the props to check
1045 * @name: the name of the key to find
1047 * Checks if a given props has a property with the given name.
1049 * Returns: TRUE if the property was found, FALSE otherwise.
1052 gst_props_has_property (GstProps *props, const gchar *name)
1054 return (gst_props_get_entry (props, name) != NULL);
1058 * gst_props_has_property_typed:
1059 * @props: the props to check
1060 * @name: the name of the key to find
1061 * @type: the type of the required property
1063 * Checks if a given props has a property with the given name and the given type.
1065 * Returns: TRUE if the property was found, FALSE otherwise.
1068 gst_props_has_property_typed (GstProps *props, const gchar *name, GstPropsType type)
1070 const GstPropsEntry *entry;
1072 entry = gst_props_get_entry (props, name);
1076 return (entry->propstype == type);
1080 * gst_props_has_fixed_property:
1081 * @props: the props to check
1082 * @name: the name of the key to find
1084 * Checks if a given props has a property with the given name that
1085 * is also fixed, ie. is not a list or a range.
1087 * Returns: TRUE if the property was found, FALSE otherwise.
1090 gst_props_has_fixed_property (GstProps *props, const gchar *name)
1092 const GstPropsEntry *entry;
1094 entry = gst_props_get_entry (props, name);
1098 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
1102 * gst_props_entry_get_type:
1103 * @entry: the props entry to query
1105 * Get the type of the given props entry.
1107 * Returns: The type of the props entry.
1110 gst_props_entry_get_type (const GstPropsEntry *entry)
1112 g_return_val_if_fail (entry != NULL, GST_PROPS_INVALID_TYPE);
1114 return entry->propstype;
1118 * gst_props_entry_get_name:
1119 * @entry: the props entry to query
1121 * Get the name of the given props entry.
1123 * Returns: The name of the props entry.
1126 gst_props_entry_get_name (const GstPropsEntry *entry)
1128 g_return_val_if_fail (entry != NULL, NULL);
1130 return g_quark_to_string (entry->propid);
1134 * gst_props_entry_is_fixed:
1135 * @entry: the props entry to query
1137 * Checks if the props entry is fixe, ie. is not a list
1140 * Returns: TRUE is the props entry is fixed.
1143 gst_props_entry_is_fixed (const GstPropsEntry *entry)
1145 g_return_val_if_fail (entry != NULL, FALSE);
1147 return !GST_PROPS_ENTRY_IS_VARIABLE (entry);
1151 gst_props_entry_getv (const GstPropsEntry *entry, gboolean safe, va_list var_args)
1155 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1161 * gst_props_entry_get:
1162 * @entry: the props entry to query
1163 * @...: a pointer to a type that can hold the value.
1165 * Gets the contents of the entry.
1167 * Returns: TRUE is the props entry could be fetched.
1170 gst_props_entry_get (const GstPropsEntry *entry, ...)
1175 g_return_val_if_fail (entry != NULL, FALSE);
1177 va_start (var_args, entry);
1178 result = gst_props_entry_getv (entry, FALSE, var_args);
1185 gst_props_entry_get_safe (const GstPropsEntry *entry, ...)
1190 g_return_val_if_fail (entry != NULL, FALSE);
1192 va_start (var_args, entry);
1193 result = gst_props_entry_getv (entry, TRUE, var_args);
1200 gst_props_getv (GstProps *props, gboolean safe, gchar *first_name, va_list var_args)
1202 while (first_name) {
1203 const GstPropsEntry *entry = gst_props_get_entry (props, first_name);
1206 if (!entry) return FALSE;
1207 GST_PROPS_ENTRY_READ (entry, var_args, safe, &result);
1208 if (!result) return FALSE;
1210 first_name = va_arg (var_args, gchar *);
1217 * @props: the props to query
1218 * @first_name: the first key
1219 * @...: a pointer to a datastructure that can hold the value.
1221 * Gets the contents of the props into given key/value pairs.
1222 * Make sure you pass a NULL terminated list.
1224 * Returns: TRUE if all of the props entries could be fetched.
1227 gst_props_get (GstProps *props, gchar *first_name, ...)
1232 va_start (var_args, first_name);
1233 ret = gst_props_getv (props, FALSE, first_name, var_args);
1240 * gst_props_get_safe:
1241 * @props: the props to query
1242 * @first_name: the first key
1243 * @...: a pointer to a datastructure that can hold the value.
1245 * Gets the contents of the props into given key/value pairs.
1247 * Returns: TRUE if all of the props entries could be fetched.
1250 gst_props_get_safe (GstProps *props, gchar *first_name, ...)
1255 va_start (var_args, first_name);
1256 ret = gst_props_getv (props, TRUE, first_name, var_args);
1263 * gst_props_entry_get_int:
1264 * @entry: the props entry to query
1265 * @val: a pointer to a gint to hold the value.
1267 * Get the contents of the entry into the given gint.
1269 * Returns: TRUE is the value could be fetched. FALSE if the
1270 * entry is not of given type or did not exist.
1273 gst_props_entry_get_int (const GstPropsEntry *entry, gint *val)
1275 return gst_props_entry_get_safe (entry, GST_PROPS_INT_TYPE, val);
1279 * gst_props_entry_get_float:
1280 * @entry: the props entry to query
1281 * @val: a pointer to a gfloat to hold the value.
1283 * Get the contents of the entry into the given gfloat.
1285 * Returns: TRUE is the value could be fetched. FALSE if the
1286 * entry is not of given type or did not exist.
1289 gst_props_entry_get_float (const GstPropsEntry *entry, gfloat *val)
1291 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_TYPE, val);
1295 * gst_props_entry_get_fourcc_int:
1296 * @entry: the props entry to query
1297 * @val: a pointer to a guint32 to hold the value.
1299 * Get the contents of the entry into the given guint32.
1301 * Returns: TRUE is the value could be fetched. FALSE if the
1302 * entry is not of given type or did not exist.
1305 gst_props_entry_get_fourcc_int (const GstPropsEntry *entry, guint32 *val)
1307 return gst_props_entry_get_safe (entry, GST_PROPS_FOURCC_TYPE, val);
1311 * gst_props_entry_get_boolean:
1312 * @entry: the props entry to query
1313 * @val: a pointer to a gboolean to hold the value.
1315 * Get the contents of the entry into the given gboolean.
1317 * Returns: TRUE is the value could be fetched. FALSE if the
1318 * entry is not of given type or did not exist.
1321 gst_props_entry_get_boolean (const GstPropsEntry *entry, gboolean *val)
1323 return gst_props_entry_get_safe (entry, GST_PROPS_BOOLEAN_TYPE, val);
1327 * gst_props_entry_get_string:
1328 * @entry: the props entry to query
1329 * @val: a pointer to a gchar* to hold the value.
1331 * Get the contents of the entry into the given gchar*.
1333 * Returns: TRUE is the value could be fetched. FALSE if the
1334 * entry is not of given type or did not exist.
1337 gst_props_entry_get_string (const GstPropsEntry *entry, const gchar **val)
1339 return gst_props_entry_get_safe (entry, GST_PROPS_STRING_TYPE, val);
1343 * gst_props_entry_get_int_range:
1344 * @entry: the props entry to query
1345 * @min: a pointer to a gint to hold the minimun value.
1346 * @max: a pointer to a gint to hold the maximum value.
1348 * Get the contents of the entry into the given gints.
1350 * Returns: TRUE is the value could be fetched. FALSE if the
1351 * entry is not of given type or did not exist.
1354 gst_props_entry_get_int_range (const GstPropsEntry *entry, gint *min, gint *max)
1356 return gst_props_entry_get_safe (entry, GST_PROPS_INT_RANGE_TYPE, min, max);
1360 * gst_props_entry_get_float_range:
1361 * @entry: the props entry to query
1362 * @min: a pointer to a gfloat to hold the minimun value.
1363 * @max: a pointer to a gfloat to hold the maximum value.
1365 * Get the contents of the entry into the given gfloats.
1367 * Returns: TRUE is the value could be fetched. FALSE if the
1368 * entry is not of given type or did not exist.
1371 gst_props_entry_get_float_range (const GstPropsEntry *entry, gfloat *min, gfloat *max)
1373 return gst_props_entry_get_safe (entry, GST_PROPS_FLOAT_RANGE_TYPE, min, max);
1377 * gst_props_entry_get_list:
1378 * @entry: the props entry to query
1379 * @val: a pointer to a GList to hold the value.
1381 * Get the contents of the entry into the given GList.
1383 * Returns: TRUE is the value could be fetched. FALSE if the
1384 * entry is not of given type or did not exist.
1387 gst_props_entry_get_list (const GstPropsEntry *entry, const GList **val)
1389 return gst_props_entry_get_safe (entry, GST_PROPS_LIST_TYPE, val);
1394 * @props: the property to merge into
1395 * @tomerge: the property to merge
1397 * Merge the properties of tomerge into props.
1399 * Returns: the new merged property
1402 gst_props_merge (GstProps *props, GstProps *tomerge)
1406 g_return_val_if_fail (props != NULL, NULL);
1407 g_return_val_if_fail (tomerge != NULL, NULL);
1409 merge_props = tomerge->properties;
1411 /* FIXME do proper merging here... */
1412 while (merge_props) {
1413 GstPropsEntry *entry = (GstPropsEntry *)merge_props->data;
1415 gst_props_add_entry (props, entry);
1417 merge_props = g_list_next (merge_props);
1424 /* entry2 is always a list, entry1 never is */
1426 gst_props_entry_check_list_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1428 GList *entrylist = entry2->data.list_data.entries;
1429 gboolean found = FALSE;
1431 while (entrylist && !found) {
1432 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1434 found |= gst_props_entry_check_compatibility (entry1, entry);
1436 entrylist = g_list_next (entrylist);
1443 gst_props_entry_check_compatibility (GstPropsEntry *entry1, GstPropsEntry *entry2)
1445 GST_DEBUG (GST_CAT_PROPERTIES,"compare: %s %s", g_quark_to_string (entry1->propid),
1446 g_quark_to_string (entry2->propid));
1448 if (entry2->propstype == GST_PROPS_LIST_TYPE && entry1->propstype != GST_PROPS_LIST_TYPE) {
1449 return gst_props_entry_check_list_compatibility (entry1, entry2);
1452 switch (entry1->propstype) {
1453 case GST_PROPS_LIST_TYPE:
1455 GList *entrylist = entry1->data.list_data.entries;
1456 gboolean valid = TRUE; /* innocent until proven guilty */
1458 while (entrylist && valid) {
1459 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1461 valid &= gst_props_entry_check_compatibility (entry, entry2);
1463 entrylist = g_list_next (entrylist);
1468 case GST_PROPS_INT_RANGE_TYPE:
1469 switch (entry2->propstype) {
1470 /* a - b <---> a - c */
1471 case GST_PROPS_INT_RANGE_TYPE:
1472 return (entry2->data.int_range_data.min <= entry1->data.int_range_data.min &&
1473 entry2->data.int_range_data.max >= entry1->data.int_range_data.max);
1478 case GST_PROPS_FLOAT_RANGE_TYPE:
1479 switch (entry2->propstype) {
1480 /* a - b <---> a - c */
1481 case GST_PROPS_FLOAT_RANGE_TYPE:
1482 return (entry2->data.float_range_data.min <= entry1->data.float_range_data.min &&
1483 entry2->data.float_range_data.max >= entry1->data.float_range_data.max);
1488 case GST_PROPS_FOURCC_TYPE:
1489 switch (entry2->propstype) {
1491 case GST_PROPS_FOURCC_TYPE:
1492 GST_DEBUG(GST_CAT_PROPERTIES,"\"%c%c%c%c\" <--> \"%c%c%c%c\" ?",
1493 (entry2->data.fourcc_data>>0)&0xff,
1494 (entry2->data.fourcc_data>>8)&0xff,
1495 (entry2->data.fourcc_data>>16)&0xff,
1496 (entry2->data.fourcc_data>>24)&0xff,
1497 (entry1->data.fourcc_data>>0)&0xff,
1498 (entry1->data.fourcc_data>>8)&0xff,
1499 (entry1->data.fourcc_data>>16)&0xff,
1500 (entry1->data.fourcc_data>>24)&0xff);
1501 return (entry2->data.fourcc_data == entry1->data.fourcc_data);
1506 case GST_PROPS_INT_TYPE:
1507 switch (entry2->propstype) {
1509 case GST_PROPS_INT_RANGE_TYPE:
1510 GST_DEBUG(GST_CAT_PROPERTIES,"%d <= %d <= %d ?",entry2->data.int_range_data.min,
1511 entry1->data.int_data,entry2->data.int_range_data.max);
1512 return (entry2->data.int_range_data.min <= entry1->data.int_data &&
1513 entry2->data.int_range_data.max >= entry1->data.int_data);
1515 case GST_PROPS_INT_TYPE:
1516 GST_DEBUG(GST_CAT_PROPERTIES,"%d == %d ?",entry1->data.int_data,entry2->data.int_data);
1517 return (entry2->data.int_data == entry1->data.int_data);
1522 case GST_PROPS_FLOAT_TYPE:
1523 switch (entry2->propstype) {
1525 case GST_PROPS_FLOAT_RANGE_TYPE:
1526 return (entry2->data.float_range_data.min <= entry1->data.float_data &&
1527 entry2->data.float_range_data.max >= entry1->data.float_data);
1529 case GST_PROPS_FLOAT_TYPE:
1530 return (entry2->data.float_data == entry1->data.float_data);
1535 case GST_PROPS_BOOLEAN_TYPE:
1536 switch (entry2->propstype) {
1538 case GST_PROPS_BOOLEAN_TYPE:
1539 return (entry2->data.bool_data == entry1->data.bool_data);
1543 case GST_PROPS_STRING_TYPE:
1544 switch (entry2->propstype) {
1546 case GST_PROPS_STRING_TYPE:
1547 GST_DEBUG(GST_CAT_PROPERTIES,"\"%s\" <--> \"%s\" ?",
1548 entry2->data.string_data.string, entry1->data.string_data.string);
1549 return (!strcmp (entry2->data.string_data.string, entry1->data.string_data.string));
1561 * gst_props_check_compatibility:
1562 * @fromprops: a property
1563 * @toprops: a property
1565 * Checks whether two capabilities are compatible.
1567 * Returns: TRUE if compatible, FALSE otherwise
1570 gst_props_check_compatibility (GstProps *fromprops, GstProps *toprops)
1576 gboolean compatible = TRUE;
1578 g_return_val_if_fail (fromprops != NULL, FALSE);
1579 g_return_val_if_fail (toprops != NULL, FALSE);
1581 sourcelist = fromprops->properties;
1582 sinklist = toprops->properties;
1584 while (sourcelist && sinklist && compatible) {
1585 GstPropsEntry *entry1;
1586 GstPropsEntry *entry2;
1588 entry1 = (GstPropsEntry *)sourcelist->data;
1589 entry2 = (GstPropsEntry *)sinklist->data;
1591 while (entry1->propid < entry2->propid) {
1593 sourcelist = g_list_next (sourcelist);
1594 if (sourcelist) entry1 = (GstPropsEntry *)sourcelist->data;
1597 while (entry1->propid > entry2->propid) {
1599 sinklist = g_list_next (sinklist);
1600 if (sinklist) entry2 = (GstPropsEntry *)sinklist->data;
1604 if (!gst_props_entry_check_compatibility (entry1, entry2)) {
1606 GST_DEBUG (GST_CAT_PROPERTIES, "%s are not compatible: ",
1607 g_quark_to_string (entry1->propid));
1610 sourcelist = g_list_next (sourcelist);
1611 sinklist = g_list_next (sinklist);
1613 if (sinklist && compatible) {
1614 GstPropsEntry *entry2;
1615 entry2 = (GstPropsEntry *)sinklist->data;
1626 static GstPropsEntry*
1627 gst_props_entry_intersect (GstPropsEntry *entry1, GstPropsEntry *entry2)
1629 GstPropsEntry *result = NULL;
1631 /* try to move the ranges and lists first */
1632 switch (entry2->propstype) {
1633 case GST_PROPS_INT_RANGE_TYPE:
1634 case GST_PROPS_FLOAT_RANGE_TYPE:
1635 case GST_PROPS_LIST_TYPE:
1637 GstPropsEntry *temp;
1647 switch (entry1->propstype) {
1648 case GST_PROPS_LIST_TYPE:
1650 GList *entrylist = entry1->data.list_data.entries;
1651 GList *intersection = NULL;
1654 GstPropsEntry *entry = (GstPropsEntry *) entrylist->data;
1655 GstPropsEntry *intersectentry;
1657 intersectentry = gst_props_entry_intersect (entry2, entry);
1659 if (intersectentry) {
1660 if (intersectentry->propstype == GST_PROPS_LIST_TYPE) {
1661 intersection = g_list_concat (intersection,
1662 intersectentry->data.list_data.entries);
1663 /* set the list to NULL because the entries are concatenated to the above
1664 * list and we don't want to free them */
1665 intersectentry->data.list_data.entries = NULL;
1666 gst_props_entry_destroy (intersectentry);
1669 intersection = g_list_prepend (intersection, intersectentry);
1672 entrylist = g_list_next (entrylist);
1675 /* check if the list only contains 1 element, if so, we can just copy it */
1676 if (g_list_next (intersection) == NULL) {
1677 result = (GstPropsEntry *) (intersection->data);
1678 g_list_free (intersection);
1680 /* else we need to create a new entry to hold the list */
1682 result = gst_props_alloc_entry ();
1683 result->propid = entry1->propid;
1684 result->propstype = GST_PROPS_LIST_TYPE;
1685 result->data.list_data.entries = g_list_reverse (intersection);
1690 case GST_PROPS_INT_RANGE_TYPE:
1691 switch (entry2->propstype) {
1692 /* a - b <---> a - c */
1693 case GST_PROPS_INT_RANGE_TYPE:
1695 gint lower = MAX (entry1->data.int_range_data.min, entry2->data.int_range_data.min);
1696 gint upper = MIN (entry1->data.int_range_data.max, entry2->data.int_range_data.max);
1698 if (lower <= upper) {
1699 result = gst_props_alloc_entry ();
1700 result->propid = entry1->propid;
1702 if (lower == upper) {
1703 result->propstype = GST_PROPS_INT_TYPE;
1704 result->data.int_data = lower;
1707 result->propstype = GST_PROPS_INT_RANGE_TYPE;
1708 result->data.int_range_data.min = lower;
1709 result->data.int_range_data.max = upper;
1714 case GST_PROPS_LIST_TYPE:
1716 GList *entries = entry2->data.list_data.entries;
1717 result = gst_props_alloc_entry ();
1718 result->propid = entry1->propid;
1719 result->propstype = GST_PROPS_LIST_TYPE;
1720 result->data.list_data.entries = NULL;
1722 GstPropsEntry *this = (GstPropsEntry *)entries->data;
1723 if (this->propstype != GST_PROPS_INT_TYPE) {
1724 /* no hope, this list doesn't even contain ints! */
1725 gst_props_entry_destroy (result);
1729 if (this->data.int_data >= entry1->data.int_range_data.min &&
1730 this->data.int_data <= entry1->data.int_range_data.max)
1732 /* prepend and reverse at the end */
1733 result->data.list_data.entries = g_list_prepend (result->data.list_data.entries,
1734 gst_props_entry_copy (this));
1736 entries = g_list_next (entries);
1739 result->data.list_data.entries = g_list_reverse (result->data.list_data.entries);
1743 case GST_PROPS_INT_TYPE:
1745 if (entry1->data.int_range_data.min <= entry2->data.int_data &&
1746 entry1->data.int_range_data.max >= entry2->data.int_data)
1748 result = gst_props_entry_copy (entry2);
1756 case GST_PROPS_FLOAT_RANGE_TYPE:
1757 switch (entry2->propstype) {
1758 /* a - b <---> a - c */
1759 case GST_PROPS_FLOAT_RANGE_TYPE:
1761 gfloat lower = MAX (entry1->data.float_range_data.min, entry2->data.float_range_data.min);
1762 gfloat upper = MIN (entry1->data.float_range_data.max, entry2->data.float_range_data.max);
1764 if (lower <= upper) {
1765 result = gst_props_alloc_entry ();
1766 result->propid = entry1->propid;
1768 if (lower == upper) {
1769 result->propstype = GST_PROPS_FLOAT_TYPE;
1770 result->data.float_data = lower;
1773 result->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
1774 result->data.float_range_data.min = lower;
1775 result->data.float_range_data.max = upper;
1780 case GST_PROPS_FLOAT_TYPE:
1781 if (entry1->data.float_range_data.min <= entry2->data.float_data &&
1782 entry1->data.float_range_data.max >= entry2->data.float_data)
1784 result = gst_props_entry_copy (entry2);
1790 case GST_PROPS_FOURCC_TYPE:
1791 switch (entry2->propstype) {
1793 case GST_PROPS_FOURCC_TYPE:
1794 if (entry1->data.fourcc_data == entry2->data.fourcc_data)
1795 result = gst_props_entry_copy (entry1);
1800 case GST_PROPS_INT_TYPE:
1801 switch (entry2->propstype) {
1803 case GST_PROPS_INT_TYPE:
1804 if (entry1->data.int_data == entry2->data.int_data)
1805 result = gst_props_entry_copy (entry1);
1810 case GST_PROPS_FLOAT_TYPE:
1811 switch (entry2->propstype) {
1813 case GST_PROPS_FLOAT_TYPE:
1814 if (entry1->data.float_data == entry2->data.float_data)
1815 result = gst_props_entry_copy (entry1);
1820 case GST_PROPS_BOOLEAN_TYPE:
1821 switch (entry2->propstype) {
1823 case GST_PROPS_BOOLEAN_TYPE:
1824 if (entry1->data.bool_data == entry2->data.bool_data)
1825 result = gst_props_entry_copy (entry1);
1829 case GST_PROPS_STRING_TYPE:
1830 switch (entry2->propstype) {
1832 case GST_PROPS_STRING_TYPE:
1833 if (!strcmp (entry1->data.string_data.string, entry2->data.string_data.string))
1834 result = gst_props_entry_copy (entry1);
1845 /* when running over the entries in sorted order we can
1846 * optimize addition with _prepend and a reverse at the end */
1847 #define gst_props_entry_add_sorted_prepend(props, entry) \
1849 /* avoid double evaluation of input */ \
1850 GstPropsEntry *toadd = (entry); \
1851 if (GST_PROPS_ENTRY_IS_VARIABLE (toadd)) \
1852 GST_PROPS_FLAG_UNSET ((props), GST_PROPS_FIXED); \
1853 props->properties = g_list_prepend ((props)->properties, toadd); \
1857 * gst_props_intersect:
1858 * @props1: a property
1859 * @props2: another property
1861 * Calculates the intersection bewteen two GstProps.
1863 * Returns: a GstProps with the intersection or NULL if the
1864 * intersection is empty. The new GstProps is floating and must
1865 * be unreffed afetr use.
1868 gst_props_intersect (GstProps *props1, GstProps *props2)
1872 GstProps *intersection;
1874 GstPropsEntry *iprops = NULL;
1876 g_return_val_if_fail (props1 != NULL, NULL);
1877 g_return_val_if_fail (props2 != NULL, NULL);
1879 intersection = gst_props_empty_new ();
1881 props1list = props1->properties;
1882 props2list = props2->properties;
1884 while (props1list && props2list) {
1885 GstPropsEntry *entry1;
1886 GstPropsEntry *entry2;
1888 entry1 = (GstPropsEntry *)props1list->data;
1889 entry2 = (GstPropsEntry *)props2list->data;
1891 while (entry1->propid < entry2->propid) {
1892 gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry1));
1894 props1list = g_list_next (props1list);
1898 entry1 = (GstPropsEntry *)props1list->data;
1900 while (entry1->propid > entry2->propid) {
1901 gst_props_entry_add_sorted_prepend (intersection, gst_props_entry_copy (entry2));
1903 props2list = g_list_next (props2list);
1907 entry2 = (GstPropsEntry *)props2list->data;
1909 /* at this point we are talking about the same property */
1910 iprops = gst_props_entry_intersect (entry1, entry2);
1912 /* common properties did not intersect, intersection is empty */
1913 gst_props_unref (intersection);
1917 gst_props_entry_add_sorted_prepend (intersection, iprops);
1919 props1list = g_list_next (props1list);
1920 props2list = g_list_next (props2list);
1924 /* at this point one of the lists could contain leftover properties, while
1925 * the other one is NULL */
1926 leftovers = props1list;
1928 leftovers = props2list;
1931 gst_props_entry_add_sorted_prepend (intersection,
1932 gst_props_entry_copy ((GstPropsEntry *) leftovers->data));
1933 leftovers = g_list_next (leftovers);
1936 intersection->properties = g_list_reverse (intersection->properties);
1938 return intersection;
1942 * gst_props_normalize:
1943 * @props: a property
1945 * Unrolls all lists in the given GstProps. This is usefull if you
1946 * want to loop over the props.
1948 * Returns: A GList with the unrolled props entries. g_list_free
1952 gst_props_normalize (GstProps *props)
1955 GList *result = NULL;
1960 entries = props->properties;
1963 GstPropsEntry *entry = (GstPropsEntry *) entries->data;
1965 if (entry->propstype == GST_PROPS_LIST_TYPE) {
1966 GList *list_entries = entry->data.list_data.entries;
1968 while (list_entries) {
1969 GstPropsEntry *list_entry = (GstPropsEntry *) list_entries->data;
1970 GstPropsEntry *new_entry;
1974 /* FIXME fixed flags is probably messed up here */
1975 newprops = gst_props_copy (props);
1976 lentry = g_list_find_custom (newprops->properties, GINT_TO_POINTER (list_entry->propid), props_find_func);
1980 new_entry = (GstPropsEntry *) lentry->data;
1981 memcpy (new_entry, list_entry, sizeof (GstPropsEntry));
1983 new_list = gst_props_normalize (newprops);
1984 result = g_list_concat (new_list, result);
1987 /* FIXME append or prepend */
1988 result = g_list_append (result, newprops);
1991 list_entries = g_list_next (list_entries);
1993 /* we break out of the loop because the other lists are
1994 * unrolled in the recursive call */
1997 entries = g_list_next (entries);
2000 /* no result, create list with input props */
2001 result = g_list_prepend (result, props);
2004 result = g_list_reverse (result);
2009 #ifndef GST_DISABLE_LOADSAVE_REGISTRY
2011 gst_props_save_thyself_func (GstPropsEntry *entry, xmlNodePtr parent)
2016 switch (entry->propstype) {
2017 case GST_PROPS_INT_TYPE:
2018 subtree = xmlNewChild (parent, NULL, "int", NULL);
2019 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2020 str = g_strdup_printf ("%d", entry->data.int_data);
2021 xmlNewProp (subtree, "value", str);
2024 case GST_PROPS_INT_RANGE_TYPE:
2025 subtree = xmlNewChild (parent, NULL, "range", NULL);
2026 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2027 str = g_strdup_printf ("%d", entry->data.int_range_data.min);
2028 xmlNewProp (subtree, "min", str);
2030 str = g_strdup_printf ("%d", entry->data.int_range_data.max);
2031 xmlNewProp (subtree, "max", str);
2034 case GST_PROPS_FLOAT_TYPE:
2035 subtree = xmlNewChild (parent, NULL, "float", NULL);
2036 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2037 str = g_strdup_printf ("%f", entry->data.float_data);
2038 xmlNewProp (subtree, "value", str);
2041 case GST_PROPS_FLOAT_RANGE_TYPE:
2042 subtree = xmlNewChild (parent, NULL, "floatrange", NULL);
2043 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2044 str = g_strdup_printf ("%f", entry->data.float_range_data.min);
2045 xmlNewProp (subtree, "min", str);
2047 str = g_strdup_printf ("%f", entry->data.float_range_data.max);
2048 xmlNewProp (subtree, "max", str);
2051 case GST_PROPS_FOURCC_TYPE:
2052 str = g_strdup_printf ("%c%c%c%c",
2053 (entry->data.fourcc_data>>0)&0xff,
2054 (entry->data.fourcc_data>>8)&0xff,
2055 (entry->data.fourcc_data>>16)&0xff,
2056 (entry->data.fourcc_data>>24)&0xff);
2057 xmlAddChild (parent, xmlNewComment (str));
2059 subtree = xmlNewChild (parent, NULL, "fourcc", NULL);
2060 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2061 str = g_strdup_printf ("%08x", entry->data.fourcc_data);
2062 xmlNewProp (subtree, "hexvalue", str);
2065 case GST_PROPS_BOOLEAN_TYPE:
2066 subtree = xmlNewChild (parent, NULL, "boolean", NULL);
2067 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2068 xmlNewProp (subtree, "value", (entry->data.bool_data ? "true" : "false"));
2070 case GST_PROPS_STRING_TYPE:
2071 subtree = xmlNewChild (parent, NULL, "string", NULL);
2072 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2073 xmlNewProp (subtree, "value", entry->data.string_data.string);
2076 g_warning ("trying to save unknown property type %d", entry->propstype);
2084 * gst_props_save_thyself:
2085 * @props: a property to save
2086 * @parent: the parent XML tree
2088 * Saves the property into an XML representation.
2090 * Returns: the new XML tree
2093 gst_props_save_thyself (GstProps *props, xmlNodePtr parent)
2098 g_return_val_if_fail (props != NULL, NULL);
2100 proplist = props->properties;
2103 GstPropsEntry *entry = (GstPropsEntry *) proplist->data;
2105 switch (entry->propstype) {
2106 case GST_PROPS_LIST_TYPE:
2107 subtree = xmlNewChild (parent, NULL, "list", NULL);
2108 xmlNewProp (subtree, "name", g_quark_to_string (entry->propid));
2109 g_list_foreach (entry->data.list_data.entries, (GFunc) gst_props_save_thyself_func, subtree);
2112 gst_props_save_thyself_func (entry, parent);
2115 proplist = g_list_next (proplist);
2121 static GstPropsEntry*
2122 gst_props_load_thyself_func (xmlNodePtr field)
2124 GstPropsEntry *entry;
2127 entry = gst_props_alloc_entry ();
2129 if (!strcmp(field->name, "int")) {
2130 entry->propstype = GST_PROPS_INT_TYPE;
2131 prop = xmlGetProp(field, "name");
2132 entry->propid = g_quark_from_string (prop);
2134 prop = xmlGetProp(field, "value");
2135 sscanf (prop, "%d", &entry->data.int_data);
2138 else if (!strcmp(field->name, "range")) {
2139 entry->propstype = GST_PROPS_INT_RANGE_TYPE;
2140 prop = xmlGetProp(field, "name");
2141 entry->propid = g_quark_from_string (prop);
2143 prop = xmlGetProp (field, "min");
2144 sscanf (prop, "%d", &entry->data.int_range_data.min);
2146 prop = xmlGetProp (field, "max");
2147 sscanf (prop, "%d", &entry->data.int_range_data.max);
2150 else if (!strcmp(field->name, "float")) {
2151 entry->propstype = GST_PROPS_FLOAT_TYPE;
2152 prop = xmlGetProp(field, "name");
2153 entry->propid = g_quark_from_string (prop);
2155 prop = xmlGetProp(field, "value");
2156 sscanf (prop, "%f", &entry->data.float_data);
2159 else if (!strcmp(field->name, "floatrange")) {
2160 entry->propstype = GST_PROPS_FLOAT_RANGE_TYPE;
2161 prop = xmlGetProp(field, "name");
2162 entry->propid = g_quark_from_string (prop);
2164 prop = xmlGetProp (field, "min");
2165 sscanf (prop, "%f", &entry->data.float_range_data.min);
2167 prop = xmlGetProp (field, "max");
2168 sscanf (prop, "%f", &entry->data.float_range_data.max);
2171 else if (!strcmp(field->name, "boolean")) {
2172 entry->propstype = GST_PROPS_BOOLEAN_TYPE;
2173 prop = xmlGetProp(field, "name");
2174 entry->propid = g_quark_from_string (prop);
2176 prop = xmlGetProp (field, "value");
2177 if (!strcmp (prop, "false")) entry->data.bool_data = 0;
2178 else entry->data.bool_data = 1;
2181 else if (!strcmp(field->name, "fourcc")) {
2182 entry->propstype = GST_PROPS_FOURCC_TYPE;
2183 prop = xmlGetProp(field, "name");
2184 entry->propid = g_quark_from_string (prop);
2186 prop = xmlGetProp (field, "hexvalue");
2187 sscanf (prop, "%08x", &entry->data.fourcc_data);
2190 else if (!strcmp(field->name, "string")) {
2191 entry->propstype = GST_PROPS_STRING_TYPE;
2192 prop = xmlGetProp(field, "name");
2193 entry->propid = g_quark_from_string (prop);
2195 entry->data.string_data.string = xmlGetProp (field, "value");
2198 gst_props_entry_destroy (entry);
2206 * gst_props_load_thyself:
2207 * @parent: the XML tree to load from
2209 * Creates a new property out of an XML tree.
2211 * Returns: the new property
2214 gst_props_load_thyself (xmlNodePtr parent)
2217 xmlNodePtr field = parent->xmlChildrenNode;
2220 props = gst_props_empty_new ();
2223 if (!strcmp (field->name, "list")) {
2224 GstPropsEntry *entry;
2225 xmlNodePtr subfield = field->xmlChildrenNode;
2227 entry = gst_props_alloc_entry ();
2228 prop = xmlGetProp (field, "name");
2229 entry->propid = g_quark_from_string (prop);
2231 entry->propstype = GST_PROPS_LIST_TYPE;
2232 entry->data.list_data.entries = NULL;
2235 GstPropsEntry *subentry = gst_props_load_thyself_func (subfield);
2238 entry->data.list_data.entries = g_list_prepend (entry->data.list_data.entries, subentry);
2240 subfield = subfield->next;
2242 entry->data.list_data.entries = g_list_reverse (entry->data.list_data.entries);
2243 gst_props_add_entry (props, entry);
2246 GstPropsEntry *entry;
2248 entry = gst_props_load_thyself_func (field);
2251 gst_props_add_entry (props, entry);
2253 field = field->next;
2258 #endif /* GST_DISABLE_LOADSAVE_REGISTRY */