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 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_template (gst_static_pad_template_get
210 (&type_find_element_sink_template), "sink");
211 gst_pad_set_activate_function (typefind->sink,
212 gst_type_find_element_activate);
213 gst_pad_set_chain_function (typefind->sink, gst_type_find_element_chain);
214 gst_pad_set_event_function (typefind->sink,
215 gst_type_find_element_handle_event);
216 gst_element_add_pad (GST_ELEMENT (typefind), typefind->sink);
219 gst_pad_new_from_template (gst_static_pad_template_get
220 (&type_find_element_src_template), "src");
221 gst_pad_set_activatepull_function (typefind->src,
222 gst_type_find_element_activate_src_pull);
223 gst_pad_set_checkgetrange_function (typefind->src,
224 gst_type_find_element_checkgetrange);
225 gst_pad_set_getrange_function (typefind->src, gst_type_find_element_getrange);
226 gst_pad_set_event_function (typefind->src, gst_type_find_element_src_event);
227 gst_pad_set_query_function (typefind->src,
228 GST_DEBUG_FUNCPTR (gst_type_find_handle_src_query));
229 gst_pad_use_fixed_caps (typefind->src);
230 gst_element_add_pad (GST_ELEMENT (typefind), typefind->src);
232 typefind->mode = MODE_TYPEFIND;
233 typefind->caps = NULL;
234 typefind->min_probability = 1;
235 typefind->max_probability = GST_TYPE_FIND_MAXIMUM;
237 typefind->store = NULL;
240 gst_type_find_element_dispose (GObject * object)
242 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (object);
244 G_OBJECT_CLASS (parent_class)->dispose (object);
246 if (typefind->store) {
247 gst_buffer_unref (typefind->store);
248 typefind->store = NULL;
252 gst_type_find_element_set_property (GObject * object, guint prop_id,
253 const GValue * value, GParamSpec * pspec)
255 GstTypeFindElement *typefind;
257 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
259 typefind = GST_TYPE_FIND_ELEMENT (object);
263 typefind->min_probability = g_value_get_uint (value);
264 g_object_notify (object, "minimum");
267 typefind->max_probability = g_value_get_uint (value);
268 g_object_notify (object, "maximum");
271 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
276 gst_type_find_element_get_property (GObject * object, guint prop_id,
277 GValue * value, GParamSpec * pspec)
279 GstTypeFindElement *typefind;
281 g_return_if_fail (GST_IS_TYPE_FIND_ELEMENT (object));
283 typefind = GST_TYPE_FIND_ELEMENT (object);
287 g_value_set_boxed (value, typefind->caps);
290 g_value_set_uint (value, typefind->min_probability);
293 g_value_set_uint (value, typefind->max_probability);
296 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
302 gst_type_find_handle_src_query (GstPad * pad, GstQuery * query)
304 GstTypeFindElement *typefind;
307 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
309 res = gst_pad_query (GST_PAD_PEER (typefind->sink), query);
313 switch (GST_QUERY_TYPE (query)) {
314 case GST_QUERY_POSITION:
316 gint64 peer_pos, peer_total;
319 if (typefind->store == NULL)
322 gst_query_parse_position (query, &format, &peer_pos, &peer_total);
324 /* FIXME: this code assumes that there's no discont in the queue */
326 case GST_FORMAT_BYTES:
327 peer_pos -= typefind->store->size;
333 gst_query_set_position (query, format, peer_pos, peer_total);
344 static const GstEventMask *
345 gst_type_find_element_src_event_mask (GstPad * pad)
347 static const GstEventMask mask[] = {
349 GST_SEEK_METHOD_SET | GST_SEEK_METHOD_CUR | GST_SEEK_METHOD_END |
350 GST_SEEK_FLAG_FLUSH},
351 /* add more if you want, event masks suck and need to die anyway */
360 gst_type_find_element_src_event (GstPad * pad, GstEvent * event)
362 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
364 if (typefind->mode != MODE_NORMAL) {
365 /* need to do more? */
366 gst_mini_object_unref (GST_MINI_OBJECT (event));
369 return gst_pad_event_default (pad, event);
373 GstTypeFindFactory *factory;
376 guint requested_size;
377 GstTypeFindElement *self;
381 static inline TypeFindEntry *
384 return g_new0 (TypeFindEntry, 1);
387 free_entry (TypeFindEntry * entry)
390 gst_caps_unref (entry->caps);
394 start_typefinding (GstTypeFindElement * typefind)
396 g_assert (typefind->possibilities == NULL);
398 GST_DEBUG_OBJECT (typefind, "starting typefinding");
399 gst_pad_set_caps (typefind->src, NULL);
400 if (typefind->caps) {
401 gst_caps_replace (&typefind->caps, NULL);
403 typefind->mode = MODE_TYPEFIND;
404 typefind->stream_length_available = TRUE;
405 typefind->stream_length = 0;
408 stop_typefinding (GstTypeFindElement * typefind)
411 gboolean push_cached_buffers;
413 gst_element_get_state (GST_ELEMENT (typefind), &state, NULL, NULL);
415 push_cached_buffers = (state >= GST_STATE_PAUSED);
417 GST_DEBUG_OBJECT (typefind, "stopping typefinding%s",
418 push_cached_buffers ? " and pushing cached buffers" : "");
419 if (typefind->possibilities != NULL) {
420 /* this should only happen on PAUSED => READY or EOS */
421 GST_LOG_OBJECT (typefind, "freeing remaining %u typefind functions",
422 g_list_length (typefind->possibilities));
423 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
424 g_list_free (typefind->possibilities);
425 typefind->possibilities = NULL;
427 //typefind->mode = MODE_TRANSITION;
429 if (typefind->store) {
430 if (!push_cached_buffers) {
431 gst_buffer_unref (typefind->store);
433 typefind->mode = MODE_NORMAL;
434 gst_buffer_set_caps (typefind->store, typefind->caps);
435 gst_pad_push (typefind->src, typefind->store);
437 typefind->store = NULL;
442 find_element_get_length (gpointer data)
444 TypeFindEntry *entry = (TypeFindEntry *) data;
445 GstTypeFindElement *typefind = entry->self;
446 GstFormat format = GST_FORMAT_BYTES;
448 if (!typefind->stream_length_available) {
449 GST_LOG_OBJECT (entry->self,
450 "'%s' called get_length () but we know it's not available",
451 GST_PLUGIN_FEATURE_NAME (entry->factory));
454 if (entry->self->stream_length == 0) {
455 if (!gst_pad_query_position (GST_PAD_PEER (entry->self->sink), &format,
456 NULL, (gint64 *) & entry->self->stream_length))
459 if (format != GST_FORMAT_BYTES) {
460 typefind->stream_length_available = FALSE;
461 entry->self->stream_length = 0;
463 GST_DEBUG_OBJECT (entry->self,
464 "'%s' called get_length () and it's %" G_GUINT64_FORMAT " bytes",
465 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->self->stream_length);
468 return entry->self->stream_length;
472 typefind->stream_length_available = FALSE;
473 GST_DEBUG_OBJECT (entry->self,
474 "'%s' called get_length () but it's not available",
475 GST_PLUGIN_FEATURE_NAME (entry->factory));
481 gst_type_find_element_handle_event (GstPad * pad, GstEvent * event)
483 gboolean res = FALSE;
484 TypeFindEntry *entry;
485 GstTypeFindElement *typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
487 GST_DEBUG_OBJECT (typefind, "got event %d in mode %d", GST_EVENT_TYPE (event),
490 switch (typefind->mode) {
492 switch (GST_EVENT_TYPE (event)) {
494 /* this should only happen when we got all available data */
496 (TypeFindEntry *) typefind->possibilities ? typefind->
497 possibilities->data : NULL;
498 if (entry && entry->probability >= typefind->min_probability) {
499 GST_INFO_OBJECT (typefind,
500 "'%s' is the best typefind left after we got all data, using it now (probability %u)",
501 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
502 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
503 0, entry->probability, entry->caps);
504 stop_typefinding (typefind);
505 gst_buffer_set_caps (typefind->store, typefind->caps);
506 gst_pad_push (typefind->src, typefind->store);
507 typefind->store = NULL;
508 res = gst_pad_event_default (pad, event);
510 res = gst_pad_event_default (pad, event);
511 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL),
513 stop_typefinding (typefind);
517 gst_mini_object_unref (GST_MINI_OBJECT (event));
523 if (FALSE) { // GST_EVENT_TYPE (event) == GST_EVENT_DISCONTINUOUS) {
524 start_typefinding (typefind);
525 gst_event_unref (event);
528 res = gst_pad_event_default (pad, event);
532 g_assert_not_reached ();
537 find_peek (gpointer data, gint64 offset, guint size)
539 TypeFindEntry *entry = (TypeFindEntry *) data;
541 GST_LOG_OBJECT (entry->self, "'%s' called peek (%" G_GINT64_FORMAT ", %u)",
542 GST_PLUGIN_FEATURE_NAME (entry->factory), offset, size);
546 if (size <= entry->self->store->size) {
547 return GST_BUFFER_DATA (entry->self->store);
549 entry->requested_size = size;
551 GST_LOG_OBJECT (entry->self,
552 "setting requested peek (%" G_GINT64_FORMAT ", %u) on '%s'", offset,
553 size, GST_PLUGIN_FEATURE_NAME (entry->factory));
558 find_suggest (gpointer data, guint probability, const GstCaps * caps)
560 TypeFindEntry *entry = (TypeFindEntry *) data;
562 GST_LOG_OBJECT (entry->self, "'%s' called suggest (%u, %" GST_PTR_FORMAT ")",
563 GST_PLUGIN_FEATURE_NAME (entry->factory), probability, caps);
564 if (((gint) probability) > entry->probability) {
565 entry->probability = probability;
566 gst_caps_replace (&entry->caps, (GstCaps *) caps);
572 compare_type_find_entry (gconstpointer a, gconstpointer b)
574 TypeFindEntry *one = (TypeFindEntry *) a;
575 TypeFindEntry *two = (TypeFindEntry *) b;
577 if (one->probability == two->probability) {
578 /* FIXME: can be improved by analyzing requests */
581 return two->probability - one->probability;
587 compare_type_find_factory (gconstpointer fac1, gconstpointer fac2)
589 return GST_PLUGIN_FEATURE (fac1)->rank - GST_PLUGIN_FEATURE (fac2)->rank;
593 gst_type_find_element_chain (GstPad * pad, GstBuffer * buffer)
595 GstTypeFindElement *typefind;
597 TypeFindEntry *entry;
599 GstFlowReturn res = GST_FLOW_OK;
600 GstTypeFind find = { find_peek, find_suggest, NULL, find_element_get_length };
602 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (pad));
604 switch (typefind->mode) {
606 gst_buffer_set_caps (buffer, typefind->caps);
607 return gst_pad_push (typefind->src, buffer);
609 gboolean done = TRUE;
612 typefind->store = gst_buffer_join (typefind->store, buffer);
614 typefind->store = buffer;
616 if (typefind->possibilities == NULL) {
617 /* not yet started, get all typefinding functions into our "queue" */
618 GList *all_factories = gst_type_find_factory_get_list ();
620 GST_INFO_OBJECT (typefind, "starting with %u typefinding functions",
621 g_list_length (all_factories));
623 all_factories = g_list_sort (all_factories, compare_type_find_factory);
624 walk = all_factories;
625 while (all_factories) {
626 entry = new_entry ();
628 entry->factory = GST_TYPE_FIND_FACTORY (all_factories->data);
629 entry->self = typefind;
630 entry->probability = 0;
631 typefind->possibilities =
632 g_list_prepend (typefind->possibilities, entry);
633 all_factories = g_list_next (all_factories);
635 gst_plugin_feature_list_free (all_factories);
638 /* call every typefind function once */
639 walk = entries = typefind->possibilities;
640 GST_INFO_OBJECT (typefind, "iterating %u typefinding functions",
641 g_list_length (entries));
642 typefind->possibilities = NULL;
644 find.data = entry = (TypeFindEntry *) walk->data;
645 walk = g_list_next (walk);
646 if (entry->probability == 0) {
647 entry->requested_size = 0;
648 gst_type_find_factory_call_function (entry->factory, &find);
650 typefind->possibilities =
651 g_list_prepend (typefind->possibilities, entry);
654 if (entry->probability == 0 && entry->requested_size == 0) {
655 GST_DEBUG_OBJECT (typefind,
656 "'%s' was removed - no chance of being the right plugin",
657 GST_PLUGIN_FEATURE_NAME (entry->factory));
659 } else if (entry->probability >= typefind->max_probability) {
660 /* wooha, got caps */
661 GstCaps *found_caps = entry->caps;
662 guint probability = entry->probability;
664 GST_INFO_OBJECT (typefind,
665 "'%s' returned %u/%u probability, using it NOW",
666 GST_PLUGIN_FEATURE_NAME (entry->factory), probability,
667 typefind->max_probability);
669 free_entry ((TypeFindEntry *) walk->data);
670 walk = g_list_next (walk);
672 walk = typefind->possibilities;
674 free_entry (walk->data);
675 walk = g_list_next (walk);
677 g_list_free (typefind->possibilities);
678 typefind->possibilities = NULL;
679 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE], 0,
680 probability, found_caps);
683 typefind->possibilities =
684 g_list_prepend (typefind->possibilities, entry);
685 if (entry->requested_size != 0)
689 g_list_free (entries);
691 /* we may now already have caps or we might be left without functions to try */
692 if (typefind->caps) {
693 stop_typefinding (typefind);
694 } else if (typefind->possibilities == NULL) {
695 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
696 stop_typefinding (typefind);
697 return GST_FLOW_ERROR;
699 TypeFindEntry *best = NULL;
701 walk = typefind->possibilities;
703 entry = (TypeFindEntry *) typefind->possibilities->data;
704 if ((!best || entry->probability > best->probability) &&
705 entry->probability >= typefind->min_probability) {
708 walk = g_list_next (walk);
712 GST_INFO_OBJECT (typefind,
713 "'%s' is the only typefind left, using it now (probability %u)",
714 GST_PLUGIN_FEATURE_NAME (entry->factory), entry->probability);
715 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
716 0, entry->probability, entry->caps);
717 g_list_foreach (typefind->possibilities, (GFunc) free_entry, NULL);
718 g_list_free (typefind->possibilities);
719 typefind->possibilities = NULL;
720 stop_typefinding (typefind);
722 GST_ELEMENT_ERROR (typefind, STREAM, TYPE_NOT_FOUND, (NULL), (NULL));
723 stop_typefinding (typefind);
724 return GST_FLOW_ERROR;
730 g_assert_not_reached ();
731 return GST_FLOW_ERROR;
738 gst_type_find_element_checkgetrange (GstPad * srcpad)
740 GstTypeFindElement *typefind;
742 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
744 return gst_pad_check_pull_range (typefind->sink);
748 gst_type_find_element_getrange (GstPad * srcpad,
749 guint64 offset, guint length, GstBuffer ** buffer)
751 GstTypeFindElement *typefind;
754 typefind = GST_TYPE_FIND_ELEMENT (GST_PAD_PARENT (srcpad));
756 ret = gst_pad_pull_range (typefind->sink, offset, length, buffer);
758 if (ret == GST_FLOW_OK && buffer && *buffer)
759 gst_buffer_set_caps (*buffer, typefind->caps);
765 gst_type_find_element_activate_src_pull (GstPad * pad, gboolean active)
767 GstTypeFindElement *typefind;
769 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
771 return gst_pad_activate_pull (typefind->sink, active);
775 gst_type_find_element_activate (GstPad * pad)
777 GstCaps *found_caps = NULL;
778 GstTypeFindElement *typefind;
780 typefind = GST_TYPE_FIND_ELEMENT (GST_OBJECT_PARENT (pad));
782 /* 1. try to activate in pull mode. if not, switch to push and succeed.
783 2. try to pull type find.
784 3. deactivate pull mode.
785 4. src pad might have been activated push by the state change. deactivate.
786 5. if we didn't find any caps, fail.
787 6. emit have-type; maybe the app connected the source pad to something.
788 7. if the sink pad is activated, we are in pull mode. succeed.
789 otherwise activate both pads in push mode and succeed.
793 if (!gst_pad_activate_pull (pad, TRUE)) {
794 start_typefinding (typefind);
795 return gst_pad_activate_push (pad, TRUE);
802 peer = gst_pad_get_peer (pad);
805 GstFormat format = GST_FORMAT_BYTES;
807 gst_pad_query_position (peer, &format, NULL, &size);
808 found_caps = gst_type_find_helper (peer, (guint64) size);
809 gst_object_unref (peer);
814 gst_pad_activate_pull (pad, FALSE);
817 gst_pad_activate_push (typefind->src, FALSE);
824 g_signal_emit (typefind, gst_type_find_element_signals[HAVE_TYPE],
826 typefind->mode = MODE_NORMAL;
827 /* FIXME see if I can unref the caps here */
830 if (gst_pad_is_active (pad))
835 ret = gst_pad_activate_push (typefind->src, TRUE);
836 ret &= gst_pad_activate_push (pad, TRUE);
841 static GstStateChangeReturn
842 gst_type_find_element_change_state (GstElement * element,
843 GstStateChange transition)
845 GstStateChangeReturn ret;
846 GstTypeFindElement *typefind;
848 typefind = GST_TYPE_FIND_ELEMENT (element);
851 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
853 switch (transition) {
854 case GST_STATE_CHANGE_PAUSED_TO_READY:
855 gst_caps_replace (&typefind->caps, NULL);