mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-22 14:06:23 +00:00
decodebin: Shut down all elements explicitly to NULL state before freeing the decode chain
Due to transient locked state during autoplugging, some elements might be ignored by the GstBin::change_state() and might still be running. Which could then cause pad-added and similar accessing decodebin state that does not exist anymore, and crash. https://bugzilla.gnome.org/show_bug.cgi?id=763625
This commit is contained in:
parent
65390b5129
commit
9c2d76fb9f
1 changed files with 75 additions and 0 deletions
|
@ -5165,6 +5165,80 @@ unblock_pads (GstDecodeBin * dbin)
|
|||
dbin->blocked_pads = NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_decode_chain_stop (GstDecodeBin * dbin, GstDecodeChain * chain,
|
||||
GQueue * elements)
|
||||
{
|
||||
GQueue *internal_elements, internal_elements_ = G_QUEUE_INIT;
|
||||
GList *l;
|
||||
|
||||
CHAIN_MUTEX_LOCK (chain);
|
||||
if (elements) {
|
||||
internal_elements = elements;
|
||||
} else {
|
||||
internal_elements = &internal_elements_;
|
||||
}
|
||||
|
||||
for (l = chain->next_groups; l; l = l->next) {
|
||||
GstDecodeGroup *group = l->data;
|
||||
GList *m;
|
||||
|
||||
for (m = group->children; m; m = m->next) {
|
||||
GstDecodeChain *chain2 = m->data;
|
||||
gst_decode_chain_stop (dbin, chain2, internal_elements);
|
||||
}
|
||||
if (group->multiqueue)
|
||||
g_queue_push_head (internal_elements, gst_object_ref (group->multiqueue));
|
||||
}
|
||||
|
||||
if (chain->active_group) {
|
||||
for (l = chain->active_group->children; l; l = l->next) {
|
||||
GstDecodeChain *chain2 = l->data;
|
||||
gst_decode_chain_stop (dbin, chain2, internal_elements);
|
||||
}
|
||||
if (chain->active_group->multiqueue)
|
||||
g_queue_push_head (internal_elements,
|
||||
gst_object_ref (chain->active_group->multiqueue));
|
||||
}
|
||||
|
||||
for (l = chain->old_groups; l; l = l->next) {
|
||||
GstDecodeGroup *group = l->data;
|
||||
GList *m;
|
||||
|
||||
for (m = group->children; m; m = m->next) {
|
||||
GstDecodeChain *chain2 = m->data;
|
||||
gst_decode_chain_stop (dbin, chain2, internal_elements);
|
||||
}
|
||||
if (group->multiqueue)
|
||||
g_queue_push_head (internal_elements, gst_object_ref (group->multiqueue));
|
||||
}
|
||||
|
||||
for (l = chain->elements; l; l = l->next) {
|
||||
GstDecodeElement *delem = l->data;
|
||||
|
||||
if (delem->capsfilter)
|
||||
g_queue_push_head (internal_elements, gst_object_ref (delem->capsfilter));
|
||||
g_queue_push_head (internal_elements, gst_object_ref (delem->element));
|
||||
}
|
||||
|
||||
CHAIN_MUTEX_UNLOCK (chain);
|
||||
|
||||
if (!elements) {
|
||||
GstElement *element;
|
||||
|
||||
EXPOSE_UNLOCK (dbin);
|
||||
/* Shut down from bottom to top */
|
||||
while ((element = g_queue_pop_tail (internal_elements))) {
|
||||
/* The bin must never ever change the state of this element anymore */
|
||||
gst_element_set_locked_state (element, TRUE);
|
||||
gst_element_set_state (element, GST_STATE_NULL);
|
||||
gst_object_unref (element);
|
||||
}
|
||||
g_queue_clear (internal_elements);
|
||||
EXPOSE_LOCK (dbin);
|
||||
}
|
||||
}
|
||||
|
||||
static GstStateChangeReturn
|
||||
gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
|
||||
{
|
||||
|
@ -5229,6 +5303,7 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition)
|
|||
do_async_done (dbin);
|
||||
EXPOSE_LOCK (dbin);
|
||||
if (dbin->decode_chain) {
|
||||
gst_decode_chain_stop (dbin, dbin->decode_chain, NULL);
|
||||
chain_to_free = dbin->decode_chain;
|
||||
gst_decode_chain_free_internal (dbin->decode_chain, TRUE);
|
||||
dbin->decode_chain = NULL;
|
||||
|
|
Loading…
Reference in a new issue