Merge branch 'master' into 0.11
[platform/upstream/gstreamer.git] / plugins / elements / gsttypefindelement.c
1 /* GStreamer
2  * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
3  *
4  * gsttypefindelement.c: element that detects type of stream
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  */
21 /**
22  * 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 \
127     GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind",           \
128         GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
129 #define gst_type_find_element_parent_class parent_class
130 G_DEFINE_TYPE_WITH_CODE (GstTypeFindElement, gst_type_find_element,
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     GstObject * parent, GstEvent * event);
145 static gboolean gst_type_find_handle_src_query (GstPad * pad,
146     GstObject * parent, GstQuery * query);
147
148 static gboolean gst_type_find_element_sink_event (GstPad * pad,
149     GstObject * parent, GstEvent * event);
150 static gboolean gst_type_find_element_setcaps (GstTypeFindElement * typefind,
151     GstCaps * caps);
152 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
153     GstObject * parent, GstBuffer * buffer);
154 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
155     GstObject * parent, guint64 offset, guint length, GstBuffer ** buffer);
156
157 static GstStateChangeReturn
158 gst_type_find_element_change_state (GstElement * element,
159     GstStateChange transition);
160 static gboolean gst_type_find_element_activate (GstPad * pad,
161     GstObject * parent);
162 static gboolean gst_type_find_element_activate_src_mode (GstPad * pad,
163     GstObject * parent, GstPadMode mode, gboolean active);
164 static GstFlowReturn
165 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
166     gboolean check_avail);
167 static void gst_type_find_element_send_cached_events (GstTypeFindElement *
168     typefind);
169
170 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
171
172 static void
173 gst_type_find_element_have_type (GstTypeFindElement * typefind,
174     guint probability, const GstCaps * caps)
175 {
176   GstCaps *copy;
177
178   g_assert (caps != NULL);
179
180   GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
181       caps, probability);
182
183   GST_OBJECT_LOCK (typefind);
184   if (typefind->caps)
185     gst_caps_unref (typefind->caps);
186   typefind->caps = gst_caps_copy (caps);
187   copy = gst_caps_ref (typefind->caps);
188   GST_OBJECT_UNLOCK (typefind);
189
190   gst_pad_push_event (typefind->src, gst_event_new_caps (copy));
191   gst_caps_unref (copy);
192 }
193
194 static void
195 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
196 {
197   GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
198   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
199
200   gobject_class->set_property = gst_type_find_element_set_property;
201   gobject_class->get_property = gst_type_find_element_get_property;
202   gobject_class->dispose = gst_type_find_element_dispose;
203
204   g_object_class_install_property (gobject_class, PROP_CAPS,
205       g_param_spec_boxed ("caps", _("caps"),
206           _("detected capabilities in stream"), GST_TYPE_CAPS,
207           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
208   g_object_class_install_property (gobject_class, PROP_MINIMUM,
209       g_param_spec_uint ("minimum", _("minimum"),
210           "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
211           GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM,
212           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
213   g_object_class_install_property (gobject_class, PROP_MAXIMUM,
214       g_param_spec_uint ("maximum", _("maximum"),
215           "probability to stop typefinding (deprecated; non-functional)",
216           GST_TYPE_FIND_MINIMUM, GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM,
217           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
218   g_object_class_install_property (gobject_class, PROP_FORCE_CAPS,
219       g_param_spec_boxed ("force-caps", _("force caps"),
220           _("force caps without doing a typefind"), GST_TYPE_CAPS,
221           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
222   /**
223    * GstTypeFindElement::have-type:
224    * @typefind: the typefind instance
225    * @probability: the probability of the type found
226    * @caps: the caps of the type found
227    *
228    * This signal gets emitted when the type and its probability has
229    * been found.
230    */
231   gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have-type",
232       G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_FIRST,
233       G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
234       gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
235       G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
236
237   typefind_class->have_type =
238       GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
239
240   gst_element_class_set_details_simple (gstelement_class,
241       "TypeFind",
242       "Generic",
243       "Finds the media type of a stream",
244       "Benjamin Otte <in7y118@public.uni-hamburg.de>");
245   gst_element_class_add_pad_template (gstelement_class,
246       gst_static_pad_template_get (&type_find_element_src_template));
247   gst_element_class_add_pad_template (gstelement_class,
248       gst_static_pad_template_get (&type_find_element_sink_template));
249
250   gstelement_class->change_state =
251       GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
252 }
253
254 static void
255 gst_type_find_element_init (GstTypeFindElement * typefind)
256 {
257   /* sinkpad */
258   typefind->sink =
259       gst_pad_new_from_static_template (&type_find_element_sink_template,
260       "sink");
261
262   gst_pad_set_activate_function (typefind->sink,
263       GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
264   gst_pad_set_chain_function (typefind->sink,
265       GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
266   gst_pad_set_event_function (typefind->sink,
267       GST_DEBUG_FUNCPTR (gst_type_find_element_sink_event));
268   gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
269
270   /* srcpad */
271   typefind->src =
272       gst_pad_new_from_static_template (&type_find_element_src_template, "src");
273
274   gst_pad_set_activatemode_function (typefind->src,
275       GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_mode));
276   gst_pad_set_getrange_function (typefind->src,
277       GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
278   gst_pad_set_event_function (typefind->src,
279       GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
280   gst_pad_set_query_function (typefind->src,
281       GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
282   gst_pad_use_fixed_caps (typefind->src);
283   gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
284
285   typefind->mode = MODE_TYPEFIND;
286   typefind->caps = NULL;
287   typefind->min_probability = 1;
288   typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
289
290   typefind->adapter = gst_adapter_new ();
291 }
292
293 static void
294 gst_type_find_element_dispose (GObject * object)
295 {
296   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
297
298   if (typefind->adapter) {
299     g_object_unref (typefind->adapter);
300     typefind->adapter = NULL;
301   }
302
303   if (typefind->force_caps) {
304     gst_caps_unref (typefind->force_caps);
305     typefind->force_caps = NULL;
306   }
307
308   G_OBJECT_CLASS (parent_class)->dispose (object);
309 }
310
311 static void
312 gst_type_find_element_set_property (GObject * object, guint prop_id,
313     const GValue * value, GParamSpec * pspec)
314 {
315   GstTypeFindElement *typefind;
316
317   typefind = GST_TYPE_FIND_ELEMENT (object);
318
319   switch (prop_id) {
320     case PROP_MINIMUM:
321       typefind->min_probability = g_value_get_uint (value);
322       break;
323     case PROP_MAXIMUM:
324       typefind->max_probability = g_value_get_uint (value);
325       break;
326     case PROP_FORCE_CAPS:
327       GST_OBJECT_LOCK (typefind);
328       if (typefind->force_caps)
329         gst_caps_unref (typefind->force_caps);
330       typefind->force_caps = g_value_dup_boxed (value);
331       GST_OBJECT_UNLOCK (typefind);
332       break;
333     default:
334       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
335       break;
336   }
337 }
338
339 static void
340 gst_type_find_element_get_property (GObject * object, guint prop_id,
341     GValue * value, GParamSpec * pspec)
342 {
343   GstTypeFindElement *typefind;
344
345   typefind = GST_TYPE_FIND_ELEMENT (object);
346
347   switch (prop_id) {
348     case PROP_CAPS:
349       GST_OBJECT_LOCK (typefind);
350       g_value_set_boxed (value, typefind->caps);
351       GST_OBJECT_UNLOCK (typefind);
352       break;
353     case PROP_MINIMUM:
354       g_value_set_uint (value, typefind->min_probability);
355       break;
356     case PROP_MAXIMUM:
357       g_value_set_uint (value, typefind->max_probability);
358       break;
359     case PROP_FORCE_CAPS:
360       GST_OBJECT_LOCK (typefind);
361       g_value_set_boxed (value, typefind->force_caps);
362       GST_OBJECT_UNLOCK (typefind);
363       break;
364     default:
365       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
366       break;
367   }
368 }
369
370 static gboolean
371 gst_type_find_handle_src_query (GstPad * pad, GstObject * parent,
372     GstQuery * query)
373 {
374   GstTypeFindElement *typefind;
375   gboolean res = FALSE;
376
377   typefind = GST_TYPE_FIND_ELEMENT (parent);
378
379   res = gst_pad_peer_query (typefind->sink, query);
380   if (!res)
381     goto out;
382
383   switch (GST_QUERY_TYPE (query)) {
384     case GST_QUERY_POSITION:
385     {
386       gint64 peer_pos;
387       GstFormat format;
388
389       gst_query_parse_position (query, &format, &peer_pos);
390
391       GST_OBJECT_LOCK (typefind);
392       /* FIXME: this code assumes that there's no discont in the queue */
393       switch (format) {
394         case GST_FORMAT_BYTES:
395           peer_pos -= gst_adapter_available (typefind->adapter);
396           break;
397         default:
398           /* FIXME */
399           break;
400       }
401       GST_OBJECT_UNLOCK (typefind);
402       gst_query_set_position (query, format, peer_pos);
403       break;
404     }
405     default:
406       break;
407   }
408
409 out:
410   return res;
411 }
412
413 #if 0
414 static const GstEventMask *
415 gst_type_find_element_src_event_mask (GstPad * pad)
416 {
417   static const GstEventMask mask[] = {
418     {GST_EVENT_SEEK,
419         GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
420           GST_SEEK_FLAG_FLUSH},
421     /* add more if you want, event masks suck and need to die anyway */
422     {0,}
423   };
424
425   return mask;
426 }
427 #endif
428
429 static gboolean
430 gst_type_find_element_src_event (GstPad * pad, GstObject * parent,
431     GstEvent * event)
432 {
433   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent);
434
435   if (typefind->mode != MODE_NORMAL) {
436     /* need to do more? */
437     gst_mini_object_unref (GST_MINI_OBJECT_CAST (event));
438     return FALSE;
439   }
440   return gst_pad_push_event (typefind->sink, event);
441 }
442
443 static void
444 start_typefinding (GstTypeFindElement * typefind)
445 {
446   GST_DEBUG_OBJECT (typefind, "starting typefinding");
447
448   GST_OBJECT_LOCK (typefind);
449   if (typefind->caps)
450     gst_caps_replace (&typefind->caps, NULL);
451   GST_OBJECT_UNLOCK (typefind);
452
453   typefind->mode = MODE_TYPEFIND;
454 }
455
456 static void
457 stop_typefinding (GstTypeFindElement * typefind)
458 {
459   GstState state;
460   gboolean push_cached_buffers;
461   gsize avail;
462   GstBuffer *buffer;
463
464   gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
465
466   push_cached_buffers = (state >= GST_STATE_PAUSED);
467
468   GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
469       push_cached_buffers ? " and pushing cached buffers" : "");
470
471   GST_OBJECT_LOCK (typefind);
472   avail = gst_adapter_available (typefind->adapter);
473   if (avail == 0)
474     goto no_data;
475
476   buffer = gst_adapter_take_buffer (typefind->adapter, avail);
477   GST_OBJECT_UNLOCK (typefind);
478
479   if (!push_cached_buffers) {
480     gst_buffer_unref (buffer);
481   } else {
482     GstPad *peer = gst_pad_get_peer (typefind->src);
483
484     typefind->mode = MODE_NORMAL;
485
486     /* make sure the user gets a meaningful error message in this case,
487      * which is not a core bug or bug of any kind (as the default error
488      * message emitted by gstpad.c otherwise would make you think) */
489     if (peer && GST_PAD_CHAINFUNC (peer) == NULL) {
490       GST_DEBUG_OBJECT (typefind, "upstream only supports push mode, while "
491           "downstream element only works in pull mode, erroring out");
492       GST_ELEMENT_ERROR (typefind, STREAM, FAILED,
493           ("%s cannot work in push mode. The operation is not supported "
494               "with this source element or protocol.",
495               G_OBJECT_TYPE_NAME (GST_PAD_PARENT (peer))),
496           ("Downstream pad %s:%s has no chainfunction, and the upstream "
497               "element does not support pull mode", GST_DEBUG_PAD_NAME (peer)));
498       typefind->mode = MODE_ERROR;      /* make the chain function error out */
499       gst_buffer_unref (buffer);
500     } else {
501       gst_type_find_element_send_cached_events (typefind);
502       gst_pad_push (typefind->src, buffer);
503     }
504     if (peer)
505       gst_object_unref (peer);
506   }
507   return;
508
509   /* ERRORS */
510 no_data:
511   {
512     GST_DEBUG_OBJECT (typefind, "we have no data to typefind");
513     GST_OBJECT_UNLOCK (typefind);
514     return;
515   }
516 }
517
518 static gboolean
519 gst_type_find_element_sink_event (GstPad * pad, GstObject * parent,
520     GstEvent * event)
521 {
522   gboolean res = FALSE;
523   GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (parent);
524
525   GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
526       GST_EVENT_TYPE_NAME (event), typefind->mode);
527
528   switch (typefind->mode) {
529     case MODE_TYPEFIND:
530       switch (GST_EVENT_TYPE (event)) {
531         case GST_EVENT_CAPS:
532         {
533           GstCaps *caps;
534
535           /* first pass the caps event downstream */
536           res = gst_pad_push_event (typefind->src, gst_event_ref (event));
537
538           /* then parse and push out our data */
539           gst_event_parse_caps (event, &caps);
540           res = gst_type_find_element_setcaps (typefind, caps);
541
542           gst_event_unref (event);
543           break;
544         }
545         case GST_EVENT_EOS:
546         {
547           GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
548           gst_type_find_element_chain_do_typefinding (typefind, FALSE);
549
550           res = gst_pad_push_event (typefind->src, event);
551           break;
552         }
553         case GST_EVENT_FLUSH_STOP:
554           GST_OBJECT_LOCK (typefind);
555           g_list_foreach (typefind->cached_events,
556               (GFunc) gst_mini_object_unref, NULL);
557           g_list_free (typefind->cached_events);
558           typefind->cached_events = NULL;
559           gst_adapter_clear (typefind->adapter);
560           GST_OBJECT_UNLOCK (typefind);
561           /* fall through */
562         case GST_EVENT_FLUSH_START:
563           res = gst_pad_push_event (typefind->src, event);
564           break;
565         default:
566           GST_DEBUG_OBJECT (typefind, "Saving %s event to send later",
567               GST_EVENT_TYPE_NAME (event));
568           GST_OBJECT_LOCK (typefind);
569           typefind->cached_events =
570               g_list_append (typefind->cached_events, event);
571           GST_OBJECT_UNLOCK (typefind);
572           res = TRUE;
573           break;
574       }
575       break;
576     case MODE_NORMAL:
577       res = gst_pad_push_event (typefind->src, event);
578       break;
579     case MODE_ERROR:
580       break;
581     default:
582       g_assert_not_reached ();
583   }
584   return res;
585 }
586
587 static void
588 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
589 {
590   GList *l, *cached_events;
591
592   GST_OBJECT_LOCK (typefind);
593   cached_events = typefind->cached_events;
594   typefind->cached_events = NULL;
595   GST_OBJECT_UNLOCK (typefind);
596
597   for (l = cached_events; l != NULL; l = l->next) {
598     GstEvent *event = GST_EVENT (l->data);
599
600     GST_DEBUG_OBJECT (typefind, "sending cached %s event",
601         GST_EVENT_TYPE_NAME (event));
602     gst_pad_push_event (typefind->src, event);
603   }
604   g_list_free (cached_events);
605 }
606
607 static gboolean
608 gst_type_find_element_setcaps (GstTypeFindElement * typefind, GstCaps * caps)
609 {
610   /* don't operate on ANY caps */
611   if (gst_caps_is_any (caps))
612     return TRUE;
613
614   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
615       GST_TYPE_FIND_MAXIMUM, caps);
616
617   /* Shortcircuit typefinding if we get caps */
618   if (typefind->mode == MODE_TYPEFIND) {
619     GstBuffer *buffer;
620     gsize avail;
621
622     GST_DEBUG_OBJECT (typefind, "Skipping typefinding, using caps from "
623         "upstream buffer: %" GST_PTR_FORMAT, caps);
624     typefind->mode = MODE_NORMAL;
625
626     gst_type_find_element_send_cached_events (typefind);
627     GST_OBJECT_LOCK (typefind);
628     avail = gst_adapter_available (typefind->adapter);
629     if (avail == 0)
630       goto no_data;
631
632     buffer = gst_adapter_take_buffer (typefind->adapter, avail);
633     GST_OBJECT_UNLOCK (typefind);
634
635     GST_DEBUG_OBJECT (typefind, "Pushing buffer: %" G_GSIZE_FORMAT, avail);
636     gst_pad_push (typefind->src, buffer);
637   }
638
639   return TRUE;
640
641 no_data:
642   {
643     GST_DEBUG_OBJECT (typefind, "no data to push");
644     GST_OBJECT_UNLOCK (typefind);
645     return TRUE;
646   }
647 }
648
649 static gchar *
650 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
651 {
652   GstQuery *query;
653   gchar *uri, *result;
654   size_t len;
655   gint find;
656
657   query = gst_query_new_uri ();
658
659   /* try getting the caps with an uri query and from the extension */
660   if (!gst_pad_peer_query (pad, query))
661     goto peer_query_failed;
662
663   gst_query_parse_uri (query, &uri);
664   if (uri == NULL)
665     goto no_uri;
666
667   GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
668
669   /* find the extension on the uri, this is everything after a '.' */
670   len = strlen (uri);
671   find = len - 1;
672
673   while (find >= 0) {
674     if (uri[find] == '.')
675       break;
676     find--;
677   }
678   if (find < 0)
679     goto no_extension;
680
681   result = g_strdup (&uri[find + 1]);
682
683   GST_DEBUG_OBJECT (typefind, "found extension %s", result);
684   gst_query_unref (query);
685   g_free (uri);
686
687   return result;
688
689   /* ERRORS */
690 peer_query_failed:
691   {
692     GST_WARNING_OBJECT (typefind, "failed to query peer uri");
693     gst_query_unref (query);
694     return NULL;
695   }
696 no_uri:
697   {
698     GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
699     gst_query_unref (query);
700     return NULL;
701   }
702 no_extension:
703   {
704     GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
705     gst_query_unref (query);
706     g_free (uri);
707     return NULL;
708   }
709 }
710
711 static GstCaps *
712 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
713     GstTypeFindProbability * probability)
714 {
715   gchar *ext;
716   GstCaps *caps;
717
718   ext = gst_type_find_get_extension (typefind, pad);
719   if (!ext)
720     return NULL;
721
722   caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
723   if (caps)
724     *probability = GST_TYPE_FIND_MAXIMUM;
725
726   g_free (ext);
727
728   return caps;
729 }
730
731 static GstFlowReturn
732 gst_type_find_element_chain (GstPad * pad, GstObject * parent,
733     GstBuffer * buffer)
734 {
735   GstTypeFindElement *typefind;
736   GstFlowReturn res = GST_FLOW_OK;
737
738   typefind = GST_TYPE_FIND_ELEMENT (parent);
739
740   GST_LOG_OBJECT (typefind, "handling buffer in mode %d", typefind->mode);
741
742   switch (typefind->mode) {
743     case MODE_ERROR:
744       /* we should already have called GST_ELEMENT_ERROR */
745       return GST_FLOW_ERROR;
746     case MODE_NORMAL:
747       /* don't take object lock as typefind->caps should not change anymore */
748       return gst_pad_push (typefind->src, buffer);
749     case MODE_TYPEFIND:
750     {
751       GST_OBJECT_LOCK (typefind);
752       gst_adapter_push (typefind->adapter, buffer);
753       GST_OBJECT_UNLOCK (typefind);
754
755       res = gst_type_find_element_chain_do_typefinding (typefind, TRUE);
756
757       if (typefind->mode == MODE_ERROR)
758         res = GST_FLOW_ERROR;
759
760       break;
761     }
762     default:
763       g_assert_not_reached ();
764       return GST_FLOW_ERROR;
765   }
766
767   return res;
768 }
769
770 static GstFlowReturn
771 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind,
772     gboolean check_avail)
773 {
774   GstTypeFindProbability probability;
775   GstCaps *caps;
776   gsize avail;
777   const guint8 *data;
778   gboolean have_min, have_max;
779
780   GST_OBJECT_LOCK (typefind);
781   avail = gst_adapter_available (typefind->adapter);
782
783   if (check_avail) {
784     have_min = avail >= TYPE_FIND_MIN_SIZE;
785     have_max = avail >= TYPE_FIND_MAX_SIZE;
786   } else {
787     have_min = TRUE;
788     have_max = TRUE;
789   }
790
791   if (!have_min)
792     goto not_enough_data;
793
794   /* map all available data */
795   data = gst_adapter_map (typefind->adapter, avail);
796   caps = gst_type_find_helper_for_data (GST_OBJECT (typefind),
797       data, avail, &probability);
798   gst_adapter_unmap (typefind->adapter);
799
800   if (caps == NULL && have_max)
801     goto no_type_found;
802   else if (caps == NULL)
803     goto wait_for_data;
804
805   /* found a type */
806   if (probability < typefind->min_probability)
807     goto low_probability;
808   GST_OBJECT_UNLOCK (typefind);
809
810   /* probability is good enough too, so let's make it known ... emiting this
811    * signal calls our object handler which sets the caps. */
812   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
813       probability, caps);
814
815   /* .. and send out the accumulated data */
816   stop_typefinding (typefind);
817   gst_caps_unref (caps);
818
819   return GST_FLOW_OK;
820
821 not_enough_data:
822   {
823     GST_DEBUG_OBJECT (typefind, "not enough data for typefinding yet "
824         "(%" G_GSIZE_FORMAT " bytes)", avail);
825     GST_OBJECT_UNLOCK (typefind);
826     return GST_FLOW_OK;
827   }
828 no_type_found:
829   {
830     GST_OBJECT_UNLOCK (typefind);
831     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
832     stop_typefinding (typefind);
833     return GST_FLOW_ERROR;
834   }
835 wait_for_data:
836   {
837     GST_DEBUG_OBJECT (typefind,
838         "no caps found with %" G_GSIZE_FORMAT " bytes of data, "
839         "waiting for more data", avail);
840     GST_OBJECT_UNLOCK (typefind);
841     return GST_FLOW_OK;
842   }
843 low_probability:
844   {
845     GST_DEBUG_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", but "
846         "probability is %u which is lower than the required minimum of %u",
847         caps, probability, typefind->min_probability);
848
849     gst_caps_unref (caps);
850
851     if (have_max)
852       goto no_type_found;
853
854     GST_OBJECT_UNLOCK (typefind);
855     GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
856     return GST_FLOW_OK;
857   }
858 }
859
860 static GstFlowReturn
861 gst_type_find_element_getrange (GstPad * srcpad, GstObject * parent,
862     guint64 offset, guint length, GstBuffer ** buffer)
863 {
864   GstTypeFindElement *typefind;
865   GstFlowReturn ret;
866
867   typefind = GST_TYPE_FIND_ELEMENT (parent);
868
869   ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
870
871   return ret;
872 }
873
874 static gboolean
875 gst_type_find_element_activate_src_mode (GstPad * pad, GstObject * parent,
876     GstPadMode mode, gboolean active)
877 {
878   gboolean res;
879   GstTypeFindElement *typefind;
880
881   typefind = GST_TYPE_FIND_ELEMENT (parent);
882
883   switch (mode) {
884     case GST_PAD_MODE_PULL:
885       res = gst_pad_activate_mode (typefind->sink, mode, active);
886       if (typefind->caps) {
887         GstCaps *caps;
888         GST_OBJECT_LOCK (typefind);
889         caps = gst_caps_ref (typefind->caps);
890         GST_OBJECT_UNLOCK (typefind);
891         gst_pad_push_event (typefind->src, gst_event_new_caps (caps));
892         gst_caps_unref (caps);
893       }
894       break;
895     default:
896       res = TRUE;
897       break;
898   }
899   return res;
900 }
901
902 static gboolean
903 gst_type_find_element_activate (GstPad * pad, GstObject * parent)
904 {
905   GstTypeFindProbability probability = GST_TYPE_FIND_NONE;
906   GstCaps *found_caps = NULL;
907   GstTypeFindElement *typefind;
908   GstQuery *query;
909   gboolean pull_mode;
910
911   typefind = GST_TYPE_FIND_ELEMENT (parent);
912
913   /* if we have force caps, use those */
914   GST_OBJECT_LOCK (typefind);
915   if (typefind->force_caps) {
916     found_caps = gst_caps_ref (typefind->force_caps);
917     probability = GST_TYPE_FIND_MAXIMUM;
918     GST_OBJECT_UNLOCK (typefind);
919     goto done;
920   }
921   GST_OBJECT_UNLOCK (typefind);
922
923   /* 1. try to activate in pull mode. if not, switch to push and succeed.
924      2. try to pull type find.
925      3. deactivate pull mode.
926      4. src pad might have been activated push by the state change. deactivate.
927      5. if we didn't find any caps, try getting the uri extension by doing an uri
928      query.
929      6. if we didn't find any caps, fail.
930      7. emit have-type; maybe the app connected the source pad to something.
931      8. if the sink pad is activated, we are in pull mode. succeed.
932      otherwise activate both pads in push mode and succeed.
933    */
934
935   /* 1 */
936   query = gst_query_new_scheduling ();
937
938   if (!gst_pad_peer_query (pad, query)) {
939     gst_query_unref (query);
940     goto typefind_push;
941   }
942
943   pull_mode = gst_query_has_scheduling_mode (query, GST_PAD_MODE_PULL);
944   gst_query_unref (query);
945
946   if (!pull_mode)
947     goto typefind_push;
948
949   if (!gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, TRUE))
950     goto typefind_push;
951
952   /* 2 */
953   GST_DEBUG_OBJECT (typefind, "find type in pull mode");
954
955   {
956     GstPad *peer;
957
958     peer = gst_pad_get_peer (pad);
959     if (peer) {
960       gint64 size;
961       gchar *ext;
962
963       if (!gst_pad_query_duration (peer, GST_FORMAT_BYTES, &size)) {
964         GST_WARNING_OBJECT (typefind, "Could not query upstream length!");
965         gst_object_unref (peer);
966         gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, FALSE);
967         return FALSE;
968       }
969
970       /* the size if 0, we cannot continue */
971       if (size == 0) {
972         /* keep message in sync with message in sink event handler */
973         GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
974             (_("Stream contains no data.")), ("Can't typefind empty stream"));
975         gst_object_unref (peer);
976         gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, FALSE);
977         return FALSE;
978       }
979       ext = gst_type_find_get_extension (typefind, pad);
980
981       found_caps =
982           gst_type_find_helper_get_range (GST_OBJECT_CAST (peer),
983           GST_OBJECT_PARENT (peer),
984           (GstTypeFindHelperGetRangeFunction) (GST_PAD_GETRANGEFUNC (peer)),
985           (guint64) size, ext, &probability);
986       g_free (ext);
987
988       GST_DEBUG ("Found caps %" GST_PTR_FORMAT, found_caps);
989
990       gst_object_unref (peer);
991     }
992   }
993
994   /* the type find helpers might have triggered setcaps here (due to upstream)
995    * setting caps on buffers, which emits typefound signal and an element
996    * could have been linked and have its pads activated
997    *
998    * If we deactivate the pads in the following steps we might mess up
999    * downstream element. We should prevent that.
1000    */
1001   if (typefind->mode == MODE_NORMAL) {
1002     /* this means we already emitted typefound */
1003     GST_DEBUG ("Already managed to typefind !");
1004     goto really_done;
1005   }
1006
1007   /* 3 */
1008   GST_DEBUG ("Deactivate pull mode");
1009   gst_pad_activate_mode (pad, GST_PAD_MODE_PULL, FALSE);
1010
1011 #if 0
1012   /* 4 */
1013   GST_DEBUG ("Deactivate push mode mode");
1014   gst_pad_activate_mode (typefind->src, GST_PAD_MODE_PUSH, FALSE);
1015 #endif
1016
1017   /* 5 */
1018   if (!found_caps || probability < typefind->min_probability) {
1019     GST_DEBUG ("Trying to guess using extension");
1020     found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
1021   }
1022
1023   /* 6 */
1024   if (!found_caps || probability < typefind->min_probability) {
1025     GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
1026     gst_caps_replace (&found_caps, NULL);
1027     return FALSE;
1028   }
1029
1030 done:
1031   /* 7 */
1032   GST_DEBUG ("Emiting found caps %" GST_PTR_FORMAT, found_caps);
1033   g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
1034       0, probability, found_caps);
1035   typefind->mode = MODE_NORMAL;
1036
1037 really_done:
1038   gst_caps_unref (found_caps);
1039
1040   /* 8 */
1041   if (gst_pad_is_active (pad))
1042     return TRUE;
1043   else {
1044     gboolean ret;
1045
1046     GST_DEBUG ("Activating in push mode");
1047     ret = gst_pad_activate_mode (typefind->src, GST_PAD_MODE_PUSH, TRUE);
1048     ret &= gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
1049     return ret;
1050   }
1051 typefind_push:
1052   {
1053     start_typefinding (typefind);
1054     return gst_pad_activate_mode (pad, GST_PAD_MODE_PUSH, TRUE);
1055   }
1056 }
1057
1058 static GstStateChangeReturn
1059 gst_type_find_element_change_state (GstElement * element,
1060     GstStateChange transition)
1061 {
1062   GstStateChangeReturn ret;
1063   GstTypeFindElement *typefind;
1064
1065   typefind = GST_TYPE_FIND_ELEMENT (element);
1066
1067
1068   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1069
1070   switch (transition) {
1071     case GST_STATE_CHANGE_PAUSED_TO_READY:
1072     case GST_STATE_CHANGE_READY_TO_NULL:
1073       GST_OBJECT_LOCK (typefind);
1074       gst_caps_replace (&typefind->caps, NULL);
1075
1076       g_list_foreach (typefind->cached_events,
1077           (GFunc) gst_mini_object_unref, NULL);
1078       g_list_free (typefind->cached_events);
1079       typefind->cached_events = NULL;
1080       typefind->mode = MODE_TYPEFIND;
1081       GST_OBJECT_UNLOCK (typefind);
1082       break;
1083     default:
1084       break;
1085   }
1086
1087   return ret;
1088 }