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