mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-11-27 04:01:08 +00:00
queue2: fix event/preroll deadlock differently
The qlock is released between popping a buffer from the queue and pushing it. When this buffer causes the sink to wait in preroll, this lets a query see that the queue is empty, and push the query then wait for it to be serviced. However, this will not be done till after peroll, and this will thus block. If upstream was waiting on buffering to reach 100% before switching to PLAYING, a deadlock would ensue. This had been fixed recently by failing queries when the queue2 was buffering, but this happens to break some other case (playbin on a local http server and matroska), while this patch works for both. See https://bugzilla.gnome.org/show_bug.cgi?id=728345
This commit is contained in:
parent
145517aa64
commit
f3dd7937a2
2 changed files with 24 additions and 7 deletions
|
@ -2339,14 +2339,21 @@ gst_queue2_handle_sink_query (GstPad * pad, GstObject * parent,
|
|||
* completely, which can not happen if we block on the query..
|
||||
* Therefore we only potentially block when we are not buffering. */
|
||||
GST_QUEUE2_MUTEX_LOCK_CHECK (queue, queue->sinkresult, out_flushing);
|
||||
if (QUEUE_IS_USING_QUEUE (queue) && !queue->is_buffering) {
|
||||
gst_queue2_locked_enqueue (queue, query, GST_QUEUE2_ITEM_TYPE_QUERY);
|
||||
if (QUEUE_IS_USING_QUEUE (queue) && (gst_queue2_is_empty (queue)
|
||||
|| !queue->use_buffering)) {
|
||||
if (!g_atomic_int_get (&queue->downstream_may_block)) {
|
||||
gst_queue2_locked_enqueue (queue, query,
|
||||
GST_QUEUE2_ITEM_TYPE_QUERY);
|
||||
|
||||
STATUS (queue, queue->sinkpad, "wait for QUERY");
|
||||
g_cond_wait (&queue->query_handled, &queue->qlock);
|
||||
if (queue->sinkresult != GST_FLOW_OK)
|
||||
goto out_flushing;
|
||||
res = queue->last_query;
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (queue, "refusing query, downstream might block");
|
||||
res = FALSE;
|
||||
}
|
||||
} else {
|
||||
GST_DEBUG_OBJECT (queue,
|
||||
"refusing query, we are not using the queue");
|
||||
|
@ -2588,6 +2595,10 @@ gst_queue2_push_one (GstQueue2 * queue)
|
|||
goto no_item;
|
||||
|
||||
next:
|
||||
STATUS (queue, queue->srcpad, "We have something dequeud");
|
||||
g_atomic_int_set (&queue->downstream_may_block,
|
||||
item_type == GST_QUEUE2_ITEM_TYPE_BUFFER ||
|
||||
item_type == GST_QUEUE2_ITEM_TYPE_BUFFER_LIST);
|
||||
GST_QUEUE2_MUTEX_UNLOCK (queue);
|
||||
|
||||
if (item_type == GST_QUEUE2_ITEM_TYPE_BUFFER) {
|
||||
|
@ -2596,6 +2607,7 @@ next:
|
|||
buffer = GST_BUFFER_CAST (data);
|
||||
|
||||
result = gst_pad_push (queue->srcpad, buffer);
|
||||
g_atomic_int_set (&queue->downstream_may_block, 0);
|
||||
|
||||
/* need to check for srcresult here as well */
|
||||
GST_QUEUE2_MUTEX_LOCK_CHECK (queue, queue->srcresult, out_flushing);
|
||||
|
@ -2627,6 +2639,7 @@ next:
|
|||
buffer_list = GST_BUFFER_LIST_CAST (data);
|
||||
|
||||
result = gst_pad_push_list (queue->srcpad, buffer_list);
|
||||
g_atomic_int_set (&queue->downstream_may_block, 0);
|
||||
|
||||
/* need to check for srcresult here as well */
|
||||
GST_QUEUE2_MUTEX_LOCK_CHECK (queue, queue->srcresult, out_flushing);
|
||||
|
@ -2641,7 +2654,9 @@ next:
|
|||
} else if (item_type == GST_QUEUE2_ITEM_TYPE_QUERY) {
|
||||
GstQuery *query = GST_QUERY_CAST (data);
|
||||
|
||||
GST_LOG_OBJECT (queue->srcpad, "Peering query %p", query);
|
||||
queue->last_query = gst_pad_peer_query (queue->srcpad, query);
|
||||
GST_LOG_OBJECT (queue->srcpad, "Peered query");
|
||||
GST_CAT_LOG_OBJECT (queue_dataflow, queue,
|
||||
"did query %p, return %d", query, queue->last_query);
|
||||
g_cond_signal (&queue->query_handled);
|
||||
|
|
|
@ -151,6 +151,8 @@ struct _GstQueue2
|
|||
|
||||
guint64 ring_buffer_max_size;
|
||||
guint8 * ring_buffer;
|
||||
|
||||
volatile gint downstream_may_block;
|
||||
};
|
||||
|
||||
struct _GstQueue2Class
|
||||
|
|
Loading…
Reference in a new issue