gst-indent run on core
[platform/upstream/gstreamer.git] / gst / gstindex.c
1 /* GStreamer
2  * Copyright (C) 2001 RidgeRun (http://www.ridgerun.com/)
3  * Written by Erik Walthinsen <omega@ridgerun.com>
4  *
5  * gstindex.c: Index for mappings and other data
6  *
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.
11  *
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.
16  *
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.
21  */
22
23 #include "gst_private.h"
24
25 #include "gstinfo.h"
26 #include "gstregistrypool.h"
27 #include "gstpad.h"
28 #include "gstindex.h"
29 #include "gstmarshal.h"
30
31 /* Index signals and args */
32 enum
33 {
34   ENTRY_ADDED,
35   LAST_SIGNAL
36 };
37
38 enum
39 {
40   ARG_0,
41   ARG_RESOLVER
42       /* FILL ME */
43 };
44
45 static void gst_index_class_init (GstIndexClass * klass);
46 static void gst_index_init (GstIndex * index);
47
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);
52
53 static GstIndexGroup *gst_index_group_new (guint groupnum);
54
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);
60
61 static GstObject *parent_class = NULL;
62 static guint gst_index_signals[LAST_SIGNAL] = { 0 };
63
64 typedef struct
65 {
66   GstIndexResolverMethod method;
67   GstIndexResolver resolver;
68   gpointer user_data;
69 } ResolverEntry;
70
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},
75 };
76
77 #define GST_TYPE_INDEX_RESOLVER (gst_index_resolver_get_type())
78 static GType
79 gst_index_resolver_get_type (void)
80 {
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"},
89     {0, NULL, NULL},
90   };
91   if (!index_resolver_type) {
92     index_resolver_type =
93         g_enum_register_static ("GstIndexResolver", index_resolver);
94   }
95   return index_resolver_type;
96 }
97
98 GType
99 gst_index_entry_get_type (void)
100 {
101   static GType index_entry_type = 0;
102
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);
107   }
108   return index_entry_type;
109 }
110
111
112 GType
113 gst_index_get_type (void)
114 {
115   static GType index_type = 0;
116
117   if (!index_type) {
118     static const GTypeInfo index_info = {
119       sizeof (GstIndexClass),
120       NULL,
121       NULL,
122       (GClassInitFunc) gst_index_class_init,
123       NULL,
124       NULL,
125       sizeof (GstIndex),
126       1,
127       (GInstanceInitFunc) gst_index_init,
128       NULL
129     };
130     index_type =
131         g_type_register_static (GST_TYPE_OBJECT, "GstIndex", &index_info, 0);
132   }
133   return index_type;
134 }
135
136 static void
137 gst_index_class_init (GstIndexClass * klass)
138 {
139   GObjectClass *gobject_class;
140   GstElementClass *gstelement_class;
141
142   gobject_class = (GObjectClass *) klass;
143   gstelement_class = (GstElementClass *) klass;
144
145   parent_class = g_type_class_ref (GST_TYPE_OBJECT);
146
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);
151
152   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_index_set_property);
153   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_index_get_property);
154
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));
159 }
160
161 static void
162 gst_index_init (GstIndex * index)
163 {
164   index->curgroup = gst_index_group_new (0);
165   index->maxgroup = 0;
166   index->groups = g_list_prepend (NULL, index->curgroup);
167
168   index->writers = g_hash_table_new (NULL, NULL);
169   index->last_id = 0;
170
171   index->method = GST_INDEX_RESOLVER_PATH;
172   index->resolver = resolvers[index->method].resolver;
173   index->resolver_user_data = resolvers[index->method].user_data;
174
175   GST_FLAG_SET (index, GST_INDEX_WRITABLE);
176   GST_FLAG_SET (index, GST_INDEX_READABLE);
177
178   GST_DEBUG ("created new index");
179 }
180
181 static void
182 gst_index_set_property (GObject * object, guint prop_id,
183     const GValue * value, GParamSpec * pspec)
184 {
185   GstIndex *index;
186
187   index = GST_INDEX (object);
188
189   switch (prop_id) {
190     case ARG_RESOLVER:
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;
194       break;
195     default:
196       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
197       break;
198   }
199 }
200
201 static void
202 gst_index_get_property (GObject * object, guint prop_id,
203     GValue * value, GParamSpec * pspec)
204 {
205   GstIndex *index;
206
207   index = GST_INDEX (object);
208
209   switch (prop_id) {
210     case ARG_RESOLVER:
211       g_value_set_enum (value, index->method);
212       break;
213     default:
214       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
215       break;
216   }
217 }
218
219 static GstIndexGroup *
220 gst_index_group_new (guint groupnum)
221 {
222   GstIndexGroup *indexgroup = g_new (GstIndexGroup, 1);
223
224   indexgroup->groupnum = groupnum;
225   indexgroup->entries = NULL;
226   indexgroup->certainty = GST_INDEX_UNKNOWN;
227   indexgroup->peergroup = -1;
228
229   GST_DEBUG ("created new index group %d", groupnum);
230
231   return indexgroup;
232 }
233
234 /**
235  * gst_index_new:
236  *
237  * Create a new tileindex object
238  *
239  * Returns: a new index object
240  */
241 GstIndex *
242 gst_index_new (void)
243 {
244   GstIndex *index;
245
246   index = g_object_new (gst_index_get_type (), NULL);
247
248   return index;
249 }
250
251 /**
252  * gst_index_commit:
253  * @index: the index to commit
254  * @id: the writer that commited the index
255  *
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
258  * to it.
259  */
260 void
261 gst_index_commit (GstIndex * index, gint id)
262 {
263   GstIndexClass *iclass;
264
265   iclass = GST_INDEX_GET_CLASS (index);
266
267   if (iclass->commit)
268     iclass->commit (index, id);
269 }
270
271
272 /**
273  * gst_index_get_group:
274  * @index: the index to get the current group from
275  *
276  * Get the id of the current group.
277  *
278  * Returns: the id of the current group.
279  */
280 gint
281 gst_index_get_group (GstIndex * index)
282 {
283   return index->curgroup->groupnum;
284 }
285
286 /**
287  * gst_index_new_group:
288  * @index: the index to create the new group in
289  *
290  * Create a new group for the given index. It will be
291  * set as the current group.
292  *
293  * Returns: the id of the newly created group.
294  */
295 gint
296 gst_index_new_group (GstIndex * index)
297 {
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;
302 }
303
304 /**
305  * gst_index_set_group:
306  * @index: the index to set the new group in
307  * @groupnum: the groupnumber to set
308  *
309  * Set the current groupnumber to the given argument.
310  *
311  * Returns: TRUE if the operation succeeded, FALSE if the group
312  * did not exist.
313  */
314 gboolean
315 gst_index_set_group (GstIndex * index, gint groupnum)
316 {
317   GList *list;
318   GstIndexGroup *indexgroup;
319
320   /* first check for null change */
321   if (groupnum == index->curgroup->groupnum)
322     return TRUE;
323
324   /* else search for the proper group */
325   list = index->groups;
326   while (list) {
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);
332       return TRUE;
333     }
334   }
335
336   /* couldn't find the group in question */
337   GST_DEBUG ("couldn't find index group %d", groupnum);
338   return FALSE;
339 }
340
341 /**
342  * gst_index_set_certainty:
343  * @index: the index to set the certainty on
344  * @certainty: the certainty to set
345  *
346  * Set the certainty of the given index.
347  */
348 void
349 gst_index_set_certainty (GstIndex * index, GstIndexCertainty certainty)
350 {
351   index->curgroup->certainty = certainty;
352 }
353
354 /**
355  * gst_index_get_certainty:
356  * @index: the index to get the certainty of
357  *
358  * Get the certainty of the given index.
359  *
360  * Returns: the certainty of the index.
361  */
362 GstIndexCertainty
363 gst_index_get_certainty (GstIndex * index)
364 {
365   return index->curgroup->certainty;
366 }
367
368 /**
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
373  *
374  * Lets the app register a custom filter function so that
375  * it can select what entries should be stored in the index.
376  */
377 void
378 gst_index_set_filter (GstIndex * index,
379     GstIndexFilter filter, gpointer user_data)
380 {
381   g_return_if_fail (GST_IS_INDEX (index));
382
383   index->filter = filter;
384   index->filter_user_data = user_data;
385 }
386
387 /**
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
392  *
393  * Lets the app register a custom function to map index
394  * ids to writer descriptions.
395  */
396 void
397 gst_index_set_resolver (GstIndex * index,
398     GstIndexResolver resolver, gpointer user_data)
399 {
400   g_return_if_fail (GST_IS_INDEX (index));
401
402   index->resolver = resolver;
403   index->resolver_user_data = user_data;
404   index->method = GST_INDEX_RESOLVER_CUSTOM;
405 }
406
407 /**
408  * gst_index_entry_copy:
409  * @entry: the entry to copy
410  *
411  * Copies an entry and returns the result.
412  */
413 GstIndexEntry *
414 gst_index_entry_copy (GstIndexEntry * entry)
415 {
416   return g_memdup (entry, sizeof (*entry));
417 }
418
419 /**
420  * gst_index_entry_free:
421  * @entry: the entry to free
422  *
423  * Free the memory used by the given entry.
424  */
425 void
426 gst_index_entry_free (GstIndexEntry * entry)
427 {
428   g_free (entry);
429 }
430
431 /**
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
436  *
437  * Adds a format entry into the index. This function is
438  * used to map dynamic GstFormat ids to their original
439  * format key.
440  *
441  * Returns: a pointer to the newly added entry in the index.
442  */
443 GstIndexEntry *
444 gst_index_add_format (GstIndex * index, gint id, GstFormat format)
445 {
446   GstIndexEntry *entry;
447   const GstFormatDefinition *def;
448
449   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
450   g_return_val_if_fail (format != 0, NULL);
451
452   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
453     return NULL;
454
455   entry = g_new0 (GstIndexEntry, 1);
456   entry->type = GST_INDEX_ENTRY_FORMAT;
457   entry->id = id;
458   entry->data.format.format = format;
459
460   def = gst_format_get_details (format);
461   entry->data.format.key = def->nick;
462
463   gst_index_add_entry (index, entry);
464
465   return entry;
466 }
467
468 /**
469  * gst_index_add_id:
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
473  *
474  * Add an id entry into the index.
475  *
476  * Returns: a pointer to the newly added entry in the index.
477  */
478 GstIndexEntry *
479 gst_index_add_id (GstIndex * index, gint id, gchar * description)
480 {
481   GstIndexEntry *entry;
482
483   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
484   g_return_val_if_fail (description != NULL, NULL);
485
486   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
487     return NULL;
488
489   entry = g_new0 (GstIndexEntry, 1);
490   entry->type = GST_INDEX_ENTRY_ID;
491   entry->id = id;
492   entry->data.id.description = description;
493
494   gst_index_add_entry (index, entry);
495
496   return entry;
497 }
498
499 static gboolean
500 gst_index_path_resolver (GstIndex * index, GstObject * writer,
501     gchar ** writer_string, gpointer data)
502 {
503   *writer_string = gst_object_get_path_string (writer);
504
505   return TRUE;
506 }
507
508 static gboolean
509 gst_index_gtype_resolver (GstIndex * index, GstObject * writer,
510     gchar ** writer_string, gpointer data)
511 {
512   if (GST_IS_PAD (writer)) {
513     GstElement *element = gst_pad_get_parent (GST_PAD (writer));
514
515     *writer_string = g_strdup_printf ("%s.%s",
516         g_type_name (G_OBJECT_TYPE (element)), gst_object_get_name (writer));
517   } else {
518     *writer_string =
519         g_strdup_printf ("%s", g_type_name (G_OBJECT_TYPE (writer)));
520   }
521
522   return TRUE;
523 }
524
525 /**
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
530  *
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. 
534  *
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
537  * in the index.
538  *
539  * Returns: TRUE if the writer would be mapped to an id.
540  */
541 gboolean
542 gst_index_get_writer_id (GstIndex * index, GstObject * writer, gint * id)
543 {
544   gchar *writer_string = NULL;
545   GstIndexEntry *entry;
546   GstIndexClass *iclass;
547   gboolean success = FALSE;
548
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);
552
553   *id = -1;
554
555   /* first try to get a previously cached id */
556   entry = g_hash_table_lookup (index->writers, writer);
557   if (entry == NULL) {
558
559     iclass = GST_INDEX_GET_CLASS (index);
560
561     /* let the app make a string */
562     if (index->resolver) {
563       gboolean res;
564
565       res =
566           index->resolver (index, writer, &writer_string,
567           index->resolver_user_data);
568       if (!res)
569         return FALSE;
570     } else {
571       g_warning ("no resolver found");
572       return FALSE;
573     }
574
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);
578     }
579     /* if the index could not resolve, we allocate one ourselves */
580     if (!success) {
581       *id = ++index->last_id;
582     }
583
584     entry = gst_index_add_id (index, *id, writer_string);
585     if (!entry) {
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;
590       entry->id = *id;
591       entry->data.id.description = writer_string;
592     }
593     g_hash_table_insert (index->writers, writer, entry);
594   } else {
595     *id = entry->id;
596   }
597
598   return TRUE;
599 }
600
601 static void
602 gst_index_add_entry (GstIndex * index, GstIndexEntry * entry)
603 {
604   GstIndexClass *iclass;
605
606   iclass = GST_INDEX_GET_CLASS (index);
607
608   if (iclass->add_entry) {
609     iclass->add_entry (index, entry);
610   }
611
612   g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
613 }
614
615 /**
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
623  *
624  * Associate given format/value pairs with each other.
625  *
626  * Returns: a pointer to the newly added entry in the index.
627  */
628 GstIndexEntry *
629 gst_index_add_associationv (GstIndex * index, gint id, GstAssocFlags flags,
630     int n, const GstIndexAssociation * list)
631 {
632   GstIndexEntry *entry;
633
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);
637
638   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
639     return NULL;
640
641   entry = g_malloc (sizeof (GstIndexEntry));
642
643   entry->type = GST_INDEX_ENTRY_ASSOCIATION;
644   entry->id = id;
645   entry->data.assoc.flags = flags;
646   entry->data.assoc.assocs = g_memdup (list, sizeof (GstIndexAssociation) * n);
647   entry->data.assoc.nassocs = n;
648
649   gst_index_add_entry (index, entry);
650
651   return entry;
652 }
653
654 /**
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
660  * @value: the value 
661  * @...: other format/value pairs or 0 to end the list
662  *
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.
666  *
667  * Returns: a pointer to the newly added entry in the index.
668  */
669 GstIndexEntry *
670 gst_index_add_association (GstIndex * index, gint id, GstAssocFlags flags,
671     GstFormat format, gint64 value, ...)
672 {
673   va_list args;
674   GstIndexEntry *entry;
675   GstIndexAssociation *list;
676   gint n_assocs = 0;
677   GstFormat cur_format;
678   GArray *array;
679
680   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
681   g_return_val_if_fail (format != 0, NULL);
682
683   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
684     return NULL;
685
686   array = g_array_new (FALSE, FALSE, sizeof (GstIndexAssociation));
687
688   va_start (args, value);
689
690   cur_format = format;
691   n_assocs = 0;
692   while (cur_format) {
693     GstIndexAssociation a;
694
695     n_assocs++;
696     cur_format = va_arg (args, GstFormat);
697     if (cur_format) {
698       a.format = cur_format;
699       a.value = va_arg (args, gint64);
700
701       g_array_append_val (array, a);
702     }
703   }
704   va_end (args);
705
706   list = (GstIndexAssociation *) g_array_free (array, FALSE);
707
708   entry = gst_index_add_associationv (index, id, flags, n_assocs, list);
709   g_free (list);
710
711   return entry;
712 }
713
714 /**
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
721  *
722  * Add the given object to the index with the given key.
723  * 
724  * Returns: a pointer to the newly added entry in the index.
725  */
726 GstIndexEntry *
727 gst_index_add_object (GstIndex * index, gint id, gchar * key,
728     GType type, gpointer object)
729 {
730   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
731     return NULL;
732
733   return NULL;
734 }
735
736 static gint
737 gst_index_compare_func (gconstpointer a, gconstpointer b, gpointer user_data)
738 {
739   return (gint) a - (gint) b;
740 }
741
742 /**
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
750  *
751  * Finds the given format/value in the index
752  *
753  * Returns: the entry associated with the value or NULL if the
754  *   value was not found.
755  */
756 GstIndexEntry *
757 gst_index_get_assoc_entry (GstIndex * index, gint id,
758     GstIndexLookupMethod method, GstAssocFlags flags,
759     GstFormat format, gint64 value)
760 {
761   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
762
763   if (id == -1)
764     return NULL;
765
766   return gst_index_get_assoc_entry_full (index, id, method, flags, format,
767       value, gst_index_compare_func, NULL);
768 }
769
770 /**
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
780  *
781  * Finds the given format/value in the index with the given
782  * compare function and user_data.
783  *
784  * Returns: the entry associated with the value or NULL if the
785  *   value was not found.
786  */
787 GstIndexEntry *
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)
791 {
792   GstIndexClass *iclass;
793
794   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
795
796   if (id == -1)
797     return NULL;
798
799   iclass = GST_INDEX_GET_CLASS (index);
800
801   if (iclass->get_assoc_entry)
802     return iclass->get_assoc_entry (index, id, method, flags, format, value,
803         func, user_data);
804
805   return NULL;
806 }
807
808 /**
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
813  *
814  * Gets alternative formats associated with the indexentry.
815  *
816  * Returns: TRUE if there was a value associated with the given 
817  * format.
818  */
819 gboolean
820 gst_index_entry_assoc_map (GstIndexEntry * entry,
821     GstFormat format, gint64 * value)
822 {
823   gint i;
824
825   g_return_val_if_fail (entry != NULL, FALSE);
826   g_return_val_if_fail (value != NULL, FALSE);
827
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);
831       return TRUE;
832     }
833   }
834   return FALSE;
835 }
836
837
838 static void gst_index_factory_class_init (GstIndexFactoryClass * klass);
839 static void gst_index_factory_init (GstIndexFactory * factory);
840
841 static GstPluginFeatureClass *factory_parent_class = NULL;
842
843 /* static guint gst_index_factory_signals[LAST_SIGNAL] = { 0 }; */
844
845 GType
846 gst_index_factory_get_type (void)
847 {
848   static GType indexfactory_type = 0;
849
850   if (!indexfactory_type) {
851     static const GTypeInfo indexfactory_info = {
852       sizeof (GstIndexFactoryClass),
853       NULL,
854       NULL,
855       (GClassInitFunc) gst_index_factory_class_init,
856       NULL,
857       NULL,
858       sizeof (GstIndexFactory),
859       0,
860       (GInstanceInitFunc) gst_index_factory_init,
861       NULL
862     };
863     indexfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE,
864         "GstIndexFactory", &indexfactory_info, 0);
865   }
866   return indexfactory_type;
867 }
868
869 static void
870 gst_index_factory_class_init (GstIndexFactoryClass * klass)
871 {
872   GObjectClass *gobject_class;
873   GstObjectClass *gstobject_class;
874   GstPluginFeatureClass *gstpluginfeature_class;
875
876   gobject_class = (GObjectClass *) klass;
877   gstobject_class = (GstObjectClass *) klass;
878   gstpluginfeature_class = (GstPluginFeatureClass *) klass;
879
880   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
881 }
882
883 static void
884 gst_index_factory_init (GstIndexFactory * factory)
885 {
886 }
887
888 /**
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
893  *
894  * Create a new indexfactory with the given parameters
895  *
896  * Returns: a new #GstIndexFactory.
897  */
898 GstIndexFactory *
899 gst_index_factory_new (const gchar * name, const gchar * longdesc, GType type)
900 {
901   GstIndexFactory *factory;
902
903   g_return_val_if_fail (name != NULL, NULL);
904   factory = gst_index_factory_find (name);
905   if (!factory) {
906     factory = GST_INDEX_FACTORY (g_object_new (GST_TYPE_INDEX_FACTORY, NULL));
907   }
908
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;
914
915   return factory;
916 }
917
918 /**
919  * gst_index_factory_destroy:
920  * @factory: factory to destroy
921  *
922  * Removes the index from the global list.
923  */
924 void
925 gst_index_factory_destroy (GstIndexFactory * factory)
926 {
927   g_return_if_fail (factory != NULL);
928
929   /* we don't free the struct bacause someone might  have a handle to it.. */
930 }
931
932 /**
933  * gst_index_factory_find:
934  * @name: name of indexfactory to find
935  *
936  * Search for an indexfactory of the given name.
937  *
938  * Returns: #GstIndexFactory if found, NULL otherwise
939  */
940 GstIndexFactory *
941 gst_index_factory_find (const gchar * name)
942 {
943   GstPluginFeature *feature;
944
945   g_return_val_if_fail (name != NULL, NULL);
946
947   GST_DEBUG ("gstindex: find \"%s\"", name);
948
949   feature = gst_registry_pool_find_feature (name, GST_TYPE_INDEX_FACTORY);
950   if (feature)
951     return GST_INDEX_FACTORY (feature);
952
953   return NULL;
954 }
955
956 /**
957  * gst_index_factory_create:
958  * @factory: the factory used to create the instance
959  *
960  * Create a new #GstIndex instance from the 
961  * given indexfactory.
962  *
963  * Returns: A new #GstIndex instance.
964  */
965 GstIndex *
966 gst_index_factory_create (GstIndexFactory * factory)
967 {
968   GstIndex *new = NULL;
969
970   g_return_val_if_fail (factory != NULL, NULL);
971
972   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
973     g_return_val_if_fail (factory->type != 0, NULL);
974
975     new = GST_INDEX (g_object_new (factory->type, NULL));
976   }
977
978   return new;
979 }
980
981 /**
982  * gst_index_factory_make:
983  * @name: the name of the factory used to create the instance
984  *
985  * Create a new #GstIndex instance from the 
986  * indexfactory with the given name.
987  *
988  * Returns: A new #GstIndex instance.
989  */
990 GstIndex *
991 gst_index_factory_make (const gchar * name)
992 {
993   GstIndexFactory *factory;
994
995   g_return_val_if_fail (name != NULL, NULL);
996
997   factory = gst_index_factory_find (name);
998
999   if (factory == NULL)
1000     return NULL;
1001
1002   return gst_index_factory_create (factory);
1003 }