make GstElementDetails const
[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 const 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 /* Require at least 2kB of data before we attempt typefinding in chain-mode.
86  * 128kB is massive overkill for the maximum, but doesn't do any harm */
87 #define TYPE_FIND_MIN_SIZE   (2*1024)
88 #define TYPE_FIND_MAX_SIZE (128*1024)
89
90 /* TypeFind signals and args */
91 enum
92 {
93   HAVE_TYPE,
94   LAST_SIGNAL
95 };
96 enum
97 {
98   ARG_0,
99   ARG_CAPS,
100   ARG_MINIMUM,
101   ARG_MAXIMUM
102 };
103 enum
104 {
105   MODE_NORMAL,                  /* act as identity */
106   MODE_TYPEFIND,                /* do typefinding  */
107   MODE_ERROR                    /* had fatal error */
108 };
109
110
111 #define _do_init(bla) \
112     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
113         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
114
115 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
116     GST_TYPE_ELEMENT, _do_init);
117
118 static void gst_type_find_element_dispose (GObject * object);
119 static void gst_type_find_element_set_property (GObject * object,
120     guint prop_id, const GValue * value, GParamSpec * pspec);
121 static void gst_type_find_element_get_property (GObject * object,
122     guint prop_id, GValue * value, GParamSpec * pspec);
123
124 #if 0
125 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
126 #endif
127
128 static gboolean gst_type_find_element_src_event (GstPad * pad,
129     GstEvent * event);
130 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
131
132 static gboolean gst_type_find_element_handle_event (GstPad * pad,
133     GstEvent * event);
134 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
135     GstBuffer * buffer);
136 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
137     guint64 offset, guint length, GstBuffer ** buffer);
138 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
139
140 static GstStateChangeReturn
141 gst_type_find_element_change_state (GstElement * element,
142     GstStateChange transition);
143 static gboolean gst_type_find_element_activate (GstPad * pad);
144 static gboolean
145 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
146 static GstFlowReturn
147 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
148 static void
149 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
150
151 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
152
153 static void
154 gst_type_find_element_have_type (GstTypeFindElement * typefind,
155     guint probability, const GstCaps * caps)
156 {
157   g_assert (typefind->caps == NULL);
158   g_assert (caps != NULL);
159
160   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT, caps);
161   typefind->caps = gst_caps_copy (caps);
162   gst_pad_set_caps (typefind->src, (GstCaps *) caps);
163 }
164
165 static void
166 gst_type_find_element_base_init (gpointer g_class)
167 {
168   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
169
170   gst_element_class_add_pad_template (gstelement_class,
171       gst_static_pad_template_get (&type_find_element_src_template));
172   gst_element_class_add_pad_template (gstelement_class,
173       gst_static_pad_template_get (&type_find_element_sink_template));
174   gst_element_class_set_details (gstelement_class,
175       &gst_type_find_element_details);
176 }
177 static void
178 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
179 {
180   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
181   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
182
183   gobject_class->set_property =
184       GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
185   gobject_class->get_property =
186       GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
187   gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
188
189   typefind_class->have_type = gst_type_find_element_have_type;
190
191   g_object_class_install_property (gobject_class, ARG_CAPS,
192       g_param_spec_boxed ("caps", _("caps"),
193           _("detected capabilities in stream"), gst_caps_get_type (),
194           G_PARAM_READABLE));
195   g_object_class_install_property (gobject_class, ARG_MINIMUM,
196       g_param_spec_uint ("minimum", _("minimum"),
197           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
198           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
199   g_object_class_install_property (gobject_class, ARG_MAXIMUM,
200       g_param_spec_uint ("maximum", _("maximum"),
201           "probability to stop typefinding (deprecated; non-functional)",
202           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
203           G_PARAM_READWRITE));
204   /**
205    * GstTypeFindElement::have-type:
206    * @typefind: the typefind instance
207    * @probability: the probability of the type found
208    * @caps: the caps of the type found
209    *
210    * This signal gets emitted when the type and its probability has 
211    * been found.
212    */
213   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
214       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
215       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
216       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
217       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
218
219   gstelement_class->change_state =
220       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
221 }
222 static void
223 gst_type_find_element_init (GstTypeFindElement * typefind,
224     GstTypeFindElementClass * g_class)
225 {
226   /* sinkpad */
227   typefind->sink =
228       gst_pad_new_from_static_template (&type_find_element_sink_template,
229       "sink");
230
231   gst_pad_set_activate_function (typefind->sink,
232       GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
233   gst_pad_set_chain_function (typefind->sink,
234       GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
235   gst_pad_set_event_function (typefind->sink,
236       GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
237   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
238
239   /* srcpad */
240   typefind->src =
241       gst_pad_new_from_static_template (&type_find_element_src_template, "src");
242
243   gst_pad_set_activatepull_function (typefind->src,
244       GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
245   gst_pad_set_checkgetrange_function (typefind->src,
246       GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
247   gst_pad_set_getrange_function (typefind->src,
248       GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
249   gst_pad_set_event_function (typefind->src,
250       GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
251   gst_pad_set_query_function (typefind->src,
252       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
253   gst_pad_use_fixed_caps (typefind->src);
254   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
255
256   typefind->mode = MODE_TYPEFIND;
257   typefind->caps = NULL;
258   typefind->min_probability = 1;
259   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
260
261   typefind->store = NULL;
262 }
263 static void
264 gst_type_find_element_dispose (GObject * object)
265 {
266   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
267
268   G_OBJECT_CLASS (parent_class)->dispose (object);
269
270   if (typefind->store) {
271     gst_buffer_unref (typefind->store);
272     typefind->store = NULL;
273   }
274 }
275 static void
276 gst_type_find_element_set_property (GObject * object, guint prop_id,
277     const GValue * value, GParamSpec * pspec)
278 {
279   GstTypeFindElement *typefind;
280
281   typefind = GST_TYPE_FIND_ELEMENT (object);
282
283   switch (prop_id) {
284     case ARG_MINIMUM:
285       typefind->min_probability = g_value_get_uint (value);
286       break;
287     case ARG_MAXIMUM:
288       typefind->max_probability = g_value_get_uint (value);
289       break;
290     default:
291       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
292       break;
293   }
294 }
295 static void
296 gst_type_find_element_get_property (GObject * object, guint prop_id,
297     GValue * value, GParamSpec * pspec)
298 {
299   GstTypeFindElement *typefind;
300
301   typefind = GST_TYPE_FIND_ELEMENT (object);
302
303   switch (prop_id) {
304     case ARG_CAPS:
305       g_value_set_boxed (value, typefind->caps);
306       break;
307     case ARG_MINIMUM:
308       g_value_set_uint (value, typefind->min_probability);
309       break;
310     case ARG_MAXIMUM:
311       g_value_set_uint (value, typefind->max_probability);
312       break;
313     default:
314       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
315       break;
316   }
317 }
318
319 static gboolean
320 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
321 {
322   GstTypeFindElement *typefind;
323   gboolean res = FALSE;
324   GstPad *peer;
325
326   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
327
328   peer = gst_pad_get_peer (typefind->sink);
329   if (peer == NULL)
330     return FALSE;
331
332   res = gst_pad_query (peer, query);
333   if (!res)
334     goto out;
335
336   switch (GST_QUERY_TYPE (query)) {
337     case GST_QUERY_POSITION:
338     {
339       gint64 peer_pos;
340       GstFormat format;
341
342       if (typefind->store == NULL)
343         goto out;
344
345       gst_query_parse_position (query, &format, &peer_pos);
346
347       /* FIXME: this code assumes that there's no discont in the queue */
348       switch (format) {
349         case GST_FORMAT_BYTES:
350           peer_pos -= typefind->store->size;
351           break;
352         default:
353           /* FIXME */
354           break;
355       }
356       gst_query_set_position (query, format, peer_pos);
357       break;
358     }
359     default:
360       break;
361   }
362
363 out:
364   gst_object_unref (peer);
365   return res;
366 }
367
368 #if 0
369 static const GstEventMask *
370 gst_type_find_element_src_event_mask (GstPad * pad)
371 {
372   static const GstEventMask mask[] = {
373     {GST_EVENT_SEEK,
374         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
375           GST_SEEK_FLAG_FLUSH},
376     /* add more if you want, event masks suck and need to die anyway */
377     {0,}
378   };
379
380   return mask;
381 }
382 #endif
383
384 static gboolean
385 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
386 {
387   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
388
389   if (typefind->mode != MODE_NORMAL) {
390     /* need to do more? */
391     gst_mini_object_unref (GST_MINI_OBJECT (event));
392     return FALSE;
393   }
394   return gst_pad_event_default (pad, event);
395 }
396
397 static void
398 start_typefinding (GstTypeFindElement * typefind)
399 {
400   GST_DEBUG_OBJECT (typefind, "starting typefinding");
401   gst_pad_set_caps (typefind->src, NULL);
402   if (typefind->caps) {
403     gst_caps_replace (&typefind->caps, NULL);
404   }
405   typefind->mode = MODE_TYPEFIND;
406 }
407
408 static void
409 stop_typefinding (GstTypeFindElement * typefind)
410 {
411   GstState state;
412   gboolean push_cached_buffers;
413
414   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
415
416   push_cached_buffers = (state >= GST_STATE_PAUSED);
417
418   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
419       push_cached_buffers ? " and pushing cached buffers" : "");
420
421   if (typefind->store) {
422     if (!push_cached_buffers) {
423       gst_buffer_unref (typefind->store);
424     } else {
425       GstPad *peer = gst_pad_get_peer (typefind->src);
426
427       typefind->mode = MODE_NORMAL;
428       gst_buffer_set_caps (typefind->store, typefind->caps);
429
430       /* make sure the user gets a meaningful error message in this case,
431        * which is not a core bug or bug of any kind (as the default error
432        * message emitted by gstpad.c otherwise would make you think) */
433       if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
434         GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
435             "downstream element only works in pull mode, erroring out");
436         GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
437             ("%s cannot work in push mode. The operation is not supported "
438                 "with this source element or protocol.",
439                 G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
440             ("Downstream pad %s:%s has no chainfunction, and the upstream "
441                 "element does not support pull mode",
442                 GST_DEBUG_PAD_NAME (peer)));
443         typefind->mode = MODE_ERROR;    /* make the chain function error out */
444       } else {
445         gst_type_find_element_send_cached_events (typefind);
446         gst_pad_push (typefind->src, typefind->store);
447       }
448
449       if (peer)
450         gst_object_unref (peer);
451     }
452     typefind->store = NULL;
453   }
454 }
455
456 static gboolean
457 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
458 {
459   gboolean res = FALSE;
460   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
461
462   GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
463       GST_EVENT_TYPE_NAME (event), typefind->mode);
464
465   switch (typefind->mode) {
466     case MODE_TYPEFIND:
467       switch (GST_EVENT_TYPE (event)) {
468         case GST_EVENT_EOS:{
469           GstTypeFindProbability prob = 0;
470           GstCaps *caps = NULL;
471
472           GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
473
474           /* we might not have started typefinding yet because there was not
475            * enough data so far; just give it a shot now and see what we get */
476           if (typefind->store) {
477             caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
478                 typefind->store, &prob);
479
480             if (caps && prob >= typefind->min_probability) {
481               g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
482                   0, prob, caps);
483             } else {
484               GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
485                   (NULL), (NULL));
486             }
487             gst_caps_replace (&caps, NULL);
488           }
489
490           stop_typefinding (typefind);
491           res = gst_pad_event_default (pad, event);
492           break;
493         }
494         default:
495           GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
496               GST_EVENT_TYPE_NAME (event));
497           typefind->cached_events =
498               g_list_append (typefind->cached_events, event);
499           res = TRUE;
500           break;
501       }
502       break;
503     case MODE_NORMAL:
504       res = gst_pad_event_default (pad, event);
505       break;
506     case MODE_ERROR:
507       break;
508     default:
509       g_assert_not_reached ();
510   }
511   return res;
512 }
513
514 static void
515 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
516 {
517   GList *l;
518
519   for (l = typefind->cached_events; l != NULL; l = l->next) {
520     GstEvent *event = GST_EVENT (l->data);
521
522     GST_DEBUG_OBJECT (typefind, "sending cached %s event",
523         GST_EVENT_TYPE_NAME (event));
524     gst_pad_push_event (typefind->src, event);
525   }
526   g_list_free (typefind->cached_events);
527   typefind->cached_events = NULL;
528 }
529
530 static GstFlowReturn
531 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
532 {
533   GstTypeFindElement *typefind;
534   GstFlowReturn res = GST_FLOW_OK;
535
536   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
537
538   /* Shortcircuit typefinding if we already have non-any caps */
539   if (typefind->mode == MODE_TYPEFIND) {
540     const GstCaps *caps = GST_BUFFER_CAPS (buffer);
541
542     if (caps && !gst_caps_is_any (caps)) {
543       GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
544           "upstream buffer: %" GST_PTR_FORMAT, caps);
545       typefind->mode = MODE_NORMAL;
546       g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
547           GST_TYPE_FIND_MAXIMUM, caps);
548
549       gst_type_find_element_send_cached_events (typefind);
550       if (typefind->store) {
551         GST_DEBUG_OBJECT (typefind, "Pushing store: %d",
552             GST_BUFFER_SIZE (typefind->store));
553         gst_buffer_set_caps (typefind->store, typefind->caps);
554         gst_pad_push (typefind->src, typefind->store);
555         typefind->store = NULL;
556       }
557     }
558   }
559
560   switch (typefind->mode) {
561     case MODE_ERROR:
562       /* we should already have called GST_ELEMENT_ERROR */
563       return GST_FLOW_ERROR;
564     case MODE_NORMAL:
565       gst_buffer_set_caps (buffer, typefind->caps);
566       return gst_pad_push (typefind->src, buffer);
567     case MODE_TYPEFIND:{
568       if (typefind->store)
569         typefind->store = gst_buffer_join (typefind->store, buffer);
570       else
571         typefind->store = buffer;
572
573       res = gst_type_find_element_chain_do_typefinding (typefind);
574
575       if (typefind->mode == MODE_ERROR)
576         res = GST_FLOW_ERROR;
577
578       break;
579     }
580     default:
581       g_assert_not_reached ();
582       return GST_FLOW_ERROR;
583   }
584
585   return res;
586 }
587
588 static GstFlowReturn
589 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
590 {
591   GstTypeFindProbability probability;
592   GstCaps *caps;
593
594   if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
595     GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
596         "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
597     return GST_FLOW_OK;
598   }
599
600   caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
601       typefind->store, &probability);
602
603   if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
604     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
605     stop_typefinding (typefind);
606     return GST_FLOW_ERROR;
607   } else if (caps == NULL) {
608     GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
609         "waiting for more data", GST_BUFFER_SIZE (typefind->store));
610     return GST_FLOW_OK;
611   }
612
613   /* found a type */
614   if (probability < typefind->min_probability) {
615     GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
616         "probability is %u which is lower than the required minimum of %u",
617         caps, probability, typefind->min_probability);
618
619     if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
620       GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
621       stop_typefinding (typefind);
622       return GST_FLOW_ERROR;
623     }
624
625     GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
626     return GST_FLOW_OK;
627   }
628
629   /* probability is good enough too, so let's make it known ... */
630   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
631       probability, caps);
632
633   /* .. and send out the accumulated data */
634   stop_typefinding (typefind);
635   return GST_FLOW_OK;
636 }
637
638 static gboolean
639 gst_type_find_element_checkgetrange (GstPad * srcpad)
640 {
641   GstTypeFindElement *typefind;
642
643   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
644
645   return gst_pad_check_pull_range (typefind->sink);
646 }
647
648 static GstFlowReturn
649 gst_type_find_element_getrange (GstPad * srcpad,
650     guint64 offset, guint length, GstBuffer ** buffer)
651 {
652   GstTypeFindElement *typefind;
653   GstFlowReturn ret;
654
655   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
656
657   ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
658
659   if (ret == GST_FLOW_OK && buffer && *buffer)
660     gst_buffer_set_caps (*buffer, typefind->caps);
661
662   return ret;
663 }
664
665 static gboolean
666 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
667 {
668   GstTypeFindElement *typefind;
669
670   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
671
672   return gst_pad_activate_pull (typefind->sink, active);
673 }
674
675 static gboolean
676 gst_type_find_element_activate (GstPad * pad)
677 {
678   GstTypeFindProbability probability = 0;
679   GstCaps *found_caps = NULL;
680   GstTypeFindElement *typefind;
681
682   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
683
684   /* 1. try to activate in pull mode. if not, switch to push and succeed.
685      2. try to pull type find.
686      3. deactivate pull mode.
687      4. src pad might have been activated push by the state change. deactivate.
688      5. if we didn't find any caps, fail.
689      6. emit have-type; maybe the app connected the source pad to something.
690      7. if the sink pad is activated, we are in pull mode. succeed.
691      otherwise activate both pads in push mode and succeed.
692    */
693
694   /* 1 */
695   if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
696     start_typefinding (typefind);
697     return gst_pad_activate_push (pad, TRUE);
698   }
699
700   /* 2 */
701   {
702     GstPad *peer;
703
704     peer = gst_pad_get_peer (pad);
705     if (peer) {
706       gint64 size;
707       GstFormat format = GST_FORMAT_BYTES;
708
709       if (!gst_pad_query_duration (peer, &format, &size)) {
710         GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
711         return FALSE;
712       }
713
714       found_caps = gst_type_find_helper_get_range (GST_OBJECT (peer),
715           (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
716           (guint64) size, &probability);
717
718       gst_object_unref (peer);
719     }
720   }
721
722   /* 3 */
723   gst_pad_activate_pull (pad, FALSE);
724
725   /* 4 */
726   gst_pad_activate_push (typefind->src, FALSE);
727
728   /* 5 */
729   if (!found_caps || probability < typefind->min_probability) {
730     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
731     gst_caps_replace (&found_caps, NULL);
732     return FALSE;
733   }
734
735   /* 6 */
736   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
737       0, probability, found_caps);
738   gst_caps_unref (found_caps);
739   typefind->mode = MODE_NORMAL;
740
741   /* 7 */
742   if (gst_pad_is_active (pad))
743     return TRUE;
744   else {
745     gboolean ret;
746
747     ret = gst_pad_activate_push (typefind->src, TRUE);
748     ret &= gst_pad_activate_push (pad, TRUE);
749     return ret;
750   }
751 }
752
753 static GstStateChangeReturn
754 gst_type_find_element_change_state (GstElement * element,
755     GstStateChange transition)
756 {
757   GstStateChangeReturn ret;
758   GstTypeFindElement *typefind;
759
760   typefind = GST_TYPE_FIND_ELEMENT (element);
761
762
763   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
764
765   switch (transition) {
766     case GST_STATE_CHANGE_PAUSED_TO_READY:
767       gst_caps_replace (&typefind->caps, NULL);
768       g_list_foreach (typefind->cached_events,
769           (GFunc) gst_mini_object_unref, NULL);
770       g_list_free (typefind->cached_events);
771       typefind->cached_events = NULL;
772       break;
773     default:
774       break;
775   }
776
777   return ret;
778 }