*.c: Don't cast to GST_OBJECT when reffing or unreffing. Large source-munging commit!!!
[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  * The element has two scheduling modes:
37  *
38  * 1) chain based, it will collect buffers and run the typefind function on
39  *    the buffer until something is found.
40  * 2) getrange based, it will proxy the getrange function to the sinkpad. It
41  *    is assumed that the peer element is happy with whatever format we 
42  *    eventually read.
43  *
44  * When the element has no connected srcpad, and the sinkpad can operate in
45  * getrange based mode, the element starts its own task to figure out the 
46  * type of the stream.
47  * 
48  */
49
50 #ifdef HAVE_CONFIG_H
51 #  include "config.h"
52 #endif
53
54 #include "gsttypefindelement.h"
55 #include "gst/gst_private.h"
56 #include "gst/gst-i18n-lib.h"
57 #include "gst/base/gsttypefindhelper.h"
58
59 #include <gst/gsttypefind.h>
60 #include <gst/gstutils.h>
61 #include <gst/gsterror.h>
62
63 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
64 #define GST_CAT_DEFAULT gst_type_find_element_debug
65
66 GstElementDetails gst_type_find_element_details =
67 GST_ELEMENT_DETAILS ("TypeFind",
68     "Generic",
69     "Finds the media type of a stream",
70     "Benjamin Otte <in7y118@public.uni-hamburg.de>");
71
72 /* generic templates */
73 GstStaticPadTemplate type_find_element_sink_template =
74 GST_STATIC_PAD_TEMPLATE ("sink",
75     GST_PAD_SINK,
76     GST_PAD_ALWAYS,
77     GST_STATIC_CAPS_ANY);
78
79 GstStaticPadTemplate type_find_element_src_template =
80 GST_STATIC_PAD_TEMPLATE ("src",
81     GST_PAD_SRC,
82     GST_PAD_ALWAYS,
83     GST_STATIC_CAPS_ANY);
84
85 /* TypeFind signals and args */
86 enum
87 {
88   HAVE_TYPE,
89   LAST_SIGNAL
90 };
91 enum
92 {
93   ARG_0,
94   ARG_CAPS,
95   ARG_MINIMUM,
96   ARG_MAXIMUM
97 };
98 enum
99 {
100   MODE_NORMAL,                  /* act as identity */
101   MODE_TYPEFIND                 /* do typefinding */
102 };
103
104
105 #define _do_init(bla) \
106     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
107         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
108
109 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
110     GST_TYPE_ELEMENT, _do_init);
111
112 static void gst_type_find_element_dispose (GObject * object);
113 static void gst_type_find_element_set_property (GObject * object,
114     guint prop_id, const GValue * value, GParamSpec * pspec);
115 static void gst_type_find_element_get_property (GObject * object,
116     guint prop_id, GValue * value, GParamSpec * pspec);
117
118 #if 0
119 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
120 #endif
121
122 static gboolean gst_type_find_element_src_event (GstPad * pad,
123     GstEvent * event);
124 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
125
126 static gboolean gst_type_find_element_handle_event (GstPad * pad,
127     GstEvent * event);
128 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
129     GstBuffer * buffer);
130 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
131     guint64 offset, guint length, GstBuffer ** buffer);
132 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
133
134 static GstElementStateReturn
135 gst_type_find_element_change_state (GstElement * element);
136 static gboolean gst_type_find_element_activate (GstPad * pad);
137 static gboolean
138 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
139
140 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
141
142 static void
143 gst_type_find_element_have_type (GstTypeFindElement * typefind,
144     guint probability, const GstCaps * caps)
145 {
146   g_assert (typefind->caps == NULL);
147   g_assert (caps != NULL);
148
149   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT, caps);
150   typefind->caps = gst_caps_copy (caps);
151   gst_pad_set_caps (typefind->src, (GstCaps *) caps);
152 }
153
154 static void
155 gst_type_find_element_base_init (gpointer g_class)
156 {
157   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
158
159   gst_element_class_add_pad_template (gstelement_class,
160       gst_static_pad_template_get (&type_find_element_src_template));
161   gst_element_class_add_pad_template (gstelement_class,
162       gst_static_pad_template_get (&type_find_element_sink_template));
163   gst_element_class_set_details (gstelement_class,
164       &gst_type_find_element_details);
165 }
166 static void
167 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
168 {
169   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
170   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
171
172   gobject_class->set_property =
173       GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
174   gobject_class->get_property =
175       GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
176   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
177
178   typefind_class->have_type = gst_type_find_element_have_type;
179
180   g_object_class_install_property (gobject_class, ARG_CAPS,
181       g_param_spec_boxed ("caps", _("caps"),
182           _("detected capabilities in stream"), gst_caps_get_type (),
183           G_PARAM_READABLE));
184   g_object_class_install_property (gobject_class, ARG_MINIMUM,
185       g_param_spec_uint ("minimum", _("minimum"),
186           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
187           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
188   g_object_class_install_property (gobject_class, ARG_MINIMUM,
189       g_param_spec_uint ("maximum", _("maximum"),
190           "probability to stop typefinding", GST_TYPE_FIND_MINIMUM,
191           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
192
193   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
194       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_LAST,
195       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
196       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
197       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
198
199   gstelement_class->change_state =
200       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
201 }
202 static void
203 gst_type_find_element_init (GstTypeFindElement * typefind)
204 {
205   /* sinkpad */
206   typefind->sink =
207       gst_pad_new_from_template (gst_static_pad_template_get
208       (&type_find_element_sink_template), "sink");
209   gst_pad_set_activate_function (typefind->sink,
210       gst_type_find_element_activate);
211   gst_pad_set_chain_function (typefind->sink, gst_type_find_element_chain);
212   gst_pad_set_event_function (typefind->sink,
213       gst_type_find_element_handle_event);
214   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
215   /* srcpad */
216   typefind->src =
217       gst_pad_new_from_template (gst_static_pad_template_get
218       (&type_find_element_src_template), "src");
219   gst_pad_set_activatepull_function (typefind->src,
220       gst_type_find_element_activate_src_pull);
221   gst_pad_set_checkgetrange_function (typefind->src,
222       gst_type_find_element_checkgetrange);
223   gst_pad_set_getrange_function (typefind->src, gst_type_find_element_getrange);
224   gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
225   gst_pad_set_query_function (typefind->src,
226       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
227   gst_pad_use_fixed_caps (typefind->src);
228   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
229
230   typefind->mode = MODE_TYPEFIND;
231   typefind->caps = NULL;
232   typefind->min_probability = 1;
233   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
234
235   typefind->store = NULL;
236 }
237 static void
238 gst_type_find_element_dispose (GObject * object)
239 {
240   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
241
242   G_OBJECT_CLASS (parent_class)->dispose (object);
243
244   if (typefind->store) {
245     gst_buffer_unref (typefind->store);
246     typefind->store = NULL;
247   }
248 }
249 static void
250 gst_type_find_element_set_property (GObject * object, guint prop_id,
251     const GValue * value, GParamSpec * pspec)
252 {
253   GstTypeFindElement *typefind;
254
255   g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
256
257   typefind = GST_TYPE_FIND_ELEMENT (object);
258
259   switch (prop_id) {
260     case ARG_MINIMUM:
261       typefind->min_probability = g_value_get_uint (value);
262       g_object_notify (object, "minimum");
263       break;
264     case ARG_MAXIMUM:
265       typefind->max_probability = g_value_get_uint (value);
266       g_object_notify (object, "maximum");
267       break;
268     default:
269       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
270       break;
271   }
272 }
273 static void
274 gst_type_find_element_get_property (GObject * object, guint prop_id,
275     GValue * value, GParamSpec * pspec)
276 {
277   GstTypeFindElement *typefind;
278
279   g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
280
281   typefind = GST_TYPE_FIND_ELEMENT (object);
282
283   switch (prop_id) {
284     case ARG_CAPS:
285       g_value_set_boxed (value, typefind->caps);
286       break;
287     case ARG_MINIMUM:
288       g_value_set_uint (value, typefind->min_probability);
289       break;
290     case ARG_MAXIMUM:
291       g_value_set_uint (value, typefind->max_probability);
292       break;
293     default:
294       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
295       break;
296   }
297 }
298
299 static gboolean
300 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
301 {
302   GstTypeFindElement *typefind;
303   gboolean res;
304
305   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
306
307   res = gst_pad_query (GST_PAD_PEER (typefind->sink), query);
308   if (!res)
309     return FALSE;
310
311   switch (GST_QUERY_TYPE (query)) {
312     case GST_QUERY_POSITION:
313     {
314       gint64 peer_pos, peer_total;
315       GstFormat format;
316
317       if (typefind->store == NULL)
318         return TRUE;
319
320       gst_query_parse_position (query, &format, &peer_pos, &peer_total);
321
322       /* FIXME: this code assumes that there's no discont in the queue */
323       switch (format) {
324         case GST_FORMAT_BYTES:
325           peer_pos -= typefind->store->size;
326           break;
327         default:
328           /* FIXME */
329           break;
330       }
331       gst_query_set_position (query, format, peer_pos, peer_total);
332       break;
333     }
334     default:
335       break;
336   }
337
338   return TRUE;
339 }
340
341 #if 0
342 static const GstEventMask *
343 gst_type_find_element_src_event_mask (GstPad * pad)
344 {
345   static const GstEventMask mask[] = {
346     {GST_EVENT_SEEK,
347         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
348           GST_SEEK_FLAG_FLUSH},
349     /* add more if you want, event masks suck and need to die anyway */
350     {0,}
351   };
352
353   return mask;
354 }
355 #endif
356
357 static gboolean
358 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
359 {
360   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
361
362   if (typefind->mode != MODE_NORMAL) {
363     /* need to do more? */
364     gst_mini_object_unref (GST_MINI_OBJECT (event));
365     return FALSE;
366   }
367   return gst_pad_event_default (pad, event);
368 }
369 typedef struct
370 {
371   GstTypeFindFactory *factory;
372   gint probability;
373   GstCaps *caps;
374   guint requested_size;
375   GstTypeFindElement *self;
376 }
377 TypeFindEntry;
378
379 static inline TypeFindEntry *
380 new_entry (void)
381 {
382   return g_new0 (TypeFindEntry, 1);
383 }
384 static void
385 free_entry (TypeFindEntry * entry)
386 {
387   if (entry->caps)
388     gst_caps_unref (entry->caps);
389   g_free (entry);
390 }
391 static void
392 start_typefinding (GstTypeFindElement * typefind)
393 {
394   g_assert (typefind->possibilities == NULL);
395
396   GST_DEBUG_OBJECT (typefind, "starting typefinding");
397   gst_pad_set_caps (typefind->src, NULL);
398   if (typefind->caps) {
399     gst_caps_replace (&typefind->caps, NULL);
400   }
401   typefind->mode = MODE_TYPEFIND;
402   typefind->stream_length_available = TRUE;
403   typefind->stream_length = 0;
404 }
405 static void
406 stop_typefinding (GstTypeFindElement * typefind)
407 {
408   GstElementState state;
409   gboolean push_cached_buffers;
410
411   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, NULL);
412
413   push_cached_buffers = (state >= GST_STATE_PAUSED);
414
415   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
416       push_cached_buffers ? " and pushing cached buffers" : "");
417   if (typefind->possibilities != NULL) {
418     /* this should only happen on PAUSED => READY or EOS */
419     GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
420         g_list_length (typefind->possibilities));
421     g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
422     g_list_free (typefind->possibilities);
423     typefind->possibilities = NULL;
424   }
425   //typefind->mode = MODE_TRANSITION;
426
427   if (typefind->store) {
428     if (!push_cached_buffers) {
429       gst_buffer_unref (typefind->store);
430     } else {
431       typefind->mode = MODE_NORMAL;
432       gst_pad_push (typefind->src, typefind->store);
433     }
434     typefind->store = NULL;
435   }
436 }
437
438 static guint64
439 find_element_get_length (gpointer data)
440 {
441   TypeFindEntry *entry = (TypeFindEntry *) data;
442   GstTypeFindElement *typefind = entry->self;
443   GstFormat format = GST_FORMAT_BYTES;
444
445   if (!typefind->stream_length_available) {
446     GST_LOG_OBJECT (entry->self,
447         "'%s' called get_length () but we know it's not available",
448         GST_PLUGIN_FEATURE_NAME (entry->factory));
449     return 0;
450   }
451   if (entry->self->stream_length == 0) {
452     if (!gst_pad_query_position (GST_PAD_PEER (entry->self->sink), &format,
453             NULL, (gint64 *) & entry->self->stream_length))
454       goto no_length;
455
456     if (format != GST_FORMAT_BYTES) {
457       typefind->stream_length_available = FALSE;
458       entry->self->stream_length = 0;
459     } else {
460       GST_DEBUG_OBJECT (entry->self,
461           "'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
462           GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
463     }
464   }
465   return entry->self->stream_length;
466
467 no_length:
468   {
469     typefind->stream_length_available = FALSE;
470     GST_DEBUG_OBJECT (entry->self,
471         "'%s' called get_length () but it's not available",
472         GST_PLUGIN_FEATURE_NAME (entry->factory));
473     return 0;
474   }
475 }
476
477 static gboolean
478 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
479 {
480   gboolean res = FALSE;
481   TypeFindEntry *entry;
482   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
483
484   GST_DEBUG_OBJECT (typefind, "got event %d in mode %d", GST_EVENT_TYPE (event),
485       typefind->mode);
486
487   switch (typefind->mode) {
488     case MODE_TYPEFIND:
489       switch (GST_EVENT_TYPE (event)) {
490         case GST_EVENT_EOS:
491           /* this should only happen when we got all available data */
492           entry =
493               (TypeFindEntry *) typefind->possibilities ? typefind->
494               possibilities->data : NULL;
495           if (entry && entry->probability >= typefind->min_probability) {
496             GST_INFO_OBJECT (typefind,
497                 "'%s' is the best typefind left after we got all data, using it now (probability %u)",
498                 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
499             g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
500                 0, entry->probability, entry->caps);
501             stop_typefinding (typefind);
502             gst_pad_push (typefind->src, typefind->store);
503             typefind->store = NULL;
504             res = gst_pad_event_default (pad, event);
505           } else {
506             res = gst_pad_event_default (pad, event);
507             GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL),
508                 (NULL));
509             stop_typefinding (typefind);
510           }
511           break;
512         default:
513           gst_mini_object_unref (GST_MINI_OBJECT (event));
514           res = TRUE;
515           break;
516       }
517       break;
518     case MODE_NORMAL:
519       if (FALSE) {              // GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) {
520         start_typefinding (typefind);
521         gst_event_unref (event);
522         res = TRUE;
523       } else {
524         res = gst_pad_event_default (pad, event);
525       }
526       break;
527     default:
528       g_assert_not_reached ();
529   }
530   return res;
531 }
532 static guint8 *
533 find_peek (gpointer data, gint64 offset, guint size)
534 {
535   TypeFindEntry *entry = (TypeFindEntry *) data;
536
537   GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
538       GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
539   if (offset != 0)
540     return NULL;
541
542   if (size <= entry->self->store->size) {
543     return GST_BUFFER_DATA (entry->self->store);
544   } else {
545     entry->requested_size = size;
546
547     GST_LOG_OBJECT (entry->self,
548         "setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
549         size, GST_PLUGIN_FEATURE_NAME (entry->factory));
550     return NULL;
551   }
552 }
553 static void
554 find_suggest (gpointer data, guint probability, const GstCaps * caps)
555 {
556   TypeFindEntry *entry = (TypeFindEntry *) data;
557
558   GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
559       GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
560   if (((gint) probability) > entry->probability) {
561     entry->probability = probability;
562     gst_caps_replace (&entry->caps, (GstCaps *) caps);
563   }
564 }
565
566 #if 0
567 static gint
568 compare_type_find_entry (gconstpointer a, gconstpointer b)
569 {
570   TypeFindEntry *one = (TypeFindEntry *) a;
571   TypeFindEntry *two = (TypeFindEntry *) b;
572
573   if (one->probability == two->probability) {
574     /* FIXME: can be improved by analyzing requests */
575     return 0;
576   } else {
577     return two->probability - one->probability;
578   }
579 }
580 #endif
581
582 static gint
583 compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
584 {
585   return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
586 }
587
588 static GstFlowReturn
589 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
590 {
591   GstTypeFindElement *typefind;
592   GList *entries;
593   TypeFindEntry *entry;
594   GList *walk;
595   GstFlowReturn res = GST_FLOW_OK;
596   GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
597
598   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
599
600   switch (typefind->mode) {
601     case MODE_NORMAL:
602       return gst_pad_push (typefind->src, buffer);
603     case MODE_TYPEFIND:{
604       gboolean done = TRUE;
605
606       if (typefind->store)
607         typefind->store = gst_buffer_join (typefind->store, buffer);
608       else
609         typefind->store = buffer;
610
611       if (typefind->possibilities == NULL) {
612         /* not yet started, get all typefinding functions into our "queue" */
613         GList *all_factories = gst_type_find_factory_get_list ();
614
615         GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
616             g_list_length (all_factories));
617
618         all_factories = g_list_sort (all_factories, compare_type_find_factory);
619         walk = all_factories;
620         while (all_factories) {
621           entry = new_entry ();
622
623           entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
624           entry->self = typefind;
625           entry->probability = 0;
626           typefind->possibilities =
627               g_list_prepend (typefind->possibilities, entry);
628           all_factories = g_list_next (all_factories);
629         }
630         g_list_free (all_factories);
631       }
632
633       /* call every typefind function once */
634       walk = entries = typefind->possibilities;
635       GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
636           g_list_length (entries));
637       typefind->possibilities = NULL;
638       while (walk) {
639         find.data = entry = (TypeFindEntry *) walk->data;
640         walk = g_list_next (walk);
641         if (entry->probability == 0) {
642           entry->requested_size = 0;
643           gst_type_find_factory_call_function (entry->factory, &find);
644         } else {
645           typefind->possibilities =
646               g_list_prepend (typefind->possibilities, entry);
647           continue;
648         }
649         if (entry->probability == 0 && entry->requested_size == 0) {
650           GST_DEBUG_OBJECT (typefind,
651               "'%s' was removed - no chance of being the right plugin",
652               GST_PLUGIN_FEATURE_NAME (entry->factory));
653           free_entry (entry);
654         } else if (entry->probability >= typefind->max_probability) {
655           /* wooha, got caps */
656           GstCaps *found_caps = entry->caps;
657           guint probability = entry->probability;
658
659           GST_INFO_OBJECT (typefind,
660               "'%s' returned %u/%u probability, using it NOW",
661               GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
662               typefind->max_probability);
663           while (walk) {
664             free_entry ((TypeFindEntry *) walk->data);
665             walk = g_list_next (walk);
666           }
667           walk = typefind->possibilities;
668           while (walk) {
669             free_entry (walk->data);
670             walk = g_list_next (walk);
671           }
672           g_list_free (typefind->possibilities);
673           typefind->possibilities = NULL;
674           g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
675               probability, found_caps);
676           free_entry (entry);
677         } else {
678           typefind->possibilities =
679               g_list_prepend (typefind->possibilities, entry);
680           if (entry->requested_size != 0)
681             done = FALSE;
682         }
683       }
684       g_list_free (entries);
685
686       /* we may now already have caps or we might be left without functions to try */
687       if (typefind->caps) {
688         stop_typefinding (typefind);
689       } else if (typefind->possibilities == NULL) {
690         GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
691         stop_typefinding (typefind);
692         return GST_FLOW_ERROR;
693       } else if (done) {
694         TypeFindEntry *best = NULL;
695
696         walk = typefind->possibilities;
697         while (walk) {
698           entry = (TypeFindEntry *) typefind->possibilities->data;
699           if ((!best || entry->probability > best->probability) &&
700               entry->probability >= typefind->min_probability) {
701             best = entry;
702           }
703           walk = g_list_next (walk);
704         }
705
706         if (best) {
707           GST_INFO_OBJECT (typefind,
708               "'%s' is the only typefind left, using it now (probability %u)",
709               GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
710           g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
711               0, entry->probability, entry->caps);
712           g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
713           g_list_free (typefind->possibilities);
714           typefind->possibilities = NULL;
715           stop_typefinding (typefind);
716         } else {
717           GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
718           stop_typefinding (typefind);
719           return GST_FLOW_ERROR;
720         }
721       }
722       break;
723     }
724     default:
725       g_assert_not_reached ();
726       return GST_FLOW_ERROR;
727   }
728
729   return res;
730 }
731
732 static gboolean
733 gst_type_find_element_checkgetrange (GstPad * srcpad)
734 {
735   GstTypeFindElement *typefind;
736
737   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
738
739   return gst_pad_check_pull_range (typefind->sink);
740 }
741
742 static GstFlowReturn
743 gst_type_find_element_getrange (GstPad * srcpad,
744     guint64 offset, guint length, GstBuffer ** buffer)
745 {
746   GstTypeFindElement *typefind;
747
748   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
749
750   return gst_pad_pull_range (typefind->sink, offset, length, buffer);
751 }
752
753 static gboolean
754 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
755 {
756   GstTypeFindElement *typefind;
757
758   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
759
760   return gst_pad_activate_pull (typefind->sink, active);
761 }
762
763 static gboolean
764 gst_type_find_element_activate (GstPad * pad)
765 {
766   GstCaps *found_caps = NULL;
767   GstTypeFindElement *typefind;
768
769   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
770
771   /* 1. try to activate in pull mode. if not, switch to push and succeed.
772      2. try to pull type find.
773      3. deactivate pull mode.
774      4. src pad might have been activated push by the state change. deactivate.
775      5. if we didn't find any caps, fail.
776      6. emit have-type; maybe the app connected the source pad to something.
777      7. if the sink pad is activated, we are in pull mode. succeed.
778      otherwise activate both pads in push mode and succeed.
779    */
780
781   /* 1 */
782   if (!gst_pad_activate_pull (pad, TRUE)) {
783     start_typefinding (typefind);
784     return gst_pad_activate_push (pad, TRUE);
785   }
786
787   /* 2 */
788   {
789     GstPad *peer;
790
791     peer = gst_pad_get_peer (pad);
792     if (peer) {
793       gint64 size;
794       GstFormat format = GST_FORMAT_BYTES;
795
796       gst_pad_query_position (peer, &format, NULL, &size);
797       found_caps = gst_type_find_helper (peer, (guint64) size);
798       gst_object_unref (peer);
799     }
800   }
801
802   /* 3 */
803   gst_pad_activate_pull (pad, FALSE);
804
805   /* 4 */
806   gst_pad_activate_push (typefind->src, FALSE);
807
808   /* 5 */
809   if (!found_caps)
810     return FALSE;
811
812   /* 6 */
813   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
814       0, 100, found_caps);
815   typefind->mode = MODE_NORMAL;
816   /* FIXME see if I can unref the caps here */
817
818   /* 7 */
819   if (gst_pad_is_active (pad))
820     return TRUE;
821   else {
822     gboolean ret;
823
824     ret = gst_pad_activate_push (typefind->src, TRUE);
825     ret &= gst_pad_activate_push (pad, TRUE);
826     return ret;
827   }
828 }
829
830 static GstElementStateReturn
831 gst_type_find_element_change_state (GstElement * element)
832 {
833   GstElementState transition;
834   GstElementStateReturn ret;
835   GstTypeFindElement *typefind;
836
837   typefind = GST_TYPE_FIND_ELEMENT (element);
838
839   transition = GST_STATE_TRANSITION (element);
840
841   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
842
843   switch (transition) {
844     case GST_STATE_PAUSED_TO_READY:
845       gst_caps_replace (&typefind->caps, NULL);
846       break;
847     default:
848       break;
849   }
850
851   return ret;
852 }