1 From 7186918c4d8ecb95f7b669205f7b06c1f462b6b2 Mon Sep 17 00:00:00 2001
2 From: Maemo Multimedia <multimedia@maemo.org>
3 Date: Thu, 22 Jan 2009 09:02:18 +0200
4 Subject: [PATCH] playbasebin: add network queue support, adding nw-queue
8 gst/playback/gstplaybasebin.c | 256 ++++++++++++++++++++++++++++++++---------
9 gst/playback/gstplaybasebin.h | 1 +
10 2 files changed, 205 insertions(+), 52 deletions(-)
12 diff --git a/gst/playback/gstplaybasebin.c b/gst/playback/gstplaybasebin.c
13 index 847e12f..7f81da6 100644
14 --- a/gst/playback/gstplaybasebin.c
15 +++ b/gst/playback/gstplaybasebin.c
18 #include <gst/pbutils/pbutils.h>
20 +#define SCAN_SINKS_FROM_REGISTRY
21 +#define PREROLL_QUEUE_MAX_BUFFERS 5
22 +#define PREROLL_QUEUE_MAX_BYTES (1 * 1024 * 1024)
23 +#define NETWORK_QUEUE_MAX_BUFFERS 100
25 GST_DEBUG_CATEGORY_STATIC (gst_play_base_bin_debug);
26 #define GST_CAT_DEFAULT gst_play_base_bin_debug
28 @@ -59,7 +64,8 @@ enum
31 ARG_SUBTITLE_ENCODING,
32 - ARG_CONNECTION_SPEED
33 + ARG_CONNECTION_SPEED,
37 static void gst_play_base_bin_class_init (GstPlayBaseBinClass * klass);
38 @@ -94,6 +100,8 @@ static void set_active_source (GstPlayBaseBin * play_base_bin,
39 static gboolean probe_triggered (GstPad * pad, GstEvent * event,
41 static void setup_substreams (GstPlayBaseBin * play_base_bin);
42 +static void queue_threshold_reached (GstElement * queue, GstPlayBaseBin
45 static GstPipelineClass *parent_class;
47 @@ -215,6 +223,10 @@ gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
48 "Network connection speed in kbps (0 = unknown)",
49 0, G_MAXUINT, DEFAULT_CONNECTION_SPEED,
50 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
51 + g_object_class_install_property (gobject_klass, ARG_NW_QUEUE,
52 + g_param_spec_boolean ("nw-queue", "Use network queue",
53 + "Use separate queue for network buffering instead of using "
54 + "internal audio/video queues.", FALSE, G_PARAM_READWRITE));
56 GST_DEBUG_CATEGORY_INIT (gst_play_base_bin_debug, "playbasebin", 0,
58 @@ -236,6 +248,7 @@ gst_play_base_bin_init (GstPlayBaseBin * play_base_bin)
59 play_base_bin->suburi = NULL;
60 play_base_bin->need_rebuild = TRUE;
61 play_base_bin->is_stream = FALSE;
62 + play_base_bin->use_nw_queue = FALSE;
63 play_base_bin->source = NULL;
64 play_base_bin->decoders = NULL;
65 play_base_bin->subtitle = NULL;
66 @@ -518,7 +531,6 @@ group_is_muted (GstPlayBaseGroup * group)
68 * Buffer/cache checking.
72 fill_buffer (GstPlayBaseBin * play_base_bin, gint percent)
74 @@ -716,12 +728,18 @@ queue_overrun (GstElement * queue, GstPlayBaseBin * play_base_bin)
76 preroll_remove_overrun (queue, play_base_bin);
78 - group_commit (play_base_bin, FALSE,
79 - GST_OBJECT_PARENT (GST_OBJECT_CAST (queue)) ==
80 - GST_OBJECT_CAST (play_base_bin->subtitle));
81 + // Commit the group only when we are using "stupid" buffering, because when
82 + // using separate network queue element this preroll queue size is much
83 + // smaller, causing premature overrun (decodebin2 is still in the
84 + // pad expose-unlocking loop when that happens)
85 + if (play_base_bin->use_nw_queue == FALSE) {
86 + group_commit (play_base_bin, FALSE,
87 + GST_OBJECT_PARENT (GST_OBJECT_CAST (queue)) ==
88 + GST_OBJECT_CAST (play_base_bin->subtitle));
90 - /* notify end of buffering */
91 - queue_threshold_reached (queue, play_base_bin);
92 + /* notify end of buffering */
93 + queue_threshold_reached (queue, play_base_bin);
97 /* this signal is only added when in streaming mode to catch underruns
98 @@ -832,6 +850,11 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin,
99 "max-size-buffers", 0, "max-size-bytes",
100 2 * 1024 * 1024, "max-size-time", play_base_bin->queue_size, NULL);
102 + } else if (play_base_bin->use_nw_queue) {
103 + g_object_set (G_OBJECT (preroll),
104 + "max-size-buffers", PREROLL_QUEUE_MAX_BUFFERS,
105 + "max-size-bytes", PREROLL_QUEUE_MAX_BYTES,
106 + "max-size-time", play_base_bin->queue_size, NULL);
108 g_object_set (G_OBJECT (preroll),
109 "max-size-buffers", 0, "max-size-bytes",
110 @@ -860,42 +883,45 @@ gen_preroll_element (GstPlayBaseBin * play_base_bin,
111 g_object_set_data (G_OBJECT (preroll), "overrun_signal_id",
112 GINT_TO_POINTER (overrun_sig));
114 - if (play_base_bin->is_stream &&
115 - ((type == GST_STREAM_TYPE_VIDEO &&
116 - group->type[GST_STREAM_TYPE_AUDIO - 1].npads == 0) ||
117 - (type == GST_STREAM_TYPE_AUDIO &&
118 - group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0))) {
122 - /* catch deadlocks when we are network buffering in time but the max-limit
123 - * in bytes is hit. */
124 - g_signal_connect (G_OBJECT (preroll), "overrun",
125 - G_CALLBACK (queue_deadlock_check), play_base_bin);
127 - /* attach pointer to playbasebin */
128 - g_object_set_data (G_OBJECT (preroll), "pbb", play_base_bin);
130 - /* give updates on queue size */
131 - sinkpad = gst_element_get_static_pad (preroll, "sink");
132 - id = gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (check_queue), preroll);
133 - GST_DEBUG_OBJECT (play_base_bin, "Attaching probe to pad %s:%s (%p)",
134 - GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
135 - g_object_set_data (G_OBJECT (preroll), "probe", GINT_TO_POINTER (id));
137 - /* catch eos and flush events so that we can ignore underruns */
138 - id = gst_pad_add_event_probe (sinkpad, G_CALLBACK (check_queue_event),
140 - g_object_set_data (G_OBJECT (preroll), "eos_probe", GINT_TO_POINTER (id));
142 - gst_object_unref (sinkpad);
143 + if (play_base_bin->use_nw_queue == FALSE) {
144 + if (play_base_bin->is_stream &&
145 + ((type == GST_STREAM_TYPE_VIDEO &&
146 + group->type[GST_STREAM_TYPE_AUDIO - 1].npads == 0) ||
147 + (type == GST_STREAM_TYPE_AUDIO &&
148 + group->type[GST_STREAM_TYPE_VIDEO - 1].npads == 0))) {
152 - /* When we connect this queue, it will start running and immediatly
153 - * fire an underrun. */
154 - g_signal_connect (G_OBJECT (preroll), "underrun",
155 - G_CALLBACK (queue_out_of_data), play_base_bin);
156 - /* configure threshold and callbacks */
157 - queue_out_of_data (preroll, play_base_bin);
158 + /* catch deadlocks when we are network buffering in time but the max-limit
159 + * in bytes is hit. */
160 + g_signal_connect (G_OBJECT (preroll), "overrun",
161 + G_CALLBACK (queue_deadlock_check), play_base_bin);
163 + /* attach pointer to playbasebin */
164 + g_object_set_data (G_OBJECT (preroll), "pbb", play_base_bin);
166 + /* give updates on queue size */
167 + sinkpad = gst_element_get_static_pad (preroll, "sink");
168 + id = gst_pad_add_buffer_probe (sinkpad, G_CALLBACK (check_queue),
170 + GST_DEBUG_OBJECT (play_base_bin, "Attaching probe to pad %s:%s (%p)",
171 + GST_DEBUG_PAD_NAME (sinkpad), sinkpad);
172 + g_object_set_data (G_OBJECT (preroll), "probe", GINT_TO_POINTER (id));
174 + /* catch eos and flush events so that we can ignore underruns */
175 + id = gst_pad_add_event_probe (sinkpad, G_CALLBACK (check_queue_event),
177 + g_object_set_data (G_OBJECT (preroll), "eos_probe", GINT_TO_POINTER (id));
179 + gst_object_unref (sinkpad);
181 + /* When we connect this queue, it will start running and immediatly
182 + * fire an underrun. */
183 + g_signal_connect (G_OBJECT (preroll), "underrun",
184 + G_CALLBACK (queue_out_of_data), play_base_bin);
185 + /* configure threshold and callbacks */
186 + queue_out_of_data (preroll, play_base_bin);
190 /* listen for EOS so we can switch groups when one ended. */
191 @@ -1508,10 +1534,7 @@ setup_subtitle (GstPlayBaseBin * play_base_bin, gchar * sub_uri)
195 - if (g_getenv ("USE_DECODEBIN2"))
196 - subdecodebin = gst_element_factory_make ("decodebin2", "subtitle-decoder");
198 - subdecodebin = gst_element_factory_make ("decodebin", "subtitle-decoder");
199 + subdecodebin = gst_element_factory_make ("decodebin2", "subtitle-decoder");
200 g_signal_connect (subdecodebin, "element-added",
201 G_CALLBACK (decodebin_element_added_cb), play_base_bin);
202 g_signal_connect (subdecodebin, "element-removed",
203 @@ -1572,7 +1595,7 @@ array_has_value (const gchar * values[], const gchar * value)
204 /* list of URIs that we consider to be streams and that need buffering.
205 * We have no mechanism yet to figure this out with a query. */
206 static const gchar *stream_uris[] = { "http://", "mms://", "mmsh://",
207 - "mmsu://", "mmst://", "myth://", NULL
208 + "mmsu://", "mmst://", "myth://", "upnpav://", "obex://", "smb://", NULL
211 /* blacklisted URIs, we know they will always fail. */
212 @@ -1974,16 +1997,80 @@ remove_decoders (GstPlayBaseBin * bin)
213 bin->decoders = NULL;
216 +#ifdef SCAN_SINKS_FROM_REGISTRY
218 +/* filter function for sink elements */
220 +gst_play_base_bin_sink_factory_filter (GstPluginFeature * feature,
221 + GstPlayBaseBin * bin)
224 + const gchar *klass;
226 + /* we only care about element factories */
227 + if (!GST_IS_ELEMENT_FACTORY (feature))
230 + klass = gst_element_factory_get_klass (GST_ELEMENT_FACTORY (feature));
232 + if (strstr (klass, "Sink") == NULL) {
236 + /* only select elements with autoplugging rank */
237 + rank = gst_plugin_feature_get_rank (feature);
238 + if (rank < GST_RANK_MARGINAL)
245 +get_supported_sink_caps (GstPlayBaseBin * bin)
247 + GList *sink_factories;
248 + GstCaps *sink_caps = gst_caps_new_empty ();
249 + GstCaps *caps = NULL;
250 + const GList *item, *pad_templates;
251 + GstStaticPadTemplate *templ;
253 + /* filter out the sink factories;
254 + stop decodebin construction when compatible sink is found */
255 + sink_factories = gst_default_registry_feature_filter (
256 + (GstPluginFeatureFilter) gst_play_base_bin_sink_factory_filter,
259 + /* scan sink caps from registry, assumes only 1 pad template per sink */
260 + for (item = sink_factories; item != NULL; item = item->next) {
262 + gst_element_factory_get_static_pad_templates (GST_ELEMENT_FACTORY
264 + templ = pad_templates->data;
265 + /* Get caps from template */
266 + caps = gst_caps_make_writable (gst_static_pad_template_get_caps (templ));
267 + if (!gst_caps_is_any (caps)) {
268 + gst_caps_append (sink_caps, caps);
270 + gst_caps_unref (caps);
274 + gst_plugin_feature_list_free (sink_factories);
275 + GST_DEBUG_OBJECT (bin, "Sink caps from registry: %" GST_PTR_FORMAT,
284 make_decoder (GstPlayBaseBin * play_base_bin)
288 /* now create the decoder element */
289 - if (g_getenv ("USE_DECODEBIN2"))
290 - decoder = gst_element_factory_make ("decodebin2", NULL);
292 - decoder = gst_element_factory_make ("decodebin", NULL);
293 + decoder = gst_element_factory_make ("decodebin2", NULL);
297 @@ -2010,6 +2097,14 @@ make_decoder (GstPlayBaseBin * play_base_bin)
299 play_base_bin->decoders = g_slist_prepend (play_base_bin->decoders, decoder);
301 +#ifdef SCAN_SINKS_FROM_REGISTRY
303 + GstCaps *sink_caps = get_supported_sink_caps (play_base_bin);
304 + g_object_set (decoder, "caps", sink_caps, NULL);
305 + gst_caps_unref (sink_caps);
312 @@ -2021,6 +2116,32 @@ no_decodebin:
316 +/* SOURCE ! NETWORK QUEUE ! DECODEBIN ! SINKS */
318 +add_network_queue (GstPlayBaseBin * play_base_bin, GstElement * decoder)
320 + gboolean ret = FALSE;
321 + GstElement *nw_queue = gst_element_factory_make ("queue2", "nw_queue");
323 + /* Add network queue to bin */
324 + if (nw_queue && gst_bin_add (GST_BIN_CAST (play_base_bin), nw_queue)) {
325 + /* Link network queue */
326 + if (gst_element_link (play_base_bin->source, nw_queue) &&
327 + gst_element_link (nw_queue, decoder)) {
328 + /* Set queue2 properties */
329 + g_object_set (G_OBJECT (nw_queue),
330 + "max-size-buffers", NETWORK_QUEUE_MAX_BUFFERS,
331 + "max-size-bytes", 0,
332 + "max-size-time", (guint64) 0,
333 + "use-buffering", TRUE, "use-rate-estimate", FALSE, NULL);
336 + gst_bin_remove (GST_BIN_CAST (play_base_bin), nw_queue);
343 remove_source (GstPlayBaseBin * bin)
345 @@ -2040,6 +2161,17 @@ remove_source (GstPlayBaseBin * bin)
347 gst_bin_remove (GST_BIN_CAST (bin), source);
350 + if (bin->use_nw_queue) {
351 + if (bin->is_stream) {
352 + GstElement *nw_queue =
353 + gst_bin_get_by_name (GST_BIN_CAST (bin), "nw_queue");
354 + GST_DEBUG_OBJECT (bin, "removing network queue element");
355 + gst_element_set_state (nw_queue, GST_STATE_NULL);
356 + gst_bin_remove (GST_BIN_CAST (bin), nw_queue);
357 + gst_object_unref (nw_queue);
363 @@ -2210,13 +2342,27 @@ setup_source (GstPlayBaseBin * play_base_bin)
364 "Source has dynamic output pads, %d pending", play_base_bin->pending);
367 + gboolean link_ok = FALSE;
369 /* no dynamic source, we can link now */
370 decoder = make_decoder (play_base_bin);
374 - if (!gst_element_link (play_base_bin->source, decoder))
375 + if (play_base_bin->use_nw_queue) {
376 + /* FIXME: network queue isn't added with source having dynamic pads */
377 + if (play_base_bin->is_stream) {
378 + GST_DEBUG_OBJECT (play_base_bin,
379 + "linking source to decoder using network queue");
380 + link_ok = add_network_queue (play_base_bin, decoder);
382 + GST_DEBUG_OBJECT (play_base_bin, "linking source to decoder");
383 + link_ok = gst_element_link (play_base_bin->source, decoder);
386 + link_ok = gst_element_link (play_base_bin->source, decoder);
392 @@ -2631,6 +2777,9 @@ gst_play_base_bin_set_property (GObject * object, guint prop_id,
397 + play_base_bin->use_nw_queue = g_value_get_boolean (value);
400 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
402 @@ -2718,6 +2867,9 @@ gst_play_base_bin_get_property (GObject * object, guint prop_id, GValue * value,
403 g_value_set_string (value, play_base_bin->subencoding);
404 GST_OBJECT_UNLOCK (play_base_bin);
407 + g_value_set_boolean (value, play_base_bin->use_nw_queue);
410 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
412 diff --git a/gst/playback/gstplaybasebin.h b/gst/playback/gstplaybasebin.h
413 index c8c8649..26c9fcd 100644
414 --- a/gst/playback/gstplaybasebin.h
415 +++ b/gst/playback/gstplaybasebin.h
416 @@ -88,6 +88,7 @@ struct _GstPlayBaseBin {
417 gboolean subtitle_done;
418 gboolean need_rebuild;
419 gboolean raw_decoding_mode; /* Use smaller queues when source outputs raw data */
420 + gboolean use_nw_queue;
422 GSList *subtitle_elements; /* subtitle elements that have 'subtitle-encoding' property */
423 gchar *subencoding; /* encoding to propagate to the above subtitle elements */