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
101 {
102 PROP_0,
103 PROP_CAPS,
104 PROP_MINIMUM,
105 PROP_MAXIMUM,
106 PROP_FORCE_CAPS,
107 PROP_LAST
108 };
109 enum
110 {
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)
163 {
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);
172 }
174 static void
175 gst_type_find_element_base_init (gpointer g_class)
176 {
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));
188 }
190 static void
191 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
192 {
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);
238 }
240 static void
241 gst_type_find_element_init (GstTypeFindElement * typefind,
242 GstTypeFindElementClass * g_class)
243 {
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;
282 }
284 static void
285 gst_type_find_element_dispose (GObject * object)
286 {
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);
299 }
301 static void
302 gst_type_find_element_set_property (GObject * object, guint prop_id,
303 const GValue * value, GParamSpec * pspec)
304 {
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 }
327 }
329 static void
330 gst_type_find_element_get_property (GObject * object, guint prop_id,
331 GValue * value, GParamSpec * pspec)
332 {
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 }
356 }
358 static gboolean
359 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
360 {
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;
405 }
407 #if 0
408 static const GstEventMask *
409 gst_type_find_element_src_event_mask (GstPad * pad)
410 {
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;
420 }
421 #endif
423 static gboolean
424 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
425 {
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);
434 }
436 static void
437 start_typefinding (GstTypeFindElement * typefind)
438 {
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;
445 }
447 static void
448 stop_typefinding (GstTypeFindElement * typefind)
449 {
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 }
493 }
495 static gboolean
496 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
497 {
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;
566 }
568 static void
569 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
570 {
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;
582 }
584 static gboolean
585 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
586 {
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;
615 }
617 static gchar *
618 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
619 {
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 }
675 }
677 static GstCaps *
678 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
679 GstTypeFindProbability * probability)
680 {
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;
695 }
697 static GstFlowReturn
698 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
699 {
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;
731 }
733 static GstFlowReturn
734 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
735 {
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;
784 }
786 static gboolean
787 gst_type_find_element_checkgetrange (GstPad * srcpad)
788 {
789 GstTypeFindElement *typefind;
791 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
793 return gst_pad_check_pull_range (typefind->sink);
794 }
796 static GstFlowReturn
797 gst_type_find_element_getrange (GstPad * srcpad,
798 guint64 offset, guint length, GstBuffer ** buffer)
799 {
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;
811 }
813 static gboolean
814 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
815 {
816 GstTypeFindElement *typefind;
818 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
820 return gst_pad_activate_pull (typefind->sink, active);
821 }
823 static gboolean
824 gst_type_find_element_activate (GstPad * pad)
825 {
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 }
927 }
929 static GstStateChangeReturn
930 gst_type_find_element_change_state (GstElement * element,
931 GstStateChange transition)
932 {
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;
956 }