2 * Copyright (C) 2001 RidgeRun (http://www.ridgerun.com/)
3 * Written by Erik Walthinsen <omega@ridgerun.com>
5 * gstindex.c: Index for mappings and other data
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 #include "gst_private.h"
26 #include "gstregistrypool.h"
29 #include "gstmarshal.h"
31 /* Index signals and args */
45 static void gst_index_class_init (GstIndexClass * klass);
46 static void gst_index_init (GstIndex * index);
48 static void gst_index_set_property (GObject * object, guint prop_id,
49 const GValue * value, GParamSpec * pspec);
50 static void gst_index_get_property (GObject * object, guint prop_id,
51 GValue * value, GParamSpec * pspec);
53 static GstIndexGroup *gst_index_group_new (guint groupnum);
55 static gboolean gst_index_path_resolver (GstIndex * index, GstObject * writer,
56 gchar ** writer_string, gpointer data);
57 static gboolean gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
58 gchar ** writer_string, gpointer data);
59 static void gst_index_add_entry (GstIndex * index, GstIndexEntry * entry);
61 static GstObject *parent_class = NULL;
62 static guint gst_index_signals[LAST_SIGNAL] = { 0 };
66 GstIndexResolverMethod method;
67 GstIndexResolver resolver;
71 static const ResolverEntry resolvers[] = {
72 {GST_INDEX_RESOLVER_CUSTOM, NULL, NULL},
73 {GST_INDEX_RESOLVER_GTYPE, gst_index_gtype_resolver, NULL},
74 {GST_INDEX_RESOLVER_PATH, gst_index_path_resolver, NULL},
77 #define GST_TYPE_INDEX_RESOLVER (gst_index_resolver_get_type())
79 gst_index_resolver_get_type (void)
81 static GType index_resolver_type = 0;
82 static GEnumValue index_resolver[] = {
83 {GST_INDEX_RESOLVER_CUSTOM, "GST_INDEX_RESOLVER_CUSTOM",
84 "Use a custom resolver"},
85 {GST_INDEX_RESOLVER_GTYPE, "GST_INDEX_RESOLVER_GTYPE",
86 "Resolve an object to its GType[.padname]"},
87 {GST_INDEX_RESOLVER_PATH, "GST_INDEX_RESOLVER_PATH",
88 "Resolve an object to its path in the pipeline"},
91 if (!index_resolver_type) {
93 g_enum_register_static ("GstIndexResolver", index_resolver);
95 return index_resolver_type;
99 gst_index_entry_get_type (void)
101 static GType index_entry_type = 0;
103 if (!index_entry_type) {
104 index_entry_type = g_boxed_type_register_static ("GstIndexEntry",
105 (GBoxedCopyFunc) gst_index_entry_copy,
106 (GBoxedFreeFunc) gst_index_entry_free);
108 return index_entry_type;
113 gst_index_get_type (void)
115 static GType index_type = 0;
118 static const GTypeInfo index_info = {
119 sizeof (GstIndexClass),
122 (GClassInitFunc) gst_index_class_init,
127 (GInstanceInitFunc) gst_index_init,
131 g_type_register_static (GST_TYPE_OBJECT, "GstIndex", &index_info, 0);
137 gst_index_class_init (GstIndexClass * klass)
139 GObjectClass *gobject_class;
140 GstElementClass *gstelement_class;
142 gobject_class = (GObjectClass *) klass;
143 gstelement_class = (GstElementClass *) klass;
145 parent_class = g_type_class_ref (GST_TYPE_OBJECT);
147 gst_index_signals[ENTRY_ADDED] =
148 g_signal_new ("entry-added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
149 G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL,
150 gst_marshal_VOID__BOXED, G_TYPE_NONE, 1, GST_TYPE_INDEX_ENTRY);
152 gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_index_set_property);
153 gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_index_get_property);
155 g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RESOLVER,
156 g_param_spec_enum ("resolver", "Resolver",
157 "Select a predefined object to string mapper",
158 GST_TYPE_INDEX_RESOLVER, GST_INDEX_RESOLVER_PATH, G_PARAM_READWRITE));
162 gst_index_init (GstIndex * index)
164 index->curgroup = gst_index_group_new (0);
166 index->groups = g_list_prepend (NULL, index->curgroup);
168 index->writers = g_hash_table_new (NULL, NULL);
171 index->method = GST_INDEX_RESOLVER_PATH;
172 index->resolver = resolvers[index->method].resolver;
173 index->resolver_user_data = resolvers[index->method].user_data;
175 GST_FLAG_SET (index, GST_INDEX_WRITABLE);
176 GST_FLAG_SET (index, GST_INDEX_READABLE);
178 GST_DEBUG ("created new index");
182 gst_index_set_property (GObject * object, guint prop_id,
183 const GValue * value, GParamSpec * pspec)
187 index = GST_INDEX (object);
191 index->method = g_value_get_enum (value);
192 index->resolver = resolvers[index->method].resolver;
193 index->resolver_user_data = resolvers[index->method].user_data;
196 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
202 gst_index_get_property (GObject * object, guint prop_id,
203 GValue * value, GParamSpec * pspec)
207 index = GST_INDEX (object);
211 g_value_set_enum (value, index->method);
214 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
219 static GstIndexGroup *
220 gst_index_group_new (guint groupnum)
222 GstIndexGroup *indexgroup = g_new (GstIndexGroup, 1);
224 indexgroup->groupnum = groupnum;
225 indexgroup->entries = NULL;
226 indexgroup->certainty = GST_INDEX_UNKNOWN;
227 indexgroup->peergroup = -1;
229 GST_DEBUG ("created new index group %d", groupnum);
237 * Create a new tileindex object
239 * Returns: a new index object
246 index = g_object_new (gst_index_get_type (), NULL);
253 * @index: the index to commit
254 * @id: the writer that commited the index
256 * Tell the index that the writer with the given id is done
257 * with this index and is not going to write any more entries
261 gst_index_commit (GstIndex * index, gint id)
263 GstIndexClass *iclass;
265 iclass = GST_INDEX_GET_CLASS (index);
268 iclass->commit (index, id);
273 * gst_index_get_group:
274 * @index: the index to get the current group from
276 * Get the id of the current group.
278 * Returns: the id of the current group.
281 gst_index_get_group (GstIndex * index)
283 return index->curgroup->groupnum;
287 * gst_index_new_group:
288 * @index: the index to create the new group in
290 * Create a new group for the given index. It will be
291 * set as the current group.
293 * Returns: the id of the newly created group.
296 gst_index_new_group (GstIndex * index)
298 index->curgroup = gst_index_group_new (++index->maxgroup);
299 index->groups = g_list_append (index->groups, index->curgroup);
300 GST_DEBUG ("created new group %d in index", index->maxgroup);
301 return index->maxgroup;
305 * gst_index_set_group:
306 * @index: the index to set the new group in
307 * @groupnum: the groupnumber to set
309 * Set the current groupnumber to the given argument.
311 * Returns: TRUE if the operation succeeded, FALSE if the group
315 gst_index_set_group (GstIndex * index, gint groupnum)
318 GstIndexGroup *indexgroup;
320 /* first check for null change */
321 if (groupnum == index->curgroup->groupnum)
324 /* else search for the proper group */
325 list = index->groups;
327 indexgroup = (GstIndexGroup *) (list->data);
328 list = g_list_next (list);
329 if (indexgroup->groupnum == groupnum) {
330 index->curgroup = indexgroup;
331 GST_DEBUG ("switched to index group %d", indexgroup->groupnum);
336 /* couldn't find the group in question */
337 GST_DEBUG ("couldn't find index group %d", groupnum);
342 * gst_index_set_certainty:
343 * @index: the index to set the certainty on
344 * @certainty: the certainty to set
346 * Set the certainty of the given index.
349 gst_index_set_certainty (GstIndex * index, GstIndexCertainty certainty)
351 index->curgroup->certainty = certainty;
355 * gst_index_get_certainty:
356 * @index: the index to get the certainty of
358 * Get the certainty of the given index.
360 * Returns: the certainty of the index.
363 gst_index_get_certainty (GstIndex * index)
365 return index->curgroup->certainty;
369 * gst_index_set_filter:
370 * @index: the index to register the filter on
371 * @filter: the filter to register
372 * @user_data: data passed to the filter function
374 * Lets the app register a custom filter function so that
375 * it can select what entries should be stored in the index.
378 gst_index_set_filter (GstIndex * index,
379 GstIndexFilter filter, gpointer user_data)
381 g_return_if_fail (GST_IS_INDEX (index));
383 index->filter = filter;
384 index->filter_user_data = user_data;
388 * gst_index_set_resolver:
389 * @index: the index to register the resolver on
390 * @resolver: the resolver to register
391 * @user_data: data passed to the resolver function
393 * Lets the app register a custom function to map index
394 * ids to writer descriptions.
397 gst_index_set_resolver (GstIndex * index,
398 GstIndexResolver resolver, gpointer user_data)
400 g_return_if_fail (GST_IS_INDEX (index));
402 index->resolver = resolver;
403 index->resolver_user_data = user_data;
404 index->method = GST_INDEX_RESOLVER_CUSTOM;
408 * gst_index_entry_copy:
409 * @entry: the entry to copy
411 * Copies an entry and returns the result.
414 gst_index_entry_copy (GstIndexEntry * entry)
416 return g_memdup (entry, sizeof (*entry));
420 * gst_index_entry_free:
421 * @entry: the entry to free
423 * Free the memory used by the given entry.
426 gst_index_entry_free (GstIndexEntry * entry)
432 * gst_index_add_format:
433 * @index: the index to add the entry to
434 * @id: the id of the index writer
435 * @format: the format to add to the index
437 * Adds a format entry into the index. This function is
438 * used to map dynamic GstFormat ids to their original
441 * Returns: a pointer to the newly added entry in the index.
444 gst_index_add_format (GstIndex * index, gint id, GstFormat format)
446 GstIndexEntry *entry;
447 const GstFormatDefinition *def;
449 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
450 g_return_val_if_fail (format != 0, NULL);
452 if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
455 entry = g_new0 (GstIndexEntry, 1);
456 entry->type = GST_INDEX_ENTRY_FORMAT;
458 entry->data.format.format = format;
460 def = gst_format_get_details (format);
461 entry->data.format.key = def->nick;
463 gst_index_add_entry (index, entry);
470 * @index: the index to add the entry to
471 * @id: the id of the index writer
472 * @description: the description of the index writer
474 * Add an id entry into the index.
476 * Returns: a pointer to the newly added entry in the index.
479 gst_index_add_id (GstIndex * index, gint id, gchar * description)
481 GstIndexEntry *entry;
483 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
484 g_return_val_if_fail (description != NULL, NULL);
486 if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
489 entry = g_new0 (GstIndexEntry, 1);
490 entry->type = GST_INDEX_ENTRY_ID;
492 entry->data.id.description = description;
494 gst_index_add_entry (index, entry);
500 gst_index_path_resolver (GstIndex * index, GstObject * writer,
501 gchar ** writer_string, gpointer data)
503 *writer_string = gst_object_get_path_string (writer);
509 gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
510 gchar ** writer_string, gpointer data)
512 if (GST_IS_PAD (writer)) {
513 GstElement *element = gst_pad_get_parent (GST_PAD (writer));
515 *writer_string = g_strdup_printf ("%s.%s",
516 g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer));
519 g_strdup_printf ("%s", g_type_name (G_OBJECT_TYPE (writer)));
526 * gst_index_get_writer_id:
527 * @index: the index to get a unique write id for
528 * @writer: the GstObject to allocate an id for
529 * @id: a pointer to a gint to hold the id
531 * Before entries can be added to the index, a writer
532 * should obtain a unique id. The methods to add new entries
533 * to the index require this id as an argument.
535 * The application can implement a custom function to map the writer object
536 * to a string. That string will be used to register or look up an id
539 * Returns: TRUE if the writer would be mapped to an id.
542 gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id)
544 gchar *writer_string = NULL;
545 GstIndexEntry *entry;
546 GstIndexClass *iclass;
547 gboolean success = FALSE;
549 g_return_val_if_fail (GST_IS_INDEX (index), FALSE);
550 g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE);
551 g_return_val_if_fail (id, FALSE);
555 /* first try to get a previously cached id */
556 entry = g_hash_table_lookup (index->writers, writer);
559 iclass = GST_INDEX_GET_CLASS (index);
561 /* let the app make a string */
562 if (index->resolver) {
566 index->resolver (index, writer, &writer_string,
567 index->resolver_user_data);
571 g_warning ("no resolver found");
575 /* if the index has a resolver, make it map this string to an id */
576 if (iclass->get_writer_id) {
577 success = iclass->get_writer_id (index, id, writer_string);
579 /* if the index could not resolve, we allocate one ourselves */
581 *id = ++index->last_id;
584 entry = gst_index_add_id (index, *id, writer_string);
586 /* index is probably not writable, make an entry anyway
587 * to keep it in our cache */
588 entry = g_new0 (GstIndexEntry, 1);
589 entry->type = GST_INDEX_ENTRY_ID;
591 entry->data.id.description = writer_string;
593 g_hash_table_insert (index->writers, writer, entry);
602 gst_index_add_entry (GstIndex * index, GstIndexEntry * entry)
604 GstIndexClass *iclass;
606 iclass = GST_INDEX_GET_CLASS (index);
608 if (iclass->add_entry) {
609 iclass->add_entry (index, entry);
612 g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
616 * gst_index_add_associationv:
617 * @index: the index to add the entry to
618 * @id: the id of the index writer
619 * @flags: optinal flags for this entry
620 * @n: number of associations
621 * @list: list of associations
622 * @...: other format/value pairs or 0 to end the list
624 * Associate given format/value pairs with each other.
626 * Returns: a pointer to the newly added entry in the index.
629 gst_index_add_associationv (GstIndex * index, gint id, GstAssocFlags flags,
630 int n, const GstIndexAssociation * list)
632 GstIndexEntry *entry;
634 g_return_val_if_fail (n > 0, NULL);
635 g_return_val_if_fail (list != NULL, NULL);
636 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
638 if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
641 entry = g_malloc (sizeof (GstIndexEntry));
643 entry->type = GST_INDEX_ENTRY_ASSOCIATION;
645 entry->data.assoc.flags = flags;
646 entry->data.assoc.assocs = g_memdup (list, sizeof (GstIndexAssociation) * n);
647 entry->data.assoc.nassocs = n;
649 gst_index_add_entry (index, entry);
655 * gst_index_add_association:
656 * @index: the index to add the entry to
657 * @id: the id of the index writer
658 * @flags: optinal flags for this entry
659 * @format: the format of the value
661 * @...: other format/value pairs or 0 to end the list
663 * Associate given format/value pairs with each other.
664 * Be sure to pass gint64 values to this functions varargs,
665 * you might want to use a gint64 cast to be sure.
667 * Returns: a pointer to the newly added entry in the index.
670 gst_index_add_association (GstIndex * index, gint id, GstAssocFlags flags,
671 GstFormat format, gint64 value, ...)
674 GstIndexEntry *entry;
675 GstIndexAssociation *list;
677 GstFormat cur_format;
680 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
681 g_return_val_if_fail (format != 0, NULL);
683 if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
686 array = g_array_new (FALSE, FALSE, sizeof (GstIndexAssociation));
688 va_start (args, value);
693 GstIndexAssociation a;
696 cur_format = va_arg (args, GstFormat);
698 a.format = cur_format;
699 a.value = va_arg (args, gint64);
701 g_array_append_val (array, a);
706 list = (GstIndexAssociation *) g_array_free (array, FALSE);
708 entry = gst_index_add_associationv (index, id, flags, n_assocs, list);
715 * gst_index_add_object:
716 * @index: the index to add the object to
717 * @id: the id of the index writer
718 * @key: a key for the object
719 * @type: the GType of the object
720 * @object: a pointer to the object to add
722 * Add the given object to the index with the given key.
724 * Returns: a pointer to the newly added entry in the index.
727 gst_index_add_object (GstIndex * index, gint id, gchar * key,
728 GType type, gpointer object)
730 if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
737 gst_index_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
739 return (gint) a - (gint) b;
743 * gst_index_get_assoc_entry:
744 * @index: the index to search
745 * @id: the id of the index writer
746 * @method: The lookup method to use
747 * @flags: Flags for the entry
748 * @format: the format of the value
749 * @value: the value to find
751 * Finds the given format/value in the index
753 * Returns: the entry associated with the value or NULL if the
754 * value was not found.
757 gst_index_get_assoc_entry (GstIndex * index, gint id,
758 GstIndexLookupMethod method, GstAssocFlags flags,
759 GstFormat format, gint64 value)
761 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
766 return gst_index_get_assoc_entry_full (index, id, method, flags, format,
767 value, gst_index_compare_func, NULL);
771 * gst_index_get_assoc_entry_full:
772 * @index: the index to search
773 * @id: the id of the index writer
774 * @method: The lookup method to use
775 * @flags: Flags for the entry
776 * @format: the format of the value
777 * @value: the value to find
778 * @func: the function used to compare entries
779 * @user_data: user data passed to the compare function
781 * Finds the given format/value in the index with the given
782 * compare function and user_data.
784 * Returns: the entry associated with the value or NULL if the
785 * value was not found.
788 gst_index_get_assoc_entry_full (GstIndex * index, gint id,
789 GstIndexLookupMethod method, GstAssocFlags flags,
790 GstFormat format, gint64 value, GCompareDataFunc func, gpointer user_data)
792 GstIndexClass *iclass;
794 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
799 iclass = GST_INDEX_GET_CLASS (index);
801 if (iclass->get_assoc_entry)
802 return iclass->get_assoc_entry (index, id, method, flags, format, value,
809 * gst_index_entry_assoc_map:
810 * @entry: the index to search
811 * @format: the format of the value the find
812 * @value: a pointer to store the value
814 * Gets alternative formats associated with the indexentry.
816 * Returns: TRUE if there was a value associated with the given
820 gst_index_entry_assoc_map (GstIndexEntry * entry,
821 GstFormat format, gint64 * value)
825 g_return_val_if_fail (entry != NULL, FALSE);
826 g_return_val_if_fail (value != NULL, FALSE);
828 for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
829 if (GST_INDEX_ASSOC_FORMAT (entry, i) == format) {
830 *value = GST_INDEX_ASSOC_VALUE (entry, i);
838 static void gst_index_factory_class_init (GstIndexFactoryClass * klass);
839 static void gst_index_factory_init (GstIndexFactory * factory);
841 static GstPluginFeatureClass *factory_parent_class = NULL;
843 /* static guint gst_index_factory_signals[LAST_SIGNAL] = { 0 }; */
846 gst_index_factory_get_type (void)
848 static GType indexfactory_type = 0;
850 if (!indexfactory_type) {
851 static const GTypeInfo indexfactory_info = {
852 sizeof (GstIndexFactoryClass),
855 (GClassInitFunc) gst_index_factory_class_init,
858 sizeof (GstIndexFactory),
860 (GInstanceInitFunc) gst_index_factory_init,
863 indexfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
864 "GstIndexFactory", &indexfactory_info, 0);
866 return indexfactory_type;
870 gst_index_factory_class_init (GstIndexFactoryClass * klass)
872 GObjectClass *gobject_class;
873 GstObjectClass *gstobject_class;
874 GstPluginFeatureClass *gstpluginfeature_class;
876 gobject_class = (GObjectClass *) klass;
877 gstobject_class = (GstObjectClass *) klass;
878 gstpluginfeature_class = (GstPluginFeatureClass *) klass;
880 factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
884 gst_index_factory_init (GstIndexFactory * factory)
889 * gst_index_factory_new:
890 * @name: name of indexfactory to create
891 * @longdesc: long description of indexfactory to create
892 * @type: the GType of the GstIndex element of this factory
894 * Create a new indexfactory with the given parameters
896 * Returns: a new #GstIndexFactory.
899 gst_index_factory_new (const gchar * name, const gchar * longdesc, GType type)
901 GstIndexFactory *factory;
903 g_return_val_if_fail (name != NULL, NULL);
904 factory = gst_index_factory_find (name);
906 factory = GST_INDEX_FACTORY (g_object_new (GST_TYPE_INDEX_FACTORY, NULL));
909 GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
910 if (factory->longdesc)
911 g_free (factory->longdesc);
912 factory->longdesc = g_strdup (longdesc);
913 factory->type = type;
919 * gst_index_factory_destroy:
920 * @factory: factory to destroy
922 * Removes the index from the global list.
925 gst_index_factory_destroy (GstIndexFactory * factory)
927 g_return_if_fail (factory != NULL);
929 /* we don't free the struct bacause someone might have a handle to it.. */
933 * gst_index_factory_find:
934 * @name: name of indexfactory to find
936 * Search for an indexfactory of the given name.
938 * Returns: #GstIndexFactory if found, NULL otherwise
941 gst_index_factory_find (const gchar * name)
943 GstPluginFeature *feature;
945 g_return_val_if_fail (name != NULL, NULL);
947 GST_DEBUG ("gstindex: find \"%s\"", name);
949 feature = gst_registry_pool_find_feature (name, GST_TYPE_INDEX_FACTORY);
951 return GST_INDEX_FACTORY (feature);
957 * gst_index_factory_create:
958 * @factory: the factory used to create the instance
960 * Create a new #GstIndex instance from the
961 * given indexfactory.
963 * Returns: A new #GstIndex instance.
966 gst_index_factory_create (GstIndexFactory * factory)
968 GstIndex *new = NULL;
970 g_return_val_if_fail (factory != NULL, NULL);
972 if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
973 g_return_val_if_fail (factory->type != 0, NULL);
975 new = GST_INDEX (g_object_new (factory->type, NULL));
982 * gst_index_factory_make:
983 * @name: the name of the factory used to create the instance
985 * Create a new #GstIndex instance from the
986 * indexfactory with the given name.
988 * Returns: A new #GstIndex instance.
991 gst_index_factory_make (const gchar * name)
993 GstIndexFactory *factory;
995 g_return_val_if_fail (name != NULL, NULL);
997 factory = gst_index_factory_find (name);
1002 return gst_index_factory_create (factory);