gst/playback/: Add some debug info to decodebin, update README

Original commit message from CVS:
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
Add some debug info to decodebin, update README
This commit is contained in:
Wim Taymans 2004-10-01 15:57:53 +00:00
parent 586f6f31da
commit f92e880040
3 changed files with 180 additions and 36 deletions

View file

@ -1,3 +1,11 @@
2004-10-01 Wim Taymans <wim@fluendo.com>
* gst/playback/README:
* gst/playback/gstdecodebin.c: (gst_decode_bin_factory_filter),
(gst_decode_bin_init), (find_compatibles), (close_pad_link),
(try_to_link_1), (no_more_pads), (close_link), (type_found):
Add some debug info to decodebin, update README
2004-10-01 Ronald S. Bultje <rbultje@ronald.bitfreak.net> 2004-10-01 Ronald S. Bultje <rbultje@ronald.bitfreak.net>
* ext/dvdnav/dvdnavsrc.c: (dvdnav_handle_navigation_event): * ext/dvdnav/dvdnavsrc.c: (dvdnav_handle_navigation_event):

View file

@ -7,9 +7,7 @@ decoderbin:
TODO TODO
- reuse of decoderbin, cleanup in READY state - reuse of decoderbin, cleanup in READY state
- debugging
- threading after demuxing? - threading after demuxing?
- better factory selection, based on Demuxer/Decoder types and ranks.
- error handling - error handling
baseplaybin: baseplaybin:

View file

