1 /* GStreamer
2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
3 *
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
8 *
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
13 *
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
18 */
19
20 /**
21 * SECTION:element-uridecodebin
22 * @title: uridecodebin
23 *
24 * Decodes data from a URI into raw media. It selects a source element that can
25 * handle the given #GstURIDecodeBin:uri scheme and connects it to a decodebin.
26 */
27
28 /* FIXME 0.11: suppress warnings for deprecated API such as GValueArray
29 * with newer GLib versions (>= 2.31.0) */
30 #define GLIB_DISABLE_DEPRECATION_WARNINGS
31
32 #ifdef HAVE_CONFIG_H
33 # include "config.h"
34 #endif
35
36 #include <string.h>
37
38 #include <gst/gst.h>
39 #include <gst/gst-i18n-plugin.h>
40 #include <gst/pbutils/missing-plugins.h>
41
42 #include "gstplay-enum.h"
43 #include "gstrawcaps.h"
44 #include "gstplaybackelements.h"
45 #include "gstplaybackutils.h"
46
47 #define GST_TYPE_URI_DECODE_BIN \
48 (gst_uri_decode_bin_get_type())
49 #define GST_URI_DECODE_BIN(obj) \
50 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_URI_DECODE_BIN,GstURIDecodeBin))
51 #define GST_URI_DECODE_BIN_CLASS(klass) \
52 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_URI_DECODE_BIN,GstURIDecodeBinClass))
53 #define GST_IS_URI_DECODE_BIN(obj) \
54 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_URI_DECODE_BIN))
55 #define GST_IS_URI_DECODE_BIN_CLASS(klass) \
56 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_URI_DECODE_BIN))
57 #define GST_URI_DECODE_BIN_CAST(obj) ((GstURIDecodeBin *) (obj))
58
59 typedef struct _GstURIDecodeBin GstURIDecodeBin;
60 typedef struct _GstURIDecodeBinClass GstURIDecodeBinClass;
61
62 #define GST_URI_DECODE_BIN_LOCK(dec) (g_mutex_lock(&((GstURIDecodeBin*)(dec))->lock))
63 #define GST_URI_DECODE_BIN_UNLOCK(dec) (g_mutex_unlock(&((GstURIDecodeBin*)(dec))->lock))
64
65 typedef struct _GstURIDecodeBinStream
66 {
67 gulong probe_id;
68 guint bitrate;
69 } GstURIDecodeBinStream;
70
71 /**
72 * GstURIDecodeBin
73 *
74 * uridecodebin element struct
75 */
76 struct _GstURIDecodeBin
77 {
78 GstBin parent_instance;
79
80 GMutex lock; /* lock for constructing */
81
82 GMutex factories_lock;
83 guint32 factories_cookie;
84 GList *factories; /* factories we can use for selecting elements */
85
86 gchar *uri;
87 guint64 connection_speed;
88 GstCaps *caps;
89 gchar *encoding;
90
91 gboolean is_stream;
92 gboolean is_adaptive;
93 gboolean need_queue;
94 guint64 buffer_duration; /* When buffering, buffer duration (ns) */
95 guint buffer_size; /* When buffering, buffer size (bytes) */
96 gboolean download;
97 gboolean use_buffering;
98 gboolean force_sw_decoders;
99
100 GstElement *source;
101 GstElement *queue;
102 GstElement *typefind;
103 guint have_type_id; /* have-type signal id from typefind */
104 /* without holding ref */
105 GSList *decodebins;
106 /* Holding strong reference to decodebin */
107 GSList *pending_decodebins;
108 GHashTable *streams;
109 guint numpads;
110
111 /* for dynamic sources */
112 guint src_np_sig_id; /* new-pad signal id */
113 guint src_nmp_sig_id; /* no-more-pads signal id */
114 gint pending;
115 GList *missing_plugin_errors;
116
117 gboolean async_pending; /* async-start has been emitted */
118
119 gboolean expose_allstreams; /* Whether to expose unknown type streams or not */
120
121 guint64 ring_buffer_max_size; /* 0 means disabled */
122 #ifdef OHOS_EXT_FUNC
123 //ohos.ext.func.0012
124 gint low_percent;
125 gint high_percent;
126 #endif
127 };
128
129 struct _GstURIDecodeBinClass
130 {
131 GstBinClass parent_class;
132
133 /* signal fired when we found a pad that we cannot decode */
134 void (*unknown_type) (GstElement * element, GstPad * pad, GstCaps * caps);
135
136 /* signal fired to know if we continue trying to decode the given caps */
137 gboolean (*autoplug_continue) (GstElement * element, GstPad * pad,
138 GstCaps * caps);
139 /* signal fired to get a list of factories to try to autoplug */
140 GValueArray *(*autoplug_factories) (GstElement * element, GstPad * pad,
141 GstCaps * caps);
142 /* signal fired to sort the factories */
143 GValueArray *(*autoplug_sort) (GstElement * element, GstPad * pad,
144 GstCaps * caps, GValueArray * factories);
145 /* signal fired to select from the proposed list of factories */
146 GstAutoplugSelectResult (*autoplug_select) (GstElement * element,
147 GstPad * pad, GstCaps * caps, GstElementFactory * factory);
148 /* signal fired when a autoplugged element that is not linked downstream
149 * or exposed wants to query something */
150 gboolean (*autoplug_query) (GstElement * element, GstPad * pad,
151 GstQuery * query);
152
153 /* emitted when all data is decoded */
154 void (*drained) (GstElement * element);
155 };
156
157 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src_%u",
158 GST_PAD_SRC,
159 GST_PAD_SOMETIMES,
160 GST_STATIC_CAPS_ANY);
161
162 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
163
164 GST_DEBUG_CATEGORY_STATIC (gst_uri_decode_bin_debug);
165 #define GST_CAT_DEFAULT gst_uri_decode_bin_debug
166
167 /* signals */
168 enum
169 {
170 SIGNAL_UNKNOWN_TYPE,
171 SIGNAL_AUTOPLUG_CONTINUE,
172 SIGNAL_AUTOPLUG_FACTORIES,
173 SIGNAL_AUTOPLUG_SELECT,
174 SIGNAL_AUTOPLUG_SORT,
175 SIGNAL_AUTOPLUG_QUERY,
176 SIGNAL_DRAINED,
177 SIGNAL_SOURCE_SETUP,
178 #ifdef OHOS_EXT_FUNC
179 // ohos.ext.func.0028
180 SIGNAL_BITRATE_PARSE_COMPLETE,
181 #endif
182 LAST_SIGNAL
183 };
184
185 /* properties */
186 #define DEFAULT_PROP_URI NULL
187 #define DEFAULT_PROP_SOURCE NULL
188 #define DEFAULT_CONNECTION_SPEED 0
189 #define DEFAULT_CAPS (gst_static_caps_get (&default_raw_caps))
190 #define DEFAULT_SUBTITLE_ENCODING NULL
191 #ifdef OHOS_EXT_FUNC
192 // ohos.ext.func.0012
193 #define DEFAULT_BUFFER_DURATION 0
194 #else
195 #define DEFAULT_BUFFER_DURATION -1
196 #endif
197 #define DEFAULT_BUFFER_SIZE -1
198 #define DEFAULT_DOWNLOAD FALSE
199 #define DEFAULT_USE_BUFFERING FALSE
200 #define DEFAULT_FORCE_SW_DECODERS FALSE
201 #define DEFAULT_EXPOSE_ALL_STREAMS TRUE
202 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
203
204 #ifdef OHOS_EXT_FUNC
205 // ohos.ext.func.0012
206 #define DEFAULT_LOW_PERCENT 10
207 #define DEFAULT_HIGH_PERCENT 99
208 #define DEFAULT_TIMEOUT 15
209 #endif
210
211 enum
212 {
213 PROP_0,
214 PROP_URI,
215 PROP_SOURCE,
216 PROP_CONNECTION_SPEED,
217 PROP_CAPS,
218 PROP_SUBTITLE_ENCODING,
219 PROP_BUFFER_SIZE,
220 PROP_BUFFER_DURATION,
221 PROP_DOWNLOAD,
222 PROP_USE_BUFFERING,
223 PROP_FORCE_SW_DECODERS,
224 PROP_EXPOSE_ALL_STREAMS,
225 #ifdef OHOS_EXT_FUNC
226 // ohos.ext.func.0012
227 PROP_LOW_PERCENT,
228 PROP_HIGH_PERCENT,
229 PROP_STATE_CHANGE,
230 PROP_EXIT_BLOCK,
231 PROP_TIMEOUT,
232 #endif
233 PROP_RING_BUFFER_MAX_SIZE
234 };
235
236 static guint gst_uri_decode_bin_signals[LAST_SIGNAL] = { 0 };
237
238 GType gst_uri_decode_bin_get_type (void);
239 #define gst_uri_decode_bin_parent_class parent_class
240 G_DEFINE_TYPE (GstURIDecodeBin, gst_uri_decode_bin, GST_TYPE_BIN);
241
242 #define _do_init \
243 GST_DEBUG_CATEGORY_INIT (gst_uri_decode_bin_debug, "uridecodebin", 0, "URI decoder element"); \
244 playback_element_init (plugin);
245 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (uridecodebin, "uridecodebin",
246 GST_RANK_NONE, GST_TYPE_URI_DECODE_BIN, _do_init);
247
248 static void remove_decoders (GstURIDecodeBin * bin, gboolean force);
249 static void gst_uri_decode_bin_set_property (GObject * object, guint prop_id,
250 const GValue * value, GParamSpec * pspec);
251 static void gst_uri_decode_bin_get_property (GObject * object, guint prop_id,
252 GValue * value, GParamSpec * pspec);
253 static void gst_uri_decode_bin_finalize (GObject * obj);
254
255 static void handle_message (GstBin * bin, GstMessage * msg);
256
257 static gboolean gst_uri_decode_bin_query (GstElement * element,
258 GstQuery * query);
259 static GstStateChangeReturn gst_uri_decode_bin_change_state (GstElement *
260 element, GstStateChange transition);
261
262 static gboolean
_gst_boolean_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)263 _gst_boolean_accumulator (GSignalInvocationHint * ihint,
264 GValue * return_accu, const GValue * handler_return, gpointer dummy)
265 {
266 gboolean myboolean;
267
268 myboolean = g_value_get_boolean (handler_return);
269 g_value_set_boolean (return_accu, myboolean);
270
271 /* stop emission if FALSE */
272 return myboolean;
273 }
274
275 static gboolean
_gst_boolean_or_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)276 _gst_boolean_or_accumulator (GSignalInvocationHint * ihint,
277 GValue * return_accu, const GValue * handler_return, gpointer dummy)
278 {
279 gboolean myboolean;
280 gboolean retboolean;
281
282 myboolean = g_value_get_boolean (handler_return);
283 retboolean = g_value_get_boolean (return_accu);
284
285 g_value_set_boolean (return_accu, myboolean || retboolean);
286
287 return TRUE;
288 }
289
290 static gboolean
_gst_array_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)291 _gst_array_accumulator (GSignalInvocationHint * ihint,
292 GValue * return_accu, const GValue * handler_return, gpointer dummy)
293 {
294 gpointer array;
295
296 array = g_value_get_boxed (handler_return);
297 g_value_set_boxed (return_accu, array);
298
299 return FALSE;
300 }
301
302 static gboolean
_gst_select_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)303 _gst_select_accumulator (GSignalInvocationHint * ihint,
304 GValue * return_accu, const GValue * handler_return, gpointer dummy)
305 {
306 GstAutoplugSelectResult res;
307
308 res = g_value_get_enum (handler_return);
309 g_value_set_enum (return_accu, res);
310
311 /* Call the next handler in the chain (if any) when the current callback
312 * returns TRY. This makes it possible to register separate autoplug-select
313 * handlers that implement different TRY/EXPOSE/SKIP strategies.
314 */
315 if (res == GST_AUTOPLUG_SELECT_TRY)
316 return TRUE;
317
318 return FALSE;
319 }
320
321 static gboolean
_gst_array_hasvalue_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)322 _gst_array_hasvalue_accumulator (GSignalInvocationHint * ihint,
323 GValue * return_accu, const GValue * handler_return, gpointer dummy)
324 {
325 gpointer array;
326
327 array = g_value_get_boxed (handler_return);
328 g_value_set_boxed (return_accu, array);
329
330 if (array != NULL)
331 return FALSE;
332
333 return TRUE;
334 }
335
336 static gboolean
gst_uri_decode_bin_autoplug_continue(GstElement * element,GstPad * pad,GstCaps * caps)337 gst_uri_decode_bin_autoplug_continue (GstElement * element, GstPad * pad,
338 GstCaps * caps)
339 {
340 /* by default we always continue */
341 return TRUE;
342 }
343
344 /* Must be called with factories lock! */
345 static void
gst_uri_decode_bin_update_factories_list(GstURIDecodeBin * dec)346 gst_uri_decode_bin_update_factories_list (GstURIDecodeBin * dec)
347 {
348 guint32 cookie;
349 GList *factories, *tmp;
350
351 cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
352 if (!dec->factories || dec->factories_cookie != cookie) {
353 if (dec->factories)
354 gst_plugin_feature_list_free (dec->factories);
355 factories =
356 gst_element_factory_list_get_elements
357 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
358
359 if (dec->force_sw_decoders) {
360 /* filter out Hardware class elements */
361 dec->factories = NULL;
362 for (tmp = factories; tmp; tmp = g_list_next (tmp)) {
363 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
364 if (!gst_element_factory_list_is_type (factory,
365 GST_ELEMENT_FACTORY_TYPE_HARDWARE)) {
366 dec->factories = g_list_prepend (dec->factories, factory);
367 } else {
368 gst_object_unref (factory);
369 }
370 }
371 g_list_free (factories);
372 } else {
373 dec->factories = factories;
374 }
375
376 dec->factories =
377 g_list_sort (dec->factories, gst_playback_utils_compare_factories_func);
378 dec->factories_cookie = cookie;
379 }
380 }
381
382 static GValueArray *
gst_uri_decode_bin_autoplug_factories(GstElement * element,GstPad * pad,GstCaps * caps)383 gst_uri_decode_bin_autoplug_factories (GstElement * element, GstPad * pad,
384 GstCaps * caps)
385 {
386 GList *list, *tmp;
387 GValueArray *result;
388 GstURIDecodeBin *dec = GST_URI_DECODE_BIN_CAST (element);
389
390 GST_DEBUG_OBJECT (element, "finding factories");
391
392 /* return all compatible factories for caps */
393 g_mutex_lock (&dec->factories_lock);
394 gst_uri_decode_bin_update_factories_list (dec);
395 list =
396 gst_element_factory_list_filter (dec->factories, caps, GST_PAD_SINK,
397 gst_caps_is_fixed (caps));
398 g_mutex_unlock (&dec->factories_lock);
399
400 result = g_value_array_new (g_list_length (list));
401 for (tmp = list; tmp; tmp = tmp->next) {
402 GstElementFactory *factory = GST_ELEMENT_FACTORY_CAST (tmp->data);
403 GValue val = { 0, };
404
405 g_value_init (&val, G_TYPE_OBJECT);
406 g_value_set_object (&val, factory);
407 g_value_array_append (result, &val);
408 g_value_unset (&val);
409 }
410 gst_plugin_feature_list_free (list);
411
412 GST_DEBUG_OBJECT (element, "autoplug-factories returns %p", result);
413
414 return result;
415 }
416
417 static GValueArray *
gst_uri_decode_bin_autoplug_sort(GstElement * element,GstPad * pad,GstCaps * caps,GValueArray * factories)418 gst_uri_decode_bin_autoplug_sort (GstElement * element, GstPad * pad,
419 GstCaps * caps, GValueArray * factories)
420 {
421 return NULL;
422 }
423
424 static GstAutoplugSelectResult
gst_uri_decode_bin_autoplug_select(GstElement * element,GstPad * pad,GstCaps * caps,GstElementFactory * factory)425 gst_uri_decode_bin_autoplug_select (GstElement * element, GstPad * pad,
426 GstCaps * caps, GstElementFactory * factory)
427 {
428 GST_DEBUG_OBJECT (element, "default autoplug-select returns TRY");
429
430 /* Try factory. */
431 return GST_AUTOPLUG_SELECT_TRY;
432 }
433
434 static gboolean
gst_uri_decode_bin_autoplug_query(GstElement * element,GstPad * pad,GstQuery * query)435 gst_uri_decode_bin_autoplug_query (GstElement * element, GstPad * pad,
436 GstQuery * query)
437 {
438 /* No query handled here */
439 return FALSE;
440 }
441
442 static void
gst_uri_decode_bin_class_init(GstURIDecodeBinClass * klass)443 gst_uri_decode_bin_class_init (GstURIDecodeBinClass * klass)
444 {
445 GObjectClass *gobject_class;
446 GstElementClass *gstelement_class;
447 GstBinClass *gstbin_class;
448
449 gobject_class = G_OBJECT_CLASS (klass);
450 gstelement_class = GST_ELEMENT_CLASS (klass);
451 gstbin_class = GST_BIN_CLASS (klass);
452
453 gobject_class->set_property = gst_uri_decode_bin_set_property;
454 gobject_class->get_property = gst_uri_decode_bin_get_property;
455 gobject_class->finalize = gst_uri_decode_bin_finalize;
456
457 g_object_class_install_property (gobject_class, PROP_URI,
458 g_param_spec_string ("uri", "URI", "URI to decode",
459 DEFAULT_PROP_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
460
461 g_object_class_install_property (gobject_class, PROP_SOURCE,
462 g_param_spec_object ("source", "Source", "Source object used",
463 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
464
465 g_object_class_install_property (gobject_class, PROP_CONNECTION_SPEED,
466 g_param_spec_uint64 ("connection-speed", "Connection Speed",
467 "Network connection speed in kbps (0 = unknown)",
468 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
469 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
470
471 g_object_class_install_property (gobject_class, PROP_CAPS,
472 g_param_spec_boxed ("caps", "Caps",
473 "The caps on which to stop decoding. (NULL = default)",
474 GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
475
476 g_object_class_install_property (gobject_class, PROP_SUBTITLE_ENCODING,
477 g_param_spec_string ("subtitle-encoding", "subtitle encoding",
478 "Encoding to assume if input subtitles are not in UTF-8 encoding. "
479 "If not set, the GST_SUBTITLE_ENCODING environment variable will "
480 "be checked for an encoding to use. If that is not set either, "
481 "ISO-8859-15 will be assumed.", NULL,
482 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
483
484 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
485 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
486 "Buffer size when buffering streams (-1 default value)",
487 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
488 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
489 #ifdef OHOS_EXT_FUNC
490 // ohos.ext.func.0012
491 g_object_class_install_property (gobject_class, PROP_BUFFER_DURATION,
492 g_param_spec_uint64 ("buffer-duration", "Buffer duration (ns)",
493 "Buffer duration when buffering streams (-1 default value)",
494 0, G_MAXUINT64 / 1000, DEFAULT_BUFFER_DURATION,
495 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
496
497 g_object_class_install_property (gobject_class, PROP_STATE_CHANGE,
498 g_param_spec_int ("state-change", "state-change from adaptive-demux",
499 "state-change from adaptive-demux", 0, (gint) (G_MAXINT32), 0,
500 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
501
502 g_object_class_install_property (gobject_class, PROP_EXIT_BLOCK,
503 g_param_spec_int ("exit-block", "EXIT BLOCK",
504 "souphttpsrc exit block", 0, (gint) (G_MAXINT32), 0,
505 G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS));
506
507 /*
508 * GstURIDecodeBin:low-percent
509 * Low threshold percent for buffering to start.
510 */
511 g_object_class_install_property (gobject_class, PROP_LOW_PERCENT,
512 g_param_spec_int ("low-percent", "Low percent",
513 "Low threshold for buffering to start", 0, 100,
514 DEFAULT_LOW_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
515 /*
516 * GstURIDecodeBin:high-percent
517 * High threshold percent for buffering to finish.
518 */
519 g_object_class_install_property (gobject_class, PROP_HIGH_PERCENT,
520 g_param_spec_int ("high-percent", "High percent",
521 "High threshold for buffering to finish", 0, 100,
522 DEFAULT_HIGH_PERCENT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
523
524 g_object_class_install_property (gobject_class, PROP_TIMEOUT,
525 g_param_spec_uint ("timeout", "timeout",
526 "Value in seconds to timeout a blocking I/O (0 = No timeout).", 0,
527 3600, DEFAULT_TIMEOUT, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
528 #else
529 g_object_class_install_property (gobject_class, PROP_BUFFER_DURATION,
530 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
531 "Buffer duration when buffering streams (-1 default value)",
532 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
533 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
534 #endif
535
536 /**
537 * GstURIDecodeBin::download:
538 *
539 * For certain media type, enable download buffering.
540 */
541 g_object_class_install_property (gobject_class, PROP_DOWNLOAD,
542 g_param_spec_boolean ("download", "Download",
543 "Attempt download buffering when buffering network streams",
544 DEFAULT_DOWNLOAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
545 /**
546 * GstURIDecodeBin::use-buffering:
547 *
548 * Emit BUFFERING messages based on low-/high-percent thresholds of the
549 * demuxed or parsed data.
550 * When download buffering is activated and used for the current media
551 * type, this property does nothing. Otherwise perform buffering on the
552 * demuxed or parsed media.
553 */
554 g_object_class_install_property (gobject_class, PROP_USE_BUFFERING,
555 g_param_spec_boolean ("use-buffering", "Use Buffering",
556 "Perform buffering on demuxed/parsed media",
557 DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
558
559 /**
560 * GstURIDecodeBin::force-sw-decoders:
561 *
562 * While auto-plugging, if set to %TRUE, those decoders within
563 * "Hardware" klass will be ignored. Otherwise they will be tried.
564 *
565 * Since: 1.18
566 */
567 g_object_class_install_property (gobject_class, PROP_FORCE_SW_DECODERS,
568 g_param_spec_boolean ("force-sw-decoders", "Software Docoders Only",
569 "Use only sofware decoders to process streams",
570 DEFAULT_FORCE_SW_DECODERS,
571 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
572
573 /**
574 * GstURIDecodeBin::expose-all-streams:
575 *
576 * Expose streams of unknown type.
577 *
578 * If set to %FALSE, then only the streams that can be decoded to the final
579 * caps (see 'caps' property) will have a pad exposed. Streams that do not
580 * match those caps but could have been decoded will not have decoder plugged
581 * in internally and will not have a pad exposed.
582 */
583 g_object_class_install_property (gobject_class, PROP_EXPOSE_ALL_STREAMS,
584 g_param_spec_boolean ("expose-all-streams", "Expose All Streams",
585 "Expose all streams, including those of unknown type or that don't match the 'caps' property",
586 DEFAULT_EXPOSE_ALL_STREAMS,
587 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
588
589 /**
590 * GstURIDecodeBin::ring-buffer-max-size:
591 *
592 * The maximum size of the ring buffer in kilobytes. If set to 0, the ring
593 * buffer is disabled. Default is 0.
594 */
595 g_object_class_install_property (gobject_class, PROP_RING_BUFFER_MAX_SIZE,
596 g_param_spec_uint64 ("ring-buffer-max-size",
597 "Max. ring buffer size (bytes)",
598 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
599 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
600 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
601
602 /**
603 * GstURIDecodeBin::unknown-type:
604 * @bin: The uridecodebin.
605 * @pad: the new pad containing caps that cannot be resolved to a 'final'.
606 * stream type.
607 * @caps: the #GstCaps of the pad that cannot be resolved.
608 *
609 * This signal is emitted when a pad for which there is no further possible
610 * decoding is added to the uridecodebin.
611 */
612 gst_uri_decode_bin_signals[SIGNAL_UNKNOWN_TYPE] =
613 g_signal_new ("unknown-type", G_TYPE_FROM_CLASS (klass),
614 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, unknown_type),
615 NULL, NULL, NULL, G_TYPE_NONE, 2, GST_TYPE_PAD, GST_TYPE_CAPS);
616
617 /**
618 * GstURIDecodeBin::autoplug-continue:
619 * @bin: The uridecodebin.
620 * @pad: The #GstPad.
621 * @caps: The #GstCaps found.
622 *
623 * This signal is emitted whenever uridecodebin finds a new stream. It is
624 * emitted before looking for any elements that can handle that stream.
625 *
626 * > Invocation of signal handlers stops after the first signal handler
627 * > returns %FALSE. Signal handlers are invoked in the order they were
628 * > connected in.
629 *
630 * Returns: %TRUE if you wish uridecodebin to look for elements that can
631 * handle the given @caps. If %FALSE, those caps will be considered as
632 * final and the pad will be exposed as such (see 'pad-added' signal of
633 * #GstElement).
634 */
635 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE] =
636 g_signal_new ("autoplug-continue", G_TYPE_FROM_CLASS (klass),
637 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass,
638 autoplug_continue), _gst_boolean_accumulator, NULL,
639 NULL, G_TYPE_BOOLEAN, 2, GST_TYPE_PAD, GST_TYPE_CAPS);
640
641 /**
642 * GstURIDecodeBin::autoplug-factories:
643 * @bin: The uridecodebin.
644 * @pad: The #GstPad.
645 * @caps: The #GstCaps found.
646 *
647 * This function is emitted when an array of possible factories for @caps on
648 * @pad is needed. Uridecodebin will by default return an array with all
649 * compatible factories, sorted by rank.
650 *
651 * If this function returns NULL, @pad will be exposed as a final caps.
652 *
653 * If this function returns an empty array, the pad will be considered as
654 * having an unhandled type media type.
655 *
656 * > Only the signal handler that is connected first will ever by invoked.
657 * > Don't connect signal handlers with the #G_CONNECT_AFTER flag to this
658 * > signal, they will never be invoked!
659 *
660 * Returns: a #GValueArray* with a list of factories to try. The factories are
661 * by default tried in the returned order or based on the index returned by
662 * "autoplug-select".
663 */
664 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES] =
665 g_signal_new ("autoplug-factories", G_TYPE_FROM_CLASS (klass),
666 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass,
667 autoplug_factories), _gst_array_accumulator, NULL,
668 NULL, G_TYPE_VALUE_ARRAY, 2, GST_TYPE_PAD, GST_TYPE_CAPS);
669
670 /**
671 * GstURIDecodeBin::autoplug-sort:
672 * @bin: The uridecodebin.
673 * @pad: The #GstPad.
674 * @caps: The #GstCaps.
675 * @factories: A #GValueArray of possible #GstElementFactory to use.
676 *
677 * Once decodebin has found the possible #GstElementFactory objects to try
678 * for @caps on @pad, this signal is emitted. The purpose of the signal is for
679 * the application to perform additional sorting or filtering on the element
680 * factory array.
681 *
682 * The callee should copy and modify @factories or return %NULL if the
683 * order should not change.
684 *
685 * > Invocation of signal handlers stops after one signal handler has
686 * > returned something else than %NULL. Signal handlers are invoked in
687 * > the order they were connected in.
688 * > Don't connect signal handlers with the #G_CONNECT_AFTER flag to this
689 * > signal, they will never be invoked!
690 *
691 * Returns: A new sorted array of #GstElementFactory objects.
692 */
693 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SORT] =
694 g_signal_new ("autoplug-sort", G_TYPE_FROM_CLASS (klass),
695 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, autoplug_sort),
696 _gst_array_hasvalue_accumulator, NULL,
697 NULL, G_TYPE_VALUE_ARRAY, 3, GST_TYPE_PAD, GST_TYPE_CAPS,
698 G_TYPE_VALUE_ARRAY | G_SIGNAL_TYPE_STATIC_SCOPE);
699
700 /**
701 * GstURIDecodeBin::autoplug-select:
702 * @bin: The uridecodebin.
703 * @pad: The #GstPad.
704 * @caps: The #GstCaps.
705 * @factory: A #GstElementFactory to use.
706 *
707 * This signal is emitted once uridecodebin has found all the possible
708 * #GstElementFactory that can be used to handle the given @caps. For each of
709 * those factories, this signal is emitted.
710 *
711 * The signal handler should return a #GstAutoplugSelectResult enum
712 * value indicating what decodebin should do next.
713 *
714 * A value of #GstAutoplugSelectResult::try will try to autoplug an element from
715 * @factory.
716 *
717 * A value of #GstAutoplugSelectResult::expose will expose @pad without plugging
718 * any element to it.
719 *
720 * A value of #GstAutoplugSelectResult::skip will skip @factory and move to the
721 * next factory.
722 *
723 * > The signal handler will not be invoked if any of the previously
724 * > registered signal handlers (if any) return a value other than
725 * > GST_AUTOPLUG_SELECT_TRY. Which also means that if you return
726 * > GST_AUTOPLUG_SELECT_TRY from one signal handler, handlers that get
727 * > registered next (again, if any) can override that decision.
728 *
729 * Returns: a #GstAutoplugSelectResult that indicates the required
730 * operation. The default handler will always return
731 * #GstAutoplugSelectResult::try.
732 */
733 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT] =
734 g_signal_new ("autoplug-select", G_TYPE_FROM_CLASS (klass),
735 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass,
736 autoplug_select), _gst_select_accumulator, NULL,
737 NULL, GST_TYPE_AUTOPLUG_SELECT_RESULT, 3, GST_TYPE_PAD, GST_TYPE_CAPS,
738 GST_TYPE_ELEMENT_FACTORY);
739
740 /**
741 * GstDecodeBin::autoplug-query:
742 * @bin: The decodebin.
743 * @child: The child element doing the query
744 * @pad: The #GstPad.
745 * @query: The #GstQuery.
746 *
747 * This signal is emitted whenever an autoplugged element that is
748 * not linked downstream yet and not exposed does a query. It can
749 * be used to tell the element about the downstream supported caps
750 * for example.
751 *
752 * Returns: %TRUE if the query was handled, %FALSE otherwise.
753 */
754 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_QUERY] =
755 g_signal_new ("autoplug-query", G_TYPE_FROM_CLASS (klass),
756 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBinClass, autoplug_query),
757 _gst_boolean_or_accumulator, NULL, NULL, G_TYPE_BOOLEAN, 3, GST_TYPE_PAD,
758 GST_TYPE_ELEMENT, GST_TYPE_QUERY | G_SIGNAL_TYPE_STATIC_SCOPE);
759
760 /**
761 * GstURIDecodeBin::drained:
762 *
763 * This signal is emitted when the data for the current uri is played.
764 */
765 gst_uri_decode_bin_signals[SIGNAL_DRAINED] =
766 g_signal_new ("drained", G_TYPE_FROM_CLASS (klass),
767 G_SIGNAL_RUN_LAST,
768 G_STRUCT_OFFSET (GstURIDecodeBinClass, drained), NULL, NULL, NULL,
769 G_TYPE_NONE, 0, G_TYPE_NONE);
770
771 /**
772 * GstURIDecodeBin::source-setup:
773 * @bin: the uridecodebin.
774 * @source: source element
775 *
776 * This signal is emitted after the source element has been created, so
777 * it can be configured by setting additional properties (e.g. set a
778 * proxy server for an http source, or set the device and read speed for
779 * an audio cd source). This is functionally equivalent to connecting to
780 * the notify::source signal, but more convenient.
781 */
782 gst_uri_decode_bin_signals[SIGNAL_SOURCE_SETUP] =
783 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
784 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
785
786 #ifdef OHOS_EXT_FUNC
787 // ohos.ext.func.0028
788 gst_uri_decode_bin_signals[SIGNAL_BITRATE_PARSE_COMPLETE] =
789 g_signal_new("bitrate-parse-complete",
790 G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
791 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE, 2, G_TYPE_POINTER, G_TYPE_UINT);
792 #endif
793
794 gst_element_class_add_static_pad_template (gstelement_class, &srctemplate);
795 gst_element_class_set_static_metadata (gstelement_class,
796 "URI Decoder", "Generic/Bin/Decoder",
797 "Autoplug and decode an URI to raw media",
798 "Wim Taymans <wim.taymans@gmail.com>");
799
800 gstelement_class->query = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_query);
801 gstelement_class->change_state =
802 GST_DEBUG_FUNCPTR (gst_uri_decode_bin_change_state);
803
804 gstbin_class->handle_message = GST_DEBUG_FUNCPTR (handle_message);
805
806 klass->autoplug_continue =
807 GST_DEBUG_FUNCPTR (gst_uri_decode_bin_autoplug_continue);
808 klass->autoplug_factories =
809 GST_DEBUG_FUNCPTR (gst_uri_decode_bin_autoplug_factories);
810 klass->autoplug_sort = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_autoplug_sort);
811 klass->autoplug_select =
812 GST_DEBUG_FUNCPTR (gst_uri_decode_bin_autoplug_select);
813 klass->autoplug_query = GST_DEBUG_FUNCPTR (gst_uri_decode_bin_autoplug_query);
814 }
815
816 static void
gst_uri_decode_bin_init(GstURIDecodeBin * dec)817 gst_uri_decode_bin_init (GstURIDecodeBin * dec)
818 {
819 /* first filter out the interesting element factories */
820 g_mutex_init (&dec->factories_lock);
821
822 g_mutex_init (&dec->lock);
823
824 dec->uri = g_strdup (DEFAULT_PROP_URI);
825 dec->connection_speed = DEFAULT_CONNECTION_SPEED;
826 dec->caps = DEFAULT_CAPS;
827 dec->encoding = g_strdup (DEFAULT_SUBTITLE_ENCODING);
828
829 dec->buffer_duration = DEFAULT_BUFFER_DURATION;
830 dec->buffer_size = DEFAULT_BUFFER_SIZE;
831 dec->download = DEFAULT_DOWNLOAD;
832 dec->use_buffering = DEFAULT_USE_BUFFERING;
833 dec->force_sw_decoders = DEFAULT_FORCE_SW_DECODERS;
834 dec->expose_allstreams = DEFAULT_EXPOSE_ALL_STREAMS;
835 dec->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
836
837 #ifdef OHOS_EXT_FUNC
838 // ohos.ext.func.0012
839 dec->low_percent = DEFAULT_LOW_PERCENT;
840 dec->high_percent = DEFAULT_HIGH_PERCENT;
841 #endif
842
843 GST_OBJECT_FLAG_SET (dec, GST_ELEMENT_FLAG_SOURCE);
844 gst_bin_set_suppressed_flags (GST_BIN (dec),
845 GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
846 }
847
848 static void
gst_uri_decode_bin_finalize(GObject * obj)849 gst_uri_decode_bin_finalize (GObject * obj)
850 {
851 GstURIDecodeBin *dec = GST_URI_DECODE_BIN (obj);
852
853 remove_decoders (dec, TRUE);
854 g_mutex_clear (&dec->lock);
855 g_mutex_clear (&dec->factories_lock);
856 g_free (dec->uri);
857 g_free (dec->encoding);
858 if (dec->factories)
859 gst_plugin_feature_list_free (dec->factories);
860 if (dec->caps)
861 gst_caps_unref (dec->caps);
862
863 G_OBJECT_CLASS (parent_class)->finalize (obj);
864 }
865
866 static void
gst_uri_decode_bin_set_encoding(GstURIDecodeBin * dec,const gchar * encoding)867 gst_uri_decode_bin_set_encoding (GstURIDecodeBin * dec, const gchar * encoding)
868 {
869 GSList *walk;
870
871 GST_URI_DECODE_BIN_LOCK (dec);
872
873 /* set property first */
874 GST_OBJECT_LOCK (dec);
875 g_free (dec->encoding);
876 dec->encoding = g_strdup (encoding);
877 GST_OBJECT_UNLOCK (dec);
878
879 /* set the property on all decodebins now */
880 for (walk = dec->decodebins; walk; walk = g_slist_next (walk)) {
881 GObject *decodebin = G_OBJECT (walk->data);
882
883 g_object_set (decodebin, "subtitle-encoding", encoding, NULL);
884 }
885 GST_URI_DECODE_BIN_UNLOCK (dec);
886 }
887
888 #ifdef OHOS_EXT_FUNC
889 // ohos.ext.func.0012
890 static void
set_property_to_decodebin(GstURIDecodeBin * dec,guint property_id,const void * property_value)891 set_property_to_decodebin (GstURIDecodeBin *dec, guint property_id, const void *property_value)
892 {
893 if (dec->decodebins == NULL) {
894 return;
895 }
896
897 GSList *walk = NULL;
898 for (walk = dec->decodebins; walk; walk = g_slist_next (walk)) {
899 if (walk->data == NULL) {
900 continue;
901 }
902 GObject *decodebin = G_OBJECT (walk->data);
903
904 if (property_id == PROP_TIMEOUT) {
905 const guint *timeout = (const guint *) property_value;
906 g_object_set (decodebin, "timeout", *timeout, NULL);
907 } else if (property_id == PROP_STATE_CHANGE) {
908 const gint *state = (const gint *) property_value;
909 g_object_set (decodebin, "state-change", *state, NULL);
910 } else if (property_id == PROP_EXIT_BLOCK) {
911 const gint *exit_block = (const gint *) property_value;
912 g_object_set (decodebin, "exit-block", *exit_block, NULL);
913 } else if (property_id == PROP_CONNECTION_SPEED) {
914 const guint64 *con_speed = (const guint64 *) property_value;
915 g_object_set (decodebin, "connection-speed", *con_speed, NULL);
916 }
917 }
918 }
919 #endif
920
921 static void
gst_uri_decode_bin_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)922 gst_uri_decode_bin_set_property (GObject * object, guint prop_id,
923 const GValue * value, GParamSpec * pspec)
924 {
925 GstURIDecodeBin *dec = GST_URI_DECODE_BIN (object);
926
927 switch (prop_id) {
928 case PROP_URI:
929 GST_OBJECT_LOCK (dec);
930 g_free (dec->uri);
931 dec->uri = g_value_dup_string (value);
932 GST_OBJECT_UNLOCK (dec);
933 break;
934 case PROP_CONNECTION_SPEED:
935 GST_OBJECT_LOCK (dec);
936 dec->connection_speed = g_value_get_uint64 (value) * 1000;
937 GST_OBJECT_UNLOCK (dec);
938 #ifdef OHOS_EXT_FUNC
939 // ohos.ext.func.0028
940 guint64 con_speed = g_value_get_uint64 (value);
941 set_property_to_decodebin(dec, prop_id, (void *)&con_speed);
942 #endif
943 break;
944 case PROP_CAPS:
945 GST_OBJECT_LOCK (dec);
946 if (dec->caps)
947 gst_caps_unref (dec->caps);
948 dec->caps = g_value_dup_boxed (value);
949 GST_OBJECT_UNLOCK (dec);
950 break;
951 case PROP_SUBTITLE_ENCODING:
952 gst_uri_decode_bin_set_encoding (dec, g_value_get_string (value));
953 break;
954 case PROP_BUFFER_SIZE:
955 dec->buffer_size = g_value_get_int (value);
956 break;
957 case PROP_BUFFER_DURATION:
958 #ifdef OHOS_EXT_FUNC
959 // ohos.ext.func.0012
960 dec->buffer_duration = g_value_get_uint64 (value);
961 #else
962 dec->buffer_duration = g_value_get_int64 (value);
963 #endif
964 break;
965 case PROP_DOWNLOAD:
966 dec->download = g_value_get_boolean (value);
967 break;
968 case PROP_USE_BUFFERING:
969 dec->use_buffering = g_value_get_boolean (value);
970 break;
971 case PROP_FORCE_SW_DECODERS:
972 dec->force_sw_decoders = g_value_get_boolean (value);
973 break;
974 case PROP_EXPOSE_ALL_STREAMS:
975 dec->expose_allstreams = g_value_get_boolean (value);
976 break;
977 case PROP_RING_BUFFER_MAX_SIZE:
978 dec->ring_buffer_max_size = g_value_get_uint64 (value);
979 break;
980 #ifdef OHOS_EXT_FUNC
981 // ohos.ext.func.0012
982 case PROP_TIMEOUT: {
983 guint timeout = g_value_get_uint (value);
984 g_object_set (dec->source, "timeout", timeout, NULL);
985 set_property_to_decodebin(dec, prop_id, (void *)&timeout);
986 break;
987 }
988 case PROP_STATE_CHANGE: {
989 gint state = g_value_get_int (value);
990 g_object_set (dec->source, "state-change", state, NULL);
991 set_property_to_decodebin(dec, prop_id, (void *)&state);
992 break;
993 }
994 case PROP_EXIT_BLOCK: {
995 gint exit_block = g_value_get_int (value);
996 g_object_set (dec->source, "exit-block", exit_block, NULL);
997 set_property_to_decodebin(dec, prop_id, (void *)&exit_block);
998 break;
999 }
1000 case PROP_LOW_PERCENT:
1001 dec->low_percent = g_value_get_int (value);
1002 GST_INFO_OBJECT (dec, "gsturidecbin set property low_percent=%d", dec->low_percent);
1003 break;
1004 case PROP_HIGH_PERCENT:
1005 dec->high_percent = g_value_get_int (value);
1006 GST_INFO_OBJECT (dec, "gsturidecbin set property high_percent=%d", dec->high_percent);
1007 break;
1008 #endif
1009 default:
1010 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1011 break;
1012 }
1013 }
1014
1015 static void
gst_uri_decode_bin_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1016 gst_uri_decode_bin_get_property (GObject * object, guint prop_id,
1017 GValue * value, GParamSpec * pspec)
1018 {
1019 GstURIDecodeBin *dec = GST_URI_DECODE_BIN (object);
1020
1021 switch (prop_id) {
1022 case PROP_URI:
1023 GST_OBJECT_LOCK (dec);
1024 g_value_set_string (value, dec->uri);
1025 GST_OBJECT_UNLOCK (dec);
1026 break;
1027 case PROP_SOURCE:
1028 GST_OBJECT_LOCK (dec);
1029 g_value_set_object (value, dec->source);
1030 GST_OBJECT_UNLOCK (dec);
1031 break;
1032 case PROP_CONNECTION_SPEED:
1033 GST_OBJECT_LOCK (dec);
1034 g_value_set_uint64 (value, dec->connection_speed / 1000);
1035 GST_OBJECT_UNLOCK (dec);
1036 break;
1037 case PROP_CAPS:
1038 GST_OBJECT_LOCK (dec);
1039 g_value_set_boxed (value, dec->caps);
1040 GST_OBJECT_UNLOCK (dec);
1041 break;
1042 case PROP_SUBTITLE_ENCODING:
1043 GST_OBJECT_LOCK (dec);
1044 g_value_set_string (value, dec->encoding);
1045 GST_OBJECT_UNLOCK (dec);
1046 break;
1047 case PROP_BUFFER_SIZE:
1048 GST_OBJECT_LOCK (dec);
1049 g_value_set_int (value, dec->buffer_size);
1050 GST_OBJECT_UNLOCK (dec);
1051 break;
1052 case PROP_BUFFER_DURATION:
1053 GST_OBJECT_LOCK (dec);
1054 #ifdef OHOS_EXT_FUNC
1055 // ohos.ext.func.0012
1056 g_value_set_uint64 (value, dec->buffer_duration);
1057 #else
1058 g_value_set_int64 (value, dec->buffer_duration);
1059 #endif
1060 GST_OBJECT_UNLOCK (dec);
1061 break;
1062 case PROP_DOWNLOAD:
1063 g_value_set_boolean (value, dec->download);
1064 break;
1065 case PROP_USE_BUFFERING:
1066 g_value_set_boolean (value, dec->use_buffering);
1067 break;
1068 case PROP_FORCE_SW_DECODERS:
1069 g_value_set_boolean (value, dec->force_sw_decoders);
1070 break;
1071 case PROP_EXPOSE_ALL_STREAMS:
1072 g_value_set_boolean (value, dec->expose_allstreams);
1073 break;
1074 case PROP_RING_BUFFER_MAX_SIZE:
1075 g_value_set_uint64 (value, dec->ring_buffer_max_size);
1076 break;
1077 #ifdef OHOS_EXT_FUNC
1078 // ohos.ext.func.0012
1079 case PROP_LOW_PERCENT:
1080 g_value_set_int (value, dec->low_percent);
1081 break;
1082 case PROP_HIGH_PERCENT:
1083 g_value_set_int (value, dec->high_percent);
1084 break;
1085 #endif
1086 default:
1087 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1088 break;
1089 }
1090 }
1091
1092 static void
do_async_start(GstURIDecodeBin * dbin)1093 do_async_start (GstURIDecodeBin * dbin)
1094 {
1095 GstMessage *message;
1096
1097 dbin->async_pending = TRUE;
1098
1099 message = gst_message_new_async_start (GST_OBJECT_CAST (dbin));
1100 GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (dbin), message);
1101 }
1102
1103 static void
do_async_done(GstURIDecodeBin * dbin)1104 do_async_done (GstURIDecodeBin * dbin)
1105 {
1106 GstMessage *message;
1107
1108 if (dbin->async_pending) {
1109 GST_DEBUG_OBJECT (dbin, "posting ASYNC_DONE");
1110 message =
1111 gst_message_new_async_done (GST_OBJECT_CAST (dbin),
1112 GST_CLOCK_TIME_NONE);
1113 GST_BIN_CLASS (parent_class)->handle_message (GST_BIN_CAST (dbin), message);
1114
1115 dbin->async_pending = FALSE;
1116 }
1117 }
1118
1119 #define DEFAULT_QUEUE_SIZE (3 * GST_SECOND)
1120 #define DEFAULT_QUEUE_MIN_THRESHOLD ((DEFAULT_QUEUE_SIZE * 30) / 100)
1121 #define DEFAULT_QUEUE_THRESHOLD ((DEFAULT_QUEUE_SIZE * 95) / 100)
1122
1123 #ifdef OHOS_EXT_FUNC
1124 // ohos.ext.func.0028
1125 static void
bitrate_parse_complete_cb(GstElement * element,gpointer input,guint num,GstURIDecodeBin * decoder)1126 bitrate_parse_complete_cb (GstElement * element, gpointer input, guint num, GstURIDecodeBin * decoder)
1127 {
1128 if ((element == NULL) || (decoder == NULL)) {
1129 return;
1130 }
1131 g_signal_emit (decoder, gst_uri_decode_bin_signals[SIGNAL_BITRATE_PARSE_COMPLETE], 0, input, num);
1132 }
1133 #endif
1134
1135 static void
unknown_type_cb(GstElement * element,GstPad * pad,GstCaps * caps,GstURIDecodeBin * decoder)1136 unknown_type_cb (GstElement * element, GstPad * pad, GstCaps * caps,
1137 GstURIDecodeBin * decoder)
1138 {
1139 gchar *capsstr;
1140
1141 capsstr = gst_caps_to_string (caps);
1142 GST_ELEMENT_WARNING (decoder, STREAM, CODEC_NOT_FOUND,
1143 (_("No decoder available for type \'%s\'."), capsstr), (NULL));
1144 g_free (capsstr);
1145 }
1146
1147 /* add a streaminfo that indicates that the stream is handled by the
1148 * given element. This usually means that a stream without actual data is
1149 * produced but one that is sunken by an element. Examples of this are:
1150 * cdaudio, a hardware decoder/sink, dvd meta bins etc...
1151 */
1152 static void
add_element_stream(GstElement * element,GstURIDecodeBin * decoder)1153 add_element_stream (GstElement * element, GstURIDecodeBin * decoder)
1154 {
1155 g_warning ("add element stream");
1156 }
1157
1158 /* when the decoder element signals that no more pads will be generated, we
1159 * can commit the current group.
1160 */
1161 static void
no_more_pads_full(GstElement * element,gboolean subs,GstURIDecodeBin * decoder)1162 no_more_pads_full (GstElement * element, gboolean subs,
1163 GstURIDecodeBin * decoder)
1164 {
1165 gboolean final;
1166
1167 /* setup phase */
1168 GST_DEBUG_OBJECT (element, "no more pads, %d pending", decoder->pending);
1169
1170 GST_URI_DECODE_BIN_LOCK (decoder);
1171 final = (decoder->pending == 0);
1172
1173 /* nothing pending, we can exit */
1174 if (final)
1175 goto done;
1176
1177 /* the object has no pending no_more_pads */
1178 if (!g_object_get_data (G_OBJECT (element), "pending"))
1179 goto done;
1180 g_object_set_data (G_OBJECT (element), "pending", NULL);
1181
1182 decoder->pending--;
1183 final = (decoder->pending == 0);
1184
1185 done:
1186 GST_URI_DECODE_BIN_UNLOCK (decoder);
1187
1188 if (final) {
1189 /* If we got not a single stream yet, that means that all
1190 * decodebins had missing plugins for all of their streams!
1191 */
1192 if (!decoder->streams || g_hash_table_size (decoder->streams) == 0) {
1193 if (decoder->missing_plugin_errors) {
1194 GString *str = g_string_new ("");
1195 GList *l;
1196
1197 for (l = decoder->missing_plugin_errors; l; l = l->next) {
1198 GstMessage *msg = l->data;
1199 gchar *debug;
1200
1201 gst_message_parse_error (msg, NULL, &debug);
1202 g_string_append (str, debug);
1203 g_free (debug);
1204 gst_message_unref (msg);
1205 }
1206 g_list_free (decoder->missing_plugin_errors);
1207 decoder->missing_plugin_errors = NULL;
1208
1209 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
1210 ("no suitable plugins found:\n%s", str->str));
1211 g_string_free (str, TRUE);
1212 } else {
1213 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
1214 ("no suitable plugins found"));
1215 }
1216 } else {
1217 gst_element_no_more_pads (GST_ELEMENT_CAST (decoder));
1218 }
1219 do_async_done (decoder);
1220 }
1221
1222 return;
1223 }
1224
1225 static void
no_more_pads(GstElement * element,GstURIDecodeBin * decoder)1226 no_more_pads (GstElement * element, GstURIDecodeBin * decoder)
1227 {
1228 no_more_pads_full (element, FALSE, decoder);
1229 }
1230
1231 static void
source_no_more_pads(GstElement * element,GstURIDecodeBin * bin)1232 source_no_more_pads (GstElement * element, GstURIDecodeBin * bin)
1233 {
1234 GST_DEBUG_OBJECT (bin, "No more pads in source element %s.",
1235 GST_ELEMENT_NAME (element));
1236
1237 g_signal_handler_disconnect (element, bin->src_np_sig_id);
1238 bin->src_np_sig_id = 0;
1239 g_signal_handler_disconnect (element, bin->src_nmp_sig_id);
1240 bin->src_nmp_sig_id = 0;
1241
1242 no_more_pads_full (element, FALSE, bin);
1243 }
1244
1245 static void
configure_stream_buffering(GstURIDecodeBin * decoder)1246 configure_stream_buffering (GstURIDecodeBin * decoder)
1247 {
1248 GstElement *queue = NULL;
1249 GHashTableIter iter;
1250 gpointer key, value;
1251 gint bitrate = 0;
1252
1253 /* automatic configuration enabled ? */
1254 if (decoder->buffer_size != -1)
1255 return;
1256
1257 GST_URI_DECODE_BIN_LOCK (decoder);
1258 if (decoder->queue)
1259 queue = gst_object_ref (decoder->queue);
1260
1261 g_hash_table_iter_init (&iter, decoder->streams);
1262 while (g_hash_table_iter_next (&iter, &key, &value)) {
1263 GstURIDecodeBinStream *stream = value;
1264
1265 if (stream->bitrate && bitrate >= 0)
1266 bitrate += stream->bitrate;
1267 else
1268 bitrate = -1;
1269 }
1270 GST_URI_DECODE_BIN_UNLOCK (decoder);
1271
1272 GST_DEBUG_OBJECT (decoder, "overall bitrate %d", bitrate);
1273 if (!queue)
1274 return;
1275
1276 if (bitrate > 0) {
1277 guint64 time;
1278 guint bytes;
1279
1280 /* all streams have a bitrate;
1281 * configure queue size based on queue duration using combined bitrate */
1282 g_object_get (queue, "max-size-time", &time, NULL);
1283 GST_DEBUG_OBJECT (decoder, "queue buffering time %" GST_TIME_FORMAT,
1284 GST_TIME_ARGS (time));
1285 if (time > 0) {
1286 bytes = gst_util_uint64_scale (time, bitrate, 8 * GST_SECOND);
1287 GST_DEBUG_OBJECT (decoder, "corresponds to buffer size %d", bytes);
1288 g_object_set (queue, "max-size-bytes", bytes, NULL);
1289 }
1290 }
1291
1292 gst_object_unref (queue);
1293 }
1294
1295 static GstPadProbeReturn
decoded_pad_event_probe(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1296 decoded_pad_event_probe (GstPad * pad, GstPadProbeInfo * info,
1297 gpointer user_data)
1298 {
1299 GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
1300 GstURIDecodeBin *decoder = user_data;
1301
1302 GST_LOG_OBJECT (pad, "%s, decoder %p", GST_EVENT_TYPE_NAME (event), decoder);
1303
1304 /* look for a bitrate tag */
1305 switch (GST_EVENT_TYPE (event)) {
1306 case GST_EVENT_TAG:
1307 {
1308 GstTagList *list;
1309 guint bitrate = 0;
1310 GstURIDecodeBinStream *stream;
1311
1312 gst_event_parse_tag (event, &list);
1313 if (!gst_tag_list_get_uint_index (list, GST_TAG_NOMINAL_BITRATE, 0,
1314 &bitrate)) {
1315 gst_tag_list_get_uint_index (list, GST_TAG_BITRATE, 0, &bitrate);
1316 }
1317 GST_DEBUG_OBJECT (pad, "found bitrate %u", bitrate);
1318 if (bitrate) {
1319 GST_URI_DECODE_BIN_LOCK (decoder);
1320 stream = g_hash_table_lookup (decoder->streams, pad);
1321 GST_URI_DECODE_BIN_UNLOCK (decoder);
1322 if (stream) {
1323 stream->bitrate = bitrate;
1324 /* no longer need this probe now */
1325 gst_pad_remove_probe (pad, stream->probe_id);
1326 /* configure buffer if possible */
1327 configure_stream_buffering (decoder);
1328 }
1329 }
1330 break;
1331 }
1332 default:
1333 break;
1334 }
1335
1336 /* never drop */
1337 return GST_PAD_PROBE_OK;
1338 }
1339
1340
1341 static gboolean
copy_sticky_events(GstPad * pad,GstEvent ** event,gpointer user_data)1342 copy_sticky_events (GstPad * pad, GstEvent ** event, gpointer user_data)
1343 {
1344 GstPad *gpad = GST_PAD_CAST (user_data);
1345
1346 GST_DEBUG_OBJECT (gpad, "store sticky event %" GST_PTR_FORMAT, *event);
1347 gst_pad_store_sticky_event (gpad, *event);
1348
1349 return TRUE;
1350 }
1351
1352 /* Called by the signal handlers when a decodebin has found a new raw pad */
1353 static void
new_decoded_pad_added_cb(GstElement * element,GstPad * pad,GstURIDecodeBin * decoder)1354 new_decoded_pad_added_cb (GstElement * element, GstPad * pad,
1355 GstURIDecodeBin * decoder)
1356 {
1357 GstPad *newpad;
1358 GstPadTemplate *pad_tmpl;
1359 gchar *padname;
1360 GstURIDecodeBinStream *stream;
1361
1362 GST_DEBUG_OBJECT (element, "new decoded pad, name: <%s>", GST_PAD_NAME (pad));
1363
1364 GST_URI_DECODE_BIN_LOCK (decoder);
1365 padname = g_strdup_printf ("src_%u", decoder->numpads);
1366 decoder->numpads++;
1367 GST_URI_DECODE_BIN_UNLOCK (decoder);
1368
1369 pad_tmpl = gst_static_pad_template_get (&srctemplate);
1370 newpad = gst_ghost_pad_new_from_template (padname, pad, pad_tmpl);
1371 gst_object_unref (pad_tmpl);
1372 g_free (padname);
1373
1374 /* store ref to the ghostpad so we can remove it */
1375 g_object_set_data (G_OBJECT (pad), "uridecodebin.ghostpad", newpad);
1376
1377 /* add event probe to monitor tags */
1378 stream = g_slice_alloc0 (sizeof (GstURIDecodeBinStream));
1379 stream->probe_id =
1380 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
1381 decoded_pad_event_probe, decoder, NULL);
1382 GST_URI_DECODE_BIN_LOCK (decoder);
1383 g_hash_table_insert (decoder->streams, pad, stream);
1384 GST_URI_DECODE_BIN_UNLOCK (decoder);
1385
1386 gst_pad_set_active (newpad, TRUE);
1387 gst_pad_sticky_events_foreach (pad, copy_sticky_events, newpad);
1388 gst_element_add_pad (GST_ELEMENT_CAST (decoder), newpad);
1389 }
1390
1391 static GstPadProbeReturn
source_pad_event_probe(GstPad * pad,GstPadProbeInfo * info,gpointer user_data)1392 source_pad_event_probe (GstPad * pad, GstPadProbeInfo * info,
1393 gpointer user_data)
1394 {
1395 GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
1396 GstURIDecodeBin *decoder = user_data;
1397
1398 GST_LOG_OBJECT (pad, "%s, decoder %p", GST_EVENT_TYPE_NAME (event), decoder);
1399
1400 if (GST_EVENT_TYPE (event) == GST_EVENT_EOS) {
1401 GST_DEBUG_OBJECT (pad, "we received EOS");
1402
1403 g_signal_emit (decoder,
1404 gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
1405 }
1406 /* never drop events */
1407 return GST_PAD_PROBE_OK;
1408 }
1409
1410 /* called when we found a raw pad on the source element. We need to set up a
1411 * padprobe to detect EOS before exposing the pad. */
1412 static void
expose_decoded_pad(GstElement * element,GstPad * pad,GstURIDecodeBin * decoder)1413 expose_decoded_pad (GstElement * element, GstPad * pad,
1414 GstURIDecodeBin * decoder)
1415 {
1416 gst_pad_add_probe (pad, GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM,
1417 source_pad_event_probe, decoder, NULL);
1418
1419 new_decoded_pad_added_cb (element, pad, decoder);
1420 }
1421
1422 static void
pad_removed_cb(GstElement * element,GstPad * pad,GstURIDecodeBin * decoder)1423 pad_removed_cb (GstElement * element, GstPad * pad, GstURIDecodeBin * decoder)
1424 {
1425 GstPad *ghost;
1426
1427 GST_DEBUG_OBJECT (element, "pad removed name: <%s:%s>",
1428 GST_DEBUG_PAD_NAME (pad));
1429
1430 /* we only care about srcpads */
1431 if (!GST_PAD_IS_SRC (pad))
1432 return;
1433
1434 if (!(ghost = g_object_get_data (G_OBJECT (pad), "uridecodebin.ghostpad")))
1435 goto no_ghost;
1436
1437 /* unghost the pad */
1438 gst_ghost_pad_set_target (GST_GHOST_PAD_CAST (ghost), NULL);
1439
1440 /* deactivate and remove */
1441 gst_pad_set_active (pad, FALSE);
1442 gst_element_remove_pad (GST_ELEMENT_CAST (decoder), ghost);
1443
1444 return;
1445
1446 /* ERRORS */
1447 no_ghost:
1448 {
1449 GST_WARNING_OBJECT (element, "no ghost pad found");
1450 return;
1451 }
1452 }
1453
1454 /* helper function to lookup stuff in lists */
1455 static gboolean
array_has_value(const gchar * values[],const gchar * value)1456 array_has_value (const gchar * values[], const gchar * value)
1457 {
1458 gint i;
1459
1460 for (i = 0; values[i]; i++) {
1461 if (g_str_has_prefix (value, values[i]))
1462 return TRUE;
1463 }
1464 return FALSE;
1465 }
1466
1467 static gboolean
array_has_uri_value(const gchar * values[],const gchar * value)1468 array_has_uri_value (const gchar * values[], const gchar * value)
1469 {
1470 gint i;
1471
1472 for (i = 0; values[i]; i++) {
1473 if (!g_ascii_strncasecmp (value, values[i], strlen (values[i])))
1474 return TRUE;
1475 }
1476 return FALSE;
1477 }
1478
1479 #ifdef OHOS_OPT_PERFORMANCE
1480 /*
1481 * ohos.opt.performance.0003
1482 * remove fd:// from network for performance.
1483 */
1484 static const gchar *stream_uris[] = { "http://", "https://", "mms://",
1485 "mmsh://", "mmsu://", "mmst://", "myth://", "ssh://", "ftp://", "sftp://",
1486 NULL
1487 };
1488 #else
1489 /* list of URIs that we consider to be streams and that need buffering.
1490 * We have no mechanism yet to figure this out with a query. */
1491 static const gchar *stream_uris[] = { "http://", "https://", "mms://",
1492 "mmsh://", "mmsu://", "mmst://", "fd://", "myth://", "ssh://",
1493 "ftp://", "sftp://",
1494 NULL
1495 };
1496 #endif
1497
1498 /* list of URIs that need a queue because they are pretty bursty */
1499 static const gchar *queue_uris[] = { "cdda://", NULL };
1500
1501 /* blacklisted URIs, we know they will always fail. */
1502 static const gchar *blacklisted_uris[] = { NULL };
1503
1504 /* media types that use adaptive streaming */
1505 static const gchar *adaptive_media[] = {
1506 "application/x-hls", "application/vnd.ms-sstr+xml",
1507 "application/dash+xml", NULL
1508 };
1509
1510 #define IS_STREAM_URI(uri) (array_has_uri_value (stream_uris, uri))
1511 #define IS_QUEUE_URI(uri) (array_has_uri_value (queue_uris, uri))
1512 #define IS_BLACKLISTED_URI(uri) (array_has_uri_value (blacklisted_uris, uri))
1513 #define IS_ADAPTIVE_MEDIA(media) (array_has_value (adaptive_media, media))
1514
1515 /*
1516 * Generate and configure a source element.
1517 *
1518 * Returns: (transfer full): a new #GstElement
1519 */
1520 static GstElement *
gen_source_element(GstURIDecodeBin * decoder)1521 gen_source_element (GstURIDecodeBin * decoder)
1522 {
1523 GObjectClass *source_class;
1524 GstElement *source;
1525 GParamSpec *pspec;
1526 GstQuery *query;
1527 GstSchedulingFlags flags;
1528 GError *err = NULL;
1529
1530 if (!decoder->uri)
1531 goto no_uri;
1532
1533 GST_LOG_OBJECT (decoder, "finding source for %s", decoder->uri);
1534
1535 if (!gst_uri_is_valid (decoder->uri))
1536 goto invalid_uri;
1537
1538 if (IS_BLACKLISTED_URI (decoder->uri))
1539 goto uri_blacklisted;
1540
1541 source =
1542 gst_element_make_from_uri (GST_URI_SRC, decoder->uri, "source", &err);
1543 if (!source)
1544 goto no_source;
1545
1546 GST_LOG_OBJECT (decoder, "found source type %s", G_OBJECT_TYPE_NAME (source));
1547
1548 source_class = G_OBJECT_GET_CLASS (source);
1549
1550 pspec = g_object_class_find_property (source_class, "connection-speed");
1551 if (pspec != NULL) {
1552 guint64 speed = decoder->connection_speed / 1000;
1553 gboolean wrong_type = FALSE;
1554
1555 if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_UINT) {
1556 GParamSpecUInt *pspecuint = G_PARAM_SPEC_UINT (pspec);
1557
1558 speed = CLAMP (speed, pspecuint->minimum, pspecuint->maximum);
1559 } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT) {
1560 GParamSpecInt *pspecint = G_PARAM_SPEC_INT (pspec);
1561
1562 speed = CLAMP (speed, pspecint->minimum, pspecint->maximum);
1563 } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_UINT64) {
1564 GParamSpecUInt64 *pspecuint = G_PARAM_SPEC_UINT64 (pspec);
1565
1566 speed = CLAMP (speed, pspecuint->minimum, pspecuint->maximum);
1567 } else if (G_PARAM_SPEC_TYPE (pspec) == G_TYPE_PARAM_INT64) {
1568 GParamSpecInt64 *pspecint = G_PARAM_SPEC_INT64 (pspec);
1569
1570 speed = CLAMP (speed, pspecint->minimum, pspecint->maximum);
1571 } else {
1572 GST_WARNING_OBJECT (decoder,
1573 "The connection speed property %" G_GUINT64_FORMAT
1574 " of type %s is not useful not setting it", speed,
1575 g_type_name (G_PARAM_SPEC_TYPE (pspec)));
1576 wrong_type = TRUE;
1577 }
1578
1579 if (!wrong_type) {
1580 g_object_set (source, "connection-speed", speed, NULL);
1581
1582 GST_DEBUG_OBJECT (decoder,
1583 "setting connection-speed=%" G_GUINT64_FORMAT " to source element",
1584 speed);
1585 }
1586 }
1587
1588 pspec = g_object_class_find_property (source_class, "subtitle-encoding");
1589 if (pspec != NULL && G_PARAM_SPEC_VALUE_TYPE (pspec) == G_TYPE_STRING) {
1590 GST_DEBUG_OBJECT (decoder,
1591 "setting subtitle-encoding=%s to source element", decoder->encoding);
1592 g_object_set (source, "subtitle-encoding", decoder->encoding, NULL);
1593 }
1594
1595 /* Sink reference before passing it to signal handler.
1596 * Language binding might otherwise sink it and then unref.
1597 * A floating ref is also tricky for a native signal handler in case
1598 * of a "transfer floating" call followed by unref
1599 * (e.g. some container_add and then container_remove).
1600 * Bottom line; best not have a floating ref boldly going into unknown code.
1601 */
1602 g_object_ref_sink (source);
1603
1604 g_signal_emit (decoder, gst_uri_decode_bin_signals[SIGNAL_SOURCE_SETUP],
1605 0, source);
1606
1607 decoder->is_stream = IS_STREAM_URI (decoder->uri);
1608
1609 query = gst_query_new_scheduling ();
1610 if (gst_element_query (source, query)) {
1611 gst_query_parse_scheduling (query, &flags, NULL, NULL, NULL);
1612 if ((flags & GST_SCHEDULING_FLAG_BANDWIDTH_LIMITED))
1613 decoder->is_stream = TRUE;
1614 }
1615 gst_query_unref (query);
1616
1617 GST_LOG_OBJECT (decoder, "source is stream: %d", decoder->is_stream);
1618
1619 decoder->need_queue = IS_QUEUE_URI (decoder->uri);
1620 GST_LOG_OBJECT (decoder, "source needs queue: %d", decoder->need_queue);
1621
1622 return source;
1623
1624 /* ERRORS */
1625 no_uri:
1626 {
1627 GST_ELEMENT_ERROR (decoder, RESOURCE, NOT_FOUND,
1628 (_("No URI specified to play from.")), (NULL));
1629 return NULL;
1630 }
1631 invalid_uri:
1632 {
1633 GST_ELEMENT_ERROR (decoder, RESOURCE, NOT_FOUND,
1634 (_("Invalid URI \"%s\"."), decoder->uri), (NULL));
1635 g_clear_error (&err);
1636 return NULL;
1637 }
1638 uri_blacklisted:
1639 {
1640 GST_ELEMENT_ERROR (decoder, RESOURCE, FAILED,
1641 (_("This stream type cannot be played yet.")), (NULL));
1642 return NULL;
1643 }
1644 no_source:
1645 {
1646 /* whoops, could not create the source element, dig a little deeper to
1647 * figure out what might be wrong. */
1648 if (err != NULL && err->code == GST_URI_ERROR_UNSUPPORTED_PROTOCOL) {
1649 gchar *prot;
1650
1651 prot = gst_uri_get_protocol (decoder->uri);
1652 if (prot == NULL)
1653 goto invalid_uri;
1654
1655 gst_element_post_message (GST_ELEMENT_CAST (decoder),
1656 gst_missing_uri_source_message_new (GST_ELEMENT (decoder), prot));
1657
1658 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN,
1659 (_("No URI handler implemented for \"%s\"."), prot), (NULL));
1660
1661 g_free (prot);
1662 } else {
1663 GST_ELEMENT_ERROR (decoder, RESOURCE, NOT_FOUND,
1664 ("%s", (err) ? err->message : "URI was not accepted by any element"),
1665 ("No element accepted URI '%s'", decoder->uri));
1666 }
1667
1668 g_clear_error (&err);
1669 return NULL;
1670 }
1671 }
1672
1673 /**
1674 * has_all_raw_caps:
1675 * @pad: a #GstPad
1676 * @all_raw: pointer to hold the result
1677 *
1678 * check if the caps of the pad are all raw. The caps are all raw if
1679 * all of its structures contain audio/x-raw or video/x-raw.
1680 *
1681 * Returns: %FALSE @pad has no caps. Else TRUE and @all_raw set t the result.
1682 */
1683 static gboolean
has_all_raw_caps(GstPad * pad,GstCaps * rawcaps,gboolean * all_raw)1684 has_all_raw_caps (GstPad * pad, GstCaps * rawcaps, gboolean * all_raw)
1685 {
1686 GstCaps *caps, *intersection;
1687 gint capssize;
1688 gboolean res = FALSE;
1689
1690 caps = gst_pad_query_caps (pad, NULL);
1691 if (caps == NULL)
1692 return FALSE;
1693
1694 GST_DEBUG_OBJECT (pad, "have caps %" GST_PTR_FORMAT, caps);
1695
1696 capssize = gst_caps_get_size (caps);
1697 /* no caps, skip and move to the next pad */
1698 if (capssize == 0 || gst_caps_is_empty (caps) || gst_caps_is_any (caps))
1699 goto done;
1700
1701 intersection = gst_caps_intersect (caps, rawcaps);
1702 *all_raw = !gst_caps_is_empty (intersection)
1703 && (gst_caps_get_size (intersection) == capssize);
1704 gst_caps_unref (intersection);
1705
1706 res = TRUE;
1707
1708 done:
1709 gst_caps_unref (caps);
1710 return res;
1711 }
1712
1713 static void
post_missing_plugin_error(GstElement * dec,const gchar * element_name)1714 post_missing_plugin_error (GstElement * dec, const gchar * element_name)
1715 {
1716 GstMessage *msg;
1717
1718 msg = gst_missing_element_message_new (dec, element_name);
1719 gst_element_post_message (dec, msg);
1720
1721 GST_ELEMENT_ERROR (dec, CORE, MISSING_PLUGIN,
1722 (_("Missing element '%s' - check your GStreamer installation."),
1723 element_name), (NULL));
1724 do_async_done (GST_URI_DECODE_BIN (dec));
1725 }
1726
1727 /**
1728 * analyse_source:
1729 * @decoder: a #GstURIDecodeBin
1730 * @is_raw: are all pads raw data
1731 * @have_out: does the source have output
1732 * @is_dynamic: is this a dynamic source
1733 * @use_queue: put a queue before raw output pads
1734 *
1735 * Check the source of @decoder and collect information about it.
1736 *
1737 * @is_raw will be set to TRUE if the source only produces raw pads. When this
1738 * function returns, all of the raw pad of the source will be added
1739 * to @decoder.
1740 *
1741 * @have_out: will be set to TRUE if the source has output pads.
1742 *
1743 * @is_dynamic: TRUE if the element will create (more) pads dynamically later
1744 * on.
1745 *
1746 * Returns: FALSE if a fatal error occurred while scanning.
1747 */
1748 static gboolean
analyse_source(GstURIDecodeBin * decoder,gboolean * is_raw,gboolean * have_out,gboolean * is_dynamic,gboolean use_queue)1749 analyse_source (GstURIDecodeBin * decoder, gboolean * is_raw,
1750 gboolean * have_out, gboolean * is_dynamic, gboolean use_queue)
1751 {
1752 GstIterator *pads_iter;
1753 gboolean done = FALSE;
1754 gboolean res = TRUE;
1755 GstCaps *rawcaps;
1756 GstPad *pad;
1757 GValue item = { 0, };
1758
1759 *have_out = FALSE;
1760 *is_raw = FALSE;
1761 *is_dynamic = FALSE;
1762
1763 g_object_get (decoder, "caps", &rawcaps, NULL);
1764 if (!rawcaps)
1765 rawcaps = DEFAULT_CAPS;
1766
1767 pads_iter = gst_element_iterate_src_pads (decoder->source);
1768 while (!done) {
1769 switch (gst_iterator_next (pads_iter, &item)) {
1770 case GST_ITERATOR_ERROR:
1771 res = FALSE;
1772 /* FALLTHROUGH */
1773 case GST_ITERATOR_DONE:
1774 done = TRUE;
1775 break;
1776 case GST_ITERATOR_RESYNC:
1777 /* reset results and resync */
1778 *have_out = FALSE;
1779 *is_raw = FALSE;
1780 *is_dynamic = FALSE;
1781 gst_iterator_resync (pads_iter);
1782 break;
1783 case GST_ITERATOR_OK:
1784 pad = g_value_dup_object (&item);
1785 /* we now officially have an output pad */
1786 *have_out = TRUE;
1787
1788 /* if FALSE, this pad has no caps and we continue with the next pad. */
1789 if (!has_all_raw_caps (pad, rawcaps, is_raw)) {
1790 gst_object_unref (pad);
1791 g_value_reset (&item);
1792 break;
1793 }
1794
1795 /* caps on source pad are all raw, we can add the pad */
1796 if (*is_raw) {
1797 GstElement *outelem;
1798
1799 if (use_queue) {
1800 GstPad *sinkpad;
1801
1802 /* insert a queue element right before the raw pad */
1803 outelem = gst_element_factory_make ("queue2", NULL);
1804 if (!outelem)
1805 goto no_queue2;
1806
1807 gst_bin_add (GST_BIN_CAST (decoder), outelem);
1808
1809 sinkpad = gst_element_get_static_pad (outelem, "sink");
1810 gst_pad_link (pad, sinkpad);
1811 gst_object_unref (sinkpad);
1812
1813 /* save queue pointer so we can remove it later */
1814 decoder->queue = outelem;
1815
1816 /* get the new raw srcpad */
1817 gst_object_unref (pad);
1818 pad = gst_element_get_static_pad (outelem, "src");
1819 } else {
1820 outelem = decoder->source;
1821 }
1822 expose_decoded_pad (outelem, pad, decoder);
1823 }
1824 gst_object_unref (pad);
1825 g_value_reset (&item);
1826 break;
1827 }
1828 }
1829 g_value_unset (&item);
1830 gst_iterator_free (pads_iter);
1831 gst_caps_unref (rawcaps);
1832
1833 if (!*have_out) {
1834 GstElementClass *elemclass;
1835 GList *walk;
1836
1837 /* element has no output pads, check for padtemplates that list SOMETIMES
1838 * pads. */
1839 elemclass = GST_ELEMENT_GET_CLASS (decoder->source);
1840
1841 walk = gst_element_class_get_pad_template_list (elemclass);
1842 while (walk != NULL) {
1843 GstPadTemplate *templ;
1844
1845 templ = (GstPadTemplate *) walk->data;
1846 if (GST_PAD_TEMPLATE_DIRECTION (templ) == GST_PAD_SRC) {
1847 if (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_SOMETIMES)
1848 *is_dynamic = TRUE;
1849 break;
1850 }
1851 walk = g_list_next (walk);
1852 }
1853 }
1854
1855 return res;
1856 no_queue2:
1857 {
1858 post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "queue2");
1859
1860 gst_object_unref (pad);
1861 g_value_unset (&item);
1862 gst_iterator_free (pads_iter);
1863 gst_caps_unref (rawcaps);
1864
1865 return FALSE;
1866 }
1867 }
1868
1869 /* Remove all decodebin from ourself
1870 * If force is FALSE, then the decodebin instances will be stored in
1871 * pending_decodebins for re-use later on.
1872 * If force is TRUE, then all decodebin instances will be unreferenced
1873 * and cleared, including the pending ones. */
1874 static void
remove_decoders(GstURIDecodeBin * bin,gboolean force)1875 remove_decoders (GstURIDecodeBin * bin, gboolean force)
1876 {
1877 GSList *walk;
1878
1879 for (walk = bin->decodebins; walk; walk = g_slist_next (walk)) {
1880 GstElement *decoder = GST_ELEMENT_CAST (walk->data);
1881
1882 GST_DEBUG_OBJECT (bin, "removing old decoder element");
1883
1884 /* Even if we reuse this decodebin, the previous topology will
1885 * be irrelevant */
1886 g_object_set_data (G_OBJECT (decoder), "uridecodebin-topology", NULL);
1887
1888 if (force) {
1889 gst_element_set_state (decoder, GST_STATE_NULL);
1890 gst_bin_remove (GST_BIN_CAST (bin), decoder);
1891 } else {
1892 GstCaps *caps;
1893
1894 gst_element_set_state (decoder, GST_STATE_READY);
1895 /* add it to our list of pending decodebins */
1896 gst_object_ref (decoder);
1897 gst_bin_remove (GST_BIN_CAST (bin), decoder);
1898 /* restore some properties we might have changed */
1899 g_object_set (decoder, "sink-caps", NULL, NULL);
1900 caps = DEFAULT_CAPS;
1901 g_object_set (decoder, "caps", caps, NULL);
1902 gst_caps_unref (caps);
1903
1904 bin->pending_decodebins =
1905 g_slist_prepend (bin->pending_decodebins, decoder);
1906 }
1907 }
1908 g_slist_free (bin->decodebins);
1909 bin->decodebins = NULL;
1910 if (force) {
1911 GSList *tmp;
1912
1913 for (tmp = bin->pending_decodebins; tmp; tmp = tmp->next) {
1914 gst_element_set_state ((GstElement *) tmp->data, GST_STATE_NULL);
1915 gst_object_unref ((GstElement *) tmp->data);
1916 }
1917 g_slist_free (bin->pending_decodebins);
1918 bin->pending_decodebins = NULL;
1919
1920 }
1921 }
1922
1923 static void
proxy_unknown_type_signal(GstElement * decodebin,GstPad * pad,GstCaps * caps,GstURIDecodeBin * dec)1924 proxy_unknown_type_signal (GstElement * decodebin, GstPad * pad, GstCaps * caps,
1925 GstURIDecodeBin * dec)
1926 {
1927 GST_DEBUG_OBJECT (dec, "unknown-type signaled");
1928
1929 g_signal_emit (dec,
1930 gst_uri_decode_bin_signals[SIGNAL_UNKNOWN_TYPE], 0, pad, caps);
1931 }
1932
1933 static gboolean
proxy_autoplug_continue_signal(GstElement * decodebin,GstPad * pad,GstCaps * caps,GstURIDecodeBin * dec)1934 proxy_autoplug_continue_signal (GstElement * decodebin, GstPad * pad,
1935 GstCaps * caps, GstURIDecodeBin * dec)
1936 {
1937 gboolean result;
1938
1939 g_signal_emit (dec,
1940 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_CONTINUE], 0, pad, caps,
1941 &result);
1942
1943 GST_DEBUG_OBJECT (dec, "autoplug-continue returned %d", result);
1944
1945 return result;
1946 }
1947
1948 static GValueArray *
proxy_autoplug_factories_signal(GstElement * decodebin,GstPad * pad,GstCaps * caps,GstURIDecodeBin * dec)1949 proxy_autoplug_factories_signal (GstElement * decodebin, GstPad * pad,
1950 GstCaps * caps, GstURIDecodeBin * dec)
1951 {
1952 GValueArray *result;
1953
1954 g_signal_emit (dec,
1955 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_FACTORIES], 0, pad, caps,
1956 &result);
1957
1958 GST_DEBUG_OBJECT (dec, "autoplug-factories returned %p", result);
1959
1960 return result;
1961 }
1962
1963 static GValueArray *
proxy_autoplug_sort_signal(GstElement * decodebin,GstPad * pad,GstCaps * caps,GValueArray * factories,GstURIDecodeBin * dec)1964 proxy_autoplug_sort_signal (GstElement * decodebin, GstPad * pad,
1965 GstCaps * caps, GValueArray * factories, GstURIDecodeBin * dec)
1966 {
1967 GValueArray *result;
1968
1969 g_signal_emit (dec,
1970 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SORT], 0, pad, caps,
1971 factories, &result);
1972
1973 GST_DEBUG_OBJECT (dec, "autoplug-sort returned %p", result);
1974
1975 return result;
1976 }
1977
1978 static GstAutoplugSelectResult
proxy_autoplug_select_signal(GstElement * decodebin,GstPad * pad,GstCaps * caps,GstElementFactory * factory,GstURIDecodeBin * dec)1979 proxy_autoplug_select_signal (GstElement * decodebin, GstPad * pad,
1980 GstCaps * caps, GstElementFactory * factory, GstURIDecodeBin * dec)
1981 {
1982 GstAutoplugSelectResult result;
1983
1984 g_signal_emit (dec,
1985 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_SELECT], 0, pad, caps, factory,
1986 &result);
1987
1988 GST_DEBUG_OBJECT (dec, "autoplug-select returned %d", result);
1989
1990 return result;
1991 }
1992
1993 static gboolean
proxy_autoplug_query_signal(GstElement * decodebin,GstPad * pad,GstElement * element,GstQuery * query,GstURIDecodeBin * dec)1994 proxy_autoplug_query_signal (GstElement * decodebin, GstPad * pad,
1995 GstElement * element, GstQuery * query, GstURIDecodeBin * dec)
1996 {
1997 gboolean ret = FALSE;
1998
1999 g_signal_emit (dec,
2000 gst_uri_decode_bin_signals[SIGNAL_AUTOPLUG_QUERY], 0, pad, element, query,
2001 &ret);
2002
2003 GST_DEBUG_OBJECT (dec, "autoplug-query returned %d", ret);
2004
2005 return ret;
2006 }
2007
2008 static void
proxy_drained_signal(GstElement * decodebin,GstURIDecodeBin * dec)2009 proxy_drained_signal (GstElement * decodebin, GstURIDecodeBin * dec)
2010 {
2011 GST_DEBUG_OBJECT (dec, "drained signaled");
2012
2013 g_signal_emit (dec, gst_uri_decode_bin_signals[SIGNAL_DRAINED], 0, NULL);
2014 }
2015
2016 #ifdef OHOS_EXT_FUNC
2017 // ohos.ext.func.0012
2018 static void
set_buffering_info(GstURIDecodeBin * decoder,GstElement * decodebin)2019 set_buffering_info (GstURIDecodeBin *decoder, GstElement *decodebin)
2020 {
2021 /* configure sizes when buffering */
2022 if (decoder->buffer_size == DEFAULT_BUFFER_SIZE) {
2023 decoder->buffer_size = 2 * 1024 * 1024; //2M
2024 }
2025
2026 if (decoder->buffer_duration == DEFAULT_BUFFER_DURATION) {
2027 decoder->buffer_duration = 5 * GST_SECOND; //5s
2028 }
2029
2030 g_object_set (decodebin, "max-size-bytes", decoder->buffer_size, "max-size-buffers",
2031 (guint) 0, "max-size-time", decoder->buffer_duration, NULL);
2032
2033 g_object_set (decodebin, "low-percent", decoder->low_percent, "high-percent", decoder->high_percent, NULL);
2034 }
2035 #endif
2036
2037 /* make a decodebin and connect to all the signals */
2038 static GstElement *
make_decoder(GstURIDecodeBin * decoder)2039 make_decoder (GstURIDecodeBin * decoder)
2040 {
2041 GstElement *decodebin;
2042 gboolean unref_dbin = FALSE;
2043
2044 /* re-use pending decodebin */
2045 if (decoder->pending_decodebins) {
2046 GSList *first = decoder->pending_decodebins;
2047 GST_LOG_OBJECT (decoder, "re-using pending decodebin");
2048 decodebin = (GstElement *) first->data;
2049 decoder->pending_decodebins =
2050 g_slist_delete_link (decoder->pending_decodebins, first);
2051 unref_dbin = TRUE;
2052 } else {
2053 GST_LOG_OBJECT (decoder, "making new decodebin");
2054
2055 /* now create the decoder element */
2056 decodebin = gst_element_factory_make ("decodebin", NULL);
2057
2058 if (!decodebin)
2059 goto no_decodebin;
2060
2061 /* sanity check */
2062 if (decodebin->numsinkpads == 0)
2063 goto no_typefind;
2064
2065 /* connect signals to proxy */
2066 g_signal_connect (decodebin, "unknown-type",
2067 G_CALLBACK (proxy_unknown_type_signal), decoder);
2068 g_signal_connect (decodebin, "autoplug-continue",
2069 G_CALLBACK (proxy_autoplug_continue_signal), decoder);
2070 g_signal_connect (decodebin, "autoplug-factories",
2071 G_CALLBACK (proxy_autoplug_factories_signal), decoder);
2072 g_signal_connect (decodebin, "autoplug-sort",
2073 G_CALLBACK (proxy_autoplug_sort_signal), decoder);
2074 g_signal_connect (decodebin, "autoplug-select",
2075 G_CALLBACK (proxy_autoplug_select_signal), decoder);
2076 g_signal_connect (decodebin, "autoplug-query",
2077 G_CALLBACK (proxy_autoplug_query_signal), decoder);
2078 g_signal_connect (decodebin, "drained",
2079 G_CALLBACK (proxy_drained_signal), decoder);
2080
2081 /* set up callbacks to create the links between decoded data
2082 * and video/audio/subtitle rendering/output. */
2083 g_signal_connect (decodebin,
2084 "pad-added", G_CALLBACK (new_decoded_pad_added_cb), decoder);
2085 g_signal_connect (decodebin,
2086 "pad-removed", G_CALLBACK (pad_removed_cb), decoder);
2087 g_signal_connect (decodebin, "no-more-pads",
2088 G_CALLBACK (no_more_pads), decoder);
2089 g_signal_connect (decodebin,
2090 "unknown-type", G_CALLBACK (unknown_type_cb), decoder);
2091
2092 #ifdef OHOS_EXT_FUNC
2093 // ohos.ext.func.0028
2094 g_signal_connect (decodebin,
2095 "bitrate-parse-complete", G_CALLBACK (bitrate_parse_complete_cb), decoder);
2096 #endif
2097 }
2098
2099 g_object_set (decodebin, "force-sw-decoders", decoder->force_sw_decoders,
2100 NULL);
2101
2102 /* configure caps if we have any */
2103 if (decoder->caps)
2104 g_object_set (decodebin, "caps", decoder->caps, NULL);
2105
2106 /* Propagate expose-all-streams and connection-speed properties */
2107 g_object_set (decodebin, "expose-all-streams", decoder->expose_allstreams,
2108 "connection-speed", decoder->connection_speed / 1000, NULL);
2109
2110 #ifdef OHOS_EXT_FUNC
2111 // ohos.ext.func.0012
2112 /*
2113 * modify for http buffering, If it is streaming, use buffering
2114 */
2115 if (!decoder->is_stream) {
2116 decoder->use_buffering = FALSE;
2117 }
2118 /*
2119 * propagate the use-buffering property but only when we are not already
2120 * doing stream buffering with queue2.
2121 */
2122 g_object_set (decodebin, "use-buffering", decoder->use_buffering, NULL);
2123 if (decoder->use_buffering) {
2124 set_buffering_info(decoder, decodebin);
2125 }
2126 #else
2127 if (!decoder->is_stream || decoder->is_adaptive) {
2128 /* propagate the use-buffering property but only when we are not already
2129 * doing stream buffering with queue2. FIXME, we might want to do stream
2130 * buffering with the multiqueue buffering instead of queue2. */
2131 g_object_set (decodebin, "use-buffering", decoder->use_buffering
2132 || decoder->is_adaptive, NULL);
2133
2134 if (decoder->use_buffering || decoder->is_adaptive) {
2135 guint max_bytes;
2136 guint64 max_time;
2137
2138 /* configure sizes when buffering */
2139 if ((max_bytes = decoder->buffer_size) == -1)
2140 max_bytes = 2 * 1024 * 1024;
2141 if ((max_time = decoder->buffer_duration) == -1)
2142 max_time = 5 * GST_SECOND;
2143
2144 g_object_set (decodebin, "max-size-bytes", max_bytes, "max-size-buffers",
2145 (guint) 0, "max-size-time", max_time, NULL);
2146 }
2147 }
2148 #endif
2149
2150 g_object_set_data (G_OBJECT (decodebin), "pending", GINT_TO_POINTER (1));
2151 g_object_set (decodebin, "subtitle-encoding", decoder->encoding, NULL);
2152 decoder->pending++;
2153 GST_LOG_OBJECT (decoder, "have %d pending dynamic objects", decoder->pending);
2154
2155 gst_bin_add (GST_BIN_CAST (decoder), decodebin);
2156
2157 decoder->decodebins = g_slist_prepend (decoder->decodebins, decodebin);
2158 /* Unref if this decodebin came from our pending_decodebins,
2159 * since we were holding strong reference to decodebin and gst_bin_add()
2160 * will increase refcount */
2161 if (unref_dbin)
2162 gst_object_unref (decodebin);
2163
2164 return decodebin;
2165
2166 /* ERRORS */
2167 no_decodebin:
2168 {
2169 post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "decodebin");
2170 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
2171 ("No decodebin element, check your installation"));
2172 do_async_done (decoder);
2173 return NULL;
2174 }
2175 no_typefind:
2176 {
2177 gst_object_unref (decodebin);
2178 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
2179 ("No typefind element, decodebin is unusable, check your installation"));
2180 do_async_done (decoder);
2181 return NULL;
2182 }
2183 }
2184
2185 /* signaled when we have a stream and we need to configure the download
2186 * buffering or regular buffering */
2187 static void
type_found(GstElement * typefind,guint probability,GstCaps * caps,GstURIDecodeBin * decoder)2188 type_found (GstElement * typefind, guint probability,
2189 GstCaps * caps, GstURIDecodeBin * decoder)
2190 {
2191 GstElement *src_elem, *dec_elem, *queue = NULL;
2192 GstStructure *s;
2193 const gchar *media_type, *elem_name;
2194 gboolean do_download = FALSE;
2195
2196 GST_DEBUG_OBJECT (decoder, "typefind found caps %" GST_PTR_FORMAT, caps);
2197
2198 s = gst_caps_get_structure (caps, 0);
2199 media_type = gst_structure_get_name (s);
2200
2201 decoder->is_adaptive = IS_ADAPTIVE_MEDIA (media_type);
2202
2203 /* only enable download buffering if the upstream duration is known */
2204 if (decoder->download) {
2205 gint64 dur;
2206
2207 do_download = (gst_element_query_duration (typefind, GST_FORMAT_BYTES, &dur)
2208 && dur != -1);
2209 }
2210
2211 dec_elem = make_decoder (decoder);
2212 if (!dec_elem)
2213 goto no_decodebin;
2214
2215 if (decoder->is_adaptive) {
2216 src_elem = typefind;
2217 } else {
2218 if (do_download) {
2219 elem_name = "downloadbuffer";
2220 } else {
2221 elem_name = "queue2";
2222 }
2223 queue = gst_element_factory_make (elem_name, NULL);
2224 if (!queue)
2225 goto no_buffer_element;
2226
2227 decoder->queue = queue;
2228
2229 GST_DEBUG_OBJECT (decoder, "check media-type %s, %d", media_type,
2230 do_download);
2231
2232 if (do_download) {
2233 gchar *temp_template, *filename;
2234 const gchar *tmp_dir, *prgname;
2235
2236 tmp_dir = g_get_user_cache_dir ();
2237 prgname = g_get_prgname ();
2238 if (prgname == NULL)
2239 prgname = "GStreamer";
2240
2241 filename = g_strdup_printf ("%s-XXXXXX", prgname);
2242
2243 /* build our filename */
2244 temp_template = g_build_filename (tmp_dir, filename, NULL);
2245
2246 GST_DEBUG_OBJECT (decoder, "enable download buffering in %s (%s, %s, %s)",
2247 temp_template, tmp_dir, prgname, filename);
2248
2249 /* configure progressive download for selected media types */
2250 g_object_set (queue, "temp-template", temp_template, NULL);
2251
2252 g_free (filename);
2253 g_free (temp_template);
2254 } else {
2255 #ifdef OHOS_EXT_FUNC
2256 // ohos.ext.func.0012
2257 /*
2258 * modify for http buffering, queue2 setting buffer is false by default
2259 */
2260 g_object_set (queue, "use-buffering", FALSE, NULL);
2261 #else
2262 g_object_set (queue, "use-buffering", TRUE, NULL);
2263 #endif
2264 g_object_set (queue, "ring-buffer-max-size",
2265 decoder->ring_buffer_max_size, NULL);
2266 /* Disable max-size-buffers */
2267 g_object_set (queue, "max-size-buffers", 0, NULL);
2268 }
2269
2270 #ifndef OHOS_EXT_FUNC
2271 // ohos.ext.func.0012
2272 /* If buffer size or duration are set, set them on the element */
2273 if (decoder->buffer_size != -1)
2274 g_object_set (queue, "max-size-bytes", decoder->buffer_size, NULL);
2275 if (decoder->buffer_duration != -1)
2276 g_object_set (queue, "max-size-time", decoder->buffer_duration, NULL);
2277 #endif
2278
2279 gst_bin_add (GST_BIN_CAST (decoder), queue);
2280
2281 if (!gst_element_link_pads (typefind, "src", queue, "sink"))
2282 goto could_not_link;
2283 src_elem = queue;
2284 }
2285
2286 /* to force caps on the decodebin element and avoid reparsing stuff by
2287 * typefind. It also avoids a deadlock in the way typefind activates pads in
2288 * the state change */
2289 g_object_set (dec_elem, "sink-caps", caps, NULL);
2290
2291 if (!gst_element_link_pads (src_elem, "src", dec_elem, "sink"))
2292 goto could_not_link;
2293
2294 /* PLAYING in one go might fail (see bug #632782) */
2295 gst_element_set_state (dec_elem, GST_STATE_PAUSED);
2296 gst_element_sync_state_with_parent (dec_elem);
2297 if (queue)
2298 gst_element_sync_state_with_parent (queue);
2299
2300 return;
2301
2302 /* ERRORS */
2303 no_decodebin:
2304 {
2305 /* error was posted */
2306 return;
2307 }
2308 could_not_link:
2309 {
2310 GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
2311 (NULL), ("Can't link typefind to decodebin element"));
2312 do_async_done (decoder);
2313 return;
2314 }
2315 no_buffer_element:
2316 {
2317 post_missing_plugin_error (GST_ELEMENT_CAST (decoder), elem_name);
2318 return;
2319 }
2320 }
2321
2322 /* setup a streaming source. This will first plug a typefind element to the
2323 * source. After we find the type, we decide to plug a queue2 and continue to
2324 * plug a decodebin starting from the found caps */
2325 static gboolean
setup_streaming(GstURIDecodeBin * decoder)2326 setup_streaming (GstURIDecodeBin * decoder)
2327 {
2328 GstElement *typefind;
2329
2330 /* now create the decoder element */
2331 typefind = gst_element_factory_make ("typefind", NULL);
2332 if (!typefind)
2333 goto no_typefind;
2334
2335 gst_bin_add (GST_BIN_CAST (decoder), typefind);
2336
2337 if (!gst_element_link_pads (decoder->source, NULL, typefind, "sink"))
2338 goto could_not_link;
2339
2340 decoder->typefind = typefind;
2341
2342 /* connect a signal to find out when the typefind element found
2343 * a type */
2344 decoder->have_type_id =
2345 g_signal_connect (decoder->typefind, "have-type",
2346 G_CALLBACK (type_found), decoder);
2347
2348 return TRUE;
2349
2350 /* ERRORS */
2351 no_typefind:
2352 {
2353 post_missing_plugin_error (GST_ELEMENT_CAST (decoder), "typefind");
2354 GST_ELEMENT_ERROR (decoder, CORE, MISSING_PLUGIN, (NULL),
2355 ("No typefind element, check your installation"));
2356 do_async_done (decoder);
2357 return FALSE;
2358 }
2359 could_not_link:
2360 {
2361 GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
2362 (NULL), ("Can't link source to typefind element"));
2363 gst_bin_remove (GST_BIN_CAST (decoder), typefind);
2364 do_async_done (decoder);
2365 return FALSE;
2366 }
2367 }
2368
2369 static void
free_stream(gpointer value)2370 free_stream (gpointer value)
2371 {
2372 g_slice_free (GstURIDecodeBinStream, value);
2373 }
2374
2375 /* remove source and all related elements */
2376 static void
remove_source(GstURIDecodeBin * bin)2377 remove_source (GstURIDecodeBin * bin)
2378 {
2379 GstElement *source = bin->source;
2380
2381 if (source) {
2382 GST_DEBUG_OBJECT (bin, "removing old src element");
2383 gst_element_set_state (source, GST_STATE_NULL);
2384
2385 if (bin->src_np_sig_id) {
2386 g_signal_handler_disconnect (source, bin->src_np_sig_id);
2387 bin->src_np_sig_id = 0;
2388 }
2389 if (bin->src_nmp_sig_id) {
2390 g_signal_handler_disconnect (source, bin->src_nmp_sig_id);
2391 bin->src_nmp_sig_id = 0;
2392 }
2393 GST_OBJECT_LOCK (bin);
2394 bin->source = NULL;
2395 GST_OBJECT_UNLOCK (bin);
2396 gst_bin_remove (GST_BIN_CAST (bin), source);
2397 }
2398 if (bin->queue) {
2399 GST_DEBUG_OBJECT (bin, "removing old queue element");
2400 gst_element_set_state (bin->queue, GST_STATE_NULL);
2401 gst_bin_remove (GST_BIN_CAST (bin), bin->queue);
2402 bin->queue = NULL;
2403 }
2404 if (bin->typefind) {
2405 GST_DEBUG_OBJECT (bin, "removing old typefind element");
2406 gst_element_set_state (bin->typefind, GST_STATE_NULL);
2407 gst_bin_remove (GST_BIN_CAST (bin), bin->typefind);
2408 bin->typefind = NULL;
2409 }
2410 if (bin->streams) {
2411 g_hash_table_destroy (bin->streams);
2412 bin->streams = NULL;
2413 }
2414 }
2415
2416 /* is called when a dynamic source element created a new pad. */
2417 static void
source_new_pad(GstElement * element,GstPad * pad,GstURIDecodeBin * bin)2418 source_new_pad (GstElement * element, GstPad * pad, GstURIDecodeBin * bin)
2419 {
2420 GstElement *decoder;
2421 gboolean is_raw;
2422 GstCaps *rawcaps;
2423 GstPad *sinkpad;
2424
2425 GST_URI_DECODE_BIN_LOCK (bin);
2426 GST_DEBUG_OBJECT (bin, "Found new pad %s.%s in source element %s",
2427 GST_DEBUG_PAD_NAME (pad), GST_ELEMENT_NAME (element));
2428
2429 g_object_get (bin, "caps", &rawcaps, NULL);
2430 if (!rawcaps)
2431 rawcaps = DEFAULT_CAPS;
2432
2433 /* if this is a pad with all raw caps, we can expose it */
2434 if (has_all_raw_caps (pad, rawcaps, &is_raw) && is_raw) {
2435 /* it's all raw, create output pads. */
2436 GST_URI_DECODE_BIN_UNLOCK (bin);
2437 gst_caps_unref (rawcaps);
2438 expose_decoded_pad (element, pad, bin);
2439 return;
2440 }
2441 gst_caps_unref (rawcaps);
2442
2443 /* not raw, create decoder */
2444 decoder = make_decoder (bin);
2445 if (!decoder)
2446 goto no_decodebin;
2447
2448 /* and link to decoder */
2449 sinkpad = gst_element_get_static_pad (decoder, "sink");
2450 if (gst_pad_link (pad, sinkpad) != GST_PAD_LINK_OK)
2451 goto could_not_link;
2452 gst_object_unref (sinkpad);
2453
2454 GST_DEBUG_OBJECT (bin, "linked decoder to new source pad");
2455
2456 gst_element_sync_state_with_parent (decoder);
2457 GST_URI_DECODE_BIN_UNLOCK (bin);
2458
2459 return;
2460
2461 /* ERRORS */
2462 no_decodebin:
2463 {
2464 /* error was posted */
2465 GST_URI_DECODE_BIN_UNLOCK (bin);
2466 return;
2467 }
2468 could_not_link:
2469 {
2470 gst_object_unref (sinkpad);
2471 GST_ELEMENT_ERROR (bin, CORE, NEGOTIATION,
2472 (NULL), ("Can't link source to decoder element"));
2473 GST_URI_DECODE_BIN_UNLOCK (bin);
2474 do_async_done (bin);
2475 return;
2476 }
2477 }
2478
2479 static gboolean
is_live_source(GstElement * source)2480 is_live_source (GstElement * source)
2481 {
2482 GObjectClass *source_class = NULL;
2483 gboolean is_live = FALSE;
2484 GParamSpec *pspec;
2485
2486 source_class = G_OBJECT_GET_CLASS (source);
2487 pspec = g_object_class_find_property (source_class, "is-live");
2488 if (!pspec || G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_BOOLEAN)
2489 return FALSE;
2490
2491 g_object_get (G_OBJECT (source), "is-live", &is_live, NULL);
2492
2493 return is_live;
2494 }
2495
2496 /* construct and run the source and decoder elements until we found
2497 * all the streams or until a preroll queue has been filled.
2498 */
2499 static gboolean
setup_source(GstURIDecodeBin * decoder)2500 setup_source (GstURIDecodeBin * decoder)
2501 {
2502 gboolean is_raw, have_out, is_dynamic;
2503 GstElement *source;
2504
2505 GST_DEBUG_OBJECT (decoder, "setup source");
2506
2507 /* delete old src */
2508 remove_source (decoder);
2509
2510 decoder->pending = 0;
2511
2512 /* create and configure an element that can handle the uri */
2513 source = gen_source_element (decoder);
2514 GST_OBJECT_LOCK (decoder);
2515 if (!(decoder->source = source)) {
2516 GST_OBJECT_UNLOCK (decoder);
2517
2518 goto no_source;
2519 }
2520 GST_OBJECT_UNLOCK (decoder);
2521
2522 /* state will be merged later - if file is not found, error will be
2523 * handled by the application right after. */
2524 gst_bin_add (GST_BIN_CAST (decoder), decoder->source);
2525 /* bin now has a ref, but the local reference is not counted */
2526 g_object_unref (decoder->source);
2527
2528 /* notify of the new source used */
2529 g_object_notify (G_OBJECT (decoder), "source");
2530
2531 if (is_live_source (decoder->source))
2532 decoder->is_stream = FALSE;
2533
2534 /* remove the old decoders now, if any */
2535 remove_decoders (decoder, FALSE);
2536
2537 /* stream admin setup */
2538 decoder->streams = g_hash_table_new_full (NULL, NULL, NULL, free_stream);
2539
2540 /* see if the source element emits raw audio/video all by itself,
2541 * if so, we can create streams for the pads and be done with it.
2542 * Also check that is has source pads, if not, we assume it will
2543 * do everything itself. */
2544 if (!analyse_source (decoder, &is_raw, &have_out, &is_dynamic,
2545 decoder->need_queue))
2546 goto invalid_source;
2547
2548 if (is_raw) {
2549 GST_DEBUG_OBJECT (decoder, "Source provides all raw data");
2550 /* source provides raw data, we added the pads and we can now signal a
2551 * no_more pads because we are done. */
2552 gst_element_no_more_pads (GST_ELEMENT_CAST (decoder));
2553 do_async_done (decoder);
2554 return TRUE;
2555 }
2556 if (!have_out && !is_dynamic) {
2557 GST_DEBUG_OBJECT (decoder, "Source has no output pads");
2558 /* create a stream to indicate that this uri is handled by a self
2559 * contained element. We are now done. */
2560 add_element_stream (decoder->source, decoder);
2561 return TRUE;
2562 }
2563 if (is_dynamic) {
2564 GST_DEBUG_OBJECT (decoder, "Source has dynamic output pads");
2565 /* connect a handler for the new-pad signal */
2566 decoder->src_np_sig_id =
2567 g_signal_connect (decoder->source, "pad-added",
2568 G_CALLBACK (source_new_pad), decoder);
2569 decoder->src_nmp_sig_id =
2570 g_signal_connect (decoder->source, "no-more-pads",
2571 G_CALLBACK (source_no_more_pads), decoder);
2572 g_object_set_data (G_OBJECT (decoder->source), "pending",
2573 GINT_TO_POINTER (1));
2574 decoder->pending++;
2575 } else {
2576 if (decoder->is_stream) {
2577 GST_DEBUG_OBJECT (decoder, "Setting up streaming");
2578 /* do the stream things here */
2579 if (!setup_streaming (decoder))
2580 goto streaming_failed;
2581 } else {
2582 GstElement *dec_elem;
2583
2584 /* no streaming source, we can link now */
2585 GST_DEBUG_OBJECT (decoder, "Plugging decodebin to source");
2586
2587 dec_elem = make_decoder (decoder);
2588 if (!dec_elem)
2589 goto no_decoder;
2590
2591 if (!gst_element_link_pads (decoder->source, NULL, dec_elem, "sink"))
2592 goto could_not_link;
2593 }
2594 }
2595 return TRUE;
2596
2597 /* ERRORS */
2598 no_source:
2599 {
2600 /* error message was already posted */
2601 return FALSE;
2602 }
2603 invalid_source:
2604 {
2605 GST_ELEMENT_ERROR (decoder, CORE, FAILED,
2606 (_("Source element is invalid.")), (NULL));
2607 return FALSE;
2608 }
2609 no_decoder:
2610 {
2611 /* message was posted */
2612 return FALSE;
2613 }
2614 streaming_failed:
2615 {
2616 /* message was posted */
2617 return FALSE;
2618 }
2619 could_not_link:
2620 {
2621 GST_ELEMENT_ERROR (decoder, CORE, NEGOTIATION,
2622 (NULL), ("Can't link source to decoder element"));
2623 return FALSE;
2624 }
2625 }
2626
2627 static void
value_list_append_structure_list(GValue * list_val,GstStructure ** first,GList * structure_list)2628 value_list_append_structure_list (GValue * list_val, GstStructure ** first,
2629 GList * structure_list)
2630 {
2631 GList *l;
2632
2633 for (l = structure_list; l != NULL; l = l->next) {
2634 GValue val = { 0, };
2635
2636 if (*first == NULL)
2637 *first = gst_structure_copy ((GstStructure *) l->data);
2638
2639 g_value_init (&val, GST_TYPE_STRUCTURE);
2640 g_value_take_boxed (&val, gst_structure_copy ((GstStructure *) l->data));
2641 gst_value_list_append_value (list_val, &val);
2642 g_value_unset (&val);
2643 }
2644 }
2645
2646 /* if it's a redirect message with multiple redirect locations we might
2647 * want to pick a different 'best' location depending on the required
2648 * bitrates and the connection speed */
2649 static GstMessage *
handle_redirect_message(GstURIDecodeBin * dec,GstMessage * msg)2650 handle_redirect_message (GstURIDecodeBin * dec, GstMessage * msg)
2651 {
2652 const GValue *locations_list, *location_val;
2653 GstMessage *new_msg;
2654 GstStructure *new_structure = NULL;
2655 GList *l_good = NULL, *l_neutral = NULL, *l_bad = NULL;
2656 GValue new_list = { 0, };
2657 guint size, i;
2658 const GstStructure *structure;
2659
2660 GST_DEBUG_OBJECT (dec, "redirect message: %" GST_PTR_FORMAT, msg);
2661 GST_DEBUG_OBJECT (dec, "connection speed: %" G_GUINT64_FORMAT,
2662 dec->connection_speed);
2663
2664 structure = gst_message_get_structure (msg);
2665 if (dec->connection_speed == 0 || structure == NULL)
2666 return msg;
2667
2668 locations_list = gst_structure_get_value (structure, "locations");
2669 if (locations_list == NULL)
2670 return msg;
2671
2672 size = gst_value_list_get_size (locations_list);
2673 if (size < 2)
2674 return msg;
2675
2676 /* maintain existing order as much as possible, just sort references
2677 * with too high a bitrate to the end (the assumption being that if
2678 * bitrates are given they are given for all interesting streams and
2679 * that the you-need-at-least-version-xyz redirect has the same bitrate
2680 * as the lowest referenced redirect alternative) */
2681 for (i = 0; i < size; ++i) {
2682 const GstStructure *s;
2683 gint bitrate = 0;
2684
2685 location_val = gst_value_list_get_value (locations_list, i);
2686 s = (const GstStructure *) g_value_get_boxed (location_val);
2687 if (!gst_structure_get_int (s, "minimum-bitrate", &bitrate) || bitrate <= 0) {
2688 GST_DEBUG_OBJECT (dec, "no bitrate: %" GST_PTR_FORMAT, s);
2689 l_neutral = g_list_append (l_neutral, (gpointer) s);
2690 } else if (bitrate > dec->connection_speed) {
2691 GST_DEBUG_OBJECT (dec, "bitrate too high: %" GST_PTR_FORMAT, s);
2692 l_bad = g_list_append (l_bad, (gpointer) s);
2693 } else if (bitrate <= dec->connection_speed) {
2694 GST_DEBUG_OBJECT (dec, "bitrate OK: %" GST_PTR_FORMAT, s);
2695 l_good = g_list_append (l_good, (gpointer) s);
2696 }
2697 }
2698
2699 g_value_init (&new_list, GST_TYPE_LIST);
2700 value_list_append_structure_list (&new_list, &new_structure, l_good);
2701 value_list_append_structure_list (&new_list, &new_structure, l_neutral);
2702 value_list_append_structure_list (&new_list, &new_structure, l_bad);
2703 gst_structure_take_value (new_structure, "locations", &new_list);
2704
2705 g_list_free (l_good);
2706 g_list_free (l_neutral);
2707 g_list_free (l_bad);
2708
2709 new_msg = gst_message_new_element (msg->src, new_structure);
2710 gst_message_unref (msg);
2711
2712 GST_DEBUG_OBJECT (dec, "new redirect message: %" GST_PTR_FORMAT, new_msg);
2713 return new_msg;
2714 }
2715
2716 static GstMessage *
make_topology_message(GstURIDecodeBin * dec)2717 make_topology_message (GstURIDecodeBin * dec)
2718 {
2719 GSList *tmp;
2720 GstStructure *aggregated_topology = NULL;
2721 GValue list = G_VALUE_INIT;
2722 GstCaps *caps = NULL;
2723 gchar *name, *proto;
2724
2725 aggregated_topology = gst_structure_new_empty ("stream-topology");
2726 g_value_init (&list, GST_TYPE_LIST);
2727
2728 for (tmp = dec->decodebins; tmp; tmp = tmp->next) {
2729 GValue item = G_VALUE_INIT;
2730 GstStructure *dec_topology =
2731 g_object_get_data (G_OBJECT (tmp->data), "uridecodebin-topology");
2732
2733 g_value_init (&item, GST_TYPE_STRUCTURE);
2734 gst_value_set_structure (&item, dec_topology);
2735 gst_value_list_append_and_take_value (&list, &item);
2736 }
2737
2738 gst_structure_take_value (aggregated_topology, "next", &list);
2739
2740 /* This is a bit wacky, but that's the best way I can find to express
2741 * uridecodebin 'caps' as subsequently shown by gst-discoverer */
2742 proto = gst_uri_get_protocol (dec->uri);
2743 name = g_strdup_printf ("application/%s", proto);
2744 g_free (proto);
2745
2746 caps = gst_caps_new_empty_simple (name);
2747 g_free (name);
2748
2749 gst_structure_set (aggregated_topology, "caps", GST_TYPE_CAPS, caps, NULL);
2750 gst_caps_unref (caps);
2751
2752 return gst_message_new_element (GST_OBJECT (dec), aggregated_topology);
2753 }
2754
2755 static void
check_topology(gpointer data,gpointer user_data)2756 check_topology (gpointer data, gpointer user_data)
2757 {
2758 gboolean *has_topo = user_data;
2759
2760 if (g_object_get_data (data, "uridecodebin-topology") == NULL)
2761 *has_topo = FALSE;
2762 }
2763
2764 static void
handle_message(GstBin * bin,GstMessage * msg)2765 handle_message (GstBin * bin, GstMessage * msg)
2766 {
2767 GstURIDecodeBin *dec = GST_URI_DECODE_BIN (bin);
2768
2769 switch (GST_MESSAGE_TYPE (msg)) {
2770 case GST_MESSAGE_ELEMENT:{
2771
2772 if (gst_message_has_name (msg, "stream-topology")) {
2773 GstElement *element = GST_ELEMENT (GST_MESSAGE_SRC (msg));
2774 gboolean has_all_topo = TRUE;
2775
2776 if (dec->pending || (dec->decodebins && dec->decodebins->next != NULL)) {
2777 const GstStructure *structure;
2778
2779 /* If there is only one, just let it through, so this case is if
2780 * there is more than one.
2781 */
2782
2783 structure = gst_message_get_structure (msg);
2784
2785 g_object_set_data_full (G_OBJECT (element), "uridecodebin-topology",
2786 gst_structure_copy (structure),
2787 (GDestroyNotify) gst_structure_free);
2788
2789 gst_message_unref (msg);
2790 msg = NULL;
2791
2792 g_slist_foreach (dec->decodebins, check_topology, &has_all_topo);
2793 if (has_all_topo)
2794 msg = make_topology_message (dec);
2795 }
2796 } else if (gst_message_has_name (msg, "redirect")) {
2797 /* sort redirect messages based on the connection speed. This simplifies
2798 * the user of this element as it can in most cases just pick the first item
2799 * of the sorted list as a good redirection candidate. It can of course
2800 * choose something else from the list if it has a better way. */
2801 msg = handle_redirect_message (dec, msg);
2802 }
2803 break;
2804 }
2805 case GST_MESSAGE_ERROR:{
2806 GError *err = NULL;
2807
2808 /* Filter out missing plugin error messages from the decodebins. Only if
2809 * all decodebins exposed no streams we will report a missing plugin
2810 * error from no_more_pads_full()
2811 */
2812 gst_message_parse_error (msg, &err, NULL);
2813 if (g_error_matches (err, GST_CORE_ERROR, GST_CORE_ERROR_MISSING_PLUGIN)
2814 || g_error_matches (err, GST_STREAM_ERROR,
2815 GST_STREAM_ERROR_CODEC_NOT_FOUND)) {
2816 dec->missing_plugin_errors =
2817 g_list_prepend (dec->missing_plugin_errors, gst_message_ref (msg));
2818
2819 no_more_pads_full (GST_ELEMENT (GST_MESSAGE_SRC (msg)), FALSE,
2820 GST_URI_DECODE_BIN (bin));
2821 gst_message_unref (msg);
2822 msg = NULL;
2823 }
2824 g_clear_error (&err);
2825 break;
2826 }
2827 default:
2828 break;
2829 }
2830
2831 if (msg)
2832 GST_BIN_CLASS (parent_class)->handle_message (bin, msg);
2833 }
2834
2835 /* generic struct passed to all query fold methods
2836 * FIXME, move to core.
2837 */
2838 typedef struct
2839 {
2840 GstQuery *query;
2841 gint64 min;
2842 gint64 max;
2843 gboolean seekable;
2844 gboolean live;
2845 } QueryFold;
2846
2847 typedef void (*QueryInitFunction) (GstURIDecodeBin * dec, QueryFold * fold);
2848 typedef void (*QueryDoneFunction) (GstURIDecodeBin * dec, QueryFold * fold);
2849
2850 /* for duration/position we collect all durations/positions and take
2851 * the MAX of all valid results */
2852 static void
decoder_query_init(GstURIDecodeBin * dec,QueryFold * fold)2853 decoder_query_init (GstURIDecodeBin * dec, QueryFold * fold)
2854 {
2855 fold->min = 0;
2856 fold->max = -1;
2857 fold->seekable = TRUE;
2858 fold->live = 0;
2859 }
2860
2861 static gboolean
decoder_query_duration_fold(const GValue * item,GValue * ret,QueryFold * fold)2862 decoder_query_duration_fold (const GValue * item, GValue * ret,
2863 QueryFold * fold)
2864 {
2865 GstPad *pad = g_value_get_object (item);
2866
2867 if (gst_pad_query (pad, fold->query)) {
2868 gint64 duration;
2869
2870 g_value_set_boolean (ret, TRUE);
2871
2872 gst_query_parse_duration (fold->query, NULL, &duration);
2873
2874 GST_DEBUG_OBJECT (pad, "got duration %" G_GINT64_FORMAT, duration);
2875
2876 if (duration > fold->max)
2877 fold->max = duration;
2878 }
2879 return TRUE;
2880 }
2881
2882 static void
decoder_query_duration_done(GstURIDecodeBin * dec,QueryFold * fold)2883 decoder_query_duration_done (GstURIDecodeBin * dec, QueryFold * fold)
2884 {
2885 GstFormat format;
2886
2887 gst_query_parse_duration (fold->query, &format, NULL);
2888 /* store max in query result */
2889 gst_query_set_duration (fold->query, format, fold->max);
2890
2891 GST_DEBUG ("max duration %" G_GINT64_FORMAT, fold->max);
2892 }
2893
2894 static gboolean
decoder_query_position_fold(const GValue * item,GValue * ret,QueryFold * fold)2895 decoder_query_position_fold (const GValue * item, GValue * ret,
2896 QueryFold * fold)
2897 {
2898 GstPad *pad = g_value_get_object (item);
2899
2900 if (gst_pad_query (pad, fold->query)) {
2901 gint64 position;
2902
2903 g_value_set_boolean (ret, TRUE);
2904
2905 gst_query_parse_position (fold->query, NULL, &position);
2906
2907 GST_DEBUG_OBJECT (pad, "got position %" G_GINT64_FORMAT, position);
2908
2909 if (position > fold->max)
2910 fold->max = position;
2911 }
2912
2913 return TRUE;
2914 }
2915
2916 static void
decoder_query_position_done(GstURIDecodeBin * dec,QueryFold * fold)2917 decoder_query_position_done (GstURIDecodeBin * dec, QueryFold * fold)
2918 {
2919 GstFormat format;
2920
2921 gst_query_parse_position (fold->query, &format, NULL);
2922 /* store max in query result */
2923 gst_query_set_position (fold->query, format, fold->max);
2924
2925 GST_DEBUG_OBJECT (dec, "max position %" G_GINT64_FORMAT, fold->max);
2926 }
2927
2928 static gboolean
decoder_query_latency_fold(const GValue * item,GValue * ret,QueryFold * fold)2929 decoder_query_latency_fold (const GValue * item, GValue * ret, QueryFold * fold)
2930 {
2931 GstPad *pad = g_value_get_object (item);
2932
2933 if (gst_pad_query (pad, fold->query)) {
2934 GstClockTime min, max;
2935 gboolean live;
2936
2937 gst_query_parse_latency (fold->query, &live, &min, &max);
2938
2939 GST_DEBUG_OBJECT (pad,
2940 "got latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
2941 ", live %d", GST_TIME_ARGS (min), GST_TIME_ARGS (max), live);
2942
2943 if (live) {
2944 /* for the combined latency we collect the MAX of all min latencies and
2945 * the MIN of all max latencies */
2946 if (min > fold->min)
2947 fold->min = min;
2948 if (fold->max == -1)
2949 fold->max = max;
2950 else if (max < fold->max)
2951 fold->max = max;
2952
2953 fold->live = TRUE;
2954 }
2955 } else {
2956 GST_LOG_OBJECT (pad, "latency query failed");
2957 g_value_set_boolean (ret, FALSE);
2958 }
2959
2960 return TRUE;
2961 }
2962
2963 static void
decoder_query_latency_done(GstURIDecodeBin * dec,QueryFold * fold)2964 decoder_query_latency_done (GstURIDecodeBin * dec, QueryFold * fold)
2965 {
2966 /* store max in query result */
2967 gst_query_set_latency (fold->query, fold->live, fold->min, fold->max);
2968
2969 GST_DEBUG_OBJECT (dec,
2970 "latency min %" GST_TIME_FORMAT ", max %" GST_TIME_FORMAT
2971 ", live %d", GST_TIME_ARGS (fold->min), GST_TIME_ARGS (fold->max),
2972 fold->live);
2973 }
2974
2975 /* we are seekable if all srcpads are seekable */
2976 static gboolean
decoder_query_seeking_fold(const GValue * item,GValue * ret,QueryFold * fold)2977 decoder_query_seeking_fold (const GValue * item, GValue * ret, QueryFold * fold)
2978 {
2979 GstPad *pad = g_value_get_object (item);
2980
2981 if (gst_pad_query (pad, fold->query)) {
2982 gboolean seekable;
2983
2984 g_value_set_boolean (ret, TRUE);
2985 gst_query_parse_seeking (fold->query, NULL, &seekable, NULL, NULL);
2986
2987 GST_DEBUG_OBJECT (pad, "got seekable %d", seekable);
2988
2989 if (fold->seekable)
2990 fold->seekable = seekable;
2991 }
2992
2993 return TRUE;
2994 }
2995
2996 static void
decoder_query_seeking_done(GstURIDecodeBin * dec,QueryFold * fold)2997 decoder_query_seeking_done (GstURIDecodeBin * dec, QueryFold * fold)
2998 {
2999 GstFormat format;
3000
3001 gst_query_parse_seeking (fold->query, &format, NULL, NULL, NULL);
3002 gst_query_set_seeking (fold->query, format, fold->seekable, 0, -1);
3003
3004 GST_DEBUG_OBJECT (dec, "seekable %d", fold->seekable);
3005 }
3006
3007 /* generic fold, return first valid result */
3008 static gboolean
decoder_query_generic_fold(const GValue * item,GValue * ret,QueryFold * fold)3009 decoder_query_generic_fold (const GValue * item, GValue * ret, QueryFold * fold)
3010 {
3011 GstPad *pad = g_value_get_object (item);
3012 gboolean res;
3013
3014 if ((res = gst_pad_query (pad, fold->query))) {
3015 g_value_set_boolean (ret, TRUE);
3016 GST_DEBUG_OBJECT (pad, "answered query %p", fold->query);
3017 }
3018
3019 /* and stop as soon as we have a valid result */
3020 return !res;
3021 }
3022
3023
3024 /* we're a bin, the default query handler iterates sink elements, which we don't
3025 * have normally. We should just query all source pads.
3026 */
3027 static gboolean
gst_uri_decode_bin_query(GstElement * element,GstQuery * query)3028 gst_uri_decode_bin_query (GstElement * element, GstQuery * query)
3029 {
3030 GstURIDecodeBin *decoder;
3031 gboolean res = FALSE;
3032 GstIterator *iter;
3033 GstIteratorFoldFunction fold_func;
3034 QueryInitFunction fold_init = NULL;
3035 QueryDoneFunction fold_done = NULL;
3036 QueryFold fold_data;
3037 GValue ret = { 0 };
3038 gboolean default_ret = FALSE;
3039
3040 decoder = GST_URI_DECODE_BIN (element);
3041
3042 switch (GST_QUERY_TYPE (query)) {
3043 case GST_QUERY_DURATION:
3044 /* iterate and collect durations */
3045 fold_func = (GstIteratorFoldFunction) decoder_query_duration_fold;
3046 fold_init = decoder_query_init;
3047 fold_done = decoder_query_duration_done;
3048 break;
3049 case GST_QUERY_POSITION:
3050 /* iterate and collect durations */
3051 fold_func = (GstIteratorFoldFunction) decoder_query_position_fold;
3052 fold_init = decoder_query_init;
3053 fold_done = decoder_query_position_done;
3054 break;
3055 case GST_QUERY_LATENCY:
3056 /* iterate and collect durations */
3057 fold_func = (GstIteratorFoldFunction) decoder_query_latency_fold;
3058 fold_init = decoder_query_init;
3059 fold_done = decoder_query_latency_done;
3060 default_ret = TRUE;
3061 break;
3062 case GST_QUERY_SEEKING:
3063 /* iterate and collect durations */
3064 fold_func = (GstIteratorFoldFunction) decoder_query_seeking_fold;
3065 fold_init = decoder_query_init;
3066 fold_done = decoder_query_seeking_done;
3067 break;
3068 default:
3069 fold_func = (GstIteratorFoldFunction) decoder_query_generic_fold;
3070 break;
3071 }
3072
3073 fold_data.query = query;
3074
3075 g_value_init (&ret, G_TYPE_BOOLEAN);
3076 g_value_set_boolean (&ret, default_ret);
3077
3078 iter = gst_element_iterate_src_pads (element);
3079 GST_DEBUG_OBJECT (element, "Sending query %p (type %d) to src pads",
3080 query, GST_QUERY_TYPE (query));
3081
3082 if (fold_init)
3083 fold_init (decoder, &fold_data);
3084
3085 while (TRUE) {
3086 GstIteratorResult ires;
3087
3088 ires = gst_iterator_fold (iter, fold_func, &ret, &fold_data);
3089
3090 switch (ires) {
3091 case GST_ITERATOR_RESYNC:
3092 gst_iterator_resync (iter);
3093 if (fold_init)
3094 fold_init (decoder, &fold_data);
3095 g_value_set_boolean (&ret, default_ret);
3096 break;
3097 case GST_ITERATOR_OK:
3098 case GST_ITERATOR_DONE:
3099 res = g_value_get_boolean (&ret);
3100 if (fold_done != NULL && res)
3101 fold_done (decoder, &fold_data);
3102 goto done;
3103 default:
3104 res = FALSE;
3105 goto done;
3106 }
3107 }
3108 done:
3109 gst_iterator_free (iter);
3110
3111 return res;
3112 }
3113
3114 static GstStateChangeReturn
gst_uri_decode_bin_change_state(GstElement * element,GstStateChange transition)3115 gst_uri_decode_bin_change_state (GstElement * element,
3116 GstStateChange transition)
3117 {
3118 GstStateChangeReturn ret;
3119 GstURIDecodeBin *decoder;
3120
3121 decoder = GST_URI_DECODE_BIN (element);
3122
3123 switch (transition) {
3124 case GST_STATE_CHANGE_READY_TO_PAUSED:
3125 do_async_start (decoder);
3126 break;
3127 default:
3128 break;
3129 }
3130
3131 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3132 if (ret == GST_STATE_CHANGE_FAILURE)
3133 goto setup_failed;
3134
3135 switch (transition) {
3136 case GST_STATE_CHANGE_READY_TO_PAUSED:
3137 GST_DEBUG ("ready to paused");
3138 if (!setup_source (decoder))
3139 goto source_failed;
3140
3141 ret = GST_STATE_CHANGE_ASYNC;
3142
3143 /* And now sync the states of everything we added */
3144 g_slist_foreach (decoder->decodebins,
3145 (GFunc) gst_element_sync_state_with_parent, NULL);
3146 if (decoder->typefind)
3147 ret = gst_element_set_state (decoder->typefind, GST_STATE_PAUSED);
3148 if (ret == GST_STATE_CHANGE_FAILURE)
3149 goto setup_failed;
3150 if (decoder->queue)
3151 ret = gst_element_set_state (decoder->queue, GST_STATE_PAUSED);
3152 if (ret == GST_STATE_CHANGE_FAILURE)
3153 goto setup_failed;
3154 if (decoder->source)
3155 ret = gst_element_set_state (decoder->source, GST_STATE_PAUSED);
3156 if (ret == GST_STATE_CHANGE_FAILURE)
3157 goto setup_failed;
3158 if (ret == GST_STATE_CHANGE_SUCCESS)
3159 ret = GST_STATE_CHANGE_ASYNC;
3160
3161 break;
3162 case GST_STATE_CHANGE_PAUSED_TO_READY:
3163 GST_DEBUG ("paused to ready");
3164 remove_decoders (decoder, FALSE);
3165 remove_source (decoder);
3166 do_async_done (decoder);
3167 g_list_free_full (decoder->missing_plugin_errors,
3168 (GDestroyNotify) gst_message_unref);
3169 decoder->missing_plugin_errors = NULL;
3170 break;
3171 case GST_STATE_CHANGE_READY_TO_NULL:
3172 GST_DEBUG ("ready to null");
3173 remove_decoders (decoder, TRUE);
3174 remove_source (decoder);
3175 break;
3176 default:
3177 break;
3178 }
3179
3180 if (ret == GST_STATE_CHANGE_NO_PREROLL)
3181 do_async_done (decoder);
3182
3183 return ret;
3184
3185 /* ERRORS */
3186 source_failed:
3187 {
3188 do_async_done (decoder);
3189 return GST_STATE_CHANGE_FAILURE;
3190 }
3191 setup_failed:
3192 {
3193 /* clean up leftover groups */
3194 do_async_done (decoder);
3195 return GST_STATE_CHANGE_FAILURE;
3196 }
3197 }
3198