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 /* FIXME: need a better solution for non-seekable streams */
25 * 1) get a list of all typefind functions sorted best to worst
26 * 2) if all elements have been called with all requested data goto 8
27 * 3) call all functions once with all available data
28 * 4) if a function returns a value >= ARG_MAXIMUM goto 8
29 * 5) all functions with a result > ARG_MINIMUM or functions that did not get
30 * all requested data (where peek returned NULL) stay in list
31 * 6) seek to requested offset of best function that still has open data
34 * 8) take best available result and use its caps
36 * The element has two scheduling modes:
38 * 1) chain based, it will collect buffers and run the typefind function on
39 * the buffer until something is found.
40 * 2) getrange based, it will proxy the getrange function to the sinkpad. It
41 * is assumed that the peer element is happy with whatever format we
44 * When the element has no connected srcpad, and the sinkpad can operate in
45 * getrange based mode, the element starts its own task to figure out the
54 #include "gsttypefindelement.h"
55 #include "gst/gst_private.h"
56 #include "gst/gst-i18n-lib.h"
57 #include "gst/base/gsttypefindhelper.h"
59 #include <gst/gsttypefind.h>
60 #include <gst/gstutils.h>
61 #include <gst/gsterror.h>
63 GST_DEBUG_CATEGORY_STATIC (gst_type_find_element_debug);
64 #define GST_CAT_DEFAULT gst_type_find_element_debug
66 static GstElementDetails gst_type_find_element_details =
67 GST_ELEMENT_DETAILS ("TypeFind",
69 "Finds the media type of a stream",
70 "Benjamin Otte <in7y118@public.uni-hamburg.de>");
72 /* generic templates */
73 GstStaticPadTemplate type_find_element_sink_template =
74 GST_STATIC_PAD_TEMPLATE ("sink",
79 GstStaticPadTemplate type_find_element_src_template =
80 GST_STATIC_PAD_TEMPLATE ("src",
85 /* TypeFind signals and args */
100 MODE_NORMAL, /* act as identity */
101 MODE_TYPEFIND /* do typefinding */
105 #define _do_init(bla) \
106 GST_DEBUG_CATEGORY_INIT (gst_type_find_element_debug, "typefind", \
107 GST_DEBUG_BG_YELLOW | GST_DEBUG_FG_GREEN, "type finding element");
109 GST_BOILERPLATE_FULL (GstTypeFindElement, gst_type_find_element, GstElement,
110 GST_TYPE_ELEMENT, _do_init);
112 static void gst_type_find_element_dispose (GObject * object);
113 static void gst_type_find_element_set_property (GObject * object,
114 guint prop_id, const GValue * value, GParamSpec * pspec);
115 static void gst_type_find_element_get_property (GObject * object,
116 guint prop_id, GValue * value, GParamSpec * pspec);
119 static const GstEventMask *gst_type_find_element_src_event_mask (GstPad * pad);
122 static gboolean gst_type_find_element_src_event (GstPad * pad,
124 static gboolean gst_type_find_handle_src_query (GstPad * pad, GstQuery * query);
126 static gboolean gst_type_find_element_handle_event (GstPad * pad,
128 static GstFlowReturn gst_type_find_element_chain (GstPad * sinkpad,
130 static GstFlowReturn gst_type_find_element_getrange (GstPad * srcpad,
131 guint64 offset, guint length, GstBuffer ** buffer);
132 static gboolean gst_type_find_element_checkgetrange (GstPad * srcpad);
134 static GstStateChangeReturn
135 gst_type_find_element_change_state (GstElement * element,
136 GstStateChange transition);
137 static gboolean gst_type_find_element_activate (GstPad * pad);
139 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
141 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
144 gst_type_find_element_have_type (GstTypeFindElement * typefind,
145 guint probability, const GstCaps * caps)
147 g_assert (typefind->caps == NULL);
148 g_assert (caps != NULL);
150 GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT, caps);
151 typefind->caps = gst_caps_copy (caps);
152 gst_pad_set_caps (typefind->src, (GstCaps *) caps);
156 gst_type_find_element_base_init (gpointer g_class)
158 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
160 gst_element_class_add_pad_template (gstelement_class,
161 gst_static_pad_template_get (&type_find_element_src_template));
162 gst_element_class_add_pad_template (gstelement_class,
163 gst_static_pad_template_get (&type_find_element_sink_template));
164 gst_element_class_set_details (gstelement_class,
165 &gst_type_find_element_details);
168 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
170 GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
171 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
173 gobject_class->set_property =
174 GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
175 gobject_class->get_property =
176 GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
177 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
179 typefind_class->have_type = gst_type_find_element_have_type;
181 g_object_class_install_property (gobject_class, ARG_CAPS,
182 g_param_spec_boxed ("caps", _("caps"),
183 _("detected capabilities in stream"), gst_caps_get_type (),
185 g_object_class_install_property (gobject_class, ARG_MINIMUM,
186 g_param_spec_uint ("minimum", _("minimum"),
187 "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
188 GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
189 g_object_class_install_property (gobject_class, ARG_MINIMUM,
190 g_param_spec_uint ("maximum", _("maximum"),
191 "probability to stop typefinding", GST_TYPE_FIND_MINIMUM,
192 GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
194 gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
195 G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_LAST,
196 G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
197 gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
198 G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
200 gstelement_class->change_state =
201 GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
204 gst_type_find_element_init (GstTypeFindElement * typefind,
205 GstTypeFindElementClass * g_class)
209 gst_pad_new_from_static_template (&type_find_element_sink_template,
212 gst_pad_set_activate_function (typefind->sink,
213 GST_DEBUG_FUNCPTR (gst_type_find_element_activate));
214 gst_pad_set_chain_function (typefind->sink,
215 GST_DEBUG_FUNCPTR (gst_type_find_element_chain));
216 gst_pad_set_event_function (typefind->sink,
217 GST_DEBUG_FUNCPTR (gst_type_find_element_handle_event));
218 gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
222 gst_pad_new_from_static_template (&type_find_element_src_template, "src");
224 gst_pad_set_activatepull_function (typefind->src,
225 GST_DEBUG_FUNCPTR (gst_type_find_element_activate_src_pull));
226 gst_pad_set_checkgetrange_function (typefind->src,
227 GST_DEBUG_FUNCPTR (gst_type_find_element_checkgetrange));
228 gst_pad_set_getrange_function (typefind->src,
229 GST_DEBUG_FUNCPTR (gst_type_find_element_getrange));
230 gst_pad_set_event_function (typefind->src,
231 GST_DEBUG_FUNCPTR (gst_type_find_element_src_event));
232 gst_pad_set_query_function (typefind->src,
233 GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
234 gst_pad_use_fixed_caps (typefind->src);
235 gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
237 typefind->mode = MODE_TYPEFIND;
238 typefind->caps = NULL;
239 typefind->min_probability = 1;
240 typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
242 typefind->store = NULL;
245 gst_type_find_element_dispose (GObject * object)
247 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
249 G_OBJECT_CLASS (parent_class)->dispose (object);
251 if (typefind->store) {
252 gst_buffer_unref (typefind->store);
253 typefind->store = NULL;
257 gst_type_find_element_set_property (GObject * object, guint prop_id,
258 const GValue * value, GParamSpec * pspec)
260 GstTypeFindElement *typefind;
262 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
264 typefind = GST_TYPE_FIND_ELEMENT (object);
268 typefind->min_probability = g_value_get_uint (value);
269 g_object_notify (object, "minimum");
272 typefind->max_probability = g_value_get_uint (value);
273 g_object_notify (object, "maximum");
276 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
281 gst_type_find_element_get_property (GObject * object, guint prop_id,
282 GValue * value, GParamSpec * pspec)
284 GstTypeFindElement *typefind;
286 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
288 typefind = GST_TYPE_FIND_ELEMENT (object);
292 g_value_set_boxed (value, typefind->caps);
295 g_value_set_uint (value, typefind->min_probability);
298 g_value_set_uint (value, typefind->max_probability);
301 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
307 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
309 GstTypeFindElement *typefind;
312 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
314 res = gst_pad_query (GST_PAD_PEER (typefind->sink), query);
318 switch (GST_QUERY_TYPE (query)) {
319 case GST_QUERY_POSITION:
324 if (typefind->store == NULL)
327 gst_query_parse_position (query, &format, &peer_pos);
329 /* FIXME: this code assumes that there's no discont in the queue */
331 case GST_FORMAT_BYTES:
332 peer_pos -= typefind->store->size;
338 gst_query_set_position (query, format, peer_pos);
349 static const GstEventMask *
350 gst_type_find_element_src_event_mask (GstPad * pad)
352 static const GstEventMask mask[] = {
354 GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
355 GST_SEEK_FLAG_FLUSH},
356 /* add more if you want, event masks suck and need to die anyway */
365 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
367 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
369 if (typefind->mode != MODE_NORMAL) {
370 /* need to do more? */
371 gst_mini_object_unref (GST_MINI_OBJECT (event));
374 return gst_pad_event_default (pad, event);
378 GstTypeFindFactory *factory;
381 guint requested_size;
382 GstTypeFindElement *self;
386 static inline TypeFindEntry *
389 return g_new0 (TypeFindEntry, 1);
392 free_entry (TypeFindEntry * entry)
395 gst_caps_unref (entry->caps);
399 start_typefinding (GstTypeFindElement * typefind)
401 g_assert (typefind->possibilities == NULL);
403 GST_DEBUG_OBJECT (typefind, "starting typefinding");
404 gst_pad_set_caps (typefind->src, NULL);
405 if (typefind->caps) {
406 gst_caps_replace (&typefind->caps, NULL);
408 typefind->mode = MODE_TYPEFIND;
409 typefind->stream_length_available = TRUE;
410 typefind->stream_length = 0;
413 stop_typefinding (GstTypeFindElement * typefind)
416 gboolean push_cached_buffers;
418 gst_element_get_state (GST_ELEMENT (typefind), &state, NULL,
419 GST_CLOCK_TIME_NONE);
421 push_cached_buffers = (state >= GST_STATE_PAUSED);
423 GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
424 push_cached_buffers ? " and pushing cached buffers" : "");
425 if (typefind->possibilities != NULL) {
426 /* this should only happen on PAUSED => READY or EOS */
427 GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
428 g_list_length (typefind->possibilities));
429 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
430 g_list_free (typefind->possibilities);
431 typefind->possibilities = NULL;
433 //typefind->mode = MODE_TRANSITION;
435 if (typefind->store) {
436 if (!push_cached_buffers) {
437 gst_buffer_unref (typefind->store);
439 typefind->mode = MODE_NORMAL;
440 gst_buffer_set_caps (typefind->store, typefind->caps);
441 gst_pad_push (typefind->src, typefind->store);
443 typefind->store = NULL;
448 find_element_get_length (gpointer data)
450 TypeFindEntry *entry = (TypeFindEntry *) data;
451 GstTypeFindElement *typefind = entry->self;
452 GstFormat format = GST_FORMAT_BYTES;
454 if (!typefind->stream_length_available) {
455 GST_LOG_OBJECT (entry->self,
456 "'%s' called get_length () but we know it's not available",
457 GST_PLUGIN_FEATURE_NAME (entry->factory));
460 if (entry->self->stream_length == 0) {
461 if (!gst_pad_query_duration (GST_PAD_PEER (entry->self->sink), &format,
462 (gint64 *) & entry->self->stream_length))
465 if (format != GST_FORMAT_BYTES) {
466 typefind->stream_length_available = FALSE;
467 entry->self->stream_length = 0;
469 GST_DEBUG_OBJECT (entry->self,
470 "'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
471 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
474 return entry->self->stream_length;
478 typefind->stream_length_available = FALSE;
479 GST_DEBUG_OBJECT (entry->self,
480 "'%s' called get_length () but it's not available",
481 GST_PLUGIN_FEATURE_NAME (entry->factory));
487 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
489 gboolean res = FALSE;
490 TypeFindEntry *entry;
491 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
493 GST_DEBUG_OBJECT (typefind, "got event %d in mode %d", GST_EVENT_TYPE (event),
496 switch (typefind->mode) {
498 switch (GST_EVENT_TYPE (event)) {
500 /* this should only happen when we got all available data */
502 (TypeFindEntry *) typefind->possibilities ? typefind->
503 possibilities->data : NULL;
504 if (entry && entry->probability >= typefind->min_probability) {
505 GST_INFO_OBJECT (typefind,
506 "'%s' is the best typefind left after we got all data, using it now (probability %u)",
507 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
508 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
509 0, entry->probability, entry->caps);
510 stop_typefinding (typefind);
511 gst_buffer_set_caps (typefind->store, typefind->caps);
512 gst_pad_push (typefind->src, typefind->store);
513 typefind->store = NULL;
514 res = gst_pad_event_default (pad, event);
516 res = gst_pad_event_default (pad, event);
517 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL),
519 stop_typefinding (typefind);
523 gst_mini_object_unref (GST_MINI_OBJECT (event));
529 if (FALSE) { // GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) {
530 start_typefinding (typefind);
531 gst_event_unref (event);
534 res = gst_pad_event_default (pad, event);
538 g_assert_not_reached ();
543 find_peek (gpointer data, gint64 offset, guint size)
545 TypeFindEntry *entry = (TypeFindEntry *) data;
547 GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
548 GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
552 if (size <= entry->self->store->size) {
553 return GST_BUFFER_DATA (entry->self->store);
555 entry->requested_size = size;
557 GST_LOG_OBJECT (entry->self,
558 "setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
559 size, GST_PLUGIN_FEATURE_NAME (entry->factory));
564 find_suggest (gpointer data, guint probability, const GstCaps * caps)
566 TypeFindEntry *entry = (TypeFindEntry *) data;
568 GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
569 GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
570 if (((gint) probability) > entry->probability) {
571 entry->probability = probability;
572 gst_caps_replace (&entry->caps, (GstCaps *) caps);
578 compare_type_find_entry (gconstpointer a, gconstpointer b)
580 TypeFindEntry *one = (TypeFindEntry *) a;
581 TypeFindEntry *two = (TypeFindEntry *) b;
583 if (one->probability == two->probability) {
584 /* FIXME: can be improved by analyzing requests */
587 return two->probability - one->probability;
593 compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
595 return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
599 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
601 GstTypeFindElement *typefind;
603 TypeFindEntry *entry;
605 GstFlowReturn res = GST_FLOW_OK;
606 GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
608 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
610 switch (typefind->mode) {
612 gst_buffer_set_caps (buffer, typefind->caps);
613 return gst_pad_push (typefind->src, buffer);
615 gboolean done = TRUE;
618 typefind->store = gst_buffer_join (typefind->store, buffer);
620 typefind->store = buffer;
622 if (typefind->possibilities == NULL) {
623 /* not yet started, get all typefinding functions into our "queue" */
624 GList *all_factories = gst_type_find_factory_get_list ();
626 GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
627 g_list_length (all_factories));
629 all_factories = g_list_sort (all_factories, compare_type_find_factory);
630 walk = all_factories;
631 while (all_factories) {
632 entry = new_entry ();
634 entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
635 entry->self = typefind;
636 entry->probability = 0;
637 typefind->possibilities =
638 g_list_prepend (typefind->possibilities, entry);
639 all_factories = g_list_next (all_factories);
641 gst_plugin_feature_list_free (all_factories);
644 /* call every typefind function once */
645 walk = entries = typefind->possibilities;
646 GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
647 g_list_length (entries));
648 typefind->possibilities = NULL;
650 find.data = entry = (TypeFindEntry *) walk->data;
651 walk = g_list_next (walk);
652 if (entry->probability == 0) {
653 entry->requested_size = 0;
654 gst_type_find_factory_call_function (entry->factory, &find);
656 typefind->possibilities =
657 g_list_prepend (typefind->possibilities, entry);
660 if (entry->probability == 0 && entry->requested_size == 0) {
661 GST_DEBUG_OBJECT (typefind,
662 "'%s' was removed - no chance of being the right plugin",
663 GST_PLUGIN_FEATURE_NAME (entry->factory));
665 } else if (entry->probability >= typefind->max_probability) {
666 /* wooha, got caps */
667 GstCaps *found_caps = entry->caps;
668 guint probability = entry->probability;
670 GST_INFO_OBJECT (typefind,
671 "'%s' returned %u/%u probability, using it NOW",
672 GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
673 typefind->max_probability);
675 free_entry ((TypeFindEntry *) walk->data);
676 walk = g_list_next (walk);
678 walk = typefind->possibilities;
680 free_entry (walk->data);
681 walk = g_list_next (walk);
683 g_list_free (typefind->possibilities);
684 typefind->possibilities = NULL;
685 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
686 probability, found_caps);
689 typefind->possibilities =
690 g_list_prepend (typefind->possibilities, entry);
691 if (entry->requested_size != 0)
695 g_list_free (entries);
697 /* we may now already have caps or we might be left without functions to try */
698 if (typefind->caps) {
699 stop_typefinding (typefind);
700 } else if (typefind->possibilities == NULL) {
701 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
702 stop_typefinding (typefind);
703 return GST_FLOW_ERROR;
705 TypeFindEntry *best = NULL;
707 walk = typefind->possibilities;
709 entry = (TypeFindEntry *) typefind->possibilities->data;
710 if ((!best || entry->probability > best->probability) &&
711 entry->probability >= typefind->min_probability) {
714 walk = g_list_next (walk);
718 GST_INFO_OBJECT (typefind,
719 "'%s' is the only typefind left, using it now (probability %u)",
720 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
721 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
722 0, entry->probability, entry->caps);
723 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
724 g_list_free (typefind->possibilities);
725 typefind->possibilities = NULL;
726 stop_typefinding (typefind);
728 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
729 stop_typefinding (typefind);
730 return GST_FLOW_ERROR;
736 g_assert_not_reached ();
737 return GST_FLOW_ERROR;
744 gst_type_find_element_checkgetrange (GstPad * srcpad)
746 GstTypeFindElement *typefind;
748 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
750 return gst_pad_check_pull_range (typefind->sink);
754 gst_type_find_element_getrange (GstPad * srcpad,
755 guint64 offset, guint length, GstBuffer ** buffer)
757 GstTypeFindElement *typefind;
760 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
762 ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
764 if (ret == GST_FLOW_OK && buffer && *buffer)
765 gst_buffer_set_caps (*buffer, typefind->caps);
771 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
773 GstTypeFindElement *typefind;
775 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
777 return gst_pad_activate_pull (typefind->sink, active);
781 gst_type_find_element_activate (GstPad * pad)
783 GstCaps *found_caps = NULL;
784 GstTypeFindElement *typefind;
786 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
788 /* 1. try to activate in pull mode. if not, switch to push and succeed.
789 2. try to pull type find.
790 3. deactivate pull mode.
791 4. src pad might have been activated push by the state change. deactivate.
792 5. if we didn't find any caps, fail.
793 6. emit have-type; maybe the app connected the source pad to something.
794 7. if the sink pad is activated, we are in pull mode. succeed.
795 otherwise activate both pads in push mode and succeed.
799 if (!gst_pad_activate_pull (pad, TRUE)) {
800 start_typefinding (typefind);
801 return gst_pad_activate_push (pad, TRUE);
808 peer = gst_pad_get_peer (pad);
811 GstFormat format = GST_FORMAT_BYTES;
813 gst_pad_query_duration (peer, &format, &size);
814 found_caps = gst_type_find_helper (peer, (guint64) size);
815 gst_object_unref (peer);
820 gst_pad_activate_pull (pad, FALSE);
823 gst_pad_activate_push (typefind->src, FALSE);
830 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
832 gst_caps_unref (found_caps);
833 typefind->mode = MODE_NORMAL;
836 if (gst_pad_is_active (pad))
841 ret = gst_pad_activate_push (typefind->src, TRUE);
842 ret &= gst_pad_activate_push (pad, TRUE);
847 static GstStateChangeReturn
848 gst_type_find_element_change_state (GstElement * element,
849 GstStateChange transition)
851 GstStateChangeReturn ret;
852 GstTypeFindElement *typefind;
854 typefind = GST_TYPE_FIND_ELEMENT (element);
857 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
859 switch (transition) {
860 case GST_STATE_CHANGE_PAUSED_TO_READY:
861 gst_caps_replace (&typefind->caps, NULL);