gst/playback/gstdecodebin.c: Handle the case where an element has multiple pads with unfixed caps as well as still po...

Original commit message from CVS:
* gst/playback/gstdecodebin.c: (find_dynamic), (dynamic_add),
(close_pad_link), (elem_is_dynamic), (unlinked), (close_link):
Handle the case where an element has multiple pads with
unfixed caps as well as still possibly producing more dynamic
pads by storing each case as a distinct entry in the dynamic list.
Fixes #38223 again.
This commit is contained in:
Jan Schmidt 2006-12-05 12:44:00 +00:00
parent bdd8747c6c
commit 35fa7a7fbd
2 changed files with 108 additions and 22 deletions

View file

@ -1,3 +1,12 @@
2006-12-05 Jan Schmidt <thaytan@mad.scientist.com>
* gst/playback/gstdecodebin.c: (find_dynamic), (dynamic_add),
(close_pad_link), (elem_is_dynamic), (unlinked), (close_link):
Handle the case where an element has multiple pads with
unfixed caps as well as still possibly producing more dynamic
pads by storing each case as a distinct entry in the dynamic list.
Fixes #38223 again.
2006-12-04 Wim Taymans <wim@fluendo.com> 2006-12-04 Wim Taymans <wim@fluendo.com>
* gst/playback/gstdecodebin.c: (close_pad_link): * gst/playback/gstdecodebin.c: (close_pad_link):

View file

