queue: don't fail in _sink_event for sticky events

Implement the same behaviour as gst_pad_push_event when pushing sticky events
fails, that is don't fail immediately but fail when data flow resumes and upstream
can aggregate properly.

This fixes segment seeks with decodebin and unlinked audio or video branches.
Fixes: https://bugzilla.gnome.org/show_bug.cgi?id=687899
This commit is contained in:
Alessandro Decina 2012-10-29 12:08:31 +00:00
parent d8413cd0a2
commit c257b19ead
2 changed files with 77 additions and 1 deletions

View file

@ -771,7 +771,17 @@ gst_queue_handle_sink_event (GstPad * pad, GstObject * parent, GstEvent * event)
default: default:
if (GST_EVENT_IS_SERIALIZED (event)) { if (GST_EVENT_IS_SERIALIZED (event)) {
/* serialized events go in the queue */ /* serialized events go in the queue */
GST_QUEUE_MUTEX_LOCK_CHECK (queue, out_flushing); GST_QUEUE_MUTEX_LOCK (queue);
if (queue->srcresult != GST_FLOW_OK) {
/* Errors in sticky event pushing are no problem and ignored here
* as they will cause more meaningful errors during data flow.
* For EOS events, that are not followed by data flow, we still
* return FALSE here though.
*/
if (!GST_EVENT_IS_STICKY (event) ||
GST_EVENT_TYPE (event) == GST_EVENT_EOS)
goto out_flow_error;
}
/* refuse more events on EOS */ /* refuse more events on EOS */
if (queue->eos) if (queue->eos)
goto out_eos; goto out_eos;
@ -802,6 +812,15 @@ out_eos:
gst_event_unref (event); gst_event_unref (event);
return FALSE; return FALSE;
} }
out_flow_error:
{
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
"refusing event, we have a downstream flow error: %s",
gst_flow_get_name (queue->srcresult));
GST_QUEUE_MUTEX_UNLOCK (queue);
gst_event_unref (event);
return FALSE;
}
} }
static gboolean static gboolean

View file

@ -630,6 +630,62 @@ GST_START_TEST (test_time_level_task_not_started)
GST_END_TEST; GST_END_TEST;
GST_START_TEST (test_sticky_not_linked)
{
GstEvent *event;
GstSegment segment;
gboolean ret;
GstFlowReturn flow_ret;
GST_DEBUG ("starting");
g_object_set (queue, "max-size-buffers", 1, NULL);
UNDERRUN_LOCK ();
fail_unless (gst_element_set_state (queue,
GST_STATE_PLAYING) == GST_STATE_CHANGE_SUCCESS,
"could not set to playing");
UNDERRUN_WAIT ();
UNDERRUN_UNLOCK ();
gst_pad_push_event (mysrcpad, gst_event_new_stream_start ("test"));
gst_segment_init (&segment, GST_FORMAT_TIME);
segment.start = 1 * GST_SECOND;
segment.stop = 5 * GST_SECOND;
segment.time = 0;
segment.position = 1 * GST_SECOND;
event = gst_event_new_segment (&segment);
ret = gst_pad_push_event (mysrcpad, event);
fail_unless (ret == TRUE);
/* the first few buffers can return OK as they are queued and gst_queue_loop
* is woken up, tries to push and sets ->srcresult to NOT_LINKED
*/
flow_ret = GST_FLOW_OK;
while (flow_ret != GST_FLOW_NOT_LINKED)
flow_ret = gst_pad_push (mysrcpad, gst_buffer_new ());
/* send a new sticky event so that it will be pushed on the next gst_pad_push
*/
event = gst_event_new_segment (&segment);
ret = gst_pad_push_event (mysrcpad, event);
fail_unless (ret == TRUE);
/* make sure that gst_queue_sink_event doesn't return FALSE if the queue is
* unlinked, as that would make gst_pad_push return ERROR
*/
flow_ret = gst_pad_push (mysrcpad, gst_buffer_new ());
fail_unless_equals_int (flow_ret, GST_FLOW_NOT_LINKED);
GST_DEBUG ("stopping");
fail_unless (gst_element_set_state (queue,
GST_STATE_NULL) == GST_STATE_CHANGE_SUCCESS, "could not set to null");
}
GST_END_TEST;
#if 0 #if 0
static gboolean static gboolean
event_equals_newsegment (GstEvent * event, gboolean update, gdouble rate, event_equals_newsegment (GstEvent * event, gboolean update, gdouble rate,
@ -773,6 +829,7 @@ queue_suite (void)
#if 0 #if 0
tcase_add_test (tc_chain, test_newsegment); tcase_add_test (tc_chain, test_newsegment);
#endif #endif
tcase_add_test (tc_chain, test_sticky_not_linked);
return s; return s;
} }