diff --git a/gst/playback/gstplaybin2.c b/gst/playback/gstplaybin2.c index 51ee43c73d..49565c8377 100644 --- a/gst/playback/gstplaybin2.c +++ b/gst/playback/gstplaybin2.c @@ -470,6 +470,8 @@ struct _GstPlayBin } duration[5]; /* cached durations */ guint64 ring_buffer_max_size; /* 0 means disabled */ + + GList *contexts; }; struct _GstPlayBinClass @@ -1530,6 +1532,8 @@ gst_play_bin_finalize (GObject * object) if (playbin->velements) g_sequence_free (playbin->velements); + g_list_free_full (playbin->contexts, (GDestroyNotify) gst_context_unref); + g_rec_mutex_clear (&playbin->lock); g_mutex_clear (&playbin->dyn_lock); g_mutex_clear (&playbin->elements_lock); @@ -4061,6 +4065,34 @@ gst_play_bin_set_context (GstElement * element, GstContext * context) } /* Pass sink messages to the application, e.g. NEED_CONTEXT messages */ +static void +gst_play_bin_update_context (GstPlayBin * playbin, GstContext * context) +{ + GList *l; + const gchar *context_type; + + GST_OBJECT_LOCK (playbin); + context_type = gst_context_get_context_type (context); + for (l = playbin->contexts; l; l = l->next) { + GstContext *tmp = l->data; + const gchar *tmp_type = gst_context_get_context_type (tmp); + + /* Always store newest context but never replace + * a persistent one by a non-persistent one */ + if (strcmp (context_type, tmp_type) == 0 && + (gst_context_is_persistent (context) || + !gst_context_is_persistent (tmp))) { + gst_context_replace ((GstContext **) & l->data, context); + break; + } + } + /* Not found? Add */ + if (l != NULL) + playbin->contexts = + g_list_prepend (playbin->contexts, gst_context_ref (context)); + GST_OBJECT_UNLOCK (playbin); +} + static GstBusSyncReply activate_sink_bus_handler (GstBus * bus, GstMessage * msg, GstPlayBin * playbin) { @@ -4081,6 +4113,37 @@ activate_sink_bus_handler (GstBus * bus, GstMessage * msg, GstPlayBin * playbin) gst_element_post_message (GST_ELEMENT_CAST (playbin), msg); else gst_message_unref (msg); + } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_NEED_CONTEXT) { + const gchar *context_type; + GList *l; + + gst_message_parse_context_type (msg, &context_type); + GST_OBJECT_LOCK (playbin); + for (l = playbin->contexts; l; l = l->next) { + GstContext *tmp = l->data; + const gchar *tmp_type = gst_context_get_context_type (tmp); + + if (strcmp (context_type, tmp_type) == 0) { + gst_element_set_context (GST_ELEMENT (GST_MESSAGE_SRC (msg)), l->data); + break; + } + } + GST_OBJECT_UNLOCK (playbin); + + /* Forward if we couldn't answer the message */ + if (l == NULL) { + gst_element_post_message (GST_ELEMENT_CAST (playbin), msg); + } else { + gst_message_unref (msg); + } + } else if (GST_MESSAGE_TYPE (msg) == GST_MESSAGE_HAVE_CONTEXT) { + GstContext *context; + + gst_message_parse_have_context (msg, &context); + gst_play_bin_update_context (playbin, context); + gst_context_unref (context); + + gst_element_post_message (GST_ELEMENT_CAST (playbin), msg); } else { gst_element_post_message (GST_ELEMENT_CAST (playbin), msg); } @@ -5379,6 +5442,7 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition) case GST_STATE_CHANGE_READY_TO_NULL: { guint i; + GList *l; /* also do missed state change down to READY */ if (do_save) @@ -5425,6 +5489,25 @@ gst_play_bin_change_state (GstElement * element, GstStateChange transition) /* make sure the groups don't perform a state change anymore until we * enable them again */ groups_set_locked_state (playbin, TRUE); + + /* Remove all non-persistent contexts */ + GST_OBJECT_LOCK (playbin); + for (l = playbin->contexts; l;) { + GstContext *context = l->data; + + if (!gst_context_is_persistent (context)) { + GList *next; + + gst_context_unref (context); + + next = l->next; + playbin->contexts = g_list_delete_link (playbin->contexts, l); + l = next; + } else { + l = l->next; + } + } + GST_OBJECT_UNLOCK (playbin); break; } default: