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