@ -1,5 +1,5 @@
/* GStreamer /* GStreamer
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu> * Copyright (C) <2004> Wim Taymans <wim@fluendo.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public * modify it under the terms of the GNU Library General Public
@ -51,26 +51,28 @@ typedef struct _GstDecodeBinClass GstDecodeBinClass;
struct _GstDecodeBin struct _GstDecodeBin
{ {
GstBin bin; GstBin bin; /* we extend GstBin */
GstElement *typefind; GstElement *typefind; /* this holds the typefind object */
gboolean threaded; gboolean threaded; /* indicating threaded execution is desired */
GList *dynamics; GList *dynamics; /* list of dynamic connections */
GList *factories; GList *factories; /* factories we can use for selecting elements */
gint numpads; gint numpads;
GList *elements; GList *elements; /* elements we added in autoplugging */
guint have_type_id; guint have_type_id; /* signal id for the typefind element */
}; };
struct _GstDecodeBinClass struct _GstDecodeBinClass
{ {
GstBinClass parent_class; GstBinClass parent_class;
/* signal we fire when a new pad has been decoded into raw audio/video */
void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last); void (*new_decoded_pad) (GstElement * element, GstPad * pad, gboolean last);
/* signal fired when we found a pad that we cannot decode */
void (*unknown_type) (GstElement * element, GstCaps * caps); void (*unknown_type) (GstElement * element, GstCaps * caps);
}; };
@ -89,12 +91,14 @@ enum
LAST_SIGNAL LAST_SIGNAL
}; };
/* this structure is created for all dynamic pads that could get created
* at runtime */
typedef struct typedef struct
{ {
gint np_sig_id; gint np_sig_id; /* signal id of new_pad */
gint nmp_sig_id; gint nmp_sig_id; /* signal id of no_more_pads */
GstElement *element; GstElement *element; /* the element sending the signal */
GstDecodeBin *decode_bin; GstDecodeBin *decode_bin; /* pointer to ourself */
} }
GstDynamic; GstDynamic;
@ -196,12 +200,19 @@ gst_decode_bin_class_init (GstDecodeBinClass * klass)
GST_DEBUG_FUNCPTR (gst_decode_bin_change_state); GST_DEBUG_FUNCPTR (gst_decode_bin_change_state);
} }
/* check if the bin is dynamic.
*
* If there are no outstanding dynamic connections, the bin is
* considered to be non-dynamic.
*/
static gboolean static gboolean
gst_decode_bin_is_dynamic (GstDecodeBin * decode_bin) gst_decode_bin_is_dynamic (GstDecodeBin * decode_bin)
{ {
return decode_bin->dynamics != NULL; return decode_bin->dynamics != NULL;
} }
/* the filter function for selecting the elements we can use in
* autoplugging */
static gboolean static gboolean
gst_decode_bin_factory_filter (GstPluginFeature * feature, gst_decode_bin_factory_filter (GstPluginFeature * feature,
GstDecodeBin * decode_bin) GstDecodeBin * decode_bin)
@ -209,14 +220,17 @@ gst_decode_bin_factory_filter (GstPluginFeature * feature,
guint rank; guint rank;
const gchar *klass; const gchar *klass;
/* we only care about element factories */
if (!GST_IS_ELEMENT_FACTORY (feature)) if (!GST_IS_ELEMENT_FACTORY (feature))
return FALSE; return FALSE;
klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature)); klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
/* only demuxers and decoders can play */
if (strstr (klass, "Demux") == NULL && strstr (klass, "Decoder") == NULL) { if (strstr (klass, "Demux") == NULL && strstr (klass, "Decoder") == NULL) {
return FALSE; return FALSE;
} }
/* only select elements with autoplugging rank */
rank = gst_plugin_feature_get_rank (feature); rank = gst_plugin_feature_get_rank (feature);
if (rank < GST_RANK_MARGINAL) if (rank < GST_RANK_MARGINAL)
return FALSE; return FALSE;
@ -224,6 +238,7 @@ gst_decode_bin_factory_filter (GstPluginFeature * feature,
return TRUE; return TRUE;
} }
/* function used to sort element features */
static gint static gint
compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2) compare_ranks (GstPluginFeature * f1, GstPluginFeature * f2)
{ {
@ -241,24 +256,33 @@ gst_decode_bin_init (GstDecodeBin * decode_bin)
{ {
GList *factories; GList *factories;
/* first filter out the interesting element factories */
factories = gst_registry_pool_feature_filter ( factories = gst_registry_pool_feature_filter (
(GstPluginFeatureFilter) gst_decode_bin_factory_filter, (GstPluginFeatureFilter) gst_decode_bin_factory_filter,
FALSE, decode_bin); FALSE, decode_bin);
/* sort them according to their ranks */
decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks); decode_bin->factories = g_list_sort (factories, (GCompareFunc) compare_ranks);
/* do some debugging */
g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL); g_list_foreach (decode_bin->factories, (GFunc) print_feature, NULL);
/* we create the typefind element only once */
decode_bin->typefind = gst_element_factory_make ("typefind", "typefind"); decode_bin->typefind = gst_element_factory_make ("typefind", "typefind");
if (!decode_bin->typefind) { if (!decode_bin->typefind) {
g_warning ("can't find typefind element"); g_warning ("can't find typefind element, decodebin will not work");
} } else {
gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind); /* add the typefind element */
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), gst_bin_add (GST_BIN (decode_bin), decode_bin->typefind);
gst_element_get_pad (decode_bin->typefind, "sink"), "sink"); /* ghost the sink pad to ourself */
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin),
gst_element_get_pad (decode_bin->typefind, "sink"), "sink");
decode_bin->have_type_id = /* connect a signal to find out when the typefind element found
g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type", * a type */
G_CALLBACK (type_found), decode_bin); decode_bin->have_type_id =
g_signal_connect (G_OBJECT (decode_bin->typefind), "have_type",
G_CALLBACK (type_found), decode_bin);
}
decode_bin->dynamics = NULL; decode_bin->dynamics = NULL;
} }
@ -291,28 +315,37 @@ gst_decode_bin_dispose (GObject * object)
} }
} }
/* this function runs through the element factories and returns a list
* of all elements that are able to sink the given caps
*/
static GList * static GList *
find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps) find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
{ {
GList *factories; GList *factories;
GList *to_try = NULL; GList *to_try = NULL;
/* loop over all the factories */
for (factories = decode_bin->factories; factories; for (factories = decode_bin->factories; factories;
factories = g_list_next (factories)) { factories = g_list_next (factories)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data); GstElementFactory *factory = GST_ELEMENT_FACTORY (factories->data);
const GList *templates; const GList *templates;
GList *walk; GList *walk;
/* get the templates from the element factory */
templates = gst_element_factory_get_pad_templates (factory); templates = gst_element_factory_get_pad_templates (factory);
for (walk = (GList *) templates; walk; walk = g_list_next (walk)) { for (walk = (GList *) templates; walk; walk = g_list_next (walk)) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (walk->data); GstPadTemplate *templ = GST_PAD_TEMPLATE (walk->data);
/* we only care about the sink templates */
if (templ->direction == GST_PAD_SINK) { if (templ->direction == GST_PAD_SINK) {
GstCaps *intersect; GstCaps *intersect;
/* try to intersect the caps with the caps of the template */
intersect = intersect =
gst_caps_intersect (caps, gst_pad_template_get_caps (templ)); gst_caps_intersect (caps, gst_pad_template_get_caps (templ));
/* check if the intersection is empty */
if (!gst_caps_is_empty (intersect)) { if (!gst_caps_is_empty (intersect)) {
/* non empty intersection, we can use this element */
to_try = g_list_append (to_try, factory); to_try = g_list_append (to_try, factory);
} }
gst_caps_free (intersect); gst_caps_free (intersect);
@ -322,6 +355,15 @@ find_compatibles (GstDecodeBin * decode_bin, const GstCaps * caps)
return to_try; return to_try;
} }
/* given a pad and a caps from an element, find the list of elements
* that could connect to the pad
*
* If the pad has a raw format, this function will create a ghostpad
* for the pad onto the decodebin.
*
* If no compatible elements could be found, this function will signal
* the unknown_type signal.
*/
static void static void
close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps, close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
GstDecodeBin * decode_bin) GstDecodeBin * decode_bin)
@ -330,29 +372,34 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
GstStructure *structure; GstStructure *structure;
const gchar *mimetype; const gchar *mimetype;
/* the caps is empty, this means the pad has no type, we can only
* decide to fire the unknown_type signal. */
if (gst_caps_is_empty (caps)) { if (gst_caps_is_empty (caps)) {
g_signal_emit (G_OBJECT (decode_bin), g_signal_emit (G_OBJECT (decode_bin),
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps); gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps);
return; return;
} }
/* FIXME, iterate over more structures? */
structure = gst_caps_get_structure (caps, 0); structure = gst_caps_get_structure (caps, 0);
mimetype = gst_structure_get_name (structure); mimetype = gst_structure_get_name (structure);
/* first see if this is raw */ /* first see if this is raw. If the type is raw, we can
* create a ghostpad for this pad. */
if (g_str_has_prefix (mimetype, "video/x-raw") || if (g_str_has_prefix (mimetype, "video/x-raw") ||
g_str_has_prefix (mimetype, "audio/x-raw")) { g_str_has_prefix (mimetype, "audio/x-raw")) {
gchar *padname; gchar *padname;
GstPad *ghost; GstPad *ghost;
gboolean dynamic; gboolean dynamic;
/* make a unique name for this new pad */
padname = g_strdup_printf ("src%d", decode_bin->numpads); padname = g_strdup_printf ("src%d", decode_bin->numpads);
decode_bin->numpads++; decode_bin->numpads++;
gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname); /* make it a ghostpad */
ghost = gst_element_add_ghost_pad (GST_ELEMENT (decode_bin), pad, padname);
ghost = gst_element_get_pad (GST_ELEMENT (decode_bin), padname);
/* see if any more pending dynamic connections exist */
dynamic = gst_decode_bin_is_dynamic (decode_bin); dynamic = gst_decode_bin_is_dynamic (decode_bin);
/* our own signal with an extra flag that this is the only pad */ /* our own signal with an extra flag that this is the only pad */
@ -363,85 +410,128 @@ close_pad_link (GstElement * element, GstPad * pad, GstCaps * caps,
return; return;
} }
/* then continue plugging */ /* then continue plugging, first find all compatible elements */
to_try = find_compatibles (decode_bin, caps); to_try = find_compatibles (decode_bin, caps);
if (to_try == NULL) { if (to_try == NULL) {
/* no compatible elements, fire the unknown_type signal, we cannot go
* on */
g_signal_emit (G_OBJECT (decode_bin), g_signal_emit (G_OBJECT (decode_bin),
gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps); gst_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, caps);
return; return;
} }
/* now try to link the elements in the to_try list to the pad */
try_to_link_1 (decode_bin, pad, to_try); try_to_link_1 (decode_bin, pad, to_try);
} }
/* given a list of element factories, try to link one of the factories
* to the given pad */
static GstElement * static GstElement *
try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories) try_to_link_1 (GstDecodeBin * decode_bin, GstPad * pad, GList * factories)
{ {
GList *walk; GList *walk;
/* loop over the factories */
for (walk = factories; walk; walk = g_list_next (walk)) { for (walk = factories; walk; walk = g_list_next (walk)) {
GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data); GstElementFactory *factory = GST_ELEMENT_FACTORY (walk->data);
GstElement *element; GstElement *element;
gboolean ret; gboolean ret;
GST_DEBUG ("trying to link %s", GST_DEBUG_OBJECT (decode_bin, "trying to link %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory))); gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
/* make an element from the factory first */
element = gst_element_factory_create (factory, NULL); element = gst_element_factory_create (factory, NULL);
if (element == NULL) if (element == NULL) {
/* hmm, strange */
GST_WARNING_OBJECT (decode_bin, "could not create an element from %s",
gst_plugin_feature_get_name (GST_PLUGIN_FEATURE (factory)));
continue; continue;
}
GST_DEBUG ("adding %s", gst_element_get_name (element)); /* now add the element to the bin first */
GST_DEBUG_OBJECT (decode_bin, "adding %s", gst_element_get_name (element));
gst_bin_add (GST_BIN (decode_bin), element); gst_bin_add (GST_BIN (decode_bin), element);
/* keep out own list of elements */
decode_bin->elements = g_list_prepend (decode_bin->elements, element); decode_bin->elements = g_list_prepend (decode_bin->elements, element);
/* try to link the given pad to a sinkpad */
/* FIXME, find the sinkpad by looping over the pads instead of
* looking it up by name */
ret = gst_pad_link (pad, gst_element_get_pad (element, "sink")); ret = gst_pad_link (pad, gst_element_get_pad (element, "sink"));
if (ret) { if (ret) {
const gchar *klass; const gchar *klass;
GstElementFactory *factory; GstElementFactory *factory;
/* The link worked, now figure out what it was that we connected */
factory = gst_element_get_factory (element); factory = gst_element_get_factory (element);
klass = gst_element_factory_get_klass (factory); klass = gst_element_factory_get_klass (factory);
/* check if we can use threads */
if (decode_bin->threaded) { if (decode_bin->threaded) {
if (strstr (klass, "Demux") != NULL) { if (strstr (klass, "Demux") != NULL) {
/* FIXME, do something with threads here */ /* FIXME, do something with threads here */
} }
} }
/* now that we added the element we can try to continue autoplugging
* on it until we have a raw type */
close_link (element, decode_bin); close_link (element, decode_bin);
/* change the state of the element to that of the parent */
gst_element_sync_state_with_parent (element); gst_element_sync_state_with_parent (element);
return element; return element;
} else { } else {
/* this element did not work, remove it again and continue trying
* other elements */
gst_bin_remove (GST_BIN (decode_bin), element); gst_bin_remove (GST_BIN (decode_bin), element);
} }
} }
return NULL; return NULL;
} }
/* This function will be called when a dynamic pad is created on an element.
* We try to continue autoplugging on this new pad. */
static void static void
new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic) new_pad (GstElement * element, GstPad * pad, GstDynamic * dynamic)
{ {
close_pad_link (element, pad, gst_pad_get_caps (pad), dynamic->decode_bin); close_pad_link (element, pad, gst_pad_get_caps (pad), dynamic->decode_bin);
} }
/* this signal is fired when an element signals the no_more_pads signal.
* This means that the element will not generate more dynamic pads and
* we can remove the element from the list of dynamic elements. When we
* have no more dynamic elements in the pipeline, we can fire a no_more_pads
* signal ourselves. */
static void static void
no_more_pads (GstElement * element, GstDynamic * dynamic) no_more_pads (GstElement * element, GstDynamic * dynamic)
{ {
GstDecodeBin *decode_bin = dynamic->decode_bin; GstDecodeBin *decode_bin = dynamic->decode_bin;
GST_DEBUG ("decodebin: no more pads"); GST_DEBUG_OBJECT (decode_bin, "no more pads on element %s",
gst_element_get_name (element));
/* disconnect signals */
g_signal_handler_disconnect (G_OBJECT (dynamic->element), dynamic->np_sig_id); g_signal_handler_disconnect (G_OBJECT (dynamic->element), dynamic->np_sig_id);
g_signal_handler_disconnect (G_OBJECT (dynamic->element), g_signal_handler_disconnect (G_OBJECT (dynamic->element),
dynamic->nmp_sig_id); dynamic->nmp_sig_id);
/* remove the element from the list of dynamic elements */
decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic); decode_bin->dynamics = g_list_remove (decode_bin->dynamics, dynamic);
g_free (dynamic); g_free (dynamic);
if (decode_bin->dynamics == NULL) /* if we have no more dynamic elements, we have no change of creating
* more pads, so we fire the no_more_pads signal */
if (decode_bin->dynamics == NULL) {
GST_DEBUG_OBJECT (decode_bin,
"no more dynamic elements, signaling no_more_pads");
gst_element_no_more_pads (GST_ELEMENT (decode_bin)); gst_element_no_more_pads (GST_ELEMENT (decode_bin));
} else {
GST_DEBUG_OBJECT (decode_bin, "we have more dynamic elements");
}
} }
/* this function inspects the given element and tries to connect something
* on the srcpads. If there are dynamic pads, it sets up a signal handler to
* continue autoplugging when they become available */
static void static void
close_link (GstElement * element, GstDecodeBin * decode_bin) close_link (GstElement * element, GstDecodeBin * decode_bin)
{ {
@ -449,43 +539,74 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
gboolean dynamic = FALSE; gboolean dynamic = FALSE;
GList *to_connect = NULL; GList *to_connect = NULL;
GST_DEBUG_OBJECT (decode_bin, "closing links with element %s",
gst_element_get_name (element));
/* loop over all the padtemplates */
for (pads = gst_element_get_pad_template_list (element); pads; for (pads = gst_element_get_pad_template_list (element); pads;
pads = g_list_next (pads)) { pads = g_list_next (pads)) {
GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data); GstPadTemplate *templ = GST_PAD_TEMPLATE (pads->data);
const gchar *templ_name;
/* we are only interested in source pads */
if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC) if (GST_PAD_TEMPLATE_DIRECTION (templ) != GST_PAD_SRC)
continue; continue;
templ_name = GST_PAD_TEMPLATE_NAME_TEMPLATE (templ);
GST_DEBUG_OBJECT (decode_bin, "got a source pad template %s", templ_name);
/* figure out what kind of pad this is */
switch (GST_PAD_TEMPLATE_PRESENCE (templ)) { switch (GST_PAD_TEMPLATE_PRESENCE (templ)) {
case GST_PAD_ALWAYS: case GST_PAD_ALWAYS:
{ {
GstPad *pad = gst_element_get_pad (element, /* get the pad that we need to autoplug */
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); GstPad *pad = gst_element_get_pad (element, templ_name);
if (pad) { if (pad) {
GST_DEBUG_OBJECT (decode_bin, "got the pad for always template %s",
templ_name);
/* here is the pad, we need to autoplug it */
to_connect = g_list_prepend (to_connect, pad); to_connect = g_list_prepend (to_connect, pad);
} else {
/* strange, pad is marked as always but it's not
* there. Fix the element */
GST_WARNING_OBJECT (decode_bin,
"could not get the pad for always template %s", templ_name);
} }
break; break;
} }
case GST_PAD_SOMETIMES: case GST_PAD_SOMETIMES:
{ {
GstPad *pad = gst_element_get_pad (element, /* try to get the pad to see if it is already created or
GST_PAD_TEMPLATE_NAME_TEMPLATE (templ)); * not */
GstPad *pad = gst_element_get_pad (element, templ_name);
if (pad) { if (pad) {
GST_DEBUG_OBJECT (decode_bin, "got the pad for sometimes template %s",
templ_name);
/* the pad is created, we need to autoplug it */
to_connect = g_list_prepend (to_connect, pad); to_connect = g_list_prepend (to_connect, pad);
} else { } else {
GST_DEBUG_OBJECT (decode_bin,
"did not get the sometimes pad of template %s", templ_name);
/* we have an element that will create dynamic pads */
dynamic = TRUE; dynamic = TRUE;
} }
break; break;
} }
case GST_PAD_REQUEST: case GST_PAD_REQUEST:
/* ignore request pads */
GST_DEBUG_OBJECT (decode_bin, "ignoring request padtemplate %s",
templ_name);
break; break;
} }
} }
if (dynamic) { if (dynamic) {
GstDynamic *dyn; GstDynamic *dyn;
GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
/* ok, this element has dynamic pads, set up the signal handlers to be
* notified of them */
dyn = g_new0 (GstDynamic, 1); dyn = g_new0 (GstDynamic, 1);
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad", dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "new-pad",
G_CALLBACK (new_pad), dyn); G_CALLBACK (new_pad), dyn);
@ -494,29 +615,46 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
dyn->element = element; dyn->element = element;
dyn->decode_bin = decode_bin; dyn->decode_bin = decode_bin;
/* and add this element to the dynamic elements */
decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn); decode_bin->dynamics = g_list_prepend (decode_bin->dynamics, dyn);
} }
/* now loop over all the pads we need to connect */
for (pads = to_connect; pads; pads = g_list_next (pads)) { for (pads = to_connect; pads; pads = g_list_next (pads)) {
GstPad *pad = GST_PAD (pads->data); GstPad *pad = GST_PAD (pads->data);
GST_DEBUG_OBJECT (decode_bin, "closing pad link for %s",
gst_pad_get_name (pad));
/* continue autoplugging on the pads */
close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin); close_pad_link (element, pad, gst_pad_get_caps (pad), decode_bin);
} }
g_list_free (to_connect); g_list_free (to_connect);
} }
/* this is the signal handler for the typefind element have_type signal.
* It tries to continue autoplugging on the typefind src pad */
static void static void
type_found (GstElement * typefind, guint probability, GstCaps * caps, type_found (GstElement * typefind, guint probability, GstCaps * caps,
GstDecodeBin * decode_bin) GstDecodeBin * decode_bin)
{ {
gboolean dynamic; gboolean dynamic;
GST_DEBUG_OBJECT (decode_bin, "typefind found caps %" GST_PTR_FORMAT, caps);
/* autoplug the new pad with the caps that the signal gave us */
close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps, close_pad_link (typefind, gst_element_get_pad (typefind, "src"), caps,
decode_bin); decode_bin);
dynamic = gst_decode_bin_is_dynamic (decode_bin); dynamic = gst_decode_bin_is_dynamic (decode_bin);
if (dynamic == FALSE) { if (dynamic == FALSE) {
GST_DEBUG_OBJECT (decode_bin, "we have no dynamic elements anymore");
/* if we have no dynamic elements, we know that no new pads
* will be created and we can signal out no_more_pads signal */
gst_element_no_more_pads (GST_ELEMENT (decode_bin)); gst_element_no_more_pads (GST_ELEMENT (decode_bin));
} else {
/* more dynamic elements exist that could create new pads */
GST_DEBUG_OBJECT (decode_bin, "we more dynamic elements");
} }
} }