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