From 5c8ef0ea05123506dfc35c70c8b165bca7435dad Mon Sep 17 00:00:00 2001 From: Myoungsun Lee Date: Thu, 30 Jul 2015 10:33:25 +0900 Subject: [PATCH] decodebin: Handle the preroll multi-queue size Overview: There are some of interleaved streams which has long-term location of audio data. It mean the audio data is located far away more than multiqueue size. In this case, because of multiqueue overrun, the pipeline is stopped. To prevent hanging-like state, the decodebin needs to handle the queue size. Caused: The multiqueue size is not enough, the pipeline will stay being stalled status and decodebin cannot complete to build decode chain. In this issue file, decodebin did not receive no_more_pads signal or audio data yet. Steps to Reproduce: play the high-resolution(4K file) files or some streaming media(push mode). Actual Results: There is no audio or subtitle. We can see only video or infinite loading. Resolution: Decodebin detect this problem, and add extra buffer size to multiqueue. The multiqueue is larger than before, the next data can be pushed the downstream element. Additional Information: The max-preroll extra buffer size is set 8MB. We can use total pre-roll buffer 10MB. Only first overrun callback can handle multiqueue size. https://bugzilla.gnome.org/show_bug.cgi?id=733235 --- gst/playback/gstdecodebin2.c | 44 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 38 insertions(+), 6 deletions(-) diff --git a/gst/playback/gstdecodebin2.c b/gst/playback/gstdecodebin2.c index 85a2ed1..6e5f362 100644 --- a/gst/playback/gstdecodebin2.c +++ b/gst/playback/gstdecodebin2.c @@ -186,6 +186,8 @@ struct _GstDecodeBin GList *filtered_errors; /* filtered error messages */ GList *buffering_status; /* element currently buffering messages */ + + gboolean extra_buffer_required; /* whether to controll queue size or not */ }; struct _GstDecodeBinClass @@ -253,6 +255,7 @@ enum #define DEFAULT_POST_STREAM_TOPOLOGY FALSE #define DEFAULT_EXPOSE_ALL_STREAMS TRUE #define DEFAULT_CONNECTION_SPEED 0 +#define DEFAULT_EXTRA_SIZE_BUFFERS_BYTES 8 * 1024 * 1024 /* 8 MB */ /* Properties */ enum @@ -1099,6 +1102,8 @@ gst_decode_bin_init (GstDecodeBin * decode_bin) decode_bin->expose_allstreams = DEFAULT_EXPOSE_ALL_STREAMS; decode_bin->connection_speed = DEFAULT_CONNECTION_SPEED; + + decode_bin->extra_buffer_required = FALSE; } static void @@ -3046,6 +3051,7 @@ no_more_pads_cb (GstElement * element, GstDecodeChain * chain) GST_DEBUG_OBJECT (element, "Setting group %p to complete", group); group->no_more_pads = TRUE; + group->dbin->extra_buffer_required = FALSE; /* this group has prerolled enough to not need more pads, * we can probably set its buffering state to playing now */ GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " @@ -3481,13 +3487,20 @@ multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group) GST_LOG_OBJECT (dbin, "multiqueue '%s' (%p) is full", GST_OBJECT_NAME (queue), queue); - group->overrun = TRUE; /* this group has prerolled enough to not need more pads, * we can probably set its buffering state to playing now */ - GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " - "'playing' buffering mode", group); - decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, - (group->parent ? group->parent->seekable : TRUE)); + if (!group->no_more_pads && group->parent->demuxer + && !dbin->extra_buffer_required) { + group->overrun = FALSE; + dbin->extra_buffer_required = TRUE; + } else { + GST_DEBUG_OBJECT (group->dbin, "Setting group %p multiqueue to " + "'playing' buffering mode", group); + group->overrun = TRUE; + dbin->extra_buffer_required = FALSE; + decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, + (group->parent ? group->parent->seekable : TRUE)); + } /* FIXME: We should make sure that everything gets exposed now * even if child chains are not complete because the will never @@ -3500,9 +3513,19 @@ multi_queue_overrun_cb (GstElement * queue, GstDecodeGroup * group) if (gst_decode_chain_is_complete (dbin->decode_chain)) { if (!gst_decode_bin_expose (dbin)) GST_WARNING_OBJECT (dbin, "Couldn't expose group"); + } else { + dbin->extra_buffer_required = TRUE; } } EXPOSE_UNLOCK (dbin); + + if (dbin->extra_buffer_required) { + GST_DEBUG_OBJECT (group->dbin, + "Setting group %p multiqueue to " "'extra_buffer_required' mode", + group); + decodebin_set_queue_size (group->dbin, group->multiqueue, FALSE, + (group->parent ? group->parent->seekable : TRUE)); + } } static void @@ -3664,7 +3687,9 @@ decodebin_set_queue_size_full (GstDecodeBin * dbin, GstElement * multiqueue, guint max_bytes, max_buffers; guint64 max_time; - GST_DEBUG_OBJECT (multiqueue, "use buffering %d", use_buffering); + GST_DEBUG_OBJECT (multiqueue, + "use buffering %d, add extra buffer size mode %d", use_buffering, + dbin->extra_buffer_required); if (preroll || use_buffering) { /* takes queue limits, initially we only queue up up to the max bytes limit, @@ -3680,6 +3705,12 @@ decodebin_set_queue_size_full (GstDecodeBin * dbin, GstElement * multiqueue, max_time = seekable ? AUTO_PREROLL_SEEKABLE_SIZE_TIME : AUTO_PREROLL_NOT_SEEKABLE_SIZE_TIME; } + } else if (dbin->extra_buffer_required) { + max_bytes = AUTO_PREROLL_SIZE_BYTES + DEFAULT_EXTRA_SIZE_BUFFERS_BYTES; + max_buffers = AUTO_PREROLL_SIZE_BUFFERS; + if ((max_time = dbin->max_size_time) == 0) + max_time = seekable ? AUTO_PREROLL_SEEKABLE_SIZE_TIME : + AUTO_PREROLL_NOT_SEEKABLE_SIZE_TIME; } else { /* update runtime limits. At runtime, we try to keep the amount of buffers * in the queues as low as possible (but at least 5 buffers). */ @@ -5170,6 +5201,7 @@ gst_decode_bin_change_state (GstElement * element, GstStateChange transition) g_list_free_full (dbin->buffering_status, (GDestroyNotify) gst_message_unref); dbin->buffering_status = NULL; + dbin->extra_buffer_required = FALSE; break; case GST_STATE_CHANGE_READY_TO_NULL: default: -- 2.7.4