decodebin2: Prune old groups before switching to the new one

In order to allow for proper functionality when a decoder only supports
one instance at a time (dsp), we must block the demuxer pads when they
get created if they are not part of the active group, preventing buffers
from being sent to the decoder (and initializing it through setcaps),
then after we switch to a new group, we unblock the demuxer pads for
the active groups. In the callback for the unblock, we prune the old
groups, making sure the previous decoder instance is destroyed before
we push a buffer to the new instance.
This commit is contained in:
Youness Alaoui 2011-09-13 23:14:10 +00:00 committed by Sebastian Dröge
parent 3e312e6e16
commit e2a038acee

View file

@ -446,6 +446,7 @@ static gboolean gst_decode_chain_is_complete (GstDecodeChain * chain);
static gboolean gst_decode_chain_expose (GstDecodeChain * chain,
GList ** endpads, gboolean * missing_plugin);
static gboolean gst_decode_chain_is_drained (GstDecodeChain * chain);
static void gst_decode_chain_prune (GstDecodeChain * chain);
static gboolean gst_decode_group_is_complete (GstDecodeGroup * group);
static GstPad *gst_decode_group_control_demuxer_pad (GstDecodeGroup * group,
GstPad * pad);
@ -2319,6 +2320,16 @@ pad_event_cb (GstPad * pad, GstEvent * event, gpointer data)
return TRUE;
}
static void
demuxer_pad_blocked_cb (GstPad * pad, gboolean blocked, GstDecodeChain * chain)
{
GstDecodeBin *dbin;
dbin = chain->dbin;
if (!blocked)
gst_decode_chain_prune (dbin->decode_chain);
}
static void
pad_added_cb (GstElement * element, GstPad * pad, GstDecodeChain * chain)
{
@ -2335,6 +2346,27 @@ pad_added_cb (GstElement * element, GstPad * pad, GstDecodeChain * chain)
gst_caps_unref (caps);
EXPOSE_LOCK (dbin);
CHAIN_MUTEX_LOCK (chain);
if (chain->demuxer &&
((GstDecodeElement *) chain->elements->data)->element == element) {
GList *l;
for (l = chain->next_groups; l; l = l->next) {
GstDecodeGroup *group = l->data;
GList *l2;
for (l2 = group->children; l2; l2 = l2->next) {
GstDecodeChain *child_chain = l2->data;
if (!gst_pad_is_blocked (child_chain->pad)) {
GST_DEBUG_OBJECT (pad, "blocking next group's pad %p", pad);
gst_pad_set_blocked_async (child_chain->pad, TRUE,
(GstPadBlockCallback) demuxer_pad_blocked_cb, chain);
}
}
}
}
CHAIN_MUTEX_UNLOCK (chain);
if (gst_decode_chain_is_complete (dbin->decode_chain)) {
GST_LOG_OBJECT (dbin,
"That was the last dynamic object, now attempting to expose the group");
@ -2867,6 +2899,76 @@ gst_decode_group_hide (GstDecodeGroup * group)
gst_decode_group_free_internal (group, TRUE);
}
static void
gst_decode_group_prune (GstDecodeGroup * group)
{
GList *l;
GST_DEBUG_OBJECT (group->dbin, "Pruning group %p", group);
for (l = group->children; l; l = l->next) {
GstDecodeChain *chain = (GstDecodeChain *) l->data;
gst_decode_chain_prune (chain);
}
GST_DEBUG_OBJECT (group->dbin, "Pruned group %p", group);
}
static void
gst_decode_chain_prune (GstDecodeChain * chain)
{
GList *l;
CHAIN_MUTEX_LOCK (chain);
GST_DEBUG_OBJECT (chain->dbin, "Pruning chain %p", chain);
if (chain->active_group)
gst_decode_group_prune (chain->active_group);
for (l = chain->next_groups; l; l = l->next) {
gst_decode_group_prune ((GstDecodeGroup *) l->data);
}
for (l = chain->old_groups; l; l = l->next) {
GstDecodeGroup *group = l->data;
/* This calls set_state(NULL) on the old elements and we're
* the streaming thread but this is one of the few cases
* when this is possible. It's guaranteed at this point
* that *this* streaming thread is not inside the elements
* currently, because it's *here* now or a different streaming
* thread is used for the elements.
*/
gst_decode_group_free (group);
}
g_list_free (chain->old_groups);
chain->old_groups = NULL;
GST_DEBUG_OBJECT (chain->dbin, "Pruned chain %p", chain);
CHAIN_MUTEX_UNLOCK (chain);
}
static void
unblock_demuxer_pads (GstDecodeChain * chain)
{
GList *l;
GST_DEBUG_OBJECT (chain->dbin, "Unblocking demuxer pad for chain %p", chain);
if (gst_pad_is_blocked (chain->pad))
gst_pad_set_blocked_async (chain->pad, FALSE,
(GstPadBlockCallback) demuxer_pad_blocked_cb, chain);
if (chain->active_group) {
for (l = chain->active_group->children; l; l = l->next) {
GstDecodeChain *child_chain = l->data;
unblock_demuxer_pads (child_chain);
}
}
}
/* configure queue sizes, this depends on the buffering method and if we are
* playing or prerolling. */
static void
@ -3241,6 +3343,7 @@ gst_decode_pad_handle_eos (GstDecodePad * pad)
EXPOSE_LOCK (dbin);
if (gst_decode_chain_is_complete (dbin->decode_chain))
gst_decode_bin_expose (dbin);
unblock_demuxer_pads (dbin->decode_chain);
EXPOSE_UNLOCK (dbin);
}