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.
24 #include "gst_private.h"
25 #include "gstregistry.h"
29 /* Index signals and args */
40 static void gst_index_class_init (GstIndexClass *klass);
41 static void gst_index_init (GstIndex *index);
43 static GstObject *parent_class = NULL;
44 static guint gst_index_signals[LAST_SIGNAL] = { 0 };
47 gst_index_get_type(void) {
48 static GType index_type = 0;
51 static const GTypeInfo index_info = {
52 sizeof(GstIndexClass),
55 (GClassInitFunc)gst_index_class_init,
60 (GInstanceInitFunc)gst_index_init,
63 index_type = g_type_register_static(GST_TYPE_OBJECT, "GstIndex", &index_info, 0);
69 gst_index_class_init (GstIndexClass *klass)
71 GObjectClass *gobject_class;
72 GstElementClass *gstelement_class;
74 gobject_class = (GObjectClass*)klass;
75 gstelement_class = (GstElementClass*)klass;
77 parent_class = g_type_class_ref(GST_TYPE_OBJECT);
79 gst_index_signals[ENTRY_ADDED] =
80 g_signal_new ("entry_added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
81 G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL,
82 gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
86 static GstIndexGroup *
87 gst_index_group_new(guint groupnum)
89 GstIndexGroup *indexgroup = g_new(GstIndexGroup,1);
91 indexgroup->groupnum = groupnum;
92 indexgroup->entries = NULL;
93 indexgroup->certainty = GST_INDEX_UNKNOWN;
94 indexgroup->peergroup = -1;
96 GST_DEBUG(0, "created new index group %d",groupnum);
102 gst_index_init (GstIndex *index)
104 index->curgroup = gst_index_group_new(0);
106 index->groups = g_list_prepend(NULL, index->curgroup);
108 index->writers = g_hash_table_new (NULL, NULL);
111 GST_FLAG_SET (index, GST_INDEX_WRITABLE);
112 GST_FLAG_SET (index, GST_INDEX_READABLE);
114 GST_DEBUG(0, "created new index");
120 * Create a new tileindex object
122 * Returns: a new index object
129 index = g_object_new (gst_index_get_type (), NULL);
136 * @index: the index to commit
137 * @id: the writer that commited the index
139 * Tell the index that the writer with the given id is done
140 * with this index and is not going to write any more entries
144 gst_index_commit (GstIndex *index, gint id)
146 GstIndexClass *iclass;
148 iclass = GST_INDEX_GET_CLASS (index);
151 iclass->commit (index, id);
156 * gst_index_get_group:
157 * @index: the index to get the current group from
159 * Get the id of the current group.
161 * Returns: the id of the current group.
164 gst_index_get_group(GstIndex *index)
166 return index->curgroup->groupnum;
170 * gst_index_new_group:
171 * @index: the index to create the new group in
173 * Create a new group for the given index. It will be
174 * set as the current group.
176 * Returns: the id of the newly created group.
179 gst_index_new_group(GstIndex *index)
181 index->curgroup = gst_index_group_new(++index->maxgroup);
182 index->groups = g_list_append(index->groups,index->curgroup);
183 GST_DEBUG(0, "created new group %d in index",index->maxgroup);
184 return index->maxgroup;
188 * gst_index_set_group:
189 * @index: the index to set the new group in
190 * @groupnum: the groupnumber to set
192 * Set the current groupnumber to the given argument.
194 * Returns: TRUE if the operation succeeded, FALSE if the group
198 gst_index_set_group(GstIndex *index, gint groupnum)
201 GstIndexGroup *indexgroup;
203 /* first check for null change */
204 if (groupnum == index->curgroup->groupnum)
207 /* else search for the proper group */
208 list = index->groups;
210 indexgroup = (GstIndexGroup *)(list->data);
211 list = g_list_next(list);
212 if (indexgroup->groupnum == groupnum) {
213 index->curgroup = indexgroup;
214 GST_DEBUG(0, "switched to index group %d", indexgroup->groupnum);
219 /* couldn't find the group in question */
220 GST_DEBUG(0, "couldn't find index group %d",groupnum);
225 * gst_index_set_certainty:
226 * @index: the index to set the certainty on
227 * @certainty: the certainty to set
229 * Set the certainty of the given index.
232 gst_index_set_certainty(GstIndex *index, GstIndexCertainty certainty)
234 index->curgroup->certainty = certainty;
238 * gst_index_get_certainty:
239 * @index: the index to get the certainty of
241 * Get the certainty of the given index.
243 * Returns: the certainty of the index.
246 gst_index_get_certainty(GstIndex *index)
248 return index->curgroup->certainty;
252 * gst_index_set_filter:
253 * @index: the index to register the filter on
254 * @filter: the filter to register
255 * @user_data: data passed to the filter function
257 * Lets the app register a custom filter function so that
258 * it can select what entries should be stored in the index.
261 gst_index_set_filter (GstIndex *index,
262 GstIndexFilter filter, gpointer user_data)
264 g_return_if_fail (GST_IS_INDEX (index));
266 index->filter = filter;
267 index->filter_user_data = user_data;
271 * gst_index_set_resolver:
272 * @index: the index to register the resolver on
273 * @resolver: the resolver to register
274 * @user_data: data passed to the resolver function
276 * Lets the app register a custom function to map index
277 * ids to writer descriptions.
280 gst_index_set_resolver (GstIndex *index,
281 GstIndexResolver resolver, gpointer user_data)
283 g_return_if_fail (GST_IS_INDEX (index));
285 index->resolver = resolver;
286 index->resolver_user_data = user_data;
290 * gst_index_entry_free:
291 * @entry: the entry to free
293 * Free the memory used by the given entry.
296 gst_index_entry_free (GstIndexEntry *entry)
302 * gst_index_add_format:
303 * @index: the index to add the entry to
304 * @id: the id of the index writer
305 * @format: the format to add to the index
307 * Adds a format entry into the index. This function is
308 * used to map dynamic GstFormat ids to their original
311 * Returns: a pointer to the newly added entry in the index.
314 gst_index_add_format (GstIndex *index, gint id, GstFormat format)
316 GstIndexEntry *entry;
317 const GstFormatDefinition* def;
318 GstIndexClass *iclass;
320 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
321 g_return_val_if_fail (format != 0, NULL);
323 if (!GST_INDEX_IS_WRITABLE (index))
326 entry = g_new0 (GstIndexEntry, 1);
327 entry->type = GST_INDEX_ENTRY_FORMAT;
329 entry->data.format.format = format;
331 def = gst_format_get_details (format);
332 entry->data.format.key = def->nick;
334 iclass = GST_INDEX_GET_CLASS (index);
336 if (iclass->add_entry)
337 iclass->add_entry (index, entry);
339 g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
346 * @index: the index to add the entry to
347 * @id: the id of the index writer
348 * @description: the description of the index writer
350 * Add an id entry into the index.
352 * Returns: a pointer to the newly added entry in the index.
355 gst_index_add_id (GstIndex *index, gint id, gchar *description)
357 GstIndexEntry *entry;
358 GstIndexClass *iclass;
360 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
361 g_return_val_if_fail (description != NULL, NULL);
363 if (!GST_INDEX_IS_WRITABLE (index))
366 entry = g_new0 (GstIndexEntry, 1);
367 entry->type = GST_INDEX_ENTRY_ID;
369 entry->data.id.description = description;
371 iclass = GST_INDEX_GET_CLASS (index);
373 if (iclass->add_entry)
374 iclass->add_entry (index, entry);
376 g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
382 * gst_index_get_writer_id:
383 * @index: the index to get a unique write id for
384 * @writer: the GstObject to allocate an id for
385 * @id: a pointer to a gint to hold the id
387 * Before entries can be added to the index, a writer
388 * should obtain a unique id. The methods to add new entries
389 * to the index require this id as an argument.
391 * The application or a GstIndex subclass can implement
392 * custom functions to map the writer object to an id.
394 * Returns: TRUE if the writer would be mapped to an id.
397 gst_index_get_writer_id (GstIndex *index, GstObject *writer, gint *id)
399 gchar *writer_string = NULL;
400 gboolean success = FALSE;
401 GstIndexEntry *entry;
402 GstIndexClass *iclass;
404 g_return_val_if_fail (GST_IS_INDEX (index), FALSE);
405 g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE);
406 g_return_val_if_fail (id, FALSE);
410 entry = g_hash_table_lookup (index->writers, writer);
412 *id = index->last_id;
414 writer_string = gst_object_get_path_string (writer);
416 gst_index_add_id (index, *id, writer_string);
418 g_hash_table_insert (index->writers, writer, entry);
421 iclass = GST_INDEX_GET_CLASS (index);
423 if (iclass->resolve_writer) {
424 success = iclass->resolve_writer (index, writer, id, &writer_string);
427 if (index->resolver) {
428 success = index->resolver (index, writer, id, &writer_string, index->resolver_user_data);
435 * gst_index_add_association:
436 * @index: the index to add the entry to
437 * @id: the id of the index writer
438 * @flags: optinal flags for this entry
439 * @format: the format of the value
441 * @...: other format/value pairs or 0 to end the list
443 * Associate given format/value pairs with eachother.
444 * Be sure to pass gint64 values to this functions varargs,
445 * you might want to use a gint64 cast to be sure.
447 * Returns: a pointer to the newly added entry in the index.
450 gst_index_add_association (GstIndex *index, gint id, GstAssocFlags flags,
451 GstFormat format, gint64 value, ...)
454 GstIndexAssociation *assoc;
455 GstIndexEntry *entry;
458 GstFormat cur_format;
459 volatile gint64 dummy;
460 GstIndexClass *iclass;
462 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
463 g_return_val_if_fail (format != 0, NULL);
465 if (!GST_INDEX_IS_WRITABLE (index))
468 va_start (args, value);
474 cur_format = va_arg (args, GstFormat);
476 dummy = va_arg (args, gint64);
480 /* make room for two assoc */
481 size = sizeof (GstIndexEntry) + (sizeof (GstIndexAssociation) * nassocs);
483 entry = g_malloc (size);
485 entry->type = GST_INDEX_ENTRY_ASSOCIATION;
487 entry->data.assoc.flags = flags;
488 assoc = (GstIndexAssociation *) (((guint8 *) entry) + sizeof (GstIndexEntry));
489 entry->data.assoc.assocs = assoc;
490 entry->data.assoc.nassocs = nassocs;
492 va_start (args, value);
494 assoc->format = format;
495 assoc->value = value;
499 format = va_arg (args, GstFormat);
501 value = va_arg (args, gint64);
505 iclass = GST_INDEX_GET_CLASS (index);
507 if (iclass->add_entry)
508 iclass->add_entry (index, entry);
510 g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
516 * gst_index_add_object:
517 * @index: the index to add the object to
518 * @id: the id of the index writer
519 * @key: a key for the object
520 * @type: the GType of the object
521 * @object: a pointer to the object to add
523 * Add the given object to the index with the given key.
525 * Returns: a pointer to the newly added entry in the index.
528 gst_index_add_object (GstIndex *index, gint id, gchar *key,
529 GType type, gpointer object)
531 if (!GST_INDEX_IS_WRITABLE (index))
538 gst_index_compare_func (gconstpointer a,
546 * gst_index_get_assoc_entry:
547 * @index: the index to search
548 * @id: the id of the index writer
549 * @method: The lookup method to use
550 * @format: the format of the value
551 * @value: the value to find
553 * Finds the given format/value in the index
555 * Returns: the entry associated with the value or NULL if the
556 * value was not found.
559 gst_index_get_assoc_entry (GstIndex *index, gint id,
560 GstIndexLookupMethod method, GstAssocFlags flags,
561 GstFormat format, gint64 value)
563 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
565 return gst_index_get_assoc_entry_full (index, id, method, flags, format, value,
566 gst_index_compare_func, NULL);
570 * gst_index_get_assoc_entry_full:
571 * @index: the index to search
572 * @id: the id of the index writer
573 * @method: The lookup method to use
574 * @format: the format of the value
575 * @value: the value to find
576 * @func: the function used to compare entries
577 * @user_data: user data passed to the compare function
579 * Finds the given format/value in the index with the given
580 * compare function and user_data.
582 * Returns: the entry associated with the value or NULL if the
583 * value was not found.
586 gst_index_get_assoc_entry_full (GstIndex *index, gint id,
587 GstIndexLookupMethod method, GstAssocFlags flags,
588 GstFormat format, gint64 value,
589 GCompareDataFunc func,
592 GstIndexClass *iclass;
594 g_return_val_if_fail (GST_IS_INDEX (index), NULL);
596 iclass = GST_INDEX_GET_CLASS (index);
598 if (iclass->get_assoc_entry)
599 return iclass->get_assoc_entry (index, id, method, flags, format, value, func, user_data);
605 * gst_index_entry_assoc_map:
606 * @entry: the index to search
607 * @format: the format of the value the find
608 * @value: a pointer to store the value
610 * Gets alternative formats associated with the indexentry.
612 * Returns: TRUE if there was a value associated with the given
616 gst_index_entry_assoc_map (GstIndexEntry *entry,
617 GstFormat format, gint64 *value)
621 g_return_val_if_fail (entry != NULL, FALSE);
622 g_return_val_if_fail (value != NULL, FALSE);
624 for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
625 if (GST_INDEX_ASSOC_FORMAT (entry, i) == format) {
626 *value = GST_INDEX_ASSOC_VALUE (entry, i);
634 static void gst_index_factory_class_init (GstIndexFactoryClass *klass);
635 static void gst_index_factory_init (GstIndexFactory *factory);
637 static GstPluginFeatureClass *factory_parent_class = NULL;
638 /* static guint gst_index_factory_signals[LAST_SIGNAL] = { 0 }; */
641 gst_index_factory_get_type (void)
643 static GType indexfactory_type = 0;
645 if (!indexfactory_type) {
646 static const GTypeInfo indexfactory_info = {
647 sizeof (GstIndexFactoryClass),
650 (GClassInitFunc) gst_index_factory_class_init,
653 sizeof(GstIndexFactory),
655 (GInstanceInitFunc) gst_index_factory_init,
658 indexfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
659 "GstIndexFactory", &indexfactory_info, 0);
661 return indexfactory_type;
665 gst_index_factory_class_init (GstIndexFactoryClass *klass)
667 GObjectClass *gobject_class;
668 GstObjectClass *gstobject_class;
669 GstPluginFeatureClass *gstpluginfeature_class;
671 gobject_class = (GObjectClass*)klass;
672 gstobject_class = (GstObjectClass*)klass;
673 gstpluginfeature_class = (GstPluginFeatureClass*) klass;
675 factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
679 gst_index_factory_init (GstIndexFactory *factory)
684 * gst_index_factory_new:
685 * @name: name of indexfactory to create
686 * @longdesc: long description of indexfactory to create
687 * @type: the GType of the GstIndex element of this factory
689 * Create a new indexfactory with the given parameters
691 * Returns: a new #GstIndexFactory.
694 gst_index_factory_new (const gchar *name, const gchar *longdesc, GType type)
696 GstIndexFactory *factory;
698 g_return_val_if_fail(name != NULL, NULL);
699 factory = gst_index_factory_find (name);
701 factory = GST_INDEX_FACTORY (g_object_new (GST_TYPE_INDEX_FACTORY, NULL));
704 GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
705 if (factory->longdesc)
706 g_free (factory->longdesc);
707 factory->longdesc = g_strdup (longdesc);
708 factory->type = type;
714 * gst_index_factory_destroy:
715 * @factory: factory to destroy
717 * Removes the index from the global list.
720 gst_index_factory_destroy (GstIndexFactory *factory)
722 g_return_if_fail (factory != NULL);
724 /* we don't free the struct bacause someone might have a handle to it.. */
728 * gst_index_factory_find:
729 * @name: name of indexfactory to find
731 * Search for an indexfactory of the given name.
733 * Returns: #GstIndexFactory if found, NULL otherwise
736 gst_index_factory_find (const gchar *name)
738 GstPluginFeature *feature;
740 g_return_val_if_fail (name != NULL, NULL);
742 GST_DEBUG (0,"gstindex: find \"%s\"", name);
744 feature = gst_registry_pool_find_feature (name, GST_TYPE_INDEX_FACTORY);
746 return GST_INDEX_FACTORY (feature);
752 * gst_index_factory_create:
753 * @factory: the factory used to create the instance
755 * Create a new #GstIndex instance from the
756 * given indexfactory.
758 * Returns: A new #GstIndex instance.
761 gst_index_factory_create (GstIndexFactory *factory)
763 GstIndex *new = NULL;
765 g_return_val_if_fail (factory != NULL, NULL);
767 if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
768 g_return_val_if_fail (factory->type != 0, NULL);
770 new = GST_INDEX (g_object_new(factory->type,NULL));
777 * gst_index_factory_make:
778 * @name: the name of the factory used to create the instance
780 * Create a new #GstIndex instance from the
781 * indexfactory with the given name.
783 * Returns: A new #GstIndex instance.
786 gst_index_factory_make (const gchar *name)
788 GstIndexFactory *factory;
790 g_return_val_if_fail (name != NULL, NULL);
792 factory = gst_index_factory_find (name);
797 return gst_index_factory_create (factory);