7d38b0ffa962cae077268816a565079b6ac227b2
[platform/upstream/gstreamer.git] / gst / elements / gsttypefind.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * gsttypefind.c: element that detects type of stream
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21
22 /* FIXME: need a better solution for non-seekable streams */
23
24 /* way of operation:
25  * 1) get a list of all typefind functions sorted best to worst
26  * 2) if all elements have been called with all requested data goto 8
27  * 3) call all functions once with all available data
28  * 4) if a function returns a value >= ARG_MAXIMUM goto 8
29  * 5) all functions with a result > ARG_MINIMUM or functions that did not get
30  *    all requested data (where peek returned NULL) stay in list
31  * 6) seek to requested offset of best function that still has open data 
32  *    requests
33  * 7) goto 2
34  * 8) take best available result and use its caps
35  */
36
37 #ifdef HAVE_CONFIG_H
38 #  include "config.h"
39 #endif
40
41 #include "gsttypefindelement.h"
42 #include "gst/gst_private.h"
43
44 #include <gst/gsttypefind.h>
45
46 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
47 #define GST_CAT_DEFAULT gst_type_find_element_debug
48
49 GstElementDetails gst_type_find_element_details = GST_ELEMENT_DETAILS (
50   "TypeFind",
51   "Generic",
52   "Finds the media type of a stream",
53   "Benjamin Otte <in7y118@public.uni-hamburg.de>"
54 );
55
56 /* generic templates */
57 GST_PAD_TEMPLATE_FACTORY (type_find_element_sink_factory,
58   "sink",
59   GST_PAD_SINK,
60   GST_PAD_ALWAYS,
61   GST_CAPS_ANY
62 );
63 GST_PAD_TEMPLATE_FACTORY (type_find_element_src_factory,
64   "src",
65   GST_PAD_SRC,
66   GST_PAD_ALWAYS,
67   GST_CAPS_ANY
68 );
69
70 /* TypeFind signals and args */
71 enum {
72   HAVE_TYPE,
73   LAST_SIGNAL
74 };
75 enum {
76   ARG_0,
77   ARG_CAPS,
78   ARG_MINIMUM,
79   ARG_MAXIMUM
80 };
81 enum {
82   MODE_NORMAL, /* act as identity */
83   MODE_TYPEFIND, /* do typefinding */
84 };
85
86
87 static void     gst_type_find_element_base_init         (gpointer g_class);
88 static void     gst_type_find_element_class_init        (gpointer       g_class,
89                                                          gpointer       class_data);
90 static void     gst_type_find_element_init              (GTypeInstance *instance,
91                                                          gpointer       g_class);
92 static void     gst_type_find_element_dispose           (GObject *      object);
93 static void     gst_type_find_element_set_property      (GObject *      object, 
94                                                          guint          prop_id,
95                                                          const GValue * value, 
96                                                          GParamSpec *   pspec);
97 static void     gst_type_find_element_get_property      (GObject *      object, 
98                                                          guint          prop_id,
99                                                          GValue *       value, 
100                                                          GParamSpec *   pspec);
101
102 static const GstEventMask *
103                 gst_type_find_element_src_event_mask    (GstPad *       pad);
104 static gboolean gst_type_find_element_src_event         (GstPad *       pad,
105                                                          GstEvent *     event);
106
107 static void     gst_type_find_element_chain             (GstPad *       sinkpad,
108                                                          GstData *      data);
109 static GstElementStateReturn
110                 gst_type_find_element_change_state      (GstElement *   element);
111
112 static GstElementClass *parent_class = NULL;
113 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
114
115 GType
116 gst_type_find_element_get_type (void)
117 {
118   static GType typefind_type = 0;
119
120   if (!typefind_type) {
121     static const GTypeInfo typefind_info = {
122       sizeof (GstTypeFindElementClass),
123       gst_type_find_element_base_init,
124       NULL,
125       gst_type_find_element_class_init,
126       NULL,
127       NULL,
128       sizeof (GstTypeFindElement),
129       0,
130       gst_type_find_element_init,
131       NULL
132     };
133     typefind_type = g_type_register_static (GST_TYPE_ELEMENT,
134                                             "GstTypeFindElement",
135                                             &typefind_info, 0);
136
137     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", 
138                              GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "typefind element");
139   }
140   return typefind_type;
141 }
142 static void
143 gst_type_find_element_have_type (GstTypeFindElement *typefind, guint probability, GstCaps *caps)
144 {
145   gchar *caps_str;
146   
147   g_assert (typefind->caps == NULL);
148   g_assert (caps != NULL);
149
150   caps_str = gst_caps_to_string (caps);
151   GST_INFO_OBJECT (typefind, "found caps %s", caps_str);
152   g_free (caps_str);
153   gst_caps_replace (&typefind->caps, caps);
154   if (gst_pad_try_set_caps (typefind->src, caps) < GST_PAD_LINK_OK) {
155     gst_element_error (GST_ELEMENT (typefind), "could not set caps on source pad");
156   }
157 }
158 static void
159 gst_type_find_element_base_init (gpointer g_class)
160 {
161   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
162   
163   gst_element_class_set_details (gstelement_class, &gst_type_find_element_details);
164 }
165 static void
166 gst_type_find_element_class_init (gpointer g_class, gpointer class_data)
167 {
168   GObjectClass *gobject_class;
169   GstElementClass *gstelement_class;
170   GstTypeFindElementClass *typefind_class;
171
172   gobject_class = G_OBJECT_CLASS (g_class);
173   gstelement_class = GST_ELEMENT_CLASS (g_class);
174   typefind_class = GST_TYPE_FIND_ELEMENT_CLASS (g_class);
175
176   parent_class = g_type_class_peek_parent (g_class);
177
178   gobject_class->set_property = GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
179   gobject_class->get_property = GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
180   gobject_class->dispose      = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
181
182   typefind_class->have_type = gst_type_find_element_have_type;
183
184   g_object_class_install_property (gobject_class, ARG_CAPS,
185           g_param_spec_boxed ("caps", _("caps"), _("detected capabilities in stream"),
186           GST_TYPE_CAPS, G_PARAM_READABLE));
187   g_object_class_install_property (gobject_class, ARG_MINIMUM,
188           g_param_spec_uint ("minimum", _("minimum"), "minimum probability required to accept caps",
189           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
190   g_object_class_install_property (gobject_class, ARG_MINIMUM,
191           g_param_spec_uint ("maximum", _("maximum"), "probability to stop typefinding",
192           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
193
194   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type", 
195           G_TYPE_FROM_CLASS (g_class), G_SIGNAL_RUN_LAST,
196           G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
197           gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
198           G_TYPE_UINT, GST_TYPE_CAPS);
199
200   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
201 }
202 static void
203 gst_type_find_element_init (GTypeInstance *instance, gpointer g_class)
204 {
205   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (instance);
206   
207   /* sinkpad */
208   typefind->sink = gst_pad_new_from_template (
209                 GST_PAD_TEMPLATE_GET (type_find_element_sink_factory), "sink");
210   gst_pad_set_chain_function (typefind->sink,
211                               gst_type_find_element_chain);
212   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
213   /* srcpad */
214   typefind->src = gst_pad_new_from_template (
215                 GST_PAD_TEMPLATE_GET (type_find_element_src_factory), "src");
216   gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
217   gst_pad_set_event_mask_function (typefind->src, gst_type_find_element_src_event_mask);
218   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
219
220   typefind->caps = NULL;
221   typefind->min_probability = 1;
222   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
223
224   typefind->store = gst_buffer_store_new ();
225
226   GST_FLAG_SET (typefind, GST_ELEMENT_EVENT_AWARE);
227 }
228 static void
229 gst_type_find_element_dispose (GObject *object)
230 {
231   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
232
233   G_OBJECT_CLASS (parent_class)->dispose (object);
234
235   if (typefind->store) {
236     g_object_unref (typefind->store);
237     typefind->store = NULL;
238   }
239 }
240 static void
241 gst_type_find_element_set_property (GObject *object, guint prop_id, 
242                                     const GValue *value, GParamSpec *pspec)
243 {
244   GstTypeFindElement *typefind;
245
246   g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
247
248   typefind = GST_TYPE_FIND_ELEMENT (object);
249
250   switch (prop_id) {
251     case ARG_MINIMUM:
252       typefind->min_probability = g_value_get_uint (value);
253       g_object_notify (object, "minimum");
254       break;
255     case ARG_MAXIMUM:
256       typefind->max_probability = g_value_get_uint (value);
257       g_object_notify (object, "maximum");
258       break;
259     default:
260       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
261       break;
262   }
263 }
264 static void
265 gst_type_find_element_get_property (GObject *object, guint prop_id, 
266                                     GValue *value, GParamSpec *pspec)
267 {
268   GstTypeFindElement *typefind;
269
270   g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
271
272   typefind = GST_TYPE_FIND_ELEMENT (object);
273
274   switch (prop_id) {
275     case ARG_CAPS:
276       g_value_set_boxed (value, typefind->caps);
277       break;
278     case ARG_MINIMUM:
279       g_value_set_uint (value, typefind->min_probability);
280       break;
281     case ARG_MAXIMUM:
282       g_value_set_uint (value, typefind->max_probability);
283       break;
284     default:
285       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
286       break;
287   }
288 }
289 static const GstEventMask *
290 gst_type_find_element_src_event_mask (GstPad *pad)
291 {
292   static const GstEventMask mask[] = {
293     { GST_EVENT_SEEK, GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END | GST_SEEK_FLAG_FLUSH},
294     /* add more if you want, event masks suck and need to die anyway */
295     { 0, }
296   };
297   
298   return mask;
299 }
300 static gboolean 
301 gst_type_find_element_src_event (GstPad *pad, GstEvent *event)
302 {
303   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
304
305   if (typefind->mode == MODE_TYPEFIND) {
306     /* need to do more? */
307     gst_data_unref (GST_DATA (event));
308     return FALSE;
309   }
310   return gst_pad_event_default (pad, event);
311 }
312 typedef struct {
313   GstTypeFindFactory *  factory;
314   gint                  probability;
315   GstCaps *             caps;
316   gint64                requested_offset;
317   guint                 requested_size;
318
319   GList *               buffers;
320   GstTypeFindElement *  self;
321 } TypeFindEntry;
322 static void
323 free_entry_buffers (TypeFindEntry *entry)
324 {
325   g_list_foreach (entry->buffers, (GFunc) gst_data_unref, NULL);
326   g_list_free (entry->buffers);
327   entry->buffers = NULL;
328 }
329 static void
330 free_entry (TypeFindEntry *entry)
331 {
332   free_entry_buffers (entry);
333   
334   if (entry->caps)
335     gst_caps_unref (entry->caps);
336   g_free (entry);
337 }
338 static void
339 start_typefinding (GstTypeFindElement *typefind)
340 {
341   g_assert (typefind->caps == NULL);
342   g_assert (typefind->possibilities == NULL);
343   
344   GST_DEBUG_OBJECT (typefind, "starting typefinding");
345   typefind->mode = MODE_TYPEFIND; 
346   typefind->stream_length_available = TRUE; 
347   typefind->stream_length = 0; 
348 }
349 static void
350 stop_typefinding (GstTypeFindElement *typefind)
351 {
352   /* stop all typefinding and set mode back to normal */
353   gboolean push_cached_buffers = gst_element_get_state (GST_ELEMENT (typefind)) == GST_STATE_PLAYING;
354   
355   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s", push_cached_buffers ? " and pushing cached buffers" : "");
356   if (typefind->possibilities != NULL) {
357     /* this should only happen on PAUSED => READY or EOS */
358     GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions", g_list_length (typefind->possibilities));
359     g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
360     g_list_free (typefind->possibilities);
361     typefind->possibilities = NULL;
362   }
363
364   typefind->mode = MODE_NORMAL;
365
366   if (push_cached_buffers) {
367     GstBuffer *buffer;
368     guint size = gst_buffer_store_get_size (typefind->store, 0);
369     if (size && (buffer = gst_buffer_store_get_buffer (typefind->store, 0, size))) {
370       gst_pad_push (typefind->src, GST_DATA (buffer));
371     } else {
372       size = 0;
373     }
374     GST_LOG_OBJECT (typefind, "seeking back to current position %u", size);
375     if (!gst_pad_send_event (GST_PAD_PEER (typefind->sink), 
376                              gst_event_new_seek (GST_SEEK_METHOD_SET | GST_FORMAT_BYTES, size))) {
377       GST_WARNING_OBJECT (typefind, "could not seek to required position %u, hope for the best", size);
378     }
379   }
380   gst_buffer_store_clear (typefind->store);
381 }
382 static guint64
383 find_element_get_length (gpointer data)
384 {
385   TypeFindEntry *entry = (TypeFindEntry *) data;
386   GstTypeFindElement *typefind = entry->self;
387   GstFormat format = GST_FORMAT_BYTES;
388   
389   if (!typefind->stream_length_available) {
390     GST_LOG_OBJECT (entry->self, "'%s' called get_length () but we know it's not available", 
391             GST_PLUGIN_FEATURE_NAME (entry->factory));
392     return 0;
393   }
394   if (entry->self->stream_length == 0) {
395     typefind->stream_length_available = gst_pad_query (GST_PAD_PEER (entry->self->sink), GST_QUERY_TOTAL, 
396             &format, &entry->self->stream_length);
397     if (format != GST_FORMAT_BYTES)
398       typefind->stream_length_available = FALSE;
399     if (!typefind->stream_length_available) {
400       GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () but it's not available", 
401               GST_PLUGIN_FEATURE_NAME (entry->factory));
402       return 0;
403     } else {
404       GST_DEBUG_OBJECT (entry->self, "'%s' called get_length () and it's %"G_GUINT64_FORMAT" bytes", 
405               GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
406     }
407   }
408   
409   return entry->self->stream_length;
410 }
411 static void
412 gst_type_find_element_handle_event (GstPad *pad, GstEvent *event)
413 {
414   TypeFindEntry *entry;
415   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
416
417   if (typefind->mode == MODE_TYPEFIND) {
418     /* need to do more? */
419     switch (GST_EVENT_TYPE (event)) {
420     case GST_EVENT_EOS:
421       /* this should only happen when we got all available data */
422       entry = (TypeFindEntry *) typefind->possibilities ? typefind->possibilities->data : NULL;
423       if (entry && entry->probability >= typefind->min_probability) {
424         GST_INFO_OBJECT (typefind, "'%s' is the best typefind left after we got all data, using it now (probability %u)", 
425                 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
426         g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
427       }
428       stop_typefinding (typefind);
429       gst_pad_event_default (pad, event);
430       break;
431     default:
432       gst_data_unref (GST_DATA (event));
433       break;
434     }
435   } else {
436     gst_pad_event_default (pad, event);
437   }
438 }
439 static guint8 *
440 find_peek (gpointer data, gint64 offset, guint size)
441 {
442   GstBuffer *buf;
443   TypeFindEntry *entry = (TypeFindEntry *) data;
444   
445   GST_LOG_OBJECT (entry->self, "'%s' called peek (%"G_GINT64_FORMAT", %u)", 
446           GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
447   if (offset >= 0) {
448     buf = gst_buffer_store_get_buffer (entry->self->store, offset, size);
449   } else {
450     /* FIXME: can we do this easily without querying length? */
451     guint64 length = find_element_get_length (data);
452
453     if (length == 0) {
454       buf = NULL;
455     } else {
456       buf = gst_buffer_store_get_buffer (entry->self->store, length + offset, size);
457     }
458   }
459
460   if (buf) {
461     entry->buffers = g_list_prepend (entry->buffers, buf);
462     return GST_BUFFER_DATA (buf);
463   } else {
464     if (entry->requested_size == 0) {
465       GST_LOG_OBJECT (entry->self, "setting requested peek (%"G_GINT64_FORMAT", %u) on '%s'", 
466               offset, size, GST_PLUGIN_FEATURE_NAME (entry->factory));
467       entry->requested_offset = offset;
468       entry->requested_size = size;
469     }
470     return NULL;
471   }
472 }
473 static void
474 find_suggest (gpointer data, guint probability, GstCaps *caps)
475 {
476   gchar *str;
477   TypeFindEntry *entry = (TypeFindEntry *) data;
478   
479   str = gst_caps_to_string (caps);
480   GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %s)", 
481           GST_PLUGIN_FEATURE_NAME (entry->factory), probability, str);
482   g_free (str);
483   if (((gint) probability) > entry->probability) {
484     entry->probability = probability;
485     gst_caps_replace (&entry->caps, caps);
486   }
487 }
488 static gint
489 compare_type_find_entry (gconstpointer a, gconstpointer b)
490 {
491   TypeFindEntry *one = (TypeFindEntry *) a;
492   TypeFindEntry *two = (TypeFindEntry *) b;
493
494   if (one->probability == two->probability) {
495     /* FIXME: can be improved by analyzing requests */
496     return 0;
497   } else {
498     return two->probability - one->probability;
499   }
500 }
501 static gint
502 compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
503 {
504   return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
505 }
506 static void
507 gst_type_find_element_chain (GstPad *pad, GstData *data)
508 {
509   GstTypeFindElement *typefind;
510   GList *entries;
511   TypeFindEntry *entry;
512   GList *walk;
513   GstTypeFind find = {find_peek, find_suggest, NULL, find_element_get_length };
514
515   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
516   if (GST_IS_EVENT (data)) {
517     gst_type_find_element_handle_event (pad, GST_EVENT (data));
518     return;
519   }
520   switch (typefind->mode) {
521     case MODE_NORMAL:
522       gst_pad_push (typefind->src, data);
523       return;
524     case MODE_TYPEFIND: {
525       gst_buffer_store_add_buffer (typefind->store, GST_BUFFER (data));
526       gst_data_unref (data);
527       if (typefind->possibilities == NULL) {
528         /* not yet started, get all typefinding functions into our "queue" */
529         GList *all_factories = gst_type_find_factory_get_list ();
530         GST_INFO_OBJECT (typefind, "starting with %u typefinding functions", 
531                          g_list_length ((GList *) all_factories));
532         
533         all_factories = g_list_sort (all_factories, compare_type_find_factory);
534         walk = all_factories;
535         while (all_factories) {
536           entry = g_new0 (TypeFindEntry, 1);
537           
538           entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
539           entry->self = typefind;
540           entry->probability = 0;
541           typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
542           all_factories = g_list_next (all_factories);
543         }
544         g_list_free (all_factories);
545       }
546       /* call every typefind function once */
547       walk = entries = typefind->possibilities;
548       GST_INFO_OBJECT (typefind, "iterating %u typefinding functions", g_list_length (entries));
549       typefind->possibilities = NULL;
550       while (walk) {
551         find.data = entry = (TypeFindEntry *) walk->data;
552         walk = g_list_next (walk);
553         entry->probability = 0;
554         entry->requested_offset = 0;
555         entry->requested_size = 0;
556         gst_type_find_factory_call_function (entry->factory, &find);
557         free_entry_buffers (entry);
558         if (entry->probability == 0 && entry->requested_size == 0) {
559           GST_DEBUG_OBJECT (typefind, "'%s' was removed - no chance of being the right plugin", 
560                   GST_PLUGIN_FEATURE_NAME (entry->factory));
561           free_entry (entry);
562         } else if (entry->probability >= typefind->max_probability) {
563           /* wooha, got caps */
564           GstCaps *found_caps = entry->caps;
565           guint probability = entry->probability;
566           
567           gst_caps_ref (found_caps);
568           GST_INFO_OBJECT (typefind, "'%s' returned %u/%u probability, using it NOW", 
569                   GST_PLUGIN_FEATURE_NAME (entry->factory), probability, typefind->max_probability);
570           while (walk) {
571             free_entry ((TypeFindEntry *) walk->data);
572             walk = g_list_next (walk);
573           }
574           walk = typefind->possibilities;
575           while (walk) {
576             free_entry (walk->data);
577             walk = g_list_next (walk);
578           }
579           typefind->possibilities = NULL;
580           g_list_free (typefind->possibilities); 
581           g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, probability, found_caps);
582           gst_caps_unref (found_caps);
583         } else {
584           typefind->possibilities = g_list_prepend (typefind->possibilities, entry);
585         }
586       }
587       g_list_free (entries);
588       /* we may now already have caps or we might be left without functions to try */
589       if (typefind->caps) {
590         stop_typefinding (typefind);
591       } else if (typefind->possibilities == NULL) {
592         gst_element_error (GST_ELEMENT (typefind), "media type could not be detected");
593       } else {
594         /* set up typefind element for next iteration */
595         typefind->possibilities = g_list_sort (typefind->possibilities, compare_type_find_entry);
596         
597         walk = typefind->possibilities;
598         while (walk) {
599           entry = (TypeFindEntry *) walk->data;
600           walk = g_list_next (walk);
601           if (entry->requested_size > 0) {
602             /* FIXME: need heuristic to find out if we should seek */
603             gint64 seek_offset;
604             GstEvent *event;
605
606             seek_offset = entry->requested_offset > 0 ? entry->requested_offset : 
607                           find_element_get_length (entry) + entry->requested_offset;
608             seek_offset += gst_buffer_store_get_size (typefind->store, seek_offset);
609             event = gst_event_new_seek (GST_FORMAT_BYTES | GST_SEEK_METHOD_SET, seek_offset);
610             if (gst_pad_send_event (GST_PAD_PEER (typefind->sink), event)) {
611               /* done seeking */
612               GST_DEBUG_OBJECT (typefind, "'%s' was reset - seeked to %"G_GINT64_FORMAT, 
613                       GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
614               break;
615             } else if (entry->requested_offset < 0) {
616               /* impossible to seek */
617               GST_DEBUG_OBJECT (typefind, "'%s' was reset - couldn't seek to %"G_GINT64_FORMAT, 
618                       GST_PLUGIN_FEATURE_NAME (entry->factory), seek_offset);
619               entry->requested_size = 0;
620               entry->requested_offset = 0;
621             }
622           }
623         }
624         /* throw out all entries that can't get more data */
625         walk = g_list_next (typefind->possibilities);
626         while (walk) {
627           GList *cur = walk;
628           entry = (TypeFindEntry *) walk->data;
629           walk = g_list_next (walk);
630           if (entry->requested_size == 0) {
631             GST_DEBUG_OBJECT (typefind, "'%s' was removed - higher possibilities available", 
632                     GST_PLUGIN_FEATURE_NAME (entry->factory));
633             free_entry (entry);
634             typefind->possibilities = g_list_delete_link (typefind->possibilities, cur);
635           }
636         }
637         if (g_list_next (typefind->possibilities) == NULL) {
638           entry = (TypeFindEntry *) typefind->possibilities->data;
639           if (entry->probability > typefind->min_probability) {
640             GST_INFO_OBJECT (typefind, "'%s' is the only typefind left, using it now (probability %u)", 
641                     GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
642             g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0, entry->probability, entry->caps);
643             free_entry (entry);
644             g_list_free (typefind->possibilities);
645             typefind->possibilities = NULL;
646             stop_typefinding (typefind);
647           }
648         }
649       }
650       break;
651     }
652     default:
653       g_assert_not_reached ();
654       return;
655   }
656 }
657 static GstElementStateReturn
658 gst_type_find_element_change_state (GstElement *element)
659 {
660   GstTypeFindElement *typefind;
661
662   typefind = GST_TYPE_FIND_ELEMENT (element);
663
664   switch (GST_STATE_TRANSITION (element)) {
665     case GST_STATE_READY_TO_PAUSED:
666       start_typefinding (typefind);
667       break;
668     case GST_STATE_PAUSED_TO_READY:
669       stop_typefinding (typefind);
670       gst_caps_replace (&typefind->caps, NULL);
671       break;
672     default:
673       break;
674   }
675   
676   return GST_ELEMENT_CLASS (parent_class)->change_state (element);
677 }