bin: Only post EOS messages after reaching the PLAYING state

Fixes bug #647756.
This commit is contained in:
Sebastian Dröge 2011-04-18 14:26:33 +02:00
parent 3872b816d2
commit 4a836cae9f

View file

@ -220,6 +220,8 @@ struct _GstBinPrivate
GstIndex *index; GstIndex *index;
/* forward messages from our children */ /* forward messages from our children */
gboolean message_forward; gboolean message_forward;
gboolean posted_eos;
}; };
typedef struct typedef struct
@ -238,12 +240,15 @@ static void gst_bin_get_property (GObject * object, guint prop_id,
static GstStateChangeReturn gst_bin_change_state_func (GstElement * element, static GstStateChangeReturn gst_bin_change_state_func (GstElement * element,
GstStateChange transition); GstStateChange transition);
static void gst_bin_state_changed (GstElement * element, GstState oldstate,
GstState newstate, GstState pending);
static GstStateChangeReturn gst_bin_get_state_func (GstElement * element, static GstStateChangeReturn gst_bin_get_state_func (GstElement * element,
GstState * state, GstState * pending, GstClockTime timeout); GstState * state, GstState * pending, GstClockTime timeout);
static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret, static void bin_handle_async_done (GstBin * bin, GstStateChangeReturn ret,
gboolean flag_pending); gboolean flag_pending);
static void bin_handle_async_start (GstBin * bin, gboolean new_base_time); static void bin_handle_async_start (GstBin * bin, gboolean new_base_time);
static void bin_push_state_continue (BinContinueData * data); static void bin_push_state_continue (BinContinueData * data);
static void bin_do_eos (GstBin * bin);
static gboolean gst_bin_add_func (GstBin * bin, GstElement * element); static gboolean gst_bin_add_func (GstBin * bin, GstElement * element);
static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element); static gboolean gst_bin_remove_func (GstBin * bin, GstElement * element);
@ -502,6 +507,7 @@ gst_bin_class_init (GstBinClass * klass)
gstelement_class->change_state = gstelement_class->change_state =
GST_DEBUG_FUNCPTR (gst_bin_change_state_func); GST_DEBUG_FUNCPTR (gst_bin_change_state_func);
gstelement_class->state_changed = GST_DEBUG_FUNCPTR (gst_bin_state_changed);
gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func); gstelement_class->get_state = GST_DEBUG_FUNCPTR (gst_bin_get_state_func);
gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func); gstelement_class->get_index = GST_DEBUG_FUNCPTR (gst_bin_get_index_func);
gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func); gstelement_class->set_index = GST_DEBUG_FUNCPTR (gst_bin_set_index_func);
@ -987,10 +993,10 @@ bin_remove_messages (GstBin * bin, GstObject * src, GstMessageType types)
* *
* call with bin LOCK */ * call with bin LOCK */
static gboolean static gboolean
is_eos (GstBin * bin) is_eos (GstBin * bin, guint32 * seqnum)
{ {
gboolean result; gboolean result;
GList *walk; GList *walk, *msgs;
result = TRUE; result = TRUE;
for (walk = bin->children; walk; walk = g_list_next (walk)) { for (walk = bin->children; walk; walk = g_list_next (walk)) {
@ -999,8 +1005,10 @@ is_eos (GstBin * bin)
element = GST_ELEMENT_CAST (walk->data); element = GST_ELEMENT_CAST (walk->data);
if (bin_element_is_sink (element, bin) == 0) { if (bin_element_is_sink (element, bin) == 0) {
/* check if element posted EOS */ /* check if element posted EOS */
if (find_message (bin, GST_OBJECT_CAST (element), GST_MESSAGE_EOS)) { if ((msgs =
find_message (bin, GST_OBJECT_CAST (element), GST_MESSAGE_EOS))) {
GST_DEBUG ("sink '%s' posted EOS", GST_ELEMENT_NAME (element)); GST_DEBUG ("sink '%s' posted EOS", GST_ELEMENT_NAME (element));
*seqnum = gst_message_get_seqnum (GST_MESSAGE_CAST (msgs->data));
} else { } else {
GST_DEBUG ("sink '%s' did not post EOS yet", GST_DEBUG ("sink '%s' did not post EOS yet",
GST_ELEMENT_NAME (element)); GST_ELEMENT_NAME (element));
@ -2387,6 +2395,19 @@ gst_bin_do_latency_func (GstBin * bin)
return res; return res;
} }
static void
gst_bin_state_changed (GstElement * element, GstState oldstate,
GstState newstate, GstState pending)
{
GstElementClass *pklass = (GstElementClass *) parent_class;
if (newstate == GST_STATE_PLAYING && pending == GST_STATE_VOID_PENDING)
bin_do_eos (GST_BIN_CAST (element));
if (pklass->state_changed)
pklass->state_changed (element, oldstate, newstate, pending);
}
static GstStateChangeReturn static GstStateChangeReturn
gst_bin_change_state_func (GstElement * element, GstStateChange transition) gst_bin_change_state_func (GstElement * element, GstStateChange transition)
{ {
@ -2427,6 +2448,7 @@ gst_bin_change_state_func (GstElement * element, GstStateChange transition)
GST_OBJECT_LOCK (bin); GST_OBJECT_LOCK (bin);
GST_DEBUG_OBJECT (element, "clearing EOS elements"); GST_DEBUG_OBJECT (element, "clearing EOS elements");
bin_remove_messages (bin, NULL, GST_MESSAGE_EOS); bin_remove_messages (bin, NULL, GST_MESSAGE_EOS);
bin->priv->posted_eos = FALSE;
GST_OBJECT_UNLOCK (bin); GST_OBJECT_UNLOCK (bin);
if (current == GST_STATE_READY) if (current == GST_STATE_READY)
if (!(gst_bin_src_pads_activate (bin, TRUE))) if (!(gst_bin_src_pads_activate (bin, TRUE)))
@ -2734,6 +2756,7 @@ gst_bin_continue_func (BinContinueData * data)
GST_STATE_UNLOCK (bin); GST_STATE_UNLOCK (bin);
GST_DEBUG_OBJECT (bin, "state continue done"); GST_DEBUG_OBJECT (bin, "state continue done");
gst_object_unref (bin); gst_object_unref (bin);
g_slice_free (BinContinueData, data); g_slice_free (BinContinueData, data);
return; return;
@ -2998,6 +3021,33 @@ nothing_pending:
} }
} }
static void
bin_do_eos (GstBin * bin)
{
guint32 seqnum = 0;
gboolean eos;
GST_OBJECT_LOCK (bin);
/* If all sinks are EOS, we're in PLAYING and no state change is pending
* we forward the EOS message to the parent bin or application
*/
eos = GST_STATE (bin) == GST_STATE_PLAYING
&& GST_STATE_PENDING (bin) == GST_STATE_VOID_PENDING
&& is_eos (bin, &seqnum);
GST_OBJECT_UNLOCK (bin);
if (eos
&& g_atomic_int_compare_and_exchange (&bin->priv->posted_eos, FALSE,
TRUE)) {
GstMessage *tmessage;
tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
gst_message_set_seqnum (tmessage, seqnum);
GST_DEBUG_OBJECT (bin,
"all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum);
gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
}
}
/* must be called with the object lock. This function releases the lock to post /* must be called with the object lock. This function releases the lock to post
* the message. */ * the message. */
static void static void
@ -3106,28 +3156,15 @@ gst_bin_handle_message_func (GstBin * bin, GstMessage * message)
} }
case GST_MESSAGE_EOS: case GST_MESSAGE_EOS:
{ {
gboolean eos;
/* collect all eos messages from the children */ /* collect all eos messages from the children */
GST_OBJECT_LOCK (bin); GST_OBJECT_LOCK (bin);
bin_do_message_forward (bin, message); bin_do_message_forward (bin, message);
/* ref message for future use */ /* ref message for future use */
gst_message_ref (message);
bin_replace_message (bin, message, GST_MESSAGE_EOS); bin_replace_message (bin, message, GST_MESSAGE_EOS);
eos = is_eos (bin);
GST_OBJECT_UNLOCK (bin); GST_OBJECT_UNLOCK (bin);
/* if we are completely EOS, we forward an EOS message */ bin_do_eos (bin);
if (eos) {
seqnum = gst_message_get_seqnum (message);
tmessage = gst_message_new_eos (GST_OBJECT_CAST (bin));
gst_message_set_seqnum (tmessage, seqnum);
GST_DEBUG_OBJECT (bin,
"all sinks posted EOS, posting seqnum #%" G_GUINT32_FORMAT, seqnum);
gst_element_post_message (GST_ELEMENT_CAST (bin), tmessage);
}
gst_message_unref (message);
break; break;
} }
case GST_MESSAGE_STATE_DIRTY: case GST_MESSAGE_STATE_DIRTY: