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