2 * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
4 * gsttypefindelement.c: element that detects type of stream
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.
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.
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.
22 * SECTION:element-typefind
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.
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).
33 * Plugins can register custom typefinders by using #GstTypeFindFactory.
36 /* FIXME: need a better solution for non-seekable streams */
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
48 * 8) take best available result and use its caps
50 * The element has two scheduling modes:
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
58 * By default it tries to do pull based typefinding (this avoids joining
59 * received buffers and holding them back in store.)
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
65 * Most of the actual implementation is in libs/gst/base/gsttypefindhelper.c.
72 #include "gst/gst_private.h"
74 #include "gsttypefindelement.h"
75 #include "gst/gst-i18n-lib.h"
76 #include "gst/base/gsttypefindhelper.h"
78 #include <gst/gsttypefind.h>
79 #include <gst/gstutils.h>
80 #include <gst/gsterror.h>
82 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
83 #define GST_CAT_DEFAULT gst_type_find_element_debug
85 /* generic templates */
86 static GstStaticPadTemplate type_find_element_sink_template =
87 GST_STATIC_PAD_TEMPLATE ("sink",
92 static GstStaticPadTemplate type_find_element_src_template =
93 GST_STATIC_PAD_TEMPLATE ("src",
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)
103 /* TypeFind signals and args */
120 MODE_NORMAL, /* act as identity */
121 MODE_TYPEFIND, /* do typefinding */
122 MODE_ERROR /* had fatal error */
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");
130 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
131 GST_TYPE_ELEMENT, _do_init);
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);
140 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
143 static gboolean gst_type_find_element_src_event (GstPad * pad,
145 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
147 static gboolean gst_type_find_element_handle_event (GstPad * pad,
149 static gboolean gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps);
150 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
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);
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);
161 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
163 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind);
165 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind);
167 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
170 gst_type_find_element_have_type (GstTypeFindElement * typefind,
171 guint probability, const GstCaps * caps)
175 g_assert (caps != NULL);
177 GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT ", probability=%u",
180 GST_OBJECT_LOCK (typefind);
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);
187 gst_pad_set_caps (typefind->src, copy);
188 gst_caps_unref (copy);
192 gst_type_find_element_base_init (gpointer g_class)
194 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
196 gst_element_class_set_details_simple (gstelement_class,
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));
208 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
210 GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
211 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
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;
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));
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
241 * This signal gets emitted when the type and its probability has
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);
250 typefind_class->have_type =
251 GST_DEBUG_FUNCPTR (gst_type_find_element_have_type);
253 gstelement_class->change_state =
254 GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
258 gst_type_find_element_init (GstTypeFindElement * typefind,
259 GstTypeFindElementClass * g_class)
263 gst_pad_new_from_static_template (&type_find_element_sink_template,
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);
278 gst_pad_new_from_static_template (&type_find_element_src_template, "src");
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);
293 typefind->mode = MODE_TYPEFIND;
294 typefind->caps = NULL;
295 typefind->min_probability = 1;
296 typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
298 typefind->store = NULL;
302 gst_type_find_element_dispose (GObject * object)
304 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
306 if (typefind->store) {
307 gst_buffer_unref (typefind->store);
308 typefind->store = NULL;
311 if (typefind->force_caps) {
312 gst_caps_unref (typefind->force_caps);
313 typefind->force_caps = NULL;
316 G_OBJECT_CLASS (parent_class)->dispose (object);
320 gst_type_find_element_set_property (GObject * object, guint prop_id,
321 const GValue * value, GParamSpec * pspec)
323 GstTypeFindElement *typefind;
325 typefind = GST_TYPE_FIND_ELEMENT (object);
329 typefind->min_probability = g_value_get_uint (value);
332 typefind->max_probability = g_value_get_uint (value);
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);
342 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
348 gst_type_find_element_get_property (GObject * object, guint prop_id,
349 GValue * value, GParamSpec * pspec)
351 GstTypeFindElement *typefind;
353 typefind = GST_TYPE_FIND_ELEMENT (object);
357 GST_OBJECT_LOCK (typefind);
358 g_value_set_boxed (value, typefind->caps);
359 GST_OBJECT_UNLOCK (typefind);
362 g_value_set_uint (value, typefind->min_probability);
365 g_value_set_uint (value, typefind->max_probability);
367 case PROP_FORCE_CAPS:
368 GST_OBJECT_LOCK (typefind);
369 g_value_set_boxed (value, typefind->force_caps);
370 GST_OBJECT_UNLOCK (typefind);
373 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
379 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
381 GstTypeFindElement *typefind;
382 gboolean res = FALSE;
385 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
387 peer = gst_pad_get_peer (typefind->sink);
391 res = gst_pad_query (peer, query);
395 switch (GST_QUERY_TYPE (query)) {
396 case GST_QUERY_POSITION:
401 GST_OBJECT_LOCK (typefind);
402 if (typefind->store == NULL) {
403 GST_OBJECT_UNLOCK (typefind);
407 gst_query_parse_position (query, &format, &peer_pos);
409 /* FIXME: this code assumes that there's no discont in the queue */
411 case GST_FORMAT_BYTES:
412 peer_pos -= GST_BUFFER_SIZE (typefind->store);
418 GST_OBJECT_UNLOCK (typefind);
419 gst_query_set_position (query, format, peer_pos);
427 gst_object_unref (peer);
432 static const GstEventMask *
433 gst_type_find_element_src_event_mask (GstPad * pad)
435 static const GstEventMask mask[] = {
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 */
448 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
450 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
452 if (typefind->mode != MODE_NORMAL) {
453 /* need to do more? */
454 gst_mini_object_unref (GST_MINI_OBJECT (event));
457 return gst_pad_push_event (typefind->sink, event);
461 start_typefinding (GstTypeFindElement * typefind)
463 GST_DEBUG_OBJECT (typefind, "starting typefinding");
464 gst_pad_set_caps (typefind->src, NULL);
466 GST_OBJECT_LOCK (typefind);
468 gst_caps_replace (&typefind->caps, NULL);
469 GST_OBJECT_UNLOCK (typefind);
471 typefind->mode = MODE_TYPEFIND;
475 stop_typefinding (GstTypeFindElement * typefind)
478 gboolean push_cached_buffers;
480 gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, 0);
482 push_cached_buffers = (state >= GST_STATE_PAUSED);
484 GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
485 push_cached_buffers ? " and pushing cached buffers" : "");
487 GST_OBJECT_LOCK (typefind);
488 if (typefind->store) {
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);
496 if (!push_cached_buffers) {
497 gst_buffer_unref (store);
499 GstPad *peer = gst_pad_get_peer (typefind->src);
501 typefind->mode = MODE_NORMAL;
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);
519 gst_type_find_element_send_cached_events (typefind);
520 gst_pad_push (typefind->src, store);
524 gst_object_unref (peer);
527 GST_OBJECT_UNLOCK (typefind);
532 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
534 gboolean res = FALSE;
535 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
537 GST_DEBUG_OBJECT (typefind, "got %s event in mode %d",
538 GST_EVENT_TYPE_NAME (event), typefind->mode);
540 switch (typefind->mode) {
542 switch (GST_EVENT_TYPE (event)) {
544 GstTypeFindProbability prob = GST_TYPE_FIND_NONE;
545 GstCaps *caps = NULL;
547 GST_INFO_OBJECT (typefind, "Got EOS and no type found yet");
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);
557 if (caps && prob >= typefind->min_probability) {
558 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
561 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND,
564 gst_caps_replace (&caps, NULL);
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"));
573 stop_typefinding (typefind);
574 res = gst_pad_push_event (typefind->src, event);
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);
586 case GST_EVENT_FLUSH_START:
587 res = gst_pad_push_event (typefind->src, event);
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);
601 res = gst_pad_push_event (typefind->src, event);
606 g_assert_not_reached ();
612 gst_type_find_element_send_cached_events (GstTypeFindElement * typefind)
614 GList *l, *cached_events;
616 GST_OBJECT_LOCK (typefind);
617 cached_events = typefind->cached_events;
618 typefind->cached_events = NULL;
619 GST_OBJECT_UNLOCK (typefind);
621 for (l = cached_events; l != NULL; l = l->next) {
622 GstEvent *event = GST_EVENT (l->data);
624 GST_DEBUG_OBJECT (typefind, "sending cached %s event",
625 GST_EVENT_TYPE_NAME (event));
626 gst_pad_push_event (typefind->src, event);
628 g_list_free (cached_events);
632 gst_type_find_element_setcaps (GstPad * pad, GstCaps * caps)
634 GstTypeFindElement *typefind;
636 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
638 /* don't operate on ANY caps */
639 if (gst_caps_is_any (caps))
642 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
643 GST_TYPE_FIND_MAXIMUM, caps);
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;
651 gst_type_find_element_send_cached_events (typefind);
652 GST_OBJECT_LOCK (typefind);
653 if (typefind->store) {
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);
661 GST_DEBUG_OBJECT (typefind, "Pushing store: %d", GST_BUFFER_SIZE (store));
662 gst_pad_push (typefind->src, store);
664 GST_OBJECT_UNLOCK (typefind);
672 gst_type_find_get_extension (GstTypeFindElement * typefind, GstPad * pad)
679 query = gst_query_new_uri ();
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;
685 gst_query_parse_uri (query, &uri);
689 GST_DEBUG_OBJECT (typefind, "finding extension of %s", uri);
691 /* find the extension on the uri, this is everything after a '.' */
696 if (uri[find] == '.')
703 result = g_strdup (&uri[find + 1]);
705 GST_DEBUG_OBJECT (typefind, "found extension %s", result);
706 gst_query_unref (query);
714 GST_WARNING_OBJECT (typefind, "failed to query peer uri");
715 gst_query_unref (query);
720 GST_WARNING_OBJECT (typefind, "could not parse the peer uri");
721 gst_query_unref (query);
726 GST_WARNING_OBJECT (typefind, "could not find uri extension in %s", uri);
727 gst_query_unref (query);
734 gst_type_find_guess_by_extension (GstTypeFindElement * typefind, GstPad * pad,
735 GstTypeFindProbability * probability)
740 ext = gst_type_find_get_extension (typefind, pad);
744 caps = gst_type_find_helper_for_extension (GST_OBJECT_CAST (typefind), ext);
746 *probability = GST_TYPE_FIND_MAXIMUM;
754 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
756 GstTypeFindElement *typefind;
757 GstFlowReturn res = GST_FLOW_OK;
759 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
761 GST_LOG_OBJECT (typefind, "handling buffer in mode %d", typefind->mode);
763 switch (typefind->mode) {
765 /* we should already have called GST_ELEMENT_ERROR */
766 return GST_FLOW_ERROR;
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);
773 GST_OBJECT_LOCK (typefind);
775 typefind->store = gst_buffer_join (typefind->store, buffer);
777 typefind->store = buffer;
778 GST_OBJECT_UNLOCK (typefind);
780 res = gst_type_find_element_chain_do_typefinding (typefind);
782 if (typefind->mode == MODE_ERROR)
783 res = GST_FLOW_ERROR;
788 g_assert_not_reached ();
789 return GST_FLOW_ERROR;
796 gst_type_find_element_chain_do_typefinding (GstTypeFindElement * typefind)
798 GstTypeFindProbability probability;
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);
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));
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);
829 gst_caps_replace (&caps, NULL);
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;
838 GST_OBJECT_UNLOCK (typefind);
839 GST_DEBUG_OBJECT (typefind, "waiting for more data to try again");
842 GST_OBJECT_UNLOCK (typefind);
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,
848 /* .. and send out the accumulated data */
849 stop_typefinding (typefind);
850 gst_caps_unref (caps);
855 gst_type_find_element_checkgetrange (GstPad * srcpad)
857 GstTypeFindElement *typefind;
859 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
861 return gst_pad_check_pull_range (typefind->sink);
865 gst_type_find_element_getrange (GstPad * srcpad,
866 guint64 offset, guint length, GstBuffer ** buffer)
868 GstTypeFindElement *typefind;
871 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
873 ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
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);
885 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
887 GstTypeFindElement *typefind;
889 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
891 return gst_pad_activate_pull (typefind->sink, active);
895 gst_type_find_element_activate (GstPad * pad)
897 GstTypeFindProbability probability = GST_TYPE_FIND_NONE;
898 GstCaps *found_caps = NULL;
899 GstTypeFindElement *typefind;
901 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
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);
911 GST_OBJECT_UNLOCK (typefind);
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
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.
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);
931 GST_DEBUG_OBJECT (typefind, "find type in pull mode");
937 peer = gst_pad_get_peer (pad);
940 GstFormat format = GST_FORMAT_BYTES;
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);
950 /* the size if 0, we cannot continue */
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);
959 ext = gst_type_find_get_extension (typefind, pad);
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);
966 gst_object_unref (peer);
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
974 * If we deactivate the pads in the following steps we might mess up
975 * downstream element. We should prevent that.
977 if (typefind->mode == MODE_NORMAL) {
978 /* this means we already emitted typefound */
979 GST_DEBUG ("Already managed to typefind !");
984 gst_pad_activate_pull (pad, FALSE);
987 gst_pad_activate_push (typefind->src, FALSE);
990 if (!found_caps || probability < typefind->min_probability) {
991 found_caps = gst_type_find_guess_by_extension (typefind, pad, &probability);
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);
1003 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
1004 0, probability, found_caps);
1005 typefind->mode = MODE_NORMAL;
1007 gst_caps_unref (found_caps);
1010 if (gst_pad_is_active (pad))
1015 ret = gst_pad_activate_push (typefind->src, TRUE);
1016 ret &= gst_pad_activate_push (pad, TRUE);
1021 static GstStateChangeReturn
1022 gst_type_find_element_change_state (GstElement * element,
1023 GstStateChange transition)
1025 GstStateChangeReturn ret;
1026 GstTypeFindElement *typefind;
1028 typefind = GST_TYPE_FIND_ELEMENT (element);
1031 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
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);
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);