diff --git a/ChangeLog b/ChangeLog index 76cede332a..8ac38edf42 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,15 @@ +2005-11-18 Wim Taymans + + * gst/gstbin.c: (gst_bin_provide_clock_func), (gst_bin_add_func), + (gst_bin_remove_func), (bin_bus_handler): + * gst/gstbin.h: + Removing a clock provider from a bin, triggers a clock lost message + so that a new clock will be selected. + Adding a clock to a bin triggers a clock provider message. + Make sure we reselect a clock when we received a clock lost message. + Keep a reference to the element that provided the clock. + + 2005-11-18 Andy Wingo * gst/net/gstnetclientclock.c (gst_net_client_clock_new): Adjust diff --git a/gst/gstbin.c b/gst/gstbin.c index 637aef08bb..cb37f38584 100644 --- a/gst/gstbin.c +++ b/gst/gstbin.c @@ -462,6 +462,7 @@ static GstClock * gst_bin_provide_clock_func (GstElement * element) { GstClock *result = NULL; + GstElement *provider = NULL; GstBin *bin; GstIterator *it; gpointer val; @@ -481,16 +482,23 @@ gst_bin_provide_clock_func (GstElement * element) GstClock *clock; clock = gst_element_provide_clock (child); - if (clock || result == NULL) { - GST_DEBUG_OBJECT (bin, "found candidate clock %p", clock); - if (result) + if (clock) { + GST_DEBUG_OBJECT (bin, "found candidate clock %p by element %s", + clock, GST_ELEMENT_NAME (child)); + if (result) { gst_object_unref (result); + gst_object_unref (provider); + } result = clock; + provider = child; + } else { + gst_object_unref (child); } - gst_object_unref (child); } gst_object_replace ((GstObject **) & bin->provided_clock, (GstObject *) result); + gst_object_replace ((GstObject **) & bin->ABI.clock_provider, + (GstObject *) provider); bin->clock_dirty = FALSE; GST_DEBUG_OBJECT (bin, "provided new clock %p", result); GST_UNLOCK (bin); @@ -668,6 +676,7 @@ gst_bin_add_func (GstBin * bin, GstElement * element) gchar *elem_name; GstIterator *it; gboolean is_sink; + GstMessage *clock_message = NULL; /* we obviously can't add ourself to ourself */ if (G_UNLIKELY (GST_ELEMENT_CAST (element) == GST_ELEMENT_CAST (bin))) @@ -702,6 +711,8 @@ gst_bin_add_func (GstBin * bin, GstElement * element) if (gst_element_provides_clock (element)) { GST_DEBUG_OBJECT (bin, "element \"%s\" can provide a clock", elem_name); bin->clock_dirty = TRUE; + clock_message = + gst_message_new_clock_provide (GST_OBJECT_CAST (bin), NULL, TRUE); } bin->children = g_list_prepend (bin->children, element); @@ -717,6 +728,10 @@ gst_bin_add_func (GstBin * bin, GstElement * element) bin->state_dirty = TRUE; GST_UNLOCK (bin); + if (clock_message) { + gst_element_post_message (GST_ELEMENT_CAST (bin), clock_message); + } + /* unlink all linked pads */ it = gst_element_iterate_pads (element); gst_iterator_foreach (it, (GFunc) unlink_pads, element); @@ -812,6 +827,7 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) gchar *elem_name; GstIterator *it; gboolean is_sink; + GstMessage *clock_message = NULL; GST_LOCK (element); /* Check if the element is already being removed and immediately @@ -852,14 +868,22 @@ gst_bin_remove_func (GstBin * bin, GstElement * element) GST_OBJECT_FLAG_UNSET (bin, GST_ELEMENT_IS_SINK); } } - if (gst_element_provides_clock (element)) { - GST_CAT_DEBUG_OBJECT (GST_CAT_PARENTAGE, bin, - "element \"%s\" could provide a clock", elem_name); + /* if the clock provider for this element is removed, we lost + * the clock as well, we need to inform the parent of this + * so that it can select a new clock */ + if (bin->ABI.clock_provider == element) { + GST_DEBUG_OBJECT (bin, "element \"%s\" provided the clock", elem_name); bin->clock_dirty = TRUE; + clock_message = + gst_message_new_clock_lost (GST_OBJECT_CAST (bin), bin->provided_clock); } bin->state_dirty = TRUE; GST_UNLOCK (bin); + if (clock_message) { + gst_element_post_message (GST_ELEMENT_CAST (bin), clock_message); + } + GST_CAT_INFO_OBJECT (GST_CAT_PARENTAGE, bin, "removed child \"%s\"", elem_name); g_free (elem_name); @@ -1930,16 +1954,59 @@ bin_bus_handler (GstBus * bus, GstMessage * message, GstBin * bin) GST_LOCK (bin); bin_remove_messages (bin, NULL, GST_MESSAGE_DURATION); GST_UNLOCK (bin); - /* fallthrough */ + goto forward; + } + case GST_MESSAGE_CLOCK_LOST: + { + gboolean playing, provided, forward; + GstClock *clock; + + gst_message_parse_clock_lost (message, &clock); + + GST_LOCK (bin); + bin->clock_dirty = TRUE; + /* if we lost the clock that we provided, post to parent but + * only if we are PLAYING. */ + provided = (clock == bin->provided_clock); + playing = (GST_STATE (bin) == GST_STATE_PLAYING); + forward = playing & provided; + GST_DEBUG_OBJECT (bin, "provided %d, playing %d, forward %d", + provided, playing, forward); + GST_UNLOCK (bin); + + if (forward) { + goto forward; + } + break; + } + case GST_MESSAGE_CLOCK_PROVIDE: + { + gboolean forward; + + GST_LOCK (bin); + bin->clock_dirty = TRUE; + /* a new clock is available, post to parent but not + * to the application */ + forward = GST_OBJECT_PARENT (bin) != NULL; + GST_UNLOCK (bin); + + if (forward) + goto forward; + break; } default: - /* Send all other messages upward */ - GST_DEBUG_OBJECT (bin, "posting message upward"); - gst_element_post_message (GST_ELEMENT_CAST (bin), message); - break; + goto forward; } return GST_BUS_DROP; + +forward: + { + /* Send all other messages upward */ + GST_DEBUG_OBJECT (bin, "posting message upward"); + gst_element_post_message (GST_ELEMENT_CAST (bin), message); + return GST_BUS_DROP; + } } /* generic struct passed to all query fold methods */ diff --git a/gst/gstbin.h b/gst/gstbin.h index 384a7fdd98..4a663f722d 100644 --- a/gst/gstbin.h +++ b/gst/gstbin.h @@ -112,7 +112,12 @@ struct _GstBin { GstClock *provided_clock; /*< private >*/ - gpointer _gst_reserved[GST_PADDING]; + union { + struct { + GstElement *clock_provider; + } ABI; + gpointer _gst_reserved[GST_PADDING+1-1]; + }; }; /**