@ -384,27 +384,59 @@ gst_decode_bin_finalize (GObject * object)
G_OBJECT_CLASS (parent_class)->finalize (object); G_OBJECT_CLASS (parent_class)->finalize (object);
} }
static GstDynamic * struct DynFind
dynamic_create (GstElement * element, GstPad * pad, GstDecodeBin * decode_bin) {
GstElement *elem;
GstPad *pad;
};
static gint
find_dynamic (GstDynamic * dyn, struct DynFind *info)
{
if (dyn->element == info->elem && dyn->pad == info->pad)
return 0;
return 1;
}
/* Add either an element (for dynamic pads/pad-added watching) or a
* pad (for delayed caps/notify::caps watching) to the dynamic list,
* taking care to ignore repeat entries so we don't end up handling a
* pad twice, for example */
static void
dynamic_add (GstElement * element, GstPad * pad, GstDecodeBin * decode_bin)
{ {
GstDynamic *dyn; GstDynamic *dyn;
struct DynFind find_info;
GList *found;
GST_DEBUG_OBJECT (element, "dynamic create"); g_return_if_fail (element != NULL || pad != NULL);
/* do a search that this entry doesn't already exist */
find_info.elem = element;
find_info.pad = pad;
found = g_list_find_custom (decode_bin->dynamics, &find_info,
(GCompareFunc) find_dynamic);
if (found != NULL)
goto exit;
/* take refs */ /* take refs */
dyn = g_new0 (GstDynamic, 1); dyn = g_new0 (GstDynamic, 1);
dyn->element = element; dyn->element = element;
dyn->pad = pad; dyn->pad = pad;
dyn->decode_bin = gst_object_ref (decode_bin); dyn->decode_bin = gst_object_ref (decode_bin);
if (element) { if (element) {
GST_DEBUG_OBJECT (decode_bin, "dynamic create for element %"
GST_PTR_FORMAT, element);
gst_object_ref (element); gst_object_ref (element);
dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "pad-added", dyn->np_sig_id = g_signal_connect (G_OBJECT (element), "pad-added",
G_CALLBACK (new_pad), dyn); G_CALLBACK (new_pad), dyn);
dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads", dyn->nmp_sig_id = g_signal_connect (G_OBJECT (element), "no-more-pads",
G_CALLBACK (no_more_pads), dyn); G_CALLBACK (no_more_pads), dyn);
} } else {
if (pad) { GST_DEBUG_OBJECT (decode_bin, "dynamic create for pad %" GST_PTR_FORMAT,
pad);
gst_object_ref (pad); gst_object_ref (pad);
dyn->caps_sig_id = g_signal_connect (G_OBJECT (pad), "notify::caps", dyn->caps_sig_id = g_signal_connect (G_OBJECT (pad), "notify::caps",
G_CALLBACK (new_caps), dyn); G_CALLBACK (new_caps), dyn);
@ -413,7 +445,15 @@ dynamic_create (GstElement * element, GstPad * pad, GstDecodeBin * decode_bin)
/* and add this element to the dynamic elements */ /* 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);
return dyn; return;
exit:
if (element) {
GST_DEBUG_OBJECT (decode_bin, "Dynamic element already added: %"
GST_PTR_FORMAT, element);
} else {
GST_DEBUG_OBJECT (decode_bin, "Dynamic pad already added: %"
GST_PTR_FORMAT, pad);
}
} }
static void static void
@ -754,7 +794,7 @@ many_types:
setup_caps_delay: setup_caps_delay:
{ {
GST_LOG_OBJECT (pad, "setting up a delayed link"); GST_LOG_OBJECT (pad, "setting up a delayed link");
dynamic_create (element, pad, decode_bin); dynamic_add (NULL, pad, decode_bin);
return; return;
} }
} }
@ -1296,23 +1336,61 @@ is_our_kid (GstElement * e, GstDecodeBin * decode_bin)
return ret; return ret;
} }
static gint static gboolean
find_dynamic (GstDynamic * dyn, GstElement * elem) elem_is_dynamic (GstElement * element, GstDecodeBin * decode_bin)
{ {
return (dyn->element == elem ? 0 : 1); GList *pads;
/* loop over all the padtemplates */
for (pads = GST_ELEMENT_GET_CLASS (element)->padtemplates; pads;
pads = g_list_next (pads)) {
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)
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)) {
case GST_PAD_SOMETIMES:
{
/* try to get the pad to see if it is already created or
* not */
GstPad *pad = gst_element_get_pad (element, templ_name);
if (pad) {
GST_DEBUG_OBJECT (decode_bin, "got the pad for sometimes template %s",
templ_name);
gst_object_unref (pad);
} 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 */
return TRUE;
}
break;
}
default:
/* Don't care about ALWAYS or REQUEST pads */
break;
}
}
return FALSE;
} }
/* This function will be called when a pad is disconnected for some reason */ /* This function will be called when a pad is disconnected for some reason */
static void static void
unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin) unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
{ {
GstDynamic *dyn;
GstElement *element, *peer; GstElement *element, *peer;
/* inactivate pad */ /* inactivate pad */
gst_pad_set_active (pad, GST_ACTIVATE_NONE); gst_pad_set_active (pad, GST_ACTIVATE_NONE);
element = gst_pad_get_parent_element (pad);
peer = gst_pad_get_parent_element (peerpad); peer = gst_pad_get_parent_element (peerpad);
if (!is_our_kid (peer, decode_bin)) if (!is_our_kid (peer, decode_bin))
@ -1324,15 +1402,16 @@ unlinked (GstPad * pad, GstPad * peerpad, GstDecodeBin * decode_bin)
/* remove all elements linked to the peerpad */ /* remove all elements linked to the peerpad */
remove_element_chain (decode_bin, peerpad); remove_element_chain (decode_bin, peerpad);
/* if an element removes two pads, then we don't want this twice */ /* Re-add as a dynamic element if needed, via close_link */
if (g_list_find_custom (decode_bin->dynamics, element, element = gst_pad_get_parent_element (pad);
(GCompareFunc) find_dynamic) != NULL) if (element) {
goto exit; if (elem_is_dynamic (element, decode_bin))
dynamic_add (element, NULL, decode_bin);
dyn = dynamic_create (element, NULL, decode_bin); gst_object_unref (element);
}
exit: exit:
gst_object_unref (element);
gst_object_unref (peer); gst_object_unref (peer);
} }
@ -1410,13 +1489,11 @@ close_link (GstElement * element, GstDecodeBin * decode_bin)
} }
} }
if (dynamic) { if (dynamic) {
GstDynamic *dyn;
GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here"); GST_DEBUG_OBJECT (decode_bin, "got a dynamic element here");
/* ok, this element has dynamic pads, set up the signal handlers to be /* ok, this element has dynamic pads, set up the signal handlers to be
* notified of them */ * notified of them */
dyn = dynamic_create (element, NULL, decode_bin); dynamic_add (element, NULL, decode_bin);
} }
/* Check if this is an element with more than 1 pad. If this element /* Check if this is an element with more than 1 pad. If this element