• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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