]> Gitweb @ Texas Instruments - Open Source Git Repositories - git.TI.com/gitweb - glsdk/gstreamer0-10.git/blob - plugins/elements/gsttypefindelement.c
0a32c6b395fc0408c848f5d290d2c2abda946a90
[glsdk/gstreamer0-10.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  * SECTION:element-typefind
23  *
24  * Determines the media-type of a stream. It applies typefind functions in the
25  * order of their rank. One the type has been deteted it sets its src pad caps
26  * to the found media type.
27  *
28  * Plugins can register custom typefinders by using #GstTypeFindFactory.
29  */
31 /* FIXME: need a better solution for non-seekable streams */
33 /* way of operation:
34  * 1) get a list of all typefind functions sorted best to worst
35  * 2) if all elements have been called with all requested data goto 8
36  * 3) call all functions once with all available data
37  * 4) if a function returns a value >= PROP_MAXIMUM goto 8
38  * 5) all functions with a result > PROP_MINIMUM or functions that did not get
39  *    all requested data (where peek returned NULL) stay in list
40  * 6) seek to requested offset of best function that still has open data
41  *    requests
42  * 7) goto 2
43  * 8) take best available result and use its caps
44  *
45  * The element has two scheduling modes:
46  *
47  * 1) chain based, it will collect buffers and run the typefind function on
48  *    the buffer until something is found.
49  * 2) getrange based, it will proxy the getrange function to the sinkpad. It
50  *    is assumed that the peer element is happy with whatever format we
51  *    eventually read.
52  *
53  * When the element has no connected srcpad, and the sinkpad can operate in
54  * getrange based mode, the element starts its own task to figure out the
55  * type of the stream.
56  *
57  */
59 #ifdef HAVE_CONFIG_H
60 #  include "config.h"
61 #endif
63 #include "gsttypefindelement.h"
64 #include "gst/gst_private.h"
65 #include "gst/gst-i18n-lib.h"
66 #include "gst/base/gsttypefindhelper.h"
68 #include <gst/gsttypefind.h>
69 #include <gst/gstutils.h>
70 #include <gst/gsterror.h>
72 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
73 #define GST_CAT_DEFAULT gst_type_find_element_debug
75 /* generic templates */
76 static GstStaticPadTemplate type_find_element_sink_template =
77 GST_STATIC_PAD_TEMPLATE ("sink",
78     GST_PAD_SINK,
79     GST_PAD_ALWAYS,
80     GST_STATIC_CAPS_ANY);
82 static GstStaticPadTemplate type_find_element_src_template =
83 GST_STATIC_PAD_TEMPLATE ("src",
84     GST_PAD_SRC,
85     GST_PAD_ALWAYS,
86     GST_STATIC_CAPS_ANY);
88 /* Require at least 2kB of data before we attempt typefinding in chain-mode.
89  * 128kB is massive overkill for the maximum, but doesn't do any harm */
90 #define TYPE_FIND_MIN_SIZE   (2*1024)
91 #define TYPE_FIND_MAX_SIZE (128*1024)
93 /* TypeFind signals and args */
94 enum
95 {
96   HAVE_TYPE,
97   LAST_SIGNAL
98 };
99 enum
101   PROP_0,
102   PROP_CAPS,
103   PROP_MINIMUM,
104   PROP_MAXIMUM,
105   PROP_FORCE_CAPS,
106   PROP_LAST
107 };
108 enum
110   MODE_NORMAL,                  /* act as identity */
111   MODE_TYPEFIND,                /* do typefinding  */
112   MODE_ERROR                    /* had fatal error */
113 };
116 #define _do_init(bla) \
117     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
118         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
120 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
121     GST_TYPE_ELEMENT, _do_init);
123 static void gst_type_find_element_dispose (GObject * object);
124 static void gst_type_find_element_set_property (GObject * object,
125     guint prop_id, const GValue * value, GParamSpec * pspec);
126 static void gst_type_find_element_get_property (GObject * object,
127     guint prop_id, GValue * value, GParamSpec * pspec);
129 #if 0
130 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
131 #endif
133 static gboolean gst_type_find_element_src_event (GstPad * pad,
134     GstEvent * event);
135 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
137 static gboolean gst_type_find_element_handle_event (GstPad * pad,
138     GstEvent * event);
139 static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
140 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
141     GstBuffer * buffer);
142 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
143     guint64 offset, guint length, GstBuffer ** buffer);
144 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
146 static GstStateChangeReturn
147 gst_type_find_element_change_state (GstElement * element,
148     GstStateChange transition);
149 static gboolean gst_type_find_element_activate (GstPad * pad);
150 static gboolean
151 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
152 static GstFlowReturn
153 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
154 static void
155 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
157 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
159 static void
160 gst_type_find_element_have_type (GstTypeFindElement * typefind,
161     guint probability, const GstCaps * caps)
163   g_assert (caps != NULL);
165   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
166       caps, probability);
167   if (typefind->caps)
168     gst_caps_unref (typefind->caps);
169   typefind->caps = gst_caps_copy (caps);
170   gst_pad_set_caps (typefind->src, (GstCaps *) caps);
173 static void
174 gst_type_find_element_base_init (gpointer g_class)
176   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
178   gst_element_class_set_details_simple (gstelement_class,
179       "TypeFind",
180       "Generic",
181       "Finds the media type of a stream",
182       "Benjamin Otte <in7y118@public.uni-hamburg.de>");
183   gst_element_class_add_pad_template (gstelement_class,
184       gst_static_pad_template_get (&type_find_element_src_template));
185   gst_element_class_add_pad_template (gstelement_class,
186       gst_static_pad_template_get (&type_find_element_sink_template));
189 static void
190 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
192   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
193   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
195   gobject_class->set_property = gst_type_find_element_set_property;
196   gobject_class->get_property = gst_type_find_element_get_property;
197   gobject_class->dispose = gst_type_find_element_dispose;
199   g_object_class_install_property (gobject_class, PROP_CAPS,
200       g_param_spec_boxed ("caps", _("caps"),
201           _("detected capabilities in stream"), gst_caps_get_type (),
202           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
203   g_object_class_install_property (gobject_class, PROP_MINIMUM,
204       g_param_spec_uint ("minimum", _("minimum"),
205           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
206           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
207           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
208   g_object_class_install_property (gobject_class, PROP_MAXIMUM,
209       g_param_spec_uint ("maximum", _("maximum"),
210           "probability to stop typefinding (deprecated; non-functional)",
211           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213   g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
214       g_param_spec_boxed ("force-caps", _("force caps"),
215           _("force caps without doing a typefind"), gst_caps_get_type (),
216           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
217   /**
218    * GstTypeFindElement::have-type:
219    * @typefind: the typefind instance
220    * @probability: the probability of the type found
221    * @caps: the caps of the type found
222    *
223    * This signal gets emitted when the type and its probability has 
224    * been found.
225    */
226   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
227       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
228       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
229       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
230       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
232   typefind_class->have_type =
233       GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
235   gstelement_class->change_state =
236       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
239 static void
240 gst_type_find_element_init (GstTypeFindElement * typefind,
241     GstTypeFindElementClass * g_class)
243   /* sinkpad */
244   typefind->sink =
245       gst_pad_new_from_static_template (&type_find_element_sink_template,
246       "sink");
248   gst_pad_set_activate_function (typefind->sink,
249       GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
250   gst_pad_set_setcaps_function (typefind->sink,
251       GST_DEBUG_FUNCPTR (gst_type_find_element_setcaps));
252   gst_pad_set_chain_function (typefind->sink,
253       GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
254   gst_pad_set_event_function (typefind->sink,
255       GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
256   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
258   /* srcpad */
259   typefind->src =
260       gst_pad_new_from_static_template (&type_find_element_src_template, "src");
262   gst_pad_set_activatepull_function (typefind->src,
263       GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
264   gst_pad_set_checkgetrange_function (typefind->src,
265       GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
266   gst_pad_set_getrange_function (typefind->src,
267       GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
268   gst_pad_set_event_function (typefind->src,
269       GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
270   gst_pad_set_query_function (typefind->src,
271       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
272   gst_pad_use_fixed_caps (typefind->src);
273   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
275   typefind->mode = MODE_TYPEFIND;
276   typefind->caps = NULL;
277   typefind->min_probability = 1;
278   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
280   typefind->store = NULL;
283 static void
284 gst_type_find_element_dispose (GObject * object)
286   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
288   if (typefind->store) {
289     gst_buffer_unref (typefind->store);
290     typefind->store = NULL;
291   }
292   if (typefind->force_caps) {
293     gst_caps_unref (typefind->force_caps);
294     typefind->force_caps = NULL;
295   }
297   G_OBJECT_CLASS (parent_class)->dispose (object);
300 static void
301 gst_type_find_element_set_property (GObject * object, guint prop_id,
302     const GValue * value, GParamSpec * pspec)
304   GstTypeFindElement *typefind;
306   typefind = GST_TYPE_FIND_ELEMENT (object);
308   switch (prop_id) {
309     case PROP_MINIMUM:
310       typefind->min_probability = g_value_get_uint (value);
311       break;
312     case PROP_MAXIMUM:
313       typefind->max_probability = g_value_get_uint (value);
314       break;
315     case PROP_FORCE_CAPS:
316       GST_OBJECT_LOCK (typefind);
317       if (typefind->force_caps)
318         gst_caps_unref (typefind->force_caps);
319       typefind->force_caps = g_value_dup_boxed (value);
320       GST_OBJECT_UNLOCK (typefind);
321       break;
322     default:
323       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
324       break;
325   }
328 static void
329 gst_type_find_element_get_property (GObject * object, guint prop_id,
330     GValue * value, GParamSpec * pspec)
332   GstTypeFindElement *typefind;
334   typefind = GST_TYPE_FIND_ELEMENT (object);
336   switch (prop_id) {
337     case PROP_CAPS:
338       g_value_set_boxed (value, typefind->caps);
339       break;
340     case PROP_MINIMUM:
341       g_value_set_uint (value, typefind->min_probability);
342       break;
343     case PROP_MAXIMUM:
344       g_value_set_uint (value, typefind->max_probability);
345       break;
346     case PROP_FORCE_CAPS:
347       GST_OBJECT_LOCK (typefind);
348       g_value_set_boxed (value, typefind->force_caps);
349       GST_OBJECT_UNLOCK (typefind);
350       break;
351     default:
352       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
353       break;
354   }
357 static gboolean
358 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
360   GstTypeFindElement *typefind;
361   gboolean res = FALSE;
362   GstPad *peer;
364   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
366   peer = gst_pad_get_peer (typefind->sink);
367   if (peer == NULL)
368     return FALSE;
370   res = gst_pad_query (peer, query);
371   if (!res)
372     goto out;
374   switch (GST_QUERY_TYPE (query)) {
375     case GST_QUERY_POSITION:
376     {
377       gint64 peer_pos;
378       GstFormat format;
380       if (typefind->store == NULL)
381         goto out;
383       gst_query_parse_position (query, &format, &peer_pos);
385       /* FIXME: this code assumes that there's no discont in the queue */
386       switch (format) {
387         case GST_FORMAT_BYTES:
388           peer_pos -= GST_BUFFER_SIZE (typefind->store);
389           break;
390         default:
391           /* FIXME */
392           break;
393       }
394       gst_query_set_position (query, format, peer_pos);
395       break;
396     }
397     default:
398       break;
399   }
401 out:
402   gst_object_unref (peer);
403   return res;
406 #if 0
407 static const GstEventMask *
408 gst_type_find_element_src_event_mask (GstPad * pad)
410   static const GstEventMask mask[] = {
411     {GST_EVENT_SEEK,
412         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
413           GST_SEEK_FLAG_FLUSH},
414     /* add more if you want, event masks suck and need to die anyway */
415     {0,}
416   };
418   return mask;
420 #endif
422 static gboolean
423 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
425   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
427   if (typefind->mode != MODE_NORMAL) {
428     /* need to do more? */
429     gst_mini_object_unref (GST_MINI_OBJECT (event));
430     return FALSE;
431   }
432   return gst_pad_push_event (typefind->sink, event);
435 static void
436 start_typefinding (GstTypeFindElement * typefind)
438   GST_DEBUG_OBJECT (typefind, "starting typefinding");
439   gst_pad_set_caps (typefind->src, NULL);
440   if (typefind->caps) {
441     gst_caps_replace (&typefind->caps, NULL);
442   }
443   typefind->mode = MODE_TYPEFIND;
446 static void
447 stop_typefinding (GstTypeFindElement * typefind)
449   GstState state;
450   gboolean push_cached_buffers;
452   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
454   push_cached_buffers = (state >= GST_STATE_PAUSED);
456   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
457       push_cached_buffers ? " and pushing cached buffers" : "");
459   if (typefind->store) {
460     if (!push_cached_buffers) {
461       gst_buffer_unref (typefind->store);
462     } else {
463       GstPad *peer = gst_pad_get_peer (typefind->src);
465       typefind->mode = MODE_NORMAL;
466       gst_buffer_set_caps (typefind->store, typefind->caps);
468       /* make sure the user gets a meaningful error message in this case,
469        * which is not a core bug or bug of any kind (as the default error
470        * message emitted by gstpad.c otherwise would make you think) */
471       if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
472         GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
473             "downstream element only works in pull mode, erroring out");
474         GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
475             ("%s cannot work in push mode. The operation is not supported "
476                 "with this source element or protocol.",
477                 G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
478             ("Downstream pad %s:%s has no chainfunction, and the upstream "
479                 "element does not support pull mode",
480                 GST_DEBUG_PAD_NAME (peer)));
481         typefind->mode = MODE_ERROR;    /* make the chain function error out */
482       } else {
483         gst_type_find_element_send_cached_events (typefind);
484         gst_pad_push (typefind->src, typefind->store);
485       }
487       if (peer)
488         gst_object_unref (peer);
489     }
490     typefind->store = NULL;
491   }
494 static gboolean
495 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
497   gboolean res = FALSE;
498   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
500   GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
501       GST_EVENT_TYPE_NAME (event), typefind->mode);
503   switch (typefind->mode) {
504     case MODE_TYPEFIND:
505       switch (GST_EVENT_TYPE (event)) {
506         case GST_EVENT_EOS:{
507           GstTypeFindProbability prob = 0;
508           GstCaps *caps = NULL;
510           GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
512           /* we might not have started typefinding yet because there was not
513            * enough data so far; just give it a shot now and see what we get */
514           if (typefind->store) {
515             caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
516                 typefind->store, &prob);
518             if (caps && prob >= typefind->min_probability) {
519               g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
520                   0, prob, caps);
521             } else {
522               GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
523                   (NULL), (NULL));
524             }
525             gst_caps_replace (&caps, NULL);
526           } else {
527             /* keep message in sync with the one in the pad activate function */
528             GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
529                 (_("Stream contains no data.")),
530                 ("Can't typefind empty stream"));
531           }
533           stop_typefinding (typefind);
534           res = gst_pad_push_event (typefind->src, event);
535           break;
536         }
537         case GST_EVENT_FLUSH_STOP:
538           g_list_foreach (typefind->cached_events,
539               (GFunc) gst_mini_object_unref, NULL);
540           g_list_free (typefind->cached_events);
541           typefind->cached_events = NULL;
542           gst_buffer_replace (&typefind->store, NULL);
543           /* fall through */
544         case GST_EVENT_FLUSH_START:
545           res = gst_pad_push_event (typefind->src, event);
546           break;
547         default:
548           GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
549               GST_EVENT_TYPE_NAME (event));
550           typefind->cached_events =
551               g_list_append (typefind->cached_events, event);
552           res = TRUE;
553           break;
554       }
555       break;
556     case MODE_NORMAL:
557       res = gst_pad_push_event (typefind->src, event);
558       break;
559     case MODE_ERROR:
560       break;
561     default:
562       g_assert_not_reached ();
563   }
564   return res;
567 static void
568 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
570   GList *l;
572   for (l = typefind->cached_events; l != NULL; l = l->next) {
573     GstEvent *event = GST_EVENT (l->data);
575     GST_DEBUG_OBJECT (typefind, "sending cached %s event",
576         GST_EVENT_TYPE_NAME (event));
577     gst_pad_push_event (typefind->src, event);
578   }
579   g_list_free (typefind->cached_events);
580   typefind->cached_events = NULL;
583 static gboolean
584 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
586   GstTypeFindElement *typefind;
588   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
590   /* don't operate on ANY caps */
591   if (gst_caps_is_any (caps))
592     return TRUE;
594   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
595       GST_TYPE_FIND_MAXIMUM, caps);
597   /* Shortcircuit typefinding if we get caps */
598   if (typefind->mode == MODE_TYPEFIND) {
599     GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
600         "upstream buffer: %" GST_PTR_FORMAT, caps);
601     typefind->mode = MODE_NORMAL;
603     gst_type_find_element_send_cached_events (typefind);
604     if (typefind->store) {
605       GST_DEBUG_OBJECT (typefind, "Pushing store: %d",
606           GST_BUFFER_SIZE (typefind->store));
607       gst_buffer_set_caps (typefind->store, typefind->caps);
608       gst_pad_push (typefind->src, typefind->store);
609       typefind->store = NULL;
610     }
611   }
613   return TRUE;
616 static gchar *
617 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
619   GstQuery *query;
620   gchar *uri, *result;
621   size_t len;
622   gint find;
624   query = gst_query_new_uri ();
626   /* try getting the caps with an uri query and from the extension */
627   if (!gst_pad_peer_query (pad, query))
628     goto peer_query_failed;
630   gst_query_parse_uri (query, &uri);
631   if (uri == NULL)
632     goto no_uri;
634   GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
636   /* find the extension on the uri, this is everything after a '.' */
637   len = strlen (uri);
638   find = len - 1;
640   while (find >= 0) {
641     if (uri[find] == '.')
642       break;
643     find--;
644   }
645   if (find < 0)
646     goto no_extension;
648   result = g_strdup (&uri[find + 1]);
650   GST_DEBUG_OBJECT (typefind, "found extension %s", result);
651   gst_query_unref (query);
653   return result;
655   /* ERRORS */
656 peer_query_failed:
657   {
658     GST_WARNING_OBJECT (typefind, "failed to query peer uri");
659     gst_query_unref (query);
660     return NULL;
661   }
662 no_uri:
663   {
664     GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
665     gst_query_unref (query);
666     return NULL;
667   }
668 no_extension:
669   {
670     GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
671     gst_query_unref (query);
672     return NULL;
673   }
676 static GstCaps *
677 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
678     GstTypeFindProbability * probability)
680   gchar *ext;
681   GstCaps *caps;
683   ext = gst_type_find_get_extension (typefind, pad);
684   if (!ext)
685     return NULL;
687   caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
688   if (caps)
689     *probability = GST_TYPE_FIND_MAXIMUM;
691   g_free (ext);
693   return caps;
696 static GstFlowReturn
697 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
699   GstTypeFindElement *typefind;
700   GstFlowReturn res = GST_FLOW_OK;
702   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
704   switch (typefind->mode) {
705     case MODE_ERROR:
706       /* we should already have called GST_ELEMENT_ERROR */
707       return GST_FLOW_ERROR;
708     case MODE_NORMAL:
709       gst_buffer_set_caps (buffer, typefind->caps);
710       return gst_pad_push (typefind->src, buffer);
711     case MODE_TYPEFIND:{
712       if (typefind->store)
713         typefind->store = gst_buffer_join (typefind->store, buffer);
714       else
715         typefind->store = buffer;
717       res = gst_type_find_element_chain_do_typefinding (typefind);
719       if (typefind->mode == MODE_ERROR)
720         res = GST_FLOW_ERROR;
722       break;
723     }
724     default:
725       g_assert_not_reached ();
726       return GST_FLOW_ERROR;
727   }
729   return res;
732 static GstFlowReturn
733 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
735   GstTypeFindProbability probability;
736   GstCaps *caps;
738   if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
739     GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
740         "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
741     return GST_FLOW_OK;
742   }
744   caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
745       typefind->store, &probability);
747   if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
748     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
749     stop_typefinding (typefind);
750     return GST_FLOW_ERROR;
751   } else if (caps == NULL) {
752     GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
753         "waiting for more data", GST_BUFFER_SIZE (typefind->store));
754     return GST_FLOW_OK;
755   }
757   /* found a type */
758   if (probability < typefind->min_probability) {
759     GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
760         "probability is %u which is lower than the required minimum of %u",
761         caps, probability, typefind->min_probability);
763     gst_caps_replace (&caps, NULL);
765     if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
766       GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
767       stop_typefinding (typefind);
768       return GST_FLOW_ERROR;
769     }
771     GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
772     return GST_FLOW_OK;
773   }
775   /* probability is good enough too, so let's make it known ... */
776   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
777       probability, caps);
779   /* .. and send out the accumulated data */
780   stop_typefinding (typefind);
781   gst_caps_unref (caps);
782   return GST_FLOW_OK;
785 static gboolean
786 gst_type_find_element_checkgetrange (GstPad * srcpad)
788   GstTypeFindElement *typefind;
790   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
792   return gst_pad_check_pull_range (typefind->sink);
795 static GstFlowReturn
796 gst_type_find_element_getrange (GstPad * srcpad,
797     guint64 offset, guint length, GstBuffer ** buffer)
799   GstTypeFindElement *typefind;
800   GstFlowReturn ret;
802   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
804   ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
806   if (ret == GST_FLOW_OK && buffer && *buffer)
807     gst_buffer_set_caps (*buffer, typefind->caps);
809   return ret;
812 static gboolean
813 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
815   GstTypeFindElement *typefind;
817   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
819   return gst_pad_activate_pull (typefind->sink, active);
822 static gboolean
823 gst_type_find_element_activate (GstPad * pad)
825   GstTypeFindProbability probability = 0;
826   GstCaps *found_caps = NULL;
827   GstTypeFindElement *typefind;
829   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
831   /* if we have force caps, use those */
832   if (typefind->force_caps) {
833     found_caps = gst_caps_ref (typefind->force_caps);
834     probability = GST_TYPE_FIND_MAXIMUM;
835     goto done;
836   }
838   /* 1. try to activate in pull mode. if not, switch to push and succeed.
839      2. try to pull type find.
840      3. deactivate pull mode.
841      4. src pad might have been activated push by the state change. deactivate.
842      5. if we didn't find any caps, try getting the uri extension by doing an uri
843      query.
844      6. if we didn't find any caps, fail.
845      7. emit have-type; maybe the app connected the source pad to something.
846      8. if the sink pad is activated, we are in pull mode. succeed.
847      otherwise activate both pads in push mode and succeed.
848    */
850   /* 1 */
851   if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
852     start_typefinding (typefind);
853     return gst_pad_activate_push (pad, TRUE);
854   }
856   /* 2 */
857   {
858     GstPad *peer;
860     peer = gst_pad_get_peer (pad);
861     if (peer) {
862       gint64 size;
863       GstFormat format = GST_FORMAT_BYTES;
864       gchar *ext;
866       if (!gst_pad_query_duration (peer, &format, &size)) {
867         GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
868         gst_object_unref (peer);
869         return FALSE;
870       }
872       /* the size if 0, we cannot continue */
873       if (size == 0) {
874         /* keep message in sync with message in sink event handler */
875         GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
876             (_("Stream contains no data.")), ("Can't typefind empty stream"));
877         gst_object_unref (peer);
878         return FALSE;
879       }
880       ext = gst_type_find_get_extension (typefind, pad);
882       found_caps = gst_type_find_helper_get_range_ext (GST_OBJECT_CAST (peer),
883           (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
884           (guint64) size, ext, &probability);
885       g_free (ext);
887       gst_object_unref (peer);
888     }
889   }
891   /* 3 */
892   gst_pad_activate_pull (pad, FALSE);
894   /* 4 */
895   gst_pad_activate_push (typefind->src, FALSE);
897   /* 5 */
898   if (!found_caps || probability < typefind->min_probability) {
899     found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
900   }
902   /* 6 */
903   if (!found_caps || probability < typefind->min_probability) {
904     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
905     gst_caps_replace (&found_caps, NULL);
906     return FALSE;
907   }
909 done:
910   /* 7 */
911   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
912       0, probability, found_caps);
913   gst_caps_unref (found_caps);
914   typefind->mode = MODE_NORMAL;
916   /* 8 */
917   if (gst_pad_is_active (pad))
918     return TRUE;
919   else {
920     gboolean ret;
922     ret = gst_pad_activate_push (typefind->src, TRUE);
923     ret &= gst_pad_activate_push (pad, TRUE);
924     return ret;
925   }
928 static GstStateChangeReturn
929 gst_type_find_element_change_state (GstElement * element,
930     GstStateChange transition)
932   GstStateChangeReturn ret;
933   GstTypeFindElement *typefind;
935   typefind = GST_TYPE_FIND_ELEMENT (element);
938   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
940   switch (transition) {
941     case GST_STATE_CHANGE_PAUSED_TO_READY:
942     case GST_STATE_CHANGE_READY_TO_NULL:
943       gst_caps_replace (&typefind->caps, NULL);
945       g_list_foreach (typefind->cached_events,
946           (GFunc) gst_mini_object_unref, NULL);
947       g_list_free (typefind->cached_events);
948       typefind->cached_events = NULL;
949       break;
950     default:
951       break;
952   }
954   return ret;