2 * Copyright (C) 2003 Benjamin Otte <in7y118@public.uni-hamburg.de>
4 * gsttypefind.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 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 GstElementStateReturn
135 gst_type_find_element_change_state (GstElement * element);
136 static gboolean gst_type_find_element_activate (GstPad * pad);
138 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active);
140 static guint gst_type_find_element_signals[LAST_SIGNAL] = { 0 };
143 gst_type_find_element_have_type (GstTypeFindElement * typefind,
144 guint probability, const GstCaps * caps)
146 g_assert (typefind->caps == NULL);
147 g_assert (caps != NULL);
149 GST_INFO_OBJECT (typefind, "found caps %" GST_PTR_FORMAT, caps);
150 typefind->caps = gst_caps_copy (caps);
151 gst_pad_set_caps (typefind->src, (GstCaps *) caps);
155 gst_type_find_element_base_init (gpointer g_class)
157 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (g_class);
159 gst_element_class_add_pad_template (gstelement_class,
160 gst_static_pad_template_get (&type_find_element_src_template));
161 gst_element_class_add_pad_template (gstelement_class,
162 gst_static_pad_template_get (&type_find_element_sink_template));
163 gst_element_class_set_details (gstelement_class,
164 &gst_type_find_element_details);
167 gst_type_find_element_class_init (GstTypeFindElementClass * typefind_class)
169 GObjectClass *gobject_class = G_OBJECT_CLASS (typefind_class);
170 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (typefind_class);
172 gobject_class->set_property =
173 GST_DEBUG_FUNCPTR (gst_type_find_element_set_property);
174 gobject_class->get_property =
175 GST_DEBUG_FUNCPTR (gst_type_find_element_get_property);
176 gobject_class->dispose = GST_DEBUG_FUNCPTR (gst_type_find_element_dispose);
178 typefind_class->have_type = gst_type_find_element_have_type;
180 g_object_class_install_property (gobject_class, ARG_CAPS,
181 g_param_spec_boxed ("caps", _("caps"),
182 _("detected capabilities in stream"), gst_caps_get_type (),
184 g_object_class_install_property (gobject_class, ARG_MINIMUM,
185 g_param_spec_uint ("minimum", _("minimum"),
186 "minimum probability required to accept caps", GST_TYPE_FIND_MINIMUM,
187 GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MINIMUM, G_PARAM_READWRITE));
188 g_object_class_install_property (gobject_class, ARG_MINIMUM,
189 g_param_spec_uint ("maximum", _("maximum"),
190 "probability to stop typefinding", GST_TYPE_FIND_MINIMUM,
191 GST_TYPE_FIND_MAXIMUM, GST_TYPE_FIND_MAXIMUM, G_PARAM_READWRITE));
193 gst_type_find_element_signals[HAVE_TYPE] = g_signal_new ("have_type",
194 G_TYPE_FROM_CLASS (typefind_class), G_SIGNAL_RUN_LAST,
195 G_STRUCT_OFFSET (GstTypeFindElementClass, have_type), NULL, NULL,
196 gst_marshal_VOID__UINT_BOXED, G_TYPE_NONE, 2,
197 G_TYPE_UINT, GST_TYPE_CAPS | G_SIGNAL_TYPE_STATIC_SCOPE);
199 gstelement_class->change_state =
200 GST_DEBUG_FUNCPTR (gst_type_find_element_change_state);
203 gst_type_find_element_init (GstTypeFindElement * typefind)
207 gst_pad_new_from_template (gst_static_pad_template_get
208 (&type_find_element_sink_template), "sink");
209 gst_pad_set_activate_function (typefind->sink,
210 gst_type_find_element_activate);
211 gst_pad_set_chain_function (typefind->sink, gst_type_find_element_chain);
212 gst_pad_set_event_function (typefind->sink,
213 gst_type_find_element_handle_event);
214 gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
217 gst_pad_new_from_template (gst_static_pad_template_get
218 (&type_find_element_src_template), "src");
219 gst_pad_set_activatepull_function (typefind->src,
220 gst_type_find_element_activate_src_pull);
221 gst_pad_set_checkgetrange_function (typefind->src,
222 gst_type_find_element_checkgetrange);
223 gst_pad_set_getrange_function (typefind->src, gst_type_find_element_getrange);
224 gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
225 gst_pad_set_query_function (typefind->src,
226 GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
227 gst_pad_use_fixed_caps (typefind->src);
228 gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
230 typefind->mode = MODE_TYPEFIND;
231 typefind->caps = NULL;
232 typefind->min_probability = 1;
233 typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
235 typefind->store = NULL;
238 gst_type_find_element_dispose (GObject * object)
240 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
242 G_OBJECT_CLASS (parent_class)->dispose (object);
244 if (typefind->store) {
245 gst_buffer_unref (typefind->store);
246 typefind->store = NULL;
250 gst_type_find_element_set_property (GObject * object, guint prop_id,
251 const GValue * value, GParamSpec * pspec)
253 GstTypeFindElement *typefind;
255 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
257 typefind = GST_TYPE_FIND_ELEMENT (object);
261 typefind->min_probability = g_value_get_uint (value);
262 g_object_notify (object, "minimum");
265 typefind->max_probability = g_value_get_uint (value);
266 g_object_notify (object, "maximum");
269 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
274 gst_type_find_element_get_property (GObject * object, guint prop_id,
275 GValue * value, GParamSpec * pspec)
277 GstTypeFindElement *typefind;
279 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
281 typefind = GST_TYPE_FIND_ELEMENT (object);
285 g_value_set_boxed (value, typefind->caps);
288 g_value_set_uint (value, typefind->min_probability);
291 g_value_set_uint (value, typefind->max_probability);
294 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
300 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
302 GstTypeFindElement *typefind;
305 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
307 res = gst_pad_query (GST_PAD_PEER (typefind->sink), query);
311 switch (GST_QUERY_TYPE (query)) {
312 case GST_QUERY_POSITION:
314 gint64 peer_pos, peer_total;
317 if (typefind->store == NULL)
320 gst_query_parse_position (query, &format, &peer_pos, &peer_total);
322 /* FIXME: this code assumes that there's no discont in the queue */
324 case GST_FORMAT_BYTES:
325 peer_pos -= typefind->store->size;
331 gst_query_set_position (query, format, peer_pos, peer_total);
342 static const GstEventMask *
343 gst_type_find_element_src_event_mask (GstPad * pad)
345 static const GstEventMask mask[] = {
347 GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
348 GST_SEEK_FLAG_FLUSH},
349 /* add more if you want, event masks suck and need to die anyway */
358 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
360 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
362 if (typefind->mode != MODE_NORMAL) {
363 /* need to do more? */
364 gst_mini_object_unref (GST_MINI_OBJECT (event));
367 return gst_pad_event_default (pad, event);
371 GstTypeFindFactory *factory;
374 guint requested_size;
375 GstTypeFindElement *self;
379 static inline TypeFindEntry *
382 return g_new0 (TypeFindEntry, 1);
385 free_entry (TypeFindEntry * entry)
388 gst_caps_unref (entry->caps);
392 start_typefinding (GstTypeFindElement * typefind)
394 g_assert (typefind->possibilities == NULL);
396 GST_DEBUG_OBJECT (typefind, "starting typefinding");
397 gst_pad_set_caps (typefind->src, NULL);
398 if (typefind->caps) {
399 gst_caps_replace (&typefind->caps, NULL);
401 typefind->mode = MODE_TYPEFIND;
402 typefind->stream_length_available = TRUE;
403 typefind->stream_length = 0;
406 stop_typefinding (GstTypeFindElement * typefind)
408 GstElementState state;
409 gboolean push_cached_buffers;
411 gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, NULL);
413 push_cached_buffers = (state >= GST_STATE_PAUSED);
415 GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
416 push_cached_buffers ? " and pushing cached buffers" : "");
417 if (typefind->possibilities != NULL) {
418 /* this should only happen on PAUSED => READY or EOS */
419 GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
420 g_list_length (typefind->possibilities));
421 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
422 g_list_free (typefind->possibilities);
423 typefind->possibilities = NULL;
425 //typefind->mode = MODE_TRANSITION;
427 if (typefind->store) {
428 if (!push_cached_buffers) {
429 gst_buffer_unref (typefind->store);
431 typefind->mode = MODE_NORMAL;
432 gst_pad_push (typefind->src, typefind->store);
434 typefind->store = NULL;
439 find_element_get_length (gpointer data)
441 TypeFindEntry *entry = (TypeFindEntry *) data;
442 GstTypeFindElement *typefind = entry->self;
443 GstFormat format = GST_FORMAT_BYTES;
445 if (!typefind->stream_length_available) {
446 GST_LOG_OBJECT (entry->self,
447 "'%s' called get_length () but we know it's not available",
448 GST_PLUGIN_FEATURE_NAME (entry->factory));
451 if (entry->self->stream_length == 0) {
452 if (!gst_pad_query_position (GST_PAD_PEER (entry->self->sink), &format,
453 NULL, (gint64 *) & entry->self->stream_length))
456 if (format != GST_FORMAT_BYTES) {
457 typefind->stream_length_available = FALSE;
458 entry->self->stream_length = 0;
460 GST_DEBUG_OBJECT (entry->self,
461 "'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
462 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
465 return entry->self->stream_length;
469 typefind->stream_length_available = FALSE;
470 GST_DEBUG_OBJECT (entry->self,
471 "'%s' called get_length () but it's not available",
472 GST_PLUGIN_FEATURE_NAME (entry->factory));
478 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
480 gboolean res = FALSE;
481 TypeFindEntry *entry;
482 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
484 GST_DEBUG_OBJECT (typefind, "got event %d in mode %d", GST_EVENT_TYPE (event),
487 switch (typefind->mode) {
489 switch (GST_EVENT_TYPE (event)) {
491 /* this should only happen when we got all available data */
493 (TypeFindEntry *) typefind->possibilities ? typefind->
494 possibilities->data : NULL;
495 if (entry && entry->probability >= typefind->min_probability) {
496 GST_INFO_OBJECT (typefind,
497 "'%s' is the best typefind left after we got all data, using it now (probability %u)",
498 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
499 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
500 0, entry->probability, entry->caps);
501 stop_typefinding (typefind);
502 gst_pad_push (typefind->src, typefind->store);
503 typefind->store = NULL;
504 res = gst_pad_event_default (pad, event);
506 res = gst_pad_event_default (pad, event);
507 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL),
509 stop_typefinding (typefind);
513 gst_mini_object_unref (GST_MINI_OBJECT (event));
519 if (FALSE) { // GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) {
520 start_typefinding (typefind);
521 gst_event_unref (event);
524 res = gst_pad_event_default (pad, event);
528 g_assert_not_reached ();
533 find_peek (gpointer data, gint64 offset, guint size)
535 TypeFindEntry *entry = (TypeFindEntry *) data;
537 GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
538 GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
542 if (size <= entry->self->store->size) {
543 return GST_BUFFER_DATA (entry->self->store);
545 entry->requested_size = size;
547 GST_LOG_OBJECT (entry->self,
548 "setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
549 size, GST_PLUGIN_FEATURE_NAME (entry->factory));
554 find_suggest (gpointer data, guint probability, const GstCaps * caps)
556 TypeFindEntry *entry = (TypeFindEntry *) data;
558 GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
559 GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
560 if (((gint) probability) > entry->probability) {
561 entry->probability = probability;
562 gst_caps_replace (&entry->caps, (GstCaps *) caps);
568 compare_type_find_entry (gconstpointer a, gconstpointer b)
570 TypeFindEntry *one = (TypeFindEntry *) a;
571 TypeFindEntry *two = (TypeFindEntry *) b;
573 if (one->probability == two->probability) {
574 /* FIXME: can be improved by analyzing requests */
577 return two->probability - one->probability;
583 compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
585 return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
589 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
591 GstTypeFindElement *typefind;
593 TypeFindEntry *entry;
595 GstFlowReturn res = GST_FLOW_OK;
596 GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
598 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
600 switch (typefind->mode) {
602 return gst_pad_push (typefind->src, buffer);
604 gboolean done = TRUE;
607 typefind->store = gst_buffer_join (typefind->store, buffer);
609 typefind->store = buffer;
611 if (typefind->possibilities == NULL) {
612 /* not yet started, get all typefinding functions into our "queue" */
613 GList *all_factories = gst_type_find_factory_get_list ();
615 GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
616 g_list_length (all_factories));
618 all_factories = g_list_sort (all_factories, compare_type_find_factory);
619 walk = all_factories;
620 while (all_factories) {
621 entry = new_entry ();
623 entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
624 entry->self = typefind;
625 entry->probability = 0;
626 typefind->possibilities =
627 g_list_prepend (typefind->possibilities, entry);
628 all_factories = g_list_next (all_factories);
630 g_list_free (all_factories);
633 /* call every typefind function once */
634 walk = entries = typefind->possibilities;
635 GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
636 g_list_length (entries));
637 typefind->possibilities = NULL;
639 find.data = entry = (TypeFindEntry *) walk->data;
640 walk = g_list_next (walk);
641 if (entry->probability == 0) {
642 entry->requested_size = 0;
643 gst_type_find_factory_call_function (entry->factory, &find);
645 typefind->possibilities =
646 g_list_prepend (typefind->possibilities, entry);
649 if (entry->probability == 0 && entry->requested_size == 0) {
650 GST_DEBUG_OBJECT (typefind,
651 "'%s' was removed - no chance of being the right plugin",
652 GST_PLUGIN_FEATURE_NAME (entry->factory));
654 } else if (entry->probability >= typefind->max_probability) {
655 /* wooha, got caps */
656 GstCaps *found_caps = entry->caps;
657 guint probability = entry->probability;
659 GST_INFO_OBJECT (typefind,
660 "'%s' returned %u/%u probability, using it NOW",
661 GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
662 typefind->max_probability);
664 free_entry ((TypeFindEntry *) walk->data);
665 walk = g_list_next (walk);
667 walk = typefind->possibilities;
669 free_entry (walk->data);
670 walk = g_list_next (walk);
672 g_list_free (typefind->possibilities);
673 typefind->possibilities = NULL;
674 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
675 probability, found_caps);
678 typefind->possibilities =
679 g_list_prepend (typefind->possibilities, entry);
680 if (entry->requested_size != 0)
684 g_list_free (entries);
686 /* we may now already have caps or we might be left without functions to try */
687 if (typefind->caps) {
688 stop_typefinding (typefind);
689 } else if (typefind->possibilities == NULL) {
690 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
691 stop_typefinding (typefind);
692 return GST_FLOW_ERROR;
694 TypeFindEntry *best = NULL;
696 walk = typefind->possibilities;
698 entry = (TypeFindEntry *) typefind->possibilities->data;
699 if ((!best || entry->probability > best->probability) &&
700 entry->probability >= typefind->min_probability) {
703 walk = g_list_next (walk);
707 GST_INFO_OBJECT (typefind,
708 "'%s' is the only typefind left, using it now (probability %u)",
709 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
710 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
711 0, entry->probability, entry->caps);
712 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
713 g_list_free (typefind->possibilities);
714 typefind->possibilities = NULL;
715 stop_typefinding (typefind);
717 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
718 stop_typefinding (typefind);
719 return GST_FLOW_ERROR;
725 g_assert_not_reached ();
726 return GST_FLOW_ERROR;
733 gst_type_find_element_checkgetrange (GstPad * srcpad)
735 GstTypeFindElement *typefind;
737 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
739 return gst_pad_check_pull_range (typefind->sink);
743 gst_type_find_element_getrange (GstPad * srcpad,
744 guint64 offset, guint length, GstBuffer ** buffer)
746 GstTypeFindElement *typefind;
748 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
750 return gst_pad_pull_range (typefind->sink, offset, length, buffer);
754 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
756 GstTypeFindElement *typefind;
758 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
760 return gst_pad_activate_pull (typefind->sink, active);
764 gst_type_find_element_activate (GstPad * pad)
766 GstCaps *found_caps = NULL;
767 GstTypeFindElement *typefind;
769 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
771 /* 1. try to activate in pull mode. if not, switch to push and succeed.
772 2. try to pull type find.
773 3. deactivate pull mode.
774 4. src pad might have been activated push by the state change. deactivate.
775 5. if we didn't find any caps, fail.
776 6. emit have-type; maybe the app connected the source pad to something.
777 7. if the sink pad is activated, we are in pull mode. succeed.
778 otherwise activate both pads in push mode and succeed.
782 if (!gst_pad_activate_pull (pad, TRUE)) {
783 start_typefinding (typefind);
784 return gst_pad_activate_push (pad, TRUE);
791 peer = gst_pad_get_peer (pad);
794 GstFormat format = GST_FORMAT_BYTES;
796 gst_pad_query_position (peer, &format, NULL, &size);
797 found_caps = gst_type_find_helper (peer, (guint64) size);
798 gst_object_unref (GST_OBJECT (peer));
803 gst_pad_activate_pull (pad, FALSE);
806 gst_pad_activate_push (typefind->src, FALSE);
813 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
815 typefind->mode = MODE_NORMAL;
816 /* FIXME see if I can unref the caps here */
819 if (gst_pad_is_active (pad))
824 ret = gst_pad_activate_push (typefind->src, TRUE);
825 ret &= gst_pad_activate_push (pad, TRUE);
830 static GstElementStateReturn
831 gst_type_find_element_change_state (GstElement * element)
833 GstElementState transition;
834 GstElementStateReturn ret;
835 GstTypeFindElement *typefind;
837 typefind = GST_TYPE_FIND_ELEMENT (element);
839 transition = GST_STATE_TRANSITION (element);
841 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
843 switch (transition) {
844 case GST_STATE_PAUSED_TO_READY:
845 gst_caps_replace (&typefind->caps, NULL);