- Added property to select predefined resolver functions
[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 "gstlog.h"
24 #include "gst_private.h"
25 #include "gstregistry.h"
26
27 #include "gstpad.h"
28 #include "gstindex.h"
29
30 /* Index signals and args */
31 enum {
32   ENTRY_ADDED,
33   LAST_SIGNAL
34 };
35
36 enum {
37   ARG_0,
38   ARG_RESOLVER,
39   /* FILL ME */
40 };
41
42 static void             gst_index_class_init            (GstIndexClass *klass);
43 static void             gst_index_init                  (GstIndex *index);
44
45 static void             gst_index_set_property          (GObject *object, guint prop_id,
46                                                          const GValue *value, GParamSpec *pspec);
47 static void             gst_index_get_property          (GObject *object, guint prop_id, 
48                                                          GValue *value, GParamSpec *pspec);
49
50 static GstIndexGroup*   gst_index_group_new             (guint groupnum);
51
52 static gboolean         gst_index_path_resolver         (GstIndex *index, GstObject *writer,
53                                                          gchar **writer_string, gpointer data);
54 static gboolean         gst_index_gtype_resolver        (GstIndex *index, GstObject *writer,
55                                                          gchar **writer_string, gpointer data);
56
57 static GstObject *parent_class = NULL;
58 static guint gst_index_signals[LAST_SIGNAL] = { 0 };
59
60 typedef struct
61 {
62   GstIndexResolverMethod method;
63   GstIndexResolver       resolver;
64   gpointer               user_data;
65 } ResolverEntry;
66
67 static const ResolverEntry resolvers[] =
68 {
69   { GST_INDEX_RESOLVER_CUSTOM, NULL, NULL },
70   { GST_INDEX_RESOLVER_GTYPE,  gst_index_gtype_resolver, NULL },
71   { GST_INDEX_RESOLVER_PATH,   gst_index_path_resolver, NULL },
72 };
73
74 #define GST_TYPE_INDEX_RESOLVER (gst_index_resolver_get_type())
75 static GType
76 gst_index_resolver_get_type (void)
77 {
78   static GType index_resolver_type = 0;
79   static GEnumValue index_resolver[] = {
80     { GST_INDEX_RESOLVER_CUSTOM, "GST_INDEX_RESOLVER_CUSTOM",  "Use a custom resolver"},
81     { GST_INDEX_RESOLVER_GTYPE,  "GST_INDEX_RESOLVER_GTYPE",   "Resolve an object to its GType[.padname]"},
82     { GST_INDEX_RESOLVER_PATH,   "GST_INDEX_RESOLVER_PATH",    "Resolve an object to its path in the pipeline"},
83     {0, NULL, NULL},
84   };
85   if (!index_resolver_type) {
86     index_resolver_type = g_enum_register_static ("GstIndexResolver", index_resolver);
87   }
88   return index_resolver_type;
89 }
90
91 GType
92 gst_index_get_type(void) {
93   static GType index_type = 0;
94
95   if (!index_type) {
96     static const GTypeInfo index_info = {
97       sizeof(GstIndexClass),
98       NULL,
99       NULL,
100       (GClassInitFunc)gst_index_class_init,
101       NULL,
102       NULL,
103       sizeof(GstIndex),
104       1,
105       (GInstanceInitFunc)gst_index_init,
106       NULL
107     };
108     index_type = g_type_register_static(GST_TYPE_OBJECT, "GstIndex", &index_info, 0);
109   }
110   return index_type;
111 }
112
113 static void
114 gst_index_class_init (GstIndexClass *klass)
115 {
116   GObjectClass *gobject_class;
117   GstElementClass *gstelement_class;
118
119   gobject_class = (GObjectClass*)klass;
120   gstelement_class = (GstElementClass*)klass;
121
122   parent_class = g_type_class_ref(GST_TYPE_OBJECT);
123
124   gst_index_signals[ENTRY_ADDED] =
125     g_signal_new ("entry_added", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST,
126                   G_STRUCT_OFFSET (GstIndexClass, entry_added), NULL, NULL,
127                   gst_marshal_VOID__POINTER, G_TYPE_NONE, 1,
128                   G_TYPE_POINTER);
129
130   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_index_set_property);
131   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_index_get_property);
132
133   g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_RESOLVER,
134     g_param_spec_enum ("resolver", "Resolver", "Select a predefined object to string mapper",
135                        GST_TYPE_INDEX_RESOLVER, GST_INDEX_RESOLVER_PATH, G_PARAM_READWRITE));
136 }
137
138 static void
139 gst_index_init (GstIndex *index)
140 {
141   index->curgroup = gst_index_group_new(0);
142   index->maxgroup = 0;
143   index->groups = g_list_prepend(NULL, index->curgroup);
144
145   index->writers = g_hash_table_new (NULL, NULL);
146   index->last_id = 0;
147
148   index->method = GST_INDEX_RESOLVER_PATH;
149   index->resolver = resolvers[index->method].resolver;
150   index->resolver_user_data = resolvers[index->method].user_data;
151
152   GST_FLAG_SET (index, GST_INDEX_WRITABLE);
153   GST_FLAG_SET (index, GST_INDEX_READABLE);
154   
155   GST_DEBUG(0, "created new index");
156 }
157
158 static void
159 gst_index_set_property (GObject *object, guint prop_id,
160                         const GValue *value, GParamSpec *pspec)
161 {
162   GstIndex *index;
163
164   index = GST_INDEX (object);
165
166   switch (prop_id) {
167     case ARG_RESOLVER:
168       index->method = g_value_get_enum (value);
169       index->resolver = resolvers[index->method].resolver;
170       index->resolver_user_data = resolvers[index->method].user_data;
171       break;
172     default:
173       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
174       break;
175   }
176 }
177
178 static void
179 gst_index_get_property (GObject *object, guint prop_id, 
180                         GValue *value, GParamSpec *pspec)
181 {
182   GstIndex *index;
183
184   index = GST_INDEX (object);
185
186   switch (prop_id) {
187     case ARG_RESOLVER:
188       g_value_set_enum (value, index->method);
189       break;
190     default:
191       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
192       break;
193   }
194 }
195
196 static GstIndexGroup *
197 gst_index_group_new(guint groupnum)
198 {
199   GstIndexGroup *indexgroup = g_new(GstIndexGroup,1);
200
201   indexgroup->groupnum = groupnum;
202   indexgroup->entries = NULL;
203   indexgroup->certainty = GST_INDEX_UNKNOWN;
204   indexgroup->peergroup = -1;
205
206   GST_DEBUG(0, "created new index group %d",groupnum);
207
208   return indexgroup;
209 }
210
211 /**
212  * gst_index_new:
213  *
214  * Create a new tileindex object
215  *
216  * Returns: a new index object
217  */
218 GstIndex*
219 gst_index_new()
220 {
221   GstIndex *index;
222
223   index = g_object_new (gst_index_get_type (), NULL);
224
225   return index;
226 }
227
228 /**
229  * gst_index_commit:
230  * @index: the index to commit
231  * @id: the writer that commited the index
232  *
233  * Tell the index that the writer with the given id is done
234  * with this index and is not going to write any more entries
235  * to it.
236  */
237 void
238 gst_index_commit (GstIndex *index, gint id)
239 {
240   GstIndexClass *iclass;
241
242   iclass = GST_INDEX_GET_CLASS (index);
243
244   if (iclass->commit)
245     iclass->commit (index, id);
246 }
247
248
249 /**
250  * gst_index_get_group:
251  * @index: the index to get the current group from
252  *
253  * Get the id of the current group.
254  *
255  * Returns: the id of the current group.
256  */
257 gint
258 gst_index_get_group(GstIndex *index)
259 {
260   return index->curgroup->groupnum;
261 }
262
263 /**
264  * gst_index_new_group:
265  * @index: the index to create the new group in
266  *
267  * Create a new group for the given index. It will be
268  * set as the current group.
269  *
270  * Returns: the id of the newly created group.
271  */
272 gint
273 gst_index_new_group(GstIndex *index)
274 {
275   index->curgroup = gst_index_group_new(++index->maxgroup);
276   index->groups = g_list_append(index->groups,index->curgroup);
277   GST_DEBUG(0, "created new group %d in index",index->maxgroup);
278   return index->maxgroup;
279 }
280
281 /**
282  * gst_index_set_group:
283  * @index: the index to set the new group in
284  * @groupnum: the groupnumber to set
285  *
286  * Set the current groupnumber to the given argument.
287  *
288  * Returns: TRUE if the operation succeeded, FALSE if the group
289  * did not exist.
290  */
291 gboolean
292 gst_index_set_group(GstIndex *index, gint groupnum)
293 {
294   GList *list;
295   GstIndexGroup *indexgroup;
296
297   /* first check for null change */
298   if (groupnum == index->curgroup->groupnum)
299     return TRUE;
300
301   /* else search for the proper group */
302   list = index->groups;
303   while (list) {
304     indexgroup = (GstIndexGroup *)(list->data);
305     list = g_list_next(list);
306     if (indexgroup->groupnum == groupnum) {
307       index->curgroup = indexgroup;
308       GST_DEBUG(0, "switched to index group %d", indexgroup->groupnum);
309       return TRUE;
310     }
311   }
312
313   /* couldn't find the group in question */
314   GST_DEBUG(0, "couldn't find index group %d",groupnum);
315   return FALSE;
316 }
317
318 /**
319  * gst_index_set_certainty:
320  * @index: the index to set the certainty on
321  * @certainty: the certainty to set
322  *
323  * Set the certainty of the given index.
324  */
325 void
326 gst_index_set_certainty(GstIndex *index, GstIndexCertainty certainty)
327 {
328   index->curgroup->certainty = certainty;
329 }
330
331 /**
332  * gst_index_get_certainty:
333  * @index: the index to get the certainty of
334  *
335  * Get the certainty of the given index.
336  *
337  * Returns: the certainty of the index.
338  */
339 GstIndexCertainty
340 gst_index_get_certainty(GstIndex *index)
341 {
342   return index->curgroup->certainty;
343 }
344
345 /**
346  * gst_index_set_filter:
347  * @index: the index to register the filter on
348  * @filter: the filter to register
349  * @user_data: data passed to the filter function
350  *
351  * Lets the app register a custom filter function so that
352  * it can select what entries should be stored in the index.
353  */
354 void
355 gst_index_set_filter (GstIndex *index, 
356                       GstIndexFilter filter, gpointer user_data)
357 {
358   g_return_if_fail (GST_IS_INDEX (index));
359
360   index->filter = filter;
361   index->filter_user_data = user_data;
362 }
363
364 /**
365  * gst_index_set_resolver:
366  * @index: the index to register the resolver on
367  * @resolver: the resolver to register
368  * @user_data: data passed to the resolver function
369  *
370  * Lets the app register a custom function to map index
371  * ids to writer descriptions.
372  */
373 void
374 gst_index_set_resolver (GstIndex *index, 
375                         GstIndexResolver resolver, gpointer user_data)
376 {
377   g_return_if_fail (GST_IS_INDEX (index));
378
379   index->resolver = resolver;
380   index->resolver_user_data = user_data;
381   index->method = GST_INDEX_RESOLVER_CUSTOM;
382 }
383
384 /**
385  * gst_index_entry_free:
386  * @entry: the entry to free
387  *
388  * Free the memory used by the given entry.
389  */
390 void
391 gst_index_entry_free (GstIndexEntry *entry)
392 {
393   g_free (entry);
394 }
395
396 /**
397  * gst_index_add_format:
398  * @index: the index to add the entry to
399  * @id: the id of the index writer
400  * @format: the format to add to the index
401  *
402  * Adds a format entry into the index. This function is
403  * used to map dynamic GstFormat ids to their original
404  * format key.
405  *
406  * Returns: a pointer to the newly added entry in the index.
407  */
408 GstIndexEntry*
409 gst_index_add_format (GstIndex *index, gint id, GstFormat format)
410 {
411   GstIndexEntry *entry;
412   const GstFormatDefinition* def;
413   GstIndexClass *iclass;
414
415   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
416   g_return_val_if_fail (format != 0, NULL);
417
418   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
419     return NULL;
420   
421   entry = g_new0 (GstIndexEntry, 1);
422   entry->type = GST_INDEX_ENTRY_FORMAT;
423   entry->id = id;
424   entry->data.format.format = format;
425
426   def = gst_format_get_details (format);
427   entry->data.format.key = def->nick;
428
429   iclass = GST_INDEX_GET_CLASS (index);
430   
431   if (iclass->add_entry)
432     iclass->add_entry (index, entry);
433
434   g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
435
436   return entry;
437 }
438
439 /**
440  * gst_index_add_id:
441  * @index: the index to add the entry to
442  * @id: the id of the index writer
443  * @description: the description of the index writer
444  *
445  * Add an id entry into the index.
446  *
447  * Returns: a pointer to the newly added entry in the index.
448  */
449 GstIndexEntry*
450 gst_index_add_id (GstIndex *index, gint id, gchar *description)
451 {
452   GstIndexEntry *entry;
453   GstIndexClass *iclass;
454
455   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
456   g_return_val_if_fail (description != NULL, NULL);
457   
458   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
459     return NULL;
460   
461   entry = g_new0 (GstIndexEntry, 1);
462   entry->type = GST_INDEX_ENTRY_ID;
463   entry->id = id;
464   entry->data.id.description = description;
465
466   iclass = GST_INDEX_GET_CLASS (index);
467
468   if (iclass->add_entry)
469     iclass->add_entry (index, entry);
470   
471   g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
472
473   return entry;
474 }
475
476 static gboolean
477 gst_index_path_resolver (GstIndex *index, GstObject *writer,
478                          gchar **writer_string, gpointer data) 
479 {
480   *writer_string = gst_object_get_path_string (writer);
481
482   return TRUE;
483 }
484
485 static gboolean
486 gst_index_gtype_resolver (GstIndex *index, GstObject *writer,
487                           gchar **writer_string, gpointer data) 
488 {
489   if (GST_IS_PAD (writer)) {
490     GstElement *element = gst_pad_get_parent (GST_PAD (writer));
491
492     *writer_string = g_strdup_printf ("%s.%s", 
493                      g_type_name (G_OBJECT_TYPE (element)),
494                      gst_object_get_name (writer));
495   }
496   else {
497     *writer_string = g_strdup_printf ("%s", g_type_name (G_OBJECT_TYPE (writer)));
498   }
499
500   return TRUE;
501 }
502
503 /**
504  * gst_index_get_writer_id:
505  * @index: the index to get a unique write id for
506  * @writer: the GstObject to allocate an id for
507  * @id: a pointer to a gint to hold the id
508  *
509  * Before entries can be added to the index, a writer
510  * should obtain a unique id. The methods to add new entries
511  * to the index require this id as an argument. 
512  *
513  * The application can implement a custom function to map the writer object 
514  * to a string. That string will be used to register or look up an id
515  * in the index.
516  *
517  * Returns: TRUE if the writer would be mapped to an id.
518  */
519 gboolean 
520 gst_index_get_writer_id (GstIndex *index, GstObject *writer, gint *id)
521 {
522   gchar *writer_string = NULL;
523   GstIndexEntry *entry;
524   GstIndexClass *iclass;
525   gboolean success = FALSE;
526
527   g_return_val_if_fail (GST_IS_INDEX (index), FALSE);
528   g_return_val_if_fail (GST_IS_OBJECT (writer), FALSE);
529   g_return_val_if_fail (id, FALSE);
530
531   *id = -1;
532
533   /* first try to get a previously cached id */
534   entry = g_hash_table_lookup (index->writers, writer);
535   if (entry == NULL) { 
536
537     iclass = GST_INDEX_GET_CLASS (index);
538
539     /* let the app make a string */
540     if (index->resolver) {
541       gboolean res;
542
543       res = index->resolver (index, writer, &writer_string, index->resolver_user_data);
544       if (!res) 
545         return FALSE;
546     }
547     else {
548       g_warning ("no resolver found");
549       return FALSE;
550     }
551
552     /* if the index has a resolver, make it map this string to an id */
553     if (iclass->get_writer_id) {
554       success = iclass->get_writer_id (index, id, writer_string);
555     }
556     /* if the index could not resolve, we allocate one ourselves */
557     if (!success) {
558       *id = index->last_id++;
559     }
560
561     entry = gst_index_add_id (index, *id, writer_string);
562     if (!entry) {
563       /* index is probably not writable, make an entry anyway
564        * to keep it in our cache */
565       entry = g_new0 (GstIndexEntry, 1);
566       entry->type = GST_INDEX_ENTRY_ID;
567       entry->id = *id;
568       entry->data.id.description = writer_string;
569     }
570     g_hash_table_insert (index->writers, writer, entry);
571   }
572   else {
573     *id = entry->id;
574   }
575
576   return TRUE;
577 }
578
579 /**
580  * gst_index_add_association:
581  * @index: the index to add the entry to
582  * @id: the id of the index writer
583  * @flags: optinal flags for this entry
584  * @format: the format of the value
585  * @value: the value 
586  * @...: other format/value pairs or 0 to end the list
587  *
588  * Associate given format/value pairs with eachother.
589  * Be sure to pass gint64 values to this functions varargs,
590  * you might want to use a gint64 cast to be sure.
591  *
592  * Returns: a pointer to the newly added entry in the index.
593  */
594 GstIndexEntry*
595 gst_index_add_association (GstIndex *index, gint id, GstAssocFlags flags, 
596                            GstFormat format, gint64 value, ...)
597 {
598   va_list args;
599   GstIndexAssociation *assoc;
600   GstIndexEntry *entry;
601   gulong size;
602   gint nassocs = 0;
603   GstFormat cur_format;
604   volatile gint64 dummy;
605   GstIndexClass *iclass;
606
607   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
608   g_return_val_if_fail (format != 0, NULL);
609   
610   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
611     return NULL;
612   
613   va_start (args, value);
614
615   cur_format = format;
616
617   while (cur_format) {
618     nassocs++;
619     cur_format = va_arg (args, GstFormat);
620     if (cur_format)
621       dummy = va_arg (args, gint64);
622   }
623   va_end (args);
624
625   /* make room for two assoc */
626   size = sizeof (GstIndexEntry) + (sizeof (GstIndexAssociation) * nassocs);
627
628   entry = g_malloc (size);
629
630   entry->type = GST_INDEX_ENTRY_ASSOCIATION;
631   entry->id = id;
632   entry->data.assoc.flags = flags;
633   assoc = (GstIndexAssociation *) (((guint8 *) entry) + sizeof (GstIndexEntry));
634   entry->data.assoc.assocs = assoc;
635   entry->data.assoc.nassocs = nassocs;
636
637   va_start (args, value);
638   while (format) {
639     assoc->format = format;
640     assoc->value = value;
641
642     assoc++;
643
644     format = va_arg (args, GstFormat);
645     if (format)
646       value = va_arg (args, gint64);
647   }
648   va_end (args);
649
650   iclass = GST_INDEX_GET_CLASS (index);
651
652   if (iclass->add_entry)
653     iclass->add_entry (index, entry);
654
655   g_signal_emit (G_OBJECT (index), gst_index_signals[ENTRY_ADDED], 0, entry);
656
657   return entry;
658 }
659
660 /**
661  * gst_index_add_object:
662  * @index: the index to add the object to
663  * @id: the id of the index writer
664  * @key: a key for the object
665  * @type: the GType of the object
666  * @object: a pointer to the object to add
667  *
668  * Add the given object to the index with the given key.
669  * 
670  * Returns: a pointer to the newly added entry in the index.
671  */
672 GstIndexEntry*
673 gst_index_add_object (GstIndex *index, gint id, gchar *key,
674                       GType type, gpointer object)
675 {
676   if (!GST_INDEX_IS_WRITABLE (index) || id == -1)
677     return NULL;
678   
679   return NULL;
680 }
681
682 static gint
683 gst_index_compare_func (gconstpointer a,
684                         gconstpointer b,
685                         gpointer user_data)
686 {
687   return a - b;  
688 }
689
690 /**
691  * gst_index_get_assoc_entry:
692  * @index: the index to search
693  * @id: the id of the index writer
694  * @method: The lookup method to use
695  * @flags: Flags for the entry
696  * @format: the format of the value
697  * @value: the value to find
698  *
699  * Finds the given format/value in the index
700  *
701  * Returns: the entry associated with the value or NULL if the
702  *   value was not found.
703  */
704 GstIndexEntry*
705 gst_index_get_assoc_entry (GstIndex *index, gint id,
706                            GstIndexLookupMethod method, GstAssocFlags flags,
707                            GstFormat format, gint64 value)
708 {
709   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
710
711   if (id == -1)
712     return NULL;
713
714   return gst_index_get_assoc_entry_full (index, id, method, flags, format, value, 
715                                   gst_index_compare_func, NULL);
716 }
717
718 /**
719  * gst_index_get_assoc_entry_full:
720  * @index: the index to search
721  * @id: the id of the index writer
722  * @method: The lookup method to use
723  * @flags: Flags for the entry
724  * @format: the format of the value
725  * @value: the value to find
726  * @func: the function used to compare entries
727  * @user_data: user data passed to the compare function
728  *
729  * Finds the given format/value in the index with the given
730  * compare function and user_data.
731  *
732  * Returns: the entry associated with the value or NULL if the
733  *   value was not found.
734  */
735 GstIndexEntry*
736 gst_index_get_assoc_entry_full (GstIndex *index, gint id,
737                                 GstIndexLookupMethod method, GstAssocFlags flags,
738                                 GstFormat format, gint64 value,
739                                 GCompareDataFunc func,
740                                 gpointer user_data)
741 {
742   GstIndexClass *iclass;
743
744   g_return_val_if_fail (GST_IS_INDEX (index), NULL);
745
746   if (id == -1)
747     return NULL;
748
749   iclass = GST_INDEX_GET_CLASS (index);
750
751   if (iclass->get_assoc_entry)
752     return iclass->get_assoc_entry (index, id, method, flags, format, value, func, user_data);
753   
754   return NULL;
755 }
756
757 /**
758  * gst_index_entry_assoc_map:
759  * @entry: the index to search
760  * @format: the format of the value the find
761  * @value: a pointer to store the value
762  *
763  * Gets alternative formats associated with the indexentry.
764  *
765  * Returns: TRUE if there was a value associated with the given 
766  * format.
767  */
768 gboolean
769 gst_index_entry_assoc_map (GstIndexEntry *entry,
770                            GstFormat format, gint64 *value)
771 {
772   gint i;
773
774   g_return_val_if_fail (entry != NULL, FALSE);
775   g_return_val_if_fail (value != NULL, FALSE);
776
777   for (i = 0; i < GST_INDEX_NASSOCS (entry); i++) {
778      if (GST_INDEX_ASSOC_FORMAT (entry, i) == format) {
779        *value = GST_INDEX_ASSOC_VALUE (entry, i);
780        return TRUE;
781      }
782   }
783   return FALSE;
784 }
785
786
787 static void             gst_index_factory_class_init            (GstIndexFactoryClass *klass);
788 static void             gst_index_factory_init          (GstIndexFactory *factory);
789
790 static GstPluginFeatureClass *factory_parent_class = NULL;
791 /* static guint gst_index_factory_signals[LAST_SIGNAL] = { 0 }; */
792
793 GType 
794 gst_index_factory_get_type (void) 
795 {
796   static GType indexfactory_type = 0;
797
798   if (!indexfactory_type) {
799     static const GTypeInfo indexfactory_info = {
800       sizeof (GstIndexFactoryClass),
801       NULL,
802       NULL,
803       (GClassInitFunc) gst_index_factory_class_init,
804       NULL,
805       NULL,
806       sizeof(GstIndexFactory),
807       0,
808       (GInstanceInitFunc) gst_index_factory_init,
809       NULL
810     };
811     indexfactory_type = g_type_register_static (GST_TYPE_PLUGIN_FEATURE, 
812                                           "GstIndexFactory", &indexfactory_info, 0);
813   }
814   return indexfactory_type;
815 }
816
817 static void
818 gst_index_factory_class_init (GstIndexFactoryClass *klass)
819 {
820   GObjectClass *gobject_class;
821   GstObjectClass *gstobject_class;
822   GstPluginFeatureClass *gstpluginfeature_class;
823
824   gobject_class = (GObjectClass*)klass;
825   gstobject_class = (GstObjectClass*)klass;
826   gstpluginfeature_class = (GstPluginFeatureClass*) klass;
827
828   factory_parent_class = g_type_class_ref (GST_TYPE_PLUGIN_FEATURE);
829 }
830
831 static void
832 gst_index_factory_init (GstIndexFactory *factory)
833 {
834 }
835
836 /**
837  * gst_index_factory_new:
838  * @name: name of indexfactory to create
839  * @longdesc: long description of indexfactory to create
840  * @type: the GType of the GstIndex element of this factory
841  *
842  * Create a new indexfactory with the given parameters
843  *
844  * Returns: a new #GstIndexFactory.
845  */
846 GstIndexFactory*
847 gst_index_factory_new (const gchar *name, const gchar *longdesc, GType type)
848 {
849   GstIndexFactory *factory;
850
851   g_return_val_if_fail(name != NULL, NULL);
852   factory = gst_index_factory_find (name);
853   if (!factory) {
854     factory = GST_INDEX_FACTORY (g_object_new (GST_TYPE_INDEX_FACTORY, NULL));
855   }
856
857   GST_PLUGIN_FEATURE_NAME (factory) = g_strdup (name);
858   if (factory->longdesc)
859     g_free (factory->longdesc);
860   factory->longdesc = g_strdup (longdesc);
861   factory->type = type;
862
863   return factory;
864 }
865
866 /**
867  * gst_index_factory_destroy:
868  * @factory: factory to destroy
869  *
870  * Removes the index from the global list.
871  */
872 void
873 gst_index_factory_destroy (GstIndexFactory *factory)
874 {
875   g_return_if_fail (factory != NULL);
876
877   /* we don't free the struct bacause someone might  have a handle to it.. */
878 }
879
880 /**
881  * gst_index_factory_find:
882  * @name: name of indexfactory to find
883  *
884  * Search for an indexfactory of the given name.
885  *
886  * Returns: #GstIndexFactory if found, NULL otherwise
887  */
888 GstIndexFactory*
889 gst_index_factory_find (const gchar *name)
890 {
891   GstPluginFeature *feature;
892
893   g_return_val_if_fail (name != NULL, NULL);
894
895   GST_DEBUG (0,"gstindex: find \"%s\"", name);
896
897   feature = gst_registry_pool_find_feature (name, GST_TYPE_INDEX_FACTORY);
898   if (feature)
899     return GST_INDEX_FACTORY (feature);
900
901   return NULL;
902 }
903
904 /**
905  * gst_index_factory_create:
906  * @factory: the factory used to create the instance
907  *
908  * Create a new #GstIndex instance from the 
909  * given indexfactory.
910  *
911  * Returns: A new #GstIndex instance.
912  */
913 GstIndex*
914 gst_index_factory_create (GstIndexFactory *factory)
915 {
916   GstIndex *new = NULL;
917
918   g_return_val_if_fail (factory != NULL, NULL);
919
920   if (gst_plugin_feature_ensure_loaded (GST_PLUGIN_FEATURE (factory))) {
921     g_return_val_if_fail (factory->type != 0, NULL);
922
923     new = GST_INDEX (g_object_new(factory->type,NULL));
924   }
925
926   return new;
927 }
928
929 /**
930  * gst_index_factory_make:
931  * @name: the name of the factory used to create the instance
932  *
933  * Create a new #GstIndex instance from the 
934  * indexfactory with the given name.
935  *
936  * Returns: A new #GstIndex instance.
937  */
938 GstIndex*
939 gst_index_factory_make (const gchar *name)
940 {
941   GstIndexFactory *factory;
942
943   g_return_val_if_fail (name != NULL, NULL);
944
945   factory = gst_index_factory_find (name);
946
947   if (factory == NULL)
948     return NULL;
949
950   return gst_index_factory_create (factory);
951 }
952