Initialize Tizen 2.3
[framework/multimedia/gstreamer0.10.git] / wearable / 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  * Whenever a type is found the #GstTypeFindElement::have-type signal is
29  * emitted, either from the streaming thread or the application thread
30  * (the latter may happen when typefinding is done pull-based from the
31  * state change function).
32  *
33  * Plugins can register custom typefinders by using #GstTypeFindFactory.
34  */
35
36 /* FIXME: need a better solution for non-seekable streams */
37
38 /* way of operation:
39  * 1) get a list of all typefind functions sorted best to worst
40  * 2) if all elements have been called with all requested data goto 8
41  * 3) call all functions once with all available data
42  * 4) if a function returns a value >= PROP_MAXIMUM goto 8
43  * 5) all functions with a result > PROP_MINIMUM or functions that did not get
44  *    all requested data (where peek returned NULL) stay in list
45  * 6) seek to requested offset of best function that still has open data
46  *    requests
47  * 7) goto 2
48  * 8) take best available result and use its caps
49  *
50  * The element has two scheduling modes:
51  *
52  * 1) chain based, it will collect buffers and run the typefind function on
53  *    the buffer until something is found.
54  * 2) getrange based, it will proxy the getrange function to the sinkpad. It
55  *    is assumed that the peer element is happy with whatever format we
56  *    eventually read.
57  *
58  * By default it tries to do pull based typefinding (this avoids joining
59  * received buffers and holding them back in store.)
60  *
61  * When the element has no connected srcpad, and the sinkpad can operate in
62  * getrange based mode, the element starts its own task to figure out the
63  * type of the stream.
64  *
65  * Most of the actual implementation is in libs/gst/base/gsttypefindhelper.c.
66  */
67
68 #ifdef HAVE_CONFIG_H
69 #  include "config.h"
70 #endif
71
72 #include "gst/gst_private.h"
73
74 #include "gsttypefindelement.h"
75 #include "gst/gst-i18n-lib.h"
76 #include "gst/base/gsttypefindhelper.h"
77
78 #include <gst/gsttypefind.h>
79 #include <gst/gstutils.h>
80 #include <gst/gsterror.h>
81
82 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
83 #define GST_CAT_DEFAULT gst_type_find_element_debug
84
85 /* generic templates */
86 static GstStaticPadTemplate type_find_element_sink_template =
87 GST_STATIC_PAD_TEMPLATE ("sink",
88     GST_PAD_SINK,
89     GST_PAD_ALWAYS,
90     GST_STATIC_CAPS_ANY);
91
92 static GstStaticPadTemplate type_find_element_src_template =
93 GST_STATIC_PAD_TEMPLATE ("src",
94     GST_PAD_SRC,
95     GST_PAD_ALWAYS,
96     GST_STATIC_CAPS_ANY);
97
98 /* Require at least 2kB of data before we attempt typefinding in chain-mode.
99  * 128kB is massive overkill for the maximum, but doesn't do any harm */
100 #define TYPE_FIND_MIN_SIZE   (2*1024)
101 #define TYPE_FIND_MAX_SIZE (128*1024)
102
103 /* TypeFind signals and args */
104 enum
105 {
106   HAVE_TYPE,
107   LAST_SIGNAL
108 };
109 enum
110 {
111   PROP_0,
112   PROP_CAPS,
113   PROP_MINIMUM,
114   PROP_MAXIMUM,
115   PROP_FORCE_CAPS,
116   PROP_LAST
117 };
118 enum
119 {
120   MODE_NORMAL,                  /* act as identity */
121   MODE_TYPEFIND,                /* do typefinding  */
122   MODE_ERROR                    /* had fatal error */
123 };
124
125
126 #define _do_init(bla) \
127     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
128         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
129
130 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
131     GST_TYPE_ELEMENT, _do_init);
132
133 static void gst_type_find_element_dispose (GObject * object);
134 static void gst_type_find_element_set_property (GObject * object,
135     guint prop_id, const GValue * value, GParamSpec * pspec);
136 static void gst_type_find_element_get_property (GObject * object,
137     guint prop_id, GValue * value, GParamSpec * pspec);
138
139 #if 0
140 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
141 #endif
142
143 static gboolean gst_type_find_element_src_event (GstPad * pad,
144     GstEvent * event);
145 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
146
147 static gboolean gst_type_find_element_handle_event (GstPad * pad,
148     GstEvent * event);
149 static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
150 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
151     GstBuffer * buffer);
152 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
153     guint64 offset, guint length, GstBuffer ** buffer);
154 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
155
156 static GstStateChangeReturn
157 gst_type_find_element_change_state (GstElement * element,
158     GstStateChange transition);
159 static gboolean gst_type_find_element_activate (GstPad * pad);
160 static gboolean
161 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
162 static GstFlowReturn
163 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
164 static void
165 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
166
167 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
168
169 static void
170 gst_type_find_element_have_type (GstTypeFindElement * typefind,
171     guint probability, const GstCaps * caps)
172 {
173   GstCaps *copy;
174
175   g_assert (caps != NULL);
176
177   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
178       caps, probability);
179
180   GST_OBJECT_LOCK (typefind);
181   if (typefind->caps)
182     gst_caps_unref (typefind->caps);
183   typefind->caps = gst_caps_copy (caps);
184   copy = gst_caps_ref (typefind->caps);
185   GST_OBJECT_UNLOCK (typefind);
186
187   gst_pad_set_caps (typefind->src, copy);
188   gst_caps_unref (copy);
189 }
190
191 static void
192 gst_type_find_element_base_init (gpointer g_class)
193 {
194   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
195
196   gst_element_class_set_details_simple (gstelement_class,
197       "TypeFind",
198       "Generic",
199       "Finds the media type of a stream",
200       "Benjamin Otte <in7y118@public.uni-hamburg.de>");
201   gst_element_class_add_pad_template (gstelement_class,
202       gst_static_pad_template_get (&type_find_element_src_template));
203   gst_element_class_add_pad_template (gstelement_class,
204       gst_static_pad_template_get (&type_find_element_sink_template));
205 }
206
207 static void
208 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
209 {
210   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
211   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
212
213   gobject_class->set_property = gst_type_find_element_set_property;
214   gobject_class->get_property = gst_type_find_element_get_property;
215   gobject_class->dispose = gst_type_find_element_dispose;
216
217   g_object_class_install_property (gobject_class, PROP_CAPS,
218       g_param_spec_boxed ("caps", _("caps"),
219           _("detected capabilities in stream"), gst_caps_get_type (),
220           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
221   g_object_class_install_property (gobject_class, PROP_MINIMUM,
222       g_param_spec_uint ("minimum", _("minimum"),
223           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
224           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
225           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
226   g_object_class_install_property (gobject_class, PROP_MAXIMUM,
227       g_param_spec_uint ("maximum", _("maximum"),
228           "probability to stop typefinding (deprecated; non-functional)",
229           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
230           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
231   g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
232       g_param_spec_boxed ("force-caps", _("force caps"),
233           _("force caps without doing a typefind"), gst_caps_get_type (),
234           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
235   /**
236    * GstTypeFindElement::have-type:
237    * @typefind: the typefind instance
238    * @probability: the probability of the type found
239    * @caps: the caps of the type found
240    *
241    * This signal gets emitted when the type and its probability has
242    * been found.
243    */
244   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have-type",
245       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
246       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
247       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
248       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
249
250   typefind_class->have_type =
251       GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
252
253   gstelement_class->change_state =
254       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
255 }
256
257 static void
258 gst_type_find_element_init (GstTypeFindElement * typefind,
259     GstTypeFindElementClass * g_class)
260 {
261   /* sinkpad */
262   typefind->sink =
263       gst_pad_new_from_static_template (&type_find_element_sink_template,
264       "sink");
265
266   gst_pad_set_activate_function (typefind->sink,
267       GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
268   gst_pad_set_setcaps_function (typefind->sink,
269       GST_DEBUG_FUNCPTR (gst_type_find_element_setcaps));
270   gst_pad_set_chain_function (typefind->sink,
271       GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
272   gst_pad_set_event_function (typefind->sink,
273       GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
274   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
275
276   /* srcpad */
277   typefind->src =
278       gst_pad_new_from_static_template (&type_find_element_src_template, "src");
279
280   gst_pad_set_activatepull_function (typefind->src,
281       GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
282   gst_pad_set_checkgetrange_function (typefind->src,
283       GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
284   gst_pad_set_getrange_function (typefind->src,
285       GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
286   gst_pad_set_event_function (typefind->src,
287       GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
288   gst_pad_set_query_function (typefind->src,
289       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
290   gst_pad_use_fixed_caps (typefind->src);
291   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
292
293   typefind->mode = MODE_TYPEFIND;
294   typefind->caps = NULL;
295   typefind->min_probability = 1;
296   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
297
298   typefind->store = NULL;
299 }
300
301 static void
302 gst_type_find_element_dispose (GObject * object)
303 {
304   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
305
306   if (typefind->store) {
307     gst_buffer_unref (typefind->store);
308     typefind->store = NULL;
309   }
310
311   if (typefind->force_caps) {
312     gst_caps_unref (typefind->force_caps);
313     typefind->force_caps = NULL;
314   }
315
316   G_OBJECT_CLASS (parent_class)->dispose (object);
317 }
318
319 static void
320 gst_type_find_element_set_property (GObject * object, guint prop_id,
321     const GValue * value, GParamSpec * pspec)
322 {
323   GstTypeFindElement *typefind;
324
325   typefind = GST_TYPE_FIND_ELEMENT (object);
326
327   switch (prop_id) {
328     case PROP_MINIMUM:
329       typefind->min_probability = g_value_get_uint (value);
330       break;
331     case PROP_MAXIMUM:
332       typefind->max_probability = g_value_get_uint (value);
333       break;
334     case PROP_FORCE_CAPS:
335       GST_OBJECT_LOCK (typefind);
336       if (typefind->force_caps)
337         gst_caps_unref (typefind->force_caps);
338       typefind->force_caps = g_value_dup_boxed (value);
339       GST_OBJECT_UNLOCK (typefind);
340       break;
341     default:
342       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
343       break;
344   }
345 }
346
347 static void
348 gst_type_find_element_get_property (GObject * object, guint prop_id,
349     GValue * value, GParamSpec * pspec)
350 {
351   GstTypeFindElement *typefind;
352
353   typefind = GST_TYPE_FIND_ELEMENT (object);
354
355   switch (prop_id) {
356     case PROP_CAPS:
357       GST_OBJECT_LOCK (typefind);
358       g_value_set_boxed (value, typefind->caps);
359       GST_OBJECT_UNLOCK (typefind);
360       break;
361     case PROP_MINIMUM:
362       g_value_set_uint (value, typefind->min_probability);
363       break;
364     case PROP_MAXIMUM:
365       g_value_set_uint (value, typefind->max_probability);
366       break;
367     case PROP_FORCE_CAPS:
368       GST_OBJECT_LOCK (typefind);
369       g_value_set_boxed (value, typefind->force_caps);
370       GST_OBJECT_UNLOCK (typefind);
371       break;
372     default:
373       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
374       break;
375   }
376 }
377
378 static gboolean
379 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
380 {
381   GstTypeFindElement *typefind;
382   gboolean res = FALSE;
383   GstPad *peer;
384
385   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
386
387   peer = gst_pad_get_peer (typefind->sink);
388   if (peer == NULL)
389     return FALSE;
390
391   res = gst_pad_query (peer, query);
392   if (!res)
393     goto out;
394
395   switch (GST_QUERY_TYPE (query)) {
396     case GST_QUERY_POSITION:
397     {
398       gint64 peer_pos;
399       GstFormat format;
400
401       GST_OBJECT_LOCK (typefind);
402       if (typefind->store == NULL) {
403         GST_OBJECT_UNLOCK (typefind);
404         goto out;
405       }
406
407       gst_query_parse_position (query, &format, &peer_pos);
408
409       /* FIXME: this code assumes that there's no discont in the queue */
410       switch (format) {
411         case GST_FORMAT_BYTES:
412           peer_pos -= GST_BUFFER_SIZE (typefind->store);
413           break;
414         default:
415           /* FIXME */
416           break;
417       }
418       GST_OBJECT_UNLOCK (typefind);
419       gst_query_set_position (query, format, peer_pos);
420       break;
421     }
422     default:
423       break;
424   }
425
426 out:
427   gst_object_unref (peer);
428   return res;
429 }
430
431 #if 0
432 static const GstEventMask *
433 gst_type_find_element_src_event_mask (GstPad * pad)
434 {
435   static const GstEventMask mask[] = {
436     {GST_EVENT_SEEK,
437         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
438           GST_SEEK_FLAG_FLUSH},
439     /* add more if you want, event masks suck and need to die anyway */
440     {0,}
441   };
442
443   return mask;
444 }
445 #endif
446
447 static gboolean
448 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
449 {
450   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
451
452   if (typefind->mode != MODE_NORMAL) {
453     /* need to do more? */
454     gst_mini_object_unref (GST_MINI_OBJECT (event));
455     return FALSE;
456   }
457   return gst_pad_push_event (typefind->sink, event);
458 }
459
460 static void
461 start_typefinding (GstTypeFindElement * typefind)
462 {
463   GST_DEBUG_OBJECT (typefind, "starting typefinding");
464   gst_pad_set_caps (typefind->src, NULL);
465
466   GST_OBJECT_LOCK (typefind);
467   if (typefind->caps)
468     gst_caps_replace (&typefind->caps, NULL);
469   GST_OBJECT_UNLOCK (typefind);
470
471   typefind->mode = MODE_TYPEFIND;
472 }
473
474 static void
475 stop_typefinding (GstTypeFindElement * typefind)
476 {
477   GstState state;
478   gboolean push_cached_buffers;
479
480   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
481
482   push_cached_buffers = (state >= GST_STATE_PAUSED);
483
484   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
485       push_cached_buffers ? " and pushing cached buffers" : "");
486
487   GST_OBJECT_LOCK (typefind);
488   if (typefind->store) {
489     GstBuffer *store;
490
491     store = gst_buffer_make_metadata_writable (typefind->store);
492     typefind->store = NULL;
493     gst_buffer_set_caps (store, typefind->caps);
494     GST_OBJECT_UNLOCK (typefind);
495
496     if (!push_cached_buffers) {
497       gst_buffer_unref (store);
498     } else {
499       GstPad *peer = gst_pad_get_peer (typefind->src);
500
501       typefind->mode = MODE_NORMAL;
502
503       /* make sure the user gets a meaningful error message in this case,
504        * which is not a core bug or bug of any kind (as the default error
505        * message emitted by gstpad.c otherwise would make you think) */
506       if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
507         GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
508             "downstream element only works in pull mode, erroring out");
509         GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
510             ("%s cannot work in push mode. The operation is not supported "
511                 "with this source element or protocol.",
512                 G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
513             ("Downstream pad %s:%s has no chainfunction, and the upstream "
514                 "element does not support pull mode",
515                 GST_DEBUG_PAD_NAME (peer)));
516         typefind->mode = MODE_ERROR;    /* make the chain function error out */
517         gst_buffer_unref (store);
518       } else {
519         gst_type_find_element_send_cached_events (typefind);
520         gst_pad_push (typefind->src, store);
521       }
522
523       if (peer)
524         gst_object_unref (peer);
525     }
526   } else {
527     GST_OBJECT_UNLOCK (typefind);
528   }
529 }
530
531 static gboolean
532 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
533 {
534   gboolean res = FALSE;
535   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
536
537   GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
538       GST_EVENT_TYPE_NAME (event), typefind->mode);
539
540   switch (typefind->mode) {
541     case MODE_TYPEFIND:
542       switch (GST_EVENT_TYPE (event)) {
543         case GST_EVENT_EOS:{
544           GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
545           GstCaps *caps = NULL;
546
547           GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
548
549           /* we might not have started typefinding yet because there was not
550            * enough data so far; just give it a shot now and see what we get */
551           GST_OBJECT_LOCK (typefind);
552           if (typefind->store) {
553             caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
554                 typefind->store, &prob);
555             GST_OBJECT_UNLOCK (typefind);
556
557             if (caps && prob >= typefind->min_probability) {
558               g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
559                   0, prob, caps);
560             } else {
561               GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
562                   (NULL), (NULL));
563             }
564             gst_caps_replace (&caps, NULL);
565           } else {
566             GST_OBJECT_UNLOCK (typefind);
567             /* keep message in sync with the one in the pad activate function */
568             GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
569                 (_("Stream contains no data.")),
570                 ("Can't typefind empty stream"));
571           }
572
573           stop_typefinding (typefind);
574           res = gst_pad_push_event (typefind->src, event);
575           break;
576         }
577         case GST_EVENT_FLUSH_STOP:
578           GST_OBJECT_LOCK (typefind);
579           g_list_foreach (typefind->cached_events,
580               (GFunc) gst_mini_object_unref, NULL);
581           g_list_free (typefind->cached_events);
582           typefind->cached_events = NULL;
583           gst_buffer_replace (&typefind->store, NULL);
584           GST_OBJECT_UNLOCK (typefind);
585           /* fall through */
586         case GST_EVENT_FLUSH_START:
587           res = gst_pad_push_event (typefind->src, event);
588           break;
589         default:
590           GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
591               GST_EVENT_TYPE_NAME (event));
592           GST_OBJECT_LOCK (typefind);
593           typefind->cached_events =
594               g_list_append (typefind->cached_events, event);
595           GST_OBJECT_UNLOCK (typefind);
596           res = TRUE;
597           break;
598       }
599       break;
600     case MODE_NORMAL:
601       res = gst_pad_push_event (typefind->src, event);
602       break;
603     case MODE_ERROR:
604       break;
605     default:
606       g_assert_not_reached ();
607   }
608   return res;
609 }
610
611 static void
612 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
613 {
614   GList *l, *cached_events;
615
616   GST_OBJECT_LOCK (typefind);
617   cached_events = typefind->cached_events;
618   typefind->cached_events = NULL;
619   GST_OBJECT_UNLOCK (typefind);
620
621   for (l = cached_events; l != NULL; l = l->next) {
622     GstEvent *event = GST_EVENT (l->data);
623
624     GST_DEBUG_OBJECT (typefind, "sending cached %s event",
625         GST_EVENT_TYPE_NAME (event));
626     gst_pad_push_event (typefind->src, event);
627   }
628   g_list_free (cached_events);
629 }
630
631 static gboolean
632 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
633 {
634   GstTypeFindElement *typefind;
635
636   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
637
638   /* don't operate on ANY caps */
639   if (gst_caps_is_any (caps))
640     return TRUE;
641
642   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
643       GST_TYPE_FIND_MAXIMUM, caps);
644
645   /* Shortcircuit typefinding if we get caps */
646   if (typefind->mode == MODE_TYPEFIND) {
647     GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
648         "upstream buffer: %" GST_PTR_FORMAT, caps);
649     typefind->mode = MODE_NORMAL;
650
651     gst_type_find_element_send_cached_events (typefind);
652     GST_OBJECT_LOCK (typefind);
653     if (typefind->store) {
654       GstBuffer *store;
655
656       store = gst_buffer_make_metadata_writable (typefind->store);
657       typefind->store = NULL;
658       gst_buffer_set_caps (store, typefind->caps);
659       GST_OBJECT_UNLOCK (typefind);
660
661       GST_DEBUG_OBJECT (typefind, "Pushing store: %d", GST_BUFFER_SIZE (store));
662       gst_pad_push (typefind->src, store);
663     } else {
664       GST_OBJECT_UNLOCK (typefind);
665     }
666   }
667
668   return TRUE;
669 }
670
671 static gchar *
672 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
673 {
674   GstQuery *query;
675   gchar *uri, *result;
676   size_t len;
677   gint find;
678
679   query = gst_query_new_uri ();
680
681   /* try getting the caps with an uri query and from the extension */
682   if (!gst_pad_peer_query (pad, query))
683     goto peer_query_failed;
684
685   gst_query_parse_uri (query, &uri);
686   if (uri == NULL)
687     goto no_uri;
688
689   GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
690
691   /* find the extension on the uri, this is everything after a '.' */
692   len = strlen (uri);
693   find = len - 1;
694
695   while (find >= 0) {
696     if (uri[find] == '.')
697       break;
698     find--;
699   }
700   if (find < 0)
701     goto no_extension;
702
703   result = g_strdup (&uri[find + 1]);
704
705   GST_DEBUG_OBJECT (typefind, "found extension %s", result);
706   gst_query_unref (query);
707   g_free (uri);
708
709   return result;
710
711   /* ERRORS */
712 peer_query_failed:
713   {
714     GST_WARNING_OBJECT (typefind, "failed to query peer uri");
715     gst_query_unref (query);
716     return NULL;
717   }
718 no_uri:
719   {
720     GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
721     gst_query_unref (query);
722     return NULL;
723   }
724 no_extension:
725   {
726     GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
727     gst_query_unref (query);
728     g_free (uri);
729     return NULL;
730   }
731 }
732
733 static GstCaps *
734 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
735     GstTypeFindProbability * probability)
736 {
737   gchar *ext;
738   GstCaps *caps;
739
740   ext = gst_type_find_get_extension (typefind, pad);
741   if (!ext)
742     return NULL;
743
744   caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
745   if (caps)
746     *probability = GST_TYPE_FIND_MAXIMUM;
747
748   g_free (ext);
749
750   return caps;
751 }
752
753 static GstFlowReturn
754 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
755 {
756   GstTypeFindElement *typefind;
757   GstFlowReturn res = GST_FLOW_OK;
758
759   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
760
761   GST_LOG_OBJECT (typefind, "handling buffer in mode %d", typefind->mode);
762
763   switch (typefind->mode) {
764     case MODE_ERROR:
765       /* we should already have called GST_ELEMENT_ERROR */
766       return GST_FLOW_ERROR;
767     case MODE_NORMAL:
768       /* don't take object lock as typefind->caps should not change anymore */
769       buffer = gst_buffer_make_metadata_writable (buffer);
770       gst_buffer_set_caps (buffer, typefind->caps);
771       return gst_pad_push (typefind->src, buffer);
772     case MODE_TYPEFIND:{
773       GST_OBJECT_LOCK (typefind);
774       if (typefind->store)
775         typefind->store = gst_buffer_join (typefind->store, buffer);
776       else
777         typefind->store = buffer;
778       GST_OBJECT_UNLOCK (typefind);
779
780       res = gst_type_find_element_chain_do_typefinding (typefind);
781
782       if (typefind->mode == MODE_ERROR)
783         res = GST_FLOW_ERROR;
784
785       break;
786     }
787     default:
788       g_assert_not_reached ();
789       return GST_FLOW_ERROR;
790   }
791
792   return res;
793 }
794
795 static GstFlowReturn
796 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
797 {
798   GstTypeFindProbability probability;
799   GstCaps *caps;
800
801   GST_OBJECT_LOCK (typefind);
802   if (GST_BUFFER_SIZE (typefind->store) < TYPE_FIND_MIN_SIZE) {
803     GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
804         "(%u bytes)", GST_BUFFER_SIZE (typefind->store));
805     GST_OBJECT_UNLOCK (typefind);
806     return GST_FLOW_OK;
807   }
808
809   caps = gst_type_find_helper_for_buffer (GST_OBJECT (typefind),
810       typefind->store, &probability);
811   if (caps == NULL && GST_BUFFER_SIZE (typefind->store) > TYPE_FIND_MAX_SIZE) {
812     GST_OBJECT_UNLOCK (typefind);
813     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
814     stop_typefinding (typefind);
815     return GST_FLOW_ERROR;
816   } else if (caps == NULL) {
817     GST_OBJECT_UNLOCK (typefind);
818     GST_DEBUG_OBJECT (typefind, "no caps found with %u bytes of data, "
819         "waiting for more data", GST_BUFFER_SIZE (typefind->store));
820     return GST_FLOW_OK;
821   }
822
823   /* found a type */
824   if (probability < typefind->min_probability) {
825     GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
826         "probability is %u which is lower than the required minimum of %u",
827         caps, probability, typefind->min_probability);
828
829     gst_caps_replace (&caps, NULL);
830
831     if (GST_BUFFER_SIZE (typefind->store) >= TYPE_FIND_MAX_SIZE) {
832       GST_OBJECT_UNLOCK (typefind);
833       GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
834       stop_typefinding (typefind);
835       return GST_FLOW_ERROR;
836     }
837
838     GST_OBJECT_UNLOCK (typefind);
839     GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
840     return GST_FLOW_OK;
841   }
842   GST_OBJECT_UNLOCK (typefind);
843
844   /* probability is good enough too, so let's make it known ... */
845   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
846       probability, caps);
847
848   /* .. and send out the accumulated data */
849   stop_typefinding (typefind);
850   gst_caps_unref (caps);
851   return GST_FLOW_OK;
852 }
853
854 static gboolean
855 gst_type_find_element_checkgetrange (GstPad * srcpad)
856 {
857   GstTypeFindElement *typefind;
858
859   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
860
861   return gst_pad_check_pull_range (typefind->sink);
862 }
863
864 static GstFlowReturn
865 gst_type_find_element_getrange (GstPad * srcpad,
866     guint64 offset, guint length, GstBuffer ** buffer)
867 {
868   GstTypeFindElement *typefind;
869   GstFlowReturn ret;
870
871   typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
872
873   ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
874
875   if (ret == GST_FLOW_OK && buffer && *buffer) {
876     /* don't take object lock as typefind->caps should not change anymore */
877     /* we assume that pulled buffers are meta-data writable */
878     gst_buffer_set_caps (*buffer, typefind->caps);
879   }
880
881   return ret;
882 }
883
884 static gboolean
885 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
886 {
887   GstTypeFindElement *typefind;
888
889   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
890
891   return gst_pad_activate_pull (typefind->sink, active);
892 }
893
894 static gboolean
895 gst_type_find_element_activate (GstPad * pad)
896 {
897   GstTypeFindProbability probability = GST_TYPE_FIND_NONE;
898   GstCaps *found_caps = NULL;
899   GstTypeFindElement *typefind;
900
901   typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
902
903   /* if we have force caps, use those */
904   GST_OBJECT_LOCK (typefind);
905   if (typefind->force_caps) {
906     found_caps = gst_caps_ref (typefind->force_caps);
907     probability = GST_TYPE_FIND_MAXIMUM;
908     GST_OBJECT_UNLOCK (typefind);
909     goto done;
910   }
911   GST_OBJECT_UNLOCK (typefind);
912
913   /* 1. try to activate in pull mode. if not, switch to push and succeed.
914      2. try to pull type find.
915      3. deactivate pull mode.
916      4. src pad might have been activated push by the state change. deactivate.
917      5. if we didn't find any caps, try getting the uri extension by doing an uri
918      query.
919      6. if we didn't find any caps, fail.
920      7. emit have-type; maybe the app connected the source pad to something.
921      8. if the sink pad is activated, we are in pull mode. succeed.
922      otherwise activate both pads in push mode and succeed.
923    */
924
925   /* 1 */
926   if (!gst_pad_check_pull_range (pad) || !gst_pad_activate_pull (pad, TRUE)) {
927     start_typefinding (typefind);
928     return gst_pad_activate_push (pad, TRUE);
929   }
930
931   GST_DEBUG_OBJECT (typefind, "find type in pull mode");
932
933   /* 2 */
934   {
935     GstPad *peer;
936
937     peer = gst_pad_get_peer (pad);
938     if (peer) {
939       gint64 size;
940       GstFormat format = GST_FORMAT_BYTES;
941       gchar *ext;
942
943       if (!gst_pad_query_duration (peer, &format, &size)) {
944         GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
945         gst_object_unref (peer);
946         gst_pad_activate_pull (pad, FALSE);
947         return FALSE;
948       }
949
950       /* the size if 0, we cannot continue */
951       if (size == 0) {
952         /* keep message in sync with message in sink event handler */
953         GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
954             (_("Stream contains no data.")), ("Can't typefind empty stream"));
955         gst_object_unref (peer);
956         gst_pad_activate_pull (pad, FALSE);
957         return FALSE;
958       }
959       ext = gst_type_find_get_extension (typefind, pad);
960
961       found_caps = gst_type_find_helper_get_range_ext (GST_OBJECT_CAST (peer),
962           (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
963           (guint64) size, ext, &probability);
964       g_free (ext);
965
966       gst_object_unref (peer);
967     }
968   }
969
970   /* the type find helpers might have triggered setcaps here (due to upstream)
971    * setting caps on buffers, which emits typefound signal and an element
972    * could have been linked and have its pads activated
973    *
974    * If we deactivate the pads in the following steps we might mess up
975    * downstream element. We should prevent that.
976    */
977   if (typefind->mode == MODE_NORMAL) {
978     /* this means we already emitted typefound */
979     GST_DEBUG ("Already managed to typefind !");
980     goto really_done;
981   }
982
983   /* 3 */
984   gst_pad_activate_pull (pad, FALSE);
985
986   /* 4 */
987   gst_pad_activate_push (typefind->src, FALSE);
988
989   /* 5 */
990   if (!found_caps || probability < typefind->min_probability) {
991     found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
992   }
993
994   /* 6 */
995   if (!found_caps || probability < typefind->min_probability) {
996     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
997     gst_caps_replace (&found_caps, NULL);
998     return FALSE;
999   }
1000
1001 done:
1002   /* 7 */
1003   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
1004       0, probability, found_caps);
1005   typefind->mode = MODE_NORMAL;
1006 really_done:
1007   gst_caps_unref (found_caps);
1008
1009   /* 8 */
1010   if (gst_pad_is_active (pad))
1011     return TRUE;
1012   else {
1013     gboolean ret;
1014
1015     ret = gst_pad_activate_push (typefind->src, TRUE);
1016     ret &= gst_pad_activate_push (pad, TRUE);
1017     return ret;
1018   }
1019 }
1020
1021 static GstStateChangeReturn
1022 gst_type_find_element_change_state (GstElement * element,
1023     GstStateChange transition)
1024 {
1025   GstStateChangeReturn ret;
1026   GstTypeFindElement *typefind;
1027
1028   typefind = GST_TYPE_FIND_ELEMENT (element);
1029
1030
1031   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1032
1033   switch (transition) {
1034     case GST_STATE_CHANGE_PAUSED_TO_READY:
1035     case GST_STATE_CHANGE_READY_TO_NULL:
1036       GST_OBJECT_LOCK (typefind);
1037       gst_caps_replace (&typefind->caps, NULL);
1038
1039       g_list_foreach (typefind->cached_events,
1040           (GFunc) gst_mini_object_unref, NULL);
1041       g_list_free (typefind->cached_events);
1042       typefind->cached_events = NULL;
1043       typefind->mode = MODE_TYPEFIND;
1044       GST_OBJECT_UNLOCK (typefind);
1045       break;
1046     default:
1047       break;
1048   }
1049
1050   return ret;
1051 }