gst_private.h: make sure gst_private.h is included before glib.h
[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 "gst/gst_private.h"
65 #include "gsttypefindelement.h"
66 #include "gst/gst-i18n-lib.h"
67 #include "gst/base/gsttypefindhelper.h"
69 #include <gst/gsttypefind.h>
70 #include <gst/gstutils.h>
71 #include <gst/gsterror.h>
73 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
74 #define GST_CAT_DEFAULT gst_type_find_element_debug
76 /* generic templates */
77 static GstStaticPadTemplate type_find_element_sink_template =
78 GST_STATIC_PAD_TEMPLATE ("sink",
79     GST_PAD_SINK,
80     GST_PAD_ALWAYS,
81     GST_STATIC_CAPS_ANY);
83 static GstStaticPadTemplate type_find_element_src_template =
84 GST_STATIC_PAD_TEMPLATE ("src",
85     GST_PAD_SRC,
86     GST_PAD_ALWAYS,
87     GST_STATIC_CAPS_ANY);
89 /* Require at least 2kB of data before we attempt typefinding in chain-mode.
90  * 128kB is massive overkill for the maximum, but doesn't do any harm */
91 #define TYPE_FIND_MIN_SIZE   (2*1024)
92 #define TYPE_FIND_MAX_SIZE (128*1024)
94 /* TypeFind signals and args */
95 enum
96 {
97   HAVE_TYPE,
98   LAST_SIGNAL
99 };
100 enum
102   PROP_0,
103   PROP_CAPS,
104   PROP_MINIMUM,
105   PROP_MAXIMUM,
106   PROP_FORCE_CAPS,
107   PROP_LAST
108 };
109 enum
111   MODE_NORMAL,                  /* act as identity */
112   MODE_TYPEFIND,                /* do typefinding  */
113   MODE_ERROR                    /* had fatal error */
114 };
117 #define _do_init(bla) \
118     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
119         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
121 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
122     GST_TYPE_ELEMENT, _do_init);
124 static void gst_type_find_element_dispose (GObject * object);
125 static void gst_type_find_element_set_property (GObject * object,
126     guint prop_id, const GValue * value, GParamSpec * pspec);
127 static void gst_type_find_element_get_property (GObject * object,
128     guint prop_id, GValue * value, GParamSpec * pspec);
130 #if 0
131 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
132 #endif
134 static gboolean gst_type_find_element_src_event (GstPad * pad,
135     GstEvent * event);
136 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
138 static gboolean gst_type_find_element_handle_event (GstPad * pad,
139     GstEvent * event);
140 static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
141 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
142     GstBuffer * buffer);
143 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
144     guint64 offset, guint length, GstBuffer ** buffer);
145 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
147 static GstStateChangeReturn
148 gst_type_find_element_change_state (GstElement * element,
149     GstStateChange transition);
150 static gboolean gst_type_find_element_activate (GstPad * pad);
151 static gboolean
152 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
153 static GstFlowReturn
154 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
155 static void
156 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
158 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
160 static void
161 gst_type_find_element_have_type (GstTypeFindElement * typefind,
162     guint probability, const GstCaps * caps)
164   g_assert (caps != NULL);
166   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
167       caps, probability);
168   if (typefind->caps)
169     gst_caps_unref (typefind->caps);
170   typefind->caps = gst_caps_copy (caps);
171   gst_pad_set_caps (typefind->src, (GstCaps *) caps);
174 static void
175 gst_type_find_element_base_init (gpointer g_class)
177   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
179   gst_element_class_set_details_simple (gstelement_class,
180       "TypeFind",
181       "Generic",
182       "Finds the media type of a stream",
183       "Benjamin Otte <in7y118@public.uni-hamburg.de>");
184   gst_element_class_add_pad_template (gstelement_class,
185       gst_static_pad_template_get (&type_find_element_src_template));
186   gst_element_class_add_pad_template (gstelement_class,
187       gst_static_pad_template_get (&type_find_element_sink_template));
190 static void
191 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
193   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
194   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
196   gobject_class->set_property = gst_type_find_element_set_property;
197   gobject_class->get_property = gst_type_find_element_get_property;
198   gobject_class->dispose = gst_type_find_element_dispose;
200   g_object_class_install_property (gobject_class, PROP_CAPS,
201       g_param_spec_boxed ("caps", _("caps"),
202           _("detected capabilities in stream"), gst_caps_get_type (),
203           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
204   g_object_class_install_property (gobject_class, PROP_MINIMUM,
205       g_param_spec_uint ("minimum", _("minimum"),
206           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
207           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
208           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
209   g_object_class_install_property (gobject_class, PROP_MAXIMUM,
210       g_param_spec_uint ("maximum", _("maximum"),
211           "probability to stop typefinding (deprecated; non-functional)",
212           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
213           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
214   g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
215       g_param_spec_boxed ("force-caps", _("force caps"),
216           _("force caps without doing a typefind"), gst_caps_get_type (),
217           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218   /**
219    * GstTypeFindElement::have-type:
220    * @typefind: the typefind instance
221    * @probability: the probability of the type found
222    * @caps: the caps of the type found
223    *
224    * This signal gets emitted when the type and its probability has 
225    * been found.
226    */
227   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
228       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
229       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
230       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
231       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
233   typefind_class->have_type =
234       GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
236   gstelement_class->change_state =
237       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
240 static void
241 gst_type_find_element_init (GstTypeFindElement * typefind,
242     GstTypeFindElementClass * g_class)
244   /* sinkpad */
245   typefind->sink =
246       gst_pad_new_from_static_template (&type_find_element_sink_template,
247       "sink");
249   gst_pad_set_activate_function (typefind->sink,
250       GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
251   gst_pad_set_setcaps_function (typefind->sink,
252       GST_DEBUG_FUNCPTR (gst_type_find_element_setcaps));
253   gst_pad_set_chain_function (typefind->sink,
254       GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
255   gst_pad_set_event_function (typefind->sink,
256       GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
257   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
259   /* srcpad */
260   typefind->src =
261       gst_pad_new_from_static_template (&type_find_element_src_template, "src");
263   gst_pad_set_activatepull_function (typefind->src,
264       GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
265   gst_pad_set_checkgetrange_function (typefind->src,
266       GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
267   gst_pad_set_getrange_function (typefind->src,
268       GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
269   gst_pad_set_event_function (typefind->src,
270       GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
271   gst_pad_set_query_function (typefind->src,
272       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
273   gst_pad_use_fixed_caps (typefind->src);
274   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
276   typefind->mode = MODE_TYPEFIND;
277   typefind->caps = NULL;
278   typefind->min_probability = 1;
279   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
281   typefind->store = NULL;
284 static void
285 gst_type_find_element_dispose (GObject * object)
287   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
289   if (typefind->store) {
290     gst_buffer_unref (typefind->store);
291     typefind->store = NULL;
292   }
293   if (typefind->force_caps) {
294     gst_caps_unref (typefind->force_caps);
295     typefind->force_caps = NULL;
296   }
298   G_OBJECT_CLASS (parent_class)->dispose (object);
301 static void
302 gst_type_find_element_set_property (GObject * object, guint prop_id,
303     const GValue * value, GParamSpec * pspec)
305   GstTypeFindElement *typefind;
307   typefind = GST_TYPE_FIND_ELEMENT (object);
309   switch (prop_id) {
310     case PROP_MINIMUM:
311       typefind->min_probability = g_value_get_uint (value);
312       break;
313     case PROP_MAXIMUM:
314       typefind->max_probability = g_value_get_uint (value);
315       break;
316     case PROP_FORCE_CAPS:
317       GST_OBJECT_LOCK (typefind);
318       if (typefind->force_caps)
319         gst_caps_unref (typefind->force_caps);
320       typefind->force_caps = g_value_dup_boxed (value);
321       GST_OBJECT_UNLOCK (typefind);
322       break;
323     default:
324       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
325       break;
326   }
329 static void
330 gst_type_find_element_get_property (GObject * object, guint prop_id,
331     GValue * value, GParamSpec * pspec)
333   GstTypeFindElement *typefind;
335   typefind = GST_TYPE_FIND_ELEMENT (object);
337   switch (prop_id) {
338     case PROP_CAPS:
339       g_value_set_boxed (value, typefind->caps);
340       break;
341     case PROP_MINIMUM:
342       g_value_set_uint (value, typefind->min_probability);
343       break;
344     case PROP_MAXIMUM:
345       g_value_set_uint (value, typefind->max_probability);
346       break;
347     case PROP_FORCE_CAPS:
348       GST_OBJECT_LOCK (typefind);
349       g_value_set_boxed (value, typefind->force_caps);
350       GST_OBJECT_UNLOCK (typefind);
351       break;
352     default:
353       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
354       break;
355   }
358 static gboolean
359 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
361   GstTypeFindElement *typefind;
362   gboolean res = FALSE;
363   GstPad *peer;
365   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
367   peer = gst_pad_get_peer (typefind->sink);
368   if (peer == NULL)
369     return FALSE;
371   res = gst_pad_query (peer, query);
372   if (!res)
373     goto out;
375   switch (GST_QUERY_TYPE (query)) {
376     case GST_QUERY_POSITION:
377     {
378       gint64 peer_pos;
379       GstFormat format;
381       if (typefind->store == NULL)
382         goto out;
384       gst_query_parse_position (query, &format, &peer_pos);
386       /* FIXME: this code assumes that there's no discont in the queue */
387       switch (format) {
388         case GST_FORMAT_BYTES:
389           peer_pos -= GST_BUFFER_SIZE (typefind->store);
390           break;
391         default:
392           /* FIXME */
393           break;
394       }
395       gst_query_set_position (query, format, peer_pos);
396       break;
397     }
398     default:
399       break;
400   }
402 out:
403   gst_object_unref (peer);
404   return res;
407 #if 0
408 static const GstEventMask *
409 gst_type_find_element_src_event_mask (GstPad * pad)
411   static const GstEventMask mask[] = {
412     {GST_EVENT_SEEK,
413         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
414           GST_SEEK_FLAG_FLUSH},
415     /* add more if you want, event masks suck and need to die anyway */
416     {0,}
417   };
419   return mask;
421 #endif
423 static gboolean
424 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
426   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
428   if (typefind->mode != MODE_NORMAL) {
429     /* need to do more? */
430     gst_mini_object_unref (GST_MINI_OBJECT (event));
431     return FALSE;
432   }
433   return gst_pad_push_event (typefind->sink, event);
436 static void
437 start_typefinding (GstTypeFindElement * typefind)
439   GST_DEBUG_OBJECT (typefind, "starting typefinding");
440   gst_pad_set_caps (typefind->src, NULL);
441   if (typefind->caps) {
442     gst_caps_replace (&typefind->caps, NULL);
443   }
444   typefind->mode = MODE_TYPEFIND;
447 static void
448 stop_typefinding (GstTypeFindElement * typefind)
450   GstState state;
451   gboolean push_cached_buffers;
453   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
455   push_cached_buffers = (state >= GST_STATE_PAUSED);
457   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
458       push_cached_buffers ? " and pushing cached buffers" : "");
460   if (typefind->store) {
461     if (!push_cached_buffers) {
462       gst_buffer_unref (typefind->store);
463     } else {
464       GstPad *peer = gst_pad_get_peer (typefind->src);
466       typefind->mode = MODE_NORMAL;
467       gst_buffer_set_caps (typefind->store, typefind->caps);
469       /* make sure the user gets a meaningful error message in this case,
470        * which is not a core bug or bug of any kind (as the default error
471        * message emitted by gstpad.c otherwise would make you think) */
472       if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
473         GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
474             "downstream element only works in pull mode, erroring out");
475         GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
476             ("%s cannot work in push mode. The operation is not supported "
477                 "with this source element or protocol.",
478                 G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
479             ("Downstream pad %s:%s has no chainfunction, and the upstream "
480                 "element does not support pull mode",
481                 GST_DEBUG_PAD_NAME (peer)));
482         typefind->mode = MODE_ERROR;    /* make the chain function error out */
483       } else {
484         gst_type_find_element_send_cached_events (typefind);
485         gst_pad_push (typefind->src, typefind->store);
486       }
488       if (peer)
489         gst_object_unref (peer);
490     }
491     typefind->store = NULL;
492   }
495 static gboolean
496 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
498   gboolean res = FALSE;
499   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
501   GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
502       GST_EVENT_TYPE_NAME (event), typefind->mode);
504   switch (typefind->mode) {
505     case MODE_TYPEFIND:
506       switch (GST_EVENT_TYPE (event)) {
507         case GST_EVENT_EOS:{
508           GstTypeFindProbability prob = 0;
509           GstCaps *caps = NULL;
511           GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
513           /* we might not have started typefinding yet because there was not
514            * enough data so far; just give it a shot now and see what we get */
515           if (typefind->store) {
516             caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
517                 typefind->store, &prob);
519             if (caps && prob >= typefind->min_probability) {
520               g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
521                   0, prob, caps);
522             } else {
523               GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
524                   (NULL), (NULL));
525             }
526             gst_caps_replace (&caps, NULL);
527           } else {
528             /* keep message in sync with the one in the pad activate function */
529             GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
530                 (_("Stream contains no data.")),
531                 ("Can't typefind empty stream"));
532           }
534           stop_typefinding (typefind);
535           res = gst_pad_push_event (typefind->src, event);
536           break;
537         }
538         case GST_EVENT_FLUSH_STOP:
539           g_list_foreach (typefind->cached_events,
540               (GFunc) gst_mini_object_unref, NULL);
541           g_list_free (typefind->cached_events);
542           typefind->cached_events = NULL;
543           gst_buffer_replace (&typefind->store, NULL);
544           /* fall through */
545         case GST_EVENT_FLUSH_START:
546           res = gst_pad_push_event (typefind->src, event);
547           break;
548         default:
549           GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
550               GST_EVENT_TYPE_NAME (event));
551           typefind->cached_events =
552               g_list_append (typefind->cached_events, event);
553           res = TRUE;
554           break;
555       }
556       break;
557     case MODE_NORMAL:
558       res = gst_pad_push_event (typefind->src, event);
559       break;
560     case MODE_ERROR:
561       break;
562     default:
563       g_assert_not_reached ();
564   }
565   return res;
568 static void
569 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
571   GList *l;
573   for (l = typefind->cached_events; l != NULL; l = l->next) {
574     GstEvent *event = GST_EVENT (l->data);
576     GST_DEBUG_OBJECT (typefind, "sending cached %s event",
577         GST_EVENT_TYPE_NAME (event));
578     gst_pad_push_event (typefind->src, event);
579   }
580   g_list_free (typefind->cached_events);
581   typefind->cached_events = NULL;
584 static gboolean
585 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
587   GstTypeFindElement *typefind;
589   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
591   /* don't operate on ANY caps */
592   if (gst_caps_is_any (caps))
593     return TRUE;
595   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
596       GST_TYPE_FIND_MAXIMUM, caps);
598   /* Shortcircuit typefinding if we get caps */
599   if (typefind->mode == MODE_TYPEFIND) {
600     GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
601         "upstream buffer: %" GST_PTR_FORMAT, caps);
602     typefind->mode = MODE_NORMAL;
604     gst_type_find_element_send_cached_events (typefind);
605     if (typefind->store) {
606       GST_DEBUG_OBJECT (typefind, "Pushing store: %d",
607           GST_BUFFER_SIZE (typefind->store));
608       gst_buffer_set_caps (typefind->store, typefind->caps);
609       gst_pad_push (typefind->src, typefind->store);
610       typefind->store = NULL;
611     }
612   }
614   return TRUE;
617 static gchar *
618 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
620   GstQuery *query;
621   gchar *uri, *result;
622   size_t len;
623   gint find;
625   query = gst_query_new_uri ();
627   /* try getting the caps with an uri query and from the extension */
628   if (!gst_pad_peer_query (pad, query))
629     goto peer_query_failed;
631   gst_query_parse_uri (query, &uri);
632   if (uri == NULL)
633     goto no_uri;
635   GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
637   /* find the extension on the uri, this is everything after a '.' */
638   len = strlen (uri);
639   find = len - 1;
641   while (find >= 0) {
642     if (uri[find] == '.')
643       break;
644     find--;
645   }
646   if (find < 0)
647     goto no_extension;
649   result = g_strdup (&uri[find + 1]);
651   GST_DEBUG_OBJECT (typefind, "found extension %s", result);
652   gst_query_unref (query);
654   return result;
656   /* ERRORS */
657 peer_query_failed:
658   {
659     GST_WARNING_OBJECT (typefind, "failed to query peer uri");
660     gst_query_unref (query);
661     return NULL;
662   }
663 no_uri:
664   {
665     GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
666     gst_query_unref (query);
667     return NULL;
668   }
669 no_extension:
670   {
671     GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
672     gst_query_unref (query);
673     return NULL;
674   }
677 static GstCaps *
678 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
679     GstTypeFindProbability * probability)
681   gchar *ext;
682   GstCaps *caps;
684   ext = gst_type_find_get_extension (typefind, pad);
685   if (!ext)
686     return NULL;
688   caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
689   if (caps)
690     *probability = GST_TYPE_FIND_MAXIMUM;
692   g_free (ext);
694   return caps;
697 static GstFlowReturn
698 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
700   GstTypeFindElement *typefind;
701   GstFlowReturn res = GST_FLOW_OK;
703   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
705   switch (typefind->mode) {
706     case MODE_ERROR:
707       /* we should already have called GST_ELEMENT_ERROR */
708       return GST_FLOW_ERROR;
709     case MODE_NORMAL:
710       gst_buffer_set_caps (buffer, typefind->caps);
711       return gst_pad_push (typefind->src, buffer);
712     case MODE_TYPEFIND:{
713       if (typefind->store)
714         typefind->store = gst_buffer_join (typefind->store, buffer);
715       else
716         typefind->store = buffer;
718       res = gst_type_find_element_chain_do_typefinding (typefind);
720       if (typefind->mode == MODE_ERROR)
721         res = GST_FLOW_ERROR;
723       break;
724     }
725     default:
726       g_assert_not_reached ();
727       return GST_FLOW_ERROR;
728   }
730   return res;
733 static GstFlowReturn
734 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
736   GstTypeFindProbability probability;
737   GstCaps *caps;
739   if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
740     GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
741         "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
742     return GST_FLOW_OK;
743   }
745   caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
746       typefind->store, &probability);
748   if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
749     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
750     stop_typefinding (typefind);
751     return GST_FLOW_ERROR;
752   } else if (caps == NULL) {
753     GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
754         "waiting for more data", GST_BUFFER_SIZE (typefind->store));
755     return GST_FLOW_OK;
756   }
758   /* found a type */
759   if (probability < typefind->min_probability) {
760     GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
761         "probability is %u which is lower than the required minimum of %u",
762         caps, probability, typefind->min_probability);
764     gst_caps_replace (&caps, NULL);
766     if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
767       GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
768       stop_typefinding (typefind);
769       return GST_FLOW_ERROR;
770     }
772     GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
773     return GST_FLOW_OK;
774   }
776   /* probability is good enough too, so let's make it known ... */
777   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
778       probability, caps);
780   /* .. and send out the accumulated data */
781   stop_typefinding (typefind);
782   gst_caps_unref (caps);
783   return GST_FLOW_OK;
786 static gboolean
787 gst_type_find_element_checkgetrange (GstPad * srcpad)
789   GstTypeFindElement *typefind;
791   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
793   return gst_pad_check_pull_range (typefind->sink);
796 static GstFlowReturn
797 gst_type_find_element_getrange (GstPad * srcpad,
798     guint64 offset, guint length, GstBuffer ** buffer)
800   GstTypeFindElement *typefind;
801   GstFlowReturn ret;
803   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
805   ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
807   if (ret == GST_FLOW_OK && buffer && *buffer)
808     gst_buffer_set_caps (*buffer, typefind->caps);
810   return ret;
813 static gboolean
814 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
816   GstTypeFindElement *typefind;
818   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
820   return gst_pad_activate_pull (typefind->sink, active);
823 static gboolean
824 gst_type_find_element_activate (GstPad * pad)
826   GstTypeFindProbability probability = 0;
827   GstCaps *found_caps = NULL;
828   GstTypeFindElement *typefind;
830   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
832   /* if we have force caps, use those */
833   if (typefind->force_caps) {
834     found_caps = gst_caps_ref (typefind->force_caps);
835     probability = GST_TYPE_FIND_MAXIMUM;
836     goto done;
837   }
839   /* 1. try to activate in pull mode. if not, switch to push and succeed.
840      2. try to pull type find.
841      3. deactivate pull mode.
842      4. src pad might have been activated push by the state change. deactivate.
843      5. if we didn't find any caps, try getting the uri extension by doing an uri
844      query.
845      6. if we didn't find any caps, fail.
846      7. emit have-type; maybe the app connected the source pad to something.
847      8. if the sink pad is activated, we are in pull mode. succeed.
848      otherwise activate both pads in push mode and succeed.
849    */
851   /* 1 */
852   if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
853     start_typefinding (typefind);
854     return gst_pad_activate_push (pad, TRUE);
855   }
857   /* 2 */
858   {
859     GstPad *peer;
861     peer = gst_pad_get_peer (pad);
862     if (peer) {
863       gint64 size;
864       GstFormat format = GST_FORMAT_BYTES;
865       gchar *ext;
867       if (!gst_pad_query_duration (peer, &format, &size)) {
868         GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
869         gst_object_unref (peer);
870         return FALSE;
871       }
873       /* the size if 0, we cannot continue */
874       if (size == 0) {
875         /* keep message in sync with message in sink event handler */
876         GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
877             (_("Stream contains no data.")), ("Can't typefind empty stream"));
878         gst_object_unref (peer);
879         return FALSE;
880       }
881       ext = gst_type_find_get_extension (typefind, pad);
883       found_caps = gst_type_find_helper_get_range_ext (GST_OBJECT_CAST (peer),
884           (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
885           (guint64) size, ext, &probability);
886       g_free (ext);
888       gst_object_unref (peer);
889     }
890   }
892   /* 3 */
893   gst_pad_activate_pull (pad, FALSE);
895   /* 4 */
896   gst_pad_activate_push (typefind->src, FALSE);
898   /* 5 */
899   if (!found_caps || probability < typefind->min_probability) {
900     found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
901   }
903   /* 6 */
904   if (!found_caps || probability < typefind->min_probability) {
905     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
906     gst_caps_replace (&found_caps, NULL);
907     return FALSE;
908   }
910 done:
911   /* 7 */
912   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
913       0, probability, found_caps);
914   gst_caps_unref (found_caps);
915   typefind->mode = MODE_NORMAL;
917   /* 8 */
918   if (gst_pad_is_active (pad))
919     return TRUE;
920   else {
921     gboolean ret;
923     ret = gst_pad_activate_push (typefind->src, TRUE);
924     ret &= gst_pad_activate_push (pad, TRUE);
925     return ret;
926   }
929 static GstStateChangeReturn
930 gst_type_find_element_change_state (GstElement * element,
931     GstStateChange transition)
933   GstStateChangeReturn ret;
934   GstTypeFindElement *typefind;
936   typefind = GST_TYPE_FIND_ELEMENT (element);
939   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
941   switch (transition) {
942     case GST_STATE_CHANGE_PAUSED_TO_READY:
943     case GST_STATE_CHANGE_READY_TO_NULL:
944       gst_caps_replace (&typefind->caps, NULL);
946       g_list_foreach (typefind->cached_events,
947           (GFunc) gst_mini_object_unref, NULL);
948       g_list_free (typefind->cached_events);
949       typefind->cached_events = NULL;
950       break;
951     default:
952       break;
953   }
955   return ret;