• 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 /* TODO/FIXME:
21  *
22  * * BUFFERING MESSAGES
23  * ** How/Where do we deal with buffering messages from a new/prerolling
24  *    source ? Ideally we want to re-use the same sourcebin ?
25  * ** Remember last buffering messages per source handler, if the SourceEntry
26  *    group_id is the one being currently outputted on the source ghostpads,
27  *    post the (last) buffering messages.
28  *    If no group_id is being outputted (still prerolling), then output
29  *    the messages directly
30  *
31  * * ASYNC HANDLING
32  * ** URIDECODEBIN3 is not async-aware.
33  *
34  * * GAPLESS HANDLING
35  * ** Correlate group_id and URI to know when/which stream is being outputted/started
36  */
37 
38 /**
39  * SECTION:element-uridecodebin3
40  * @title: uridecodebin3
41  *
42  * Decodes data from a URI into raw media. It selects a source element that can
43  * handle the given #GstURIDecodeBin3:uri scheme and connects it to a decodebin.
44  */
45 
46 #ifdef HAVE_CONFIG_H
47 #  include "config.h"
48 #endif
49 
50 #include <string.h>
51 
52 #include <gst/gst.h>
53 #include <gst/gst-i18n-plugin.h>
54 #include <gst/pbutils/missing-plugins.h>
55 
56 #include "gstplay-enum.h"
57 #include "gstrawcaps.h"
58 #include "gstplaybackelements.h"
59 #include "gstplaybackutils.h"
60 
61 #define GST_TYPE_URI_DECODE_BIN3 \
62   (gst_uri_decode_bin3_get_type())
63 #define GST_URI_DECODE_BIN3(obj) \
64   (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_URI_DECODE_BIN3,GstURIDecodeBin3))
65 #define GST_URI_DECODE_BIN3_CLASS(klass) \
66   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_URI_DECODE_BIN3,GstURIDecodeBin3Class))
67 #define GST_IS_URI_DECODE_BIN3(obj) \
68   (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_URI_DECODE_BIN3))
69 #define GST_IS_URI_DECODE_BIN3_CLASS(klass) \
70   (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_URI_DECODE_BIN3))
71 #define GST_URI_DECODE_BIN3_CAST(obj) ((GstURIDecodeBin3 *) (obj))
72 
73 typedef struct _GstSourceGroup GstSourceGroup;
74 typedef struct _GstURIDecodeBin3 GstURIDecodeBin3;
75 typedef struct _GstURIDecodeBin3Class GstURIDecodeBin3Class;
76 
77 #define GST_URI_DECODE_BIN3_LOCK(dec) (g_mutex_lock(&((GstURIDecodeBin3*)(dec))->lock))
78 #define GST_URI_DECODE_BIN3_UNLOCK(dec) (g_mutex_unlock(&((GstURIDecodeBin3*)(dec))->lock))
79 
80 typedef struct _GstPlayItem GstPlayItem;
81 typedef struct _GstSourceItem GstSourceItem;
82 typedef struct _GstSourceHandler GstSourceHandler;
83 typedef struct _OutputPad OutputPad;
84 
85 /* A structure describing a play item, which travels through the elements
86  * over time. */
87 struct _GstPlayItem
88 {
89   GstURIDecodeBin3 *uridecodebin;
90 
91   /* Main URI */
92   GstSourceItem *main_item;
93 
94   /* Auxiliary URI */
95   /* FIXME : Replace by a list later */
96   GstSourceItem *sub_item;
97 
98   /* The group_id used to identify this play item via STREAM_START events
99    * This is the group_id which will be used externally (i.e. rewritten
100    * to outgoing STREAM_START events and in emitted signals).
101    * The urisourcebin-specific group_id is located in GstSourceItem */
102   guint group_id;
103 
104   /* Is this play item the one being currently outputted by decodebin3
105    * and on our source ghostpads */
106   gboolean currently_outputted;
107 };
108 
109 struct _GstSourceItem
110 {
111   /* The GstPlayItem to which this GstSourceItem belongs to */
112   GstPlayItem *play_item;
113 
114   gchar *uri;
115 
116   /* The urisourcebin controlling this uri
117    * Can be NULL */
118   GstSourceHandler *handler;
119 
120   /* Last buffering information */
121   gint last_perc;
122   GstMessage *last_buffering_message;
123 
124   /* The groupid created by urisourcebin for this uri */
125   guint internal_groupid;
126 
127   /* FIXME : Add tag lists and other uri-specific items here ? */
128 };
129 
130 /* Structure wrapping everything related to a urisourcebin */
131 struct _GstSourceHandler
132 {
133   GstURIDecodeBin3 *uridecodebin;
134 
135   GstElement *urisourcebin;
136 
137   /* Signal handlers */
138   gulong pad_added_id;
139   gulong pad_removed_id;
140   gulong source_setup_id;
141   gulong about_to_finish_id;
142 
143   /* TRUE if the controlled urisourcebin was added to uridecodebin */
144   gboolean active;
145 
146   /* whether urisourcebin is drained or not.
147    * Reset if/when setting a new URI */
148   gboolean drained;
149 
150   /* Whether urisourcebin posted EOS on all pads and
151    * there is no pending entry */
152   gboolean is_eos;
153 
154   /* TRUE if the urisourcebin handles main item */
155   gboolean is_main_source;
156 
157   /* buffering message stored for after switching */
158   GstMessage *pending_buffering_msg;
159 };
160 
161 /* Controls an output source pad */
162 struct _OutputPad
163 {
164   GstURIDecodeBin3 *uridecodebin;
165 
166   GstPad *target_pad;
167   GstPad *ghost_pad;
168 
169   /* Downstream event probe id */
170   gulong probe_id;
171 
172   /* TRUE if the pad saw EOS. Reset to FALSE on STREAM_START */
173   gboolean is_eos;
174 
175   /* The last seen (i.e. current) group_id
176    * Can be (guint)-1 if no group_id was seen yet */
177   guint current_group_id;
178 };
179 
180 /**
181  * GstURIDecodeBin3
182  *
183  * uridecodebin3 element struct
184  */
185 struct _GstURIDecodeBin3
186 {
187   GstBin parent_instance;
188 
189   GMutex lock;                  /* lock for constructing */
190 
191   /* Properties */
192   GstElement *source;
193   guint64 connection_speed;     /* In bits/sec (0 = unknown) */
194   GstCaps *caps;
195   guint64 buffer_duration;      /* When buffering, buffer duration (ns) */
196   guint buffer_size;            /* When buffering, buffer size (bytes) */
197   gboolean download;
198   gboolean use_buffering;
199   guint64 ring_buffer_max_size;
200 
201   GList *play_items;            /* List of GstPlayItem ordered by time of
202                                  * creation. Head of list is therefore the
203                                  * current (or pending if initial) one being
204                                  * outputted */
205   GstPlayItem *current;         /* Currently active GstPlayItem. Can be NULL
206                                  * if no entry is active yet (i.e. no source
207                                  * pads) */
208 
209   /* sources.
210    * FIXME : Replace by a more modular system later on */
211   GstSourceHandler *main_handler;
212   GstSourceHandler *sub_handler;
213 
214   /* URI handling
215    * FIXME : Switch to a playlist-based API */
216   gchar *uri;
217   gboolean uri_changed;         /* TRUE if uri changed */
218   gchar *suburi;
219   gboolean suburi_changed;      /* TRUE if suburi changed */
220 
221   /* A global decodebin3 that's used to actually do decoding */
222   GstElement *decodebin;
223 
224   /* db3 signals */
225   gulong db_pad_added_id;
226   gulong db_pad_removed_id;
227   gulong db_select_stream_id;
228   gulong db_about_to_finish_id;
229 
230   GList *output_pads;           /* List of OutputPad */
231 
232   GList *source_handlers;       /* List of SourceHandler */
233 
234   /* Whether we already signalled about-to-finish or not
235    * FIXME: Track this by group-id ! */
236   gboolean posted_about_to_finish;
237 };
238 
239 static gint
gst_uridecodebin3_select_stream(GstURIDecodeBin3 * dbin,GstStreamCollection * collection,GstStream * stream)240 gst_uridecodebin3_select_stream (GstURIDecodeBin3 * dbin,
241     GstStreamCollection * collection, GstStream * stream)
242 {
243   GST_LOG_OBJECT (dbin, "default select-stream, returning -1");
244 
245   return -1;
246 }
247 
248 struct _GstURIDecodeBin3Class
249 {
250   GstBinClass parent_class;
251 
252     gint (*select_stream) (GstURIDecodeBin3 * dbin,
253       GstStreamCollection * collection, GstStream * stream);
254 };
255 
256 GST_DEBUG_CATEGORY_STATIC (gst_uri_decode_bin3_debug);
257 #define GST_CAT_DEFAULT gst_uri_decode_bin3_debug
258 
259 /* signals */
260 enum
261 {
262   SIGNAL_SELECT_STREAM,
263   SIGNAL_SOURCE_SETUP,
264   SIGNAL_ABOUT_TO_FINISH,
265   LAST_SIGNAL
266 };
267 
268 #if 0
269 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw(ANY)");
270 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw(ANY)");
271 #endif
272 
273 /* properties */
274 #define DEFAULT_PROP_URI            NULL
275 #define DEFAULT_PROP_SUBURI            NULL
276 #define DEFAULT_CONNECTION_SPEED    0
277 #define DEFAULT_CAPS                (gst_static_caps_get (&default_raw_caps))
278 #define DEFAULT_BUFFER_DURATION     -1
279 #define DEFAULT_BUFFER_SIZE         -1
280 #define DEFAULT_DOWNLOAD            FALSE
281 #define DEFAULT_USE_BUFFERING       FALSE
282 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
283 
284 enum
285 {
286   PROP_0,
287   PROP_URI,
288   PROP_CURRENT_URI,
289   PROP_SUBURI,
290   PROP_CURRENT_SUBURI,
291   PROP_SOURCE,
292   PROP_CONNECTION_SPEED,
293   PROP_BUFFER_SIZE,
294   PROP_BUFFER_DURATION,
295   PROP_DOWNLOAD,
296   PROP_USE_BUFFERING,
297   PROP_RING_BUFFER_MAX_SIZE,
298   PROP_CAPS
299 };
300 
301 static guint gst_uri_decode_bin3_signals[LAST_SIGNAL] = { 0 };
302 
303 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
304 
305 static GstStaticPadTemplate video_src_template =
306 GST_STATIC_PAD_TEMPLATE ("video_%u",
307     GST_PAD_SRC,
308     GST_PAD_SOMETIMES,
309     GST_STATIC_CAPS_ANY);
310 
311 static GstStaticPadTemplate audio_src_template =
312 GST_STATIC_PAD_TEMPLATE ("audio_%u",
313     GST_PAD_SRC,
314     GST_PAD_SOMETIMES,
315     GST_STATIC_CAPS_ANY);
316 
317 static GstStaticPadTemplate text_src_template =
318 GST_STATIC_PAD_TEMPLATE ("text_%u",
319     GST_PAD_SRC,
320     GST_PAD_SOMETIMES,
321     GST_STATIC_CAPS_ANY);
322 
323 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
324     GST_PAD_SRC,
325     GST_PAD_SOMETIMES,
326     GST_STATIC_CAPS_ANY);
327 
328 GType gst_uri_decode_bin3_get_type (void);
329 #define gst_uri_decode_bin3_parent_class parent_class
330 G_DEFINE_TYPE (GstURIDecodeBin3, gst_uri_decode_bin3, GST_TYPE_BIN);
331 
332 #define _do_init \
333     GST_DEBUG_CATEGORY_INIT (gst_uri_decode_bin3_debug, "uridecodebin3", 0, "URI decoder element 3"); \
334     playback_element_init (plugin);
335 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (uridecodebin3, "uridecodebin3",
336     GST_RANK_NONE, GST_TYPE_URI_DECODE_BIN3, _do_init);
337 
338 #define REMOVE_SIGNAL(obj,id)            \
339 if (id) {                                \
340   g_signal_handler_disconnect (obj, id); \
341   id = 0;                                \
342 }
343 
344 static void gst_uri_decode_bin3_set_property (GObject * object, guint prop_id,
345     const GValue * value, GParamSpec * pspec);
346 static void gst_uri_decode_bin3_get_property (GObject * object, guint prop_id,
347     GValue * value, GParamSpec * pspec);
348 static void gst_uri_decode_bin3_finalize (GObject * obj);
349 static GstSourceHandler *new_source_handler (GstURIDecodeBin3 * uridecodebin,
350     gboolean is_main);
351 
352 static GstStateChangeReturn gst_uri_decode_bin3_change_state (GstElement *
353     element, GstStateChange transition);
354 static gboolean gst_uri_decodebin3_send_event (GstElement * element,
355     GstEvent * event);
356 
357 static gboolean
_gst_int_accumulator(GSignalInvocationHint * ihint,GValue * return_accu,const GValue * handler_return,gpointer dummy)358 _gst_int_accumulator (GSignalInvocationHint * ihint,
359     GValue * return_accu, const GValue * handler_return, gpointer dummy)
360 {
361   gint res = g_value_get_int (handler_return);
362 
363   g_value_set_int (return_accu, res);
364 
365   if (res == -1)
366     return TRUE;
367 
368   return FALSE;
369 }
370 
371 
372 static void
gst_uri_decode_bin3_class_init(GstURIDecodeBin3Class * klass)373 gst_uri_decode_bin3_class_init (GstURIDecodeBin3Class * klass)
374 {
375   GObjectClass *gobject_class;
376   GstElementClass *gstelement_class;
377 
378   gobject_class = G_OBJECT_CLASS (klass);
379   gstelement_class = GST_ELEMENT_CLASS (klass);
380 
381   gobject_class->set_property = gst_uri_decode_bin3_set_property;
382   gobject_class->get_property = gst_uri_decode_bin3_get_property;
383   gobject_class->finalize = gst_uri_decode_bin3_finalize;
384 
385   g_object_class_install_property (gobject_class, PROP_URI,
386       g_param_spec_string ("uri", "URI", "URI to decode",
387           DEFAULT_PROP_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
388 
389   g_object_class_install_property (gobject_class, PROP_CURRENT_URI,
390       g_param_spec_string ("current-uri", "Current URI",
391           "The currently playing URI", NULL,
392           G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
393 
394   g_object_class_install_property (gobject_class, PROP_SUBURI,
395       g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
396           NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
397 
398   g_object_class_install_property (gobject_class, PROP_CURRENT_SUBURI,
399       g_param_spec_string ("current-suburi", "Current .sub-URI",
400           "The currently playing URI of a subtitle",
401           NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
402 
403   g_object_class_install_property (gobject_class, PROP_SOURCE,
404       g_param_spec_object ("source", "Source", "Source object used",
405           GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
406 
407   g_object_class_install_property (gobject_class, PROP_CONNECTION_SPEED,
408       g_param_spec_uint64 ("connection-speed", "Connection Speed",
409           "Network connection speed in kbps (0 = unknown)",
410           0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
411           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
412 
413   g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
414       g_param_spec_int ("buffer-size", "Buffer size (bytes)",
415           "Buffer size when buffering streams (-1 default value)",
416           -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
417           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
418 
419   g_object_class_install_property (gobject_class, PROP_BUFFER_DURATION,
420       g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
421           "Buffer duration when buffering streams (-1 default value)",
422           -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
423           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
424 
425   /**
426    * GstURIDecodeBin3::download:
427    *
428    * For certain media type, enable download buffering.
429    */
430   g_object_class_install_property (gobject_class, PROP_DOWNLOAD,
431       g_param_spec_boolean ("download", "Download",
432           "Attempt download buffering when buffering network streams",
433           DEFAULT_DOWNLOAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
434   /**
435    * GstURIDecodeBin3::use-buffering:
436    *
437    * Emit BUFFERING messages based on low-/high-percent thresholds of the
438    * demuxed or parsed data.
439    * When download buffering is activated and used for the current media
440    * type, this property does nothing. Otherwise perform buffering on the
441    * demuxed or parsed media.
442    */
443   g_object_class_install_property (gobject_class, PROP_USE_BUFFERING,
444       g_param_spec_boolean ("use-buffering", "Use Buffering",
445           "Perform buffering on demuxed/parsed media",
446           DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
447 
448   /**
449    * GstURIDecodeBin3::ring-buffer-max-size
450    *
451    * The maximum size of the ring buffer in kilobytes. If set to 0, the ring
452    * buffer is disabled. Default is 0.
453    */
454   g_object_class_install_property (gobject_class, PROP_RING_BUFFER_MAX_SIZE,
455       g_param_spec_uint64 ("ring-buffer-max-size",
456           "Max. ring buffer size (bytes)",
457           "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
458           0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
459           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
460 
461   g_object_class_install_property (gobject_class, PROP_CAPS,
462       g_param_spec_boxed ("caps", "Caps",
463           "The caps on which to stop decoding. (NULL = default)",
464           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
465 
466   /**
467    * GstURIDecodebin3::select-stream
468    * @decodebin: a #GstURIDecodebin3
469    * @collection: a #GstStreamCollection
470    * @stream: a #GstStream
471    *
472    * This signal is emitted whenever @decodebin needs to decide whether
473    * to expose a @stream of a given @collection.
474    *
475    * Note that the prefered way to select streams is to listen to
476    * GST_MESSAGE_STREAM_COLLECTION on the bus and send a
477    * GST_EVENT_SELECT_STREAMS with the streams the user wants.
478    *
479    * Returns: 1 if the stream should be selected, 0 if it shouldn't be selected.
480    * A value of -1 (default) lets @decodebin decide what to do with the stream.
481    * */
482   gst_uri_decode_bin3_signals[SIGNAL_SELECT_STREAM] =
483       g_signal_new ("select-stream", G_TYPE_FROM_CLASS (klass),
484       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBin3Class, select_stream),
485       _gst_int_accumulator, NULL, NULL, G_TYPE_INT, 2,
486       GST_TYPE_STREAM_COLLECTION, GST_TYPE_STREAM);
487 
488   /**
489    * GstURIDecodeBin3::source-setup:
490    * @bin: the uridecodebin.
491    * @source: source element
492    *
493    * This signal is emitted after a source element has been created, so
494    * it can be configured by setting additional properties (e.g. set a
495    * proxy server for an http source, or set the device and read speed for
496    * an audio cd source).
497    */
498   gst_uri_decode_bin3_signals[SIGNAL_SOURCE_SETUP] =
499       g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
500       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
501   /**
502    * GstURIDecodeBin3::about-to-finish:
503    *
504    * This signal is emitted when the data for the selected URI is
505    * entirely buffered and it is safe to specify another URI.
506    */
507   gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH] =
508       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
509       G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
510 
511 
512   gst_element_class_add_static_pad_template (gstelement_class,
513       &video_src_template);
514   gst_element_class_add_static_pad_template (gstelement_class,
515       &audio_src_template);
516   gst_element_class_add_static_pad_template (gstelement_class,
517       &text_src_template);
518   gst_element_class_add_static_pad_template (gstelement_class, &src_template);
519   gst_element_class_set_static_metadata (gstelement_class,
520       "URI Decoder", "Generic/Bin/Decoder",
521       "Autoplug and decode an URI to raw media",
522       "Edward Hervey <edward@centricular.com>, Jan Schmidt <jan@centricular.com>");
523 
524   gstelement_class->change_state = gst_uri_decode_bin3_change_state;
525   gstelement_class->send_event =
526       GST_DEBUG_FUNCPTR (gst_uri_decodebin3_send_event);
527 
528   klass->select_stream = gst_uridecodebin3_select_stream;
529 }
530 
531 static GstPadProbeReturn
db_src_probe(GstPad * pad,GstPadProbeInfo * info,OutputPad * output)532 db_src_probe (GstPad * pad, GstPadProbeInfo * info, OutputPad * output)
533 {
534   /* FIXME : IMPLEMENT */
535 
536   /* EOS : Mark pad as EOS */
537 
538   /* STREAM_START : Store group_id and check if currently active
539    *  PlayEntry changed */
540 
541   return GST_PAD_PROBE_OK;
542 }
543 
544 static OutputPad *
add_output_pad(GstURIDecodeBin3 * dec,GstPad * target_pad)545 add_output_pad (GstURIDecodeBin3 * dec, GstPad * target_pad)
546 {
547   OutputPad *output;
548   gchar *pad_name;
549   GstEvent *stream_start;
550 
551   output = g_slice_new0 (OutputPad);
552 
553   GST_LOG_OBJECT (dec, "Created output %p", output);
554 
555   output->uridecodebin = dec;
556   output->target_pad = target_pad;
557   output->current_group_id = (guint) - 1;
558   pad_name = gst_pad_get_name (target_pad);
559   output->ghost_pad = gst_ghost_pad_new (pad_name, target_pad);
560   g_free (pad_name);
561 
562   gst_pad_set_active (output->ghost_pad, TRUE);
563 
564   stream_start = gst_pad_get_sticky_event (target_pad,
565       GST_EVENT_STREAM_START, 0);
566   if (stream_start) {
567     gst_pad_store_sticky_event (output->ghost_pad, stream_start);
568     gst_event_unref (stream_start);
569   } else {
570     GST_WARNING_OBJECT (target_pad,
571         "Exposing pad without stored stream-start event");
572   }
573 
574   gst_element_add_pad (GST_ELEMENT (dec), output->ghost_pad);
575 
576   output->probe_id =
577       gst_pad_add_probe (output->target_pad,
578       GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) db_src_probe,
579       output, NULL);
580 
581   /* FIXME: LOCK TO PROTECT PAD LIST */
582   dec->output_pads = g_list_append (dec->output_pads, output);
583 
584   return output;
585 }
586 
587 static void
db_pad_added_cb(GstElement * element,GstPad * pad,GstURIDecodeBin3 * dec)588 db_pad_added_cb (GstElement * element, GstPad * pad, GstURIDecodeBin3 * dec)
589 {
590   GST_DEBUG_OBJECT (dec, "Wrapping new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
591 
592   if (GST_PAD_IS_SRC (pad))
593     add_output_pad (dec, pad);
594 }
595 
596 static void
db_pad_removed_cb(GstElement * element,GstPad * pad,GstURIDecodeBin3 * dec)597 db_pad_removed_cb (GstElement * element, GstPad * pad, GstURIDecodeBin3 * dec)
598 {
599   GList *tmp;
600   OutputPad *output = NULL;
601 
602   if (!GST_PAD_IS_SRC (pad))
603     return;
604 
605   GST_DEBUG_OBJECT (dec, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
606   /* FIXME: LOCK for list access */
607 
608   for (tmp = dec->output_pads; tmp; tmp = tmp->next) {
609     OutputPad *cand = (OutputPad *) tmp->data;
610 
611     if (cand->target_pad == pad) {
612       output = cand;
613       dec->output_pads = g_list_delete_link (dec->output_pads, tmp);
614       break;
615     }
616   }
617 
618   if (output) {
619     GST_LOG_OBJECT (element, "Removing output %p", output);
620     /* Remove source ghost pad */
621     gst_ghost_pad_set_target ((GstGhostPad *) output->ghost_pad, NULL);
622     gst_element_remove_pad ((GstElement *) dec, output->ghost_pad);
623 
624     /* FIXME : Update global/current PlayEntry group_id (did we switch ?) */
625 
626     /* Remove event probe */
627     gst_pad_remove_probe (output->target_pad, output->probe_id);
628 
629     g_slice_free (OutputPad, output);
630   }
631 }
632 
633 static gint
db_select_stream_cb(GstElement * decodebin,GstStreamCollection * collection,GstStream * stream,GstURIDecodeBin3 * uridecodebin)634 db_select_stream_cb (GstElement * decodebin,
635     GstStreamCollection * collection, GstStream * stream,
636     GstURIDecodeBin3 * uridecodebin)
637 {
638   gint response = -1;
639 
640   g_signal_emit (uridecodebin,
641       gst_uri_decode_bin3_signals[SIGNAL_SELECT_STREAM], 0, collection, stream,
642       &response);
643   return response;
644 }
645 
646 static void
db_about_to_finish_cb(GstElement * decodebin,GstURIDecodeBin3 * uridecodebin)647 db_about_to_finish_cb (GstElement * decodebin, GstURIDecodeBin3 * uridecodebin)
648 {
649   if (!uridecodebin->posted_about_to_finish) {
650     uridecodebin->posted_about_to_finish = TRUE;
651     g_signal_emit (uridecodebin,
652         gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
653   }
654 }
655 
656 static void
gst_uri_decode_bin3_init(GstURIDecodeBin3 * dec)657 gst_uri_decode_bin3_init (GstURIDecodeBin3 * dec)
658 {
659   g_mutex_init (&dec->lock);
660 
661   dec->uri = DEFAULT_PROP_URI;
662   dec->suburi = DEFAULT_PROP_SUBURI;
663   dec->connection_speed = DEFAULT_CONNECTION_SPEED;
664   dec->caps = DEFAULT_CAPS;
665   dec->buffer_duration = DEFAULT_BUFFER_DURATION;
666   dec->buffer_size = DEFAULT_BUFFER_SIZE;
667   dec->download = DEFAULT_DOWNLOAD;
668   dec->use_buffering = DEFAULT_USE_BUFFERING;
669   dec->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
670 
671   dec->decodebin = gst_element_factory_make ("decodebin3", NULL);
672   gst_bin_add (GST_BIN_CAST (dec), dec->decodebin);
673   dec->db_pad_added_id =
674       g_signal_connect (dec->decodebin, "pad-added",
675       G_CALLBACK (db_pad_added_cb), dec);
676   dec->db_pad_removed_id =
677       g_signal_connect (dec->decodebin, "pad-removed",
678       G_CALLBACK (db_pad_removed_cb), dec);
679   dec->db_select_stream_id =
680       g_signal_connect (dec->decodebin, "select-stream",
681       G_CALLBACK (db_select_stream_cb), dec);
682   dec->db_about_to_finish_id =
683       g_signal_connect (dec->decodebin, "about-to-finish",
684       G_CALLBACK (db_about_to_finish_cb), dec);
685 
686   GST_OBJECT_FLAG_SET (dec, GST_ELEMENT_FLAG_SOURCE);
687   gst_bin_set_suppressed_flags (GST_BIN (dec),
688       GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
689 }
690 
691 static void
gst_uri_decode_bin3_finalize(GObject * obj)692 gst_uri_decode_bin3_finalize (GObject * obj)
693 {
694   GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (obj);
695 
696   g_mutex_clear (&dec->lock);
697   g_free (dec->uri);
698   g_free (dec->suburi);
699 
700   G_OBJECT_CLASS (parent_class)->finalize (obj);
701 }
702 
703 static GstStateChangeReturn
activate_source_item(GstSourceItem * item)704 activate_source_item (GstSourceItem * item)
705 {
706   GstSourceHandler *handler = item->handler;
707 
708   if (handler == NULL) {
709     GST_WARNING ("Can't activate item without a handler");
710     return GST_STATE_CHANGE_FAILURE;
711   }
712 
713   g_object_set (handler->urisourcebin, "uri", item->uri, NULL);
714   if (!handler->active) {
715     gst_bin_add ((GstBin *) handler->uridecodebin, handler->urisourcebin);
716     /* if (!gst_element_sync_state_with_parent (handler->urisourcebin)) */
717     /*   return GST_STATE_CHANGE_FAILURE; */
718     handler->active = TRUE;
719   }
720 
721   return GST_STATE_CHANGE_SUCCESS;
722 }
723 
724 static void
src_pad_added_cb(GstElement * element,GstPad * pad,GstSourceHandler * handler)725 src_pad_added_cb (GstElement * element, GstPad * pad,
726     GstSourceHandler * handler)
727 {
728   GstURIDecodeBin3 *uridecodebin;
729   GstPad *sinkpad = NULL;
730   GstPadLinkReturn res;
731   GstPlayItem *current_play_item;
732   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
733 
734   uridecodebin = handler->uridecodebin;
735   current_play_item = uridecodebin->current;
736 
737   GST_DEBUG_OBJECT (uridecodebin,
738       "New pad %" GST_PTR_FORMAT " from source %" GST_PTR_FORMAT, pad, element);
739 
740   /* FIXME: Add probe to unify group_id and detect EOS */
741 
742   /* Try to link to main sink pad only if it's from a main handler */
743   if (handler->is_main_source) {
744     sinkpad = gst_element_get_static_pad (uridecodebin->decodebin, "sink");
745     if (gst_pad_is_linked (sinkpad)) {
746       gst_object_unref (sinkpad);
747       sinkpad = NULL;
748     }
749   }
750 
751   if (sinkpad == NULL)
752     sinkpad =
753         gst_element_request_pad_simple (uridecodebin->decodebin, "sink_%u");
754 
755   if (sinkpad) {
756     GST_DEBUG_OBJECT (uridecodebin,
757         "Linking %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, pad, sinkpad);
758     res = gst_pad_link (pad, sinkpad);
759     gst_object_unref (sinkpad);
760     if (GST_PAD_LINK_FAILED (res))
761       goto link_failed;
762   }
763 
764   /* Activate sub_item after the main source activation was finished */
765   if (handler->is_main_source && current_play_item->sub_item
766       && !current_play_item->sub_item->handler) {
767     current_play_item->sub_item->handler =
768         new_source_handler (uridecodebin, FALSE);
769     ret = activate_source_item (current_play_item->sub_item);
770     if (ret == GST_STATE_CHANGE_FAILURE)
771       goto sub_item_activation_failed;
772   }
773 
774   return;
775 
776 link_failed:
777   {
778     GST_ERROR_OBJECT (uridecodebin,
779         "failed to link pad %s:%s to decodebin, reason %s (%d)",
780         GST_DEBUG_PAD_NAME (pad), gst_pad_link_get_name (res), res);
781     return;
782   }
783 sub_item_activation_failed:
784   {
785     GST_ERROR_OBJECT (uridecodebin,
786         "failed to activate subtitle playback item");
787     return;
788   }
789 }
790 
791 static void
src_pad_removed_cb(GstElement * element,GstPad * pad,GstSourceHandler * handler)792 src_pad_removed_cb (GstElement * element, GstPad * pad,
793     GstSourceHandler * handler)
794 {
795   GstURIDecodeBin3 *uridecodebin = handler->uridecodebin;
796   GstPad *peer_pad = gst_pad_get_peer (pad);
797 
798   if (peer_pad) {
799     GstPadTemplate *templ = gst_pad_get_pad_template (peer_pad);
800 
801     GST_DEBUG_OBJECT (uridecodebin,
802         "Source %" GST_PTR_FORMAT " removed pad %" GST_PTR_FORMAT " peer %"
803         GST_PTR_FORMAT, element, pad, peer_pad);
804 
805     if (templ) {
806       if (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_REQUEST) {
807         GST_DEBUG_OBJECT (uridecodebin,
808             "Releasing decodebin pad %" GST_PTR_FORMAT, peer_pad);
809         gst_element_release_request_pad (uridecodebin->decodebin, peer_pad);
810       }
811       gst_object_unref (templ);
812     }
813 
814     gst_object_unref (peer_pad);
815   }
816 }
817 
818 static void
src_source_setup_cb(GstElement * element,GstElement * source,GstSourceHandler * handler)819 src_source_setup_cb (GstElement * element, GstElement * source,
820     GstSourceHandler * handler)
821 {
822   g_signal_emit (handler->uridecodebin,
823       gst_uri_decode_bin3_signals[SIGNAL_SOURCE_SETUP], 0, source, NULL);
824 }
825 
826 static void
src_about_to_finish_cb(GstElement * element,GstSourceHandler * handler)827 src_about_to_finish_cb (GstElement * element, GstSourceHandler * handler)
828 {
829   /* FIXME : check if all sources are done */
830   if (!handler->uridecodebin->posted_about_to_finish) {
831     handler->uridecodebin->posted_about_to_finish = TRUE;
832     g_signal_emit (handler->uridecodebin,
833         gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
834   }
835 }
836 
837 static GstSourceHandler *
new_source_handler(GstURIDecodeBin3 * uridecodebin,gboolean is_main)838 new_source_handler (GstURIDecodeBin3 * uridecodebin, gboolean is_main)
839 {
840   GstSourceHandler *handler;
841 
842   handler = g_slice_new0 (GstSourceHandler);
843 
844   handler->uridecodebin = uridecodebin;
845   handler->is_main_source = is_main;
846   handler->urisourcebin = gst_element_factory_make ("urisourcebin", NULL);
847   /* Set pending properties */
848   g_object_set (handler->urisourcebin,
849       "connection-speed", uridecodebin->connection_speed / 1000,
850       "download", uridecodebin->download,
851       "use-buffering", uridecodebin->use_buffering,
852       "buffer-duration", uridecodebin->buffer_duration,
853       "buffer-size", uridecodebin->buffer_size,
854       "ring-buffer-max-size", uridecodebin->ring_buffer_max_size, NULL);
855 
856   handler->pad_added_id =
857       g_signal_connect (handler->urisourcebin, "pad-added",
858       (GCallback) src_pad_added_cb, handler);
859   handler->pad_removed_id =
860       g_signal_connect (handler->urisourcebin, "pad-removed",
861       (GCallback) src_pad_removed_cb, handler);
862   handler->source_setup_id =
863       g_signal_connect (handler->urisourcebin, "source-setup",
864       (GCallback) src_source_setup_cb, handler);
865   handler->about_to_finish_id =
866       g_signal_connect (handler->urisourcebin, "about-to-finish",
867       (GCallback) src_about_to_finish_cb, handler);
868 
869   uridecodebin->source_handlers =
870       g_list_append (uridecodebin->source_handlers, handler);
871 
872   return handler;
873 }
874 
875 static void
gst_uri_decode_bin3_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)876 gst_uri_decode_bin3_set_property (GObject * object, guint prop_id,
877     const GValue * value, GParamSpec * pspec)
878 {
879   GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (object);
880 
881   switch (prop_id) {
882     case PROP_URI:
883       if (dec->uri)
884         g_free (dec->uri);
885       dec->uri = g_value_dup_string (value);
886       break;
887     case PROP_SUBURI:
888       if (dec->suburi)
889         g_free (dec->suburi);
890       dec->suburi = g_value_dup_string (value);
891       break;
892     case PROP_CONNECTION_SPEED:
893       GST_URI_DECODE_BIN3_LOCK (dec);
894       dec->connection_speed = g_value_get_uint64 (value) * 1000;
895       GST_URI_DECODE_BIN3_UNLOCK (dec);
896       break;
897     case PROP_BUFFER_SIZE:
898       dec->buffer_size = g_value_get_int (value);
899       break;
900     case PROP_BUFFER_DURATION:
901       dec->buffer_duration = g_value_get_int64 (value);
902       break;
903     case PROP_DOWNLOAD:
904       dec->download = g_value_get_boolean (value);
905       break;
906     case PROP_USE_BUFFERING:
907       dec->use_buffering = g_value_get_boolean (value);
908       break;
909     case PROP_RING_BUFFER_MAX_SIZE:
910       dec->ring_buffer_max_size = g_value_get_uint64 (value);
911       break;
912     case PROP_CAPS:
913       GST_OBJECT_LOCK (dec);
914       if (dec->caps)
915         gst_caps_unref (dec->caps);
916       dec->caps = g_value_dup_boxed (value);
917       GST_OBJECT_UNLOCK (dec);
918       break;
919     default:
920       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
921       break;
922   }
923 }
924 
925 static void
gst_uri_decode_bin3_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)926 gst_uri_decode_bin3_get_property (GObject * object, guint prop_id,
927     GValue * value, GParamSpec * pspec)
928 {
929   GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (object);
930 
931   switch (prop_id) {
932     case PROP_URI:
933     {
934       g_value_set_string (value, dec->uri);
935       break;
936     }
937     case PROP_CURRENT_URI:
938     {
939       if (dec->current && dec->current->main_item) {
940         g_value_set_string (value, dec->current->main_item->uri);
941       } else {
942         g_value_set_string (value, NULL);
943       }
944       break;
945     }
946     case PROP_SUBURI:
947     {
948       g_value_set_string (value, dec->suburi);
949       break;
950     }
951     case PROP_CURRENT_SUBURI:
952     {
953       if (dec->current && dec->current->sub_item) {
954         g_value_set_string (value, dec->current->sub_item->uri);
955       } else {
956         g_value_set_string (value, NULL);
957       }
958       break;
959     }
960     case PROP_SOURCE:
961     {
962       GST_OBJECT_LOCK (dec);
963       g_value_set_object (value, dec->source);
964       GST_OBJECT_UNLOCK (dec);
965       break;
966     }
967     case PROP_CONNECTION_SPEED:
968       GST_URI_DECODE_BIN3_LOCK (dec);
969       g_value_set_uint64 (value, dec->connection_speed / 1000);
970       GST_URI_DECODE_BIN3_UNLOCK (dec);
971       break;
972     case PROP_BUFFER_SIZE:
973       GST_OBJECT_LOCK (dec);
974       g_value_set_int (value, dec->buffer_size);
975       GST_OBJECT_UNLOCK (dec);
976       break;
977     case PROP_BUFFER_DURATION:
978       GST_OBJECT_LOCK (dec);
979       g_value_set_int64 (value, dec->buffer_duration);
980       GST_OBJECT_UNLOCK (dec);
981       break;
982     case PROP_DOWNLOAD:
983       g_value_set_boolean (value, dec->download);
984       break;
985     case PROP_USE_BUFFERING:
986       g_value_set_boolean (value, dec->use_buffering);
987       break;
988     case PROP_RING_BUFFER_MAX_SIZE:
989       g_value_set_uint64 (value, dec->ring_buffer_max_size);
990       break;
991     case PROP_CAPS:
992       GST_OBJECT_LOCK (dec);
993       g_value_set_boxed (value, dec->caps);
994       GST_OBJECT_UNLOCK (dec);
995       break;
996     default:
997       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
998       break;
999   }
1000 }
1001 
1002 static void
free_source_handler(GstURIDecodeBin3 * uridecodebin,GstSourceHandler * handler)1003 free_source_handler (GstURIDecodeBin3 * uridecodebin,
1004     GstSourceHandler * handler)
1005 {
1006   GST_LOG_OBJECT (uridecodebin, "source handler %p", handler);
1007   if (handler->active) {
1008     GST_LOG_OBJECT (uridecodebin, "Removing %" GST_PTR_FORMAT,
1009         handler->urisourcebin);
1010     gst_element_set_state (handler->urisourcebin, GST_STATE_NULL);
1011     gst_bin_remove ((GstBin *) uridecodebin, handler->urisourcebin);
1012   }
1013   uridecodebin->source_handlers =
1014       g_list_remove (uridecodebin->source_handlers, handler);
1015   g_slice_free (GstSourceHandler, handler);
1016 }
1017 
1018 static GstSourceItem *
new_source_item(GstURIDecodeBin3 * dec,GstPlayItem * item,gchar * uri)1019 new_source_item (GstURIDecodeBin3 * dec, GstPlayItem * item, gchar * uri)
1020 {
1021   GstSourceItem *sourceitem = g_slice_new0 (GstSourceItem);
1022 
1023   sourceitem->play_item = item;
1024   sourceitem->uri = uri;
1025 
1026   return sourceitem;
1027 }
1028 
1029 static void
free_source_item(GstURIDecodeBin3 * uridecodebin,GstSourceItem * item)1030 free_source_item (GstURIDecodeBin3 * uridecodebin, GstSourceItem * item)
1031 {
1032   GST_LOG_OBJECT (uridecodebin, "source item %p", item);
1033   if (item->handler)
1034     free_source_handler (uridecodebin, item->handler);
1035   g_slice_free (GstSourceItem, item);
1036 }
1037 
1038 static GstPlayItem *
new_play_item(GstURIDecodeBin3 * dec,gchar * uri,gchar * suburi)1039 new_play_item (GstURIDecodeBin3 * dec, gchar * uri, gchar * suburi)
1040 {
1041   GstPlayItem *item = g_slice_new0 (GstPlayItem);
1042 
1043   item->uridecodebin = dec;
1044   item->main_item = new_source_item (dec, item, uri);
1045   if (suburi)
1046     item->sub_item = new_source_item (dec, item, suburi);
1047 
1048   return item;
1049 }
1050 
1051 static void
free_play_item(GstURIDecodeBin3 * dec,GstPlayItem * item)1052 free_play_item (GstURIDecodeBin3 * dec, GstPlayItem * item)
1053 {
1054   GST_LOG_OBJECT (dec, "play item %p", item);
1055   if (item->main_item)
1056     free_source_item (dec, item->main_item);
1057   if (item->sub_item)
1058     free_source_item (dec, item->sub_item);
1059 
1060   g_slice_free (GstPlayItem, item);
1061 }
1062 
1063 /* Sync source handlers for the given play item. Might require creating/removing some
1064  * and/or configure the handlers accordingly */
1065 static GstStateChangeReturn
assign_handlers_to_item(GstURIDecodeBin3 * dec,GstPlayItem * item)1066 assign_handlers_to_item (GstURIDecodeBin3 * dec, GstPlayItem * item)
1067 {
1068   GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1069 
1070   /* FIXME : Go over existing handlers to see if we can assign some to the
1071    * given item */
1072 
1073   /* Create missing handlers */
1074   if (item->main_item->handler == NULL) {
1075     item->main_item->handler = new_source_handler (dec, TRUE);
1076     ret = activate_source_item (item->main_item);
1077     if (ret == GST_STATE_CHANGE_FAILURE)
1078       return ret;
1079   }
1080 
1081   return ret;
1082 }
1083 
1084 /* Called to activate the next play item */
1085 static GstStateChangeReturn
activate_next_play_item(GstURIDecodeBin3 * dec)1086 activate_next_play_item (GstURIDecodeBin3 * dec)
1087 {
1088   GstPlayItem *item;
1089   GstStateChangeReturn ret;
1090 
1091   /* If there is no current play entry, create one from the uri/suburi
1092    * FIXME : Use a playlist API in the future */
1093   item = new_play_item (dec, dec->uri, dec->suburi);
1094 
1095   ret = assign_handlers_to_item (dec, item);
1096   if (ret == GST_STATE_CHANGE_FAILURE) {
1097     free_play_item (dec, item);
1098     return ret;
1099   }
1100 
1101   dec->play_items = g_list_append (dec->play_items, item);
1102   dec->current = dec->play_items->data;
1103 
1104   return ret;
1105 }
1106 
1107 static void
free_play_items(GstURIDecodeBin3 * dec)1108 free_play_items (GstURIDecodeBin3 * dec)
1109 {
1110   GList *tmp;
1111 
1112   for (tmp = dec->play_items; tmp; tmp = tmp->next) {
1113     GstPlayItem *item = (GstPlayItem *) tmp->data;
1114     free_play_item (dec, item);
1115   }
1116 
1117   g_list_free (dec->play_items);
1118   dec->play_items = NULL;
1119   dec->current = NULL;
1120 }
1121 
1122 static GstStateChangeReturn
gst_uri_decode_bin3_change_state(GstElement * element,GstStateChange transition)1123 gst_uri_decode_bin3_change_state (GstElement * element,
1124     GstStateChange transition)
1125 {
1126   GstStateChangeReturn ret;
1127   GstURIDecodeBin3 *uridecodebin = (GstURIDecodeBin3 *) element;
1128 
1129   switch (transition) {
1130     case GST_STATE_CHANGE_NULL_TO_READY:
1131       g_object_set (uridecodebin->decodebin, "caps", uridecodebin->caps, NULL);
1132       break;
1133     case GST_STATE_CHANGE_READY_TO_PAUSED:
1134       ret = activate_next_play_item (uridecodebin);
1135       if (ret == GST_STATE_CHANGE_FAILURE)
1136         goto failure;
1137     default:
1138       break;
1139   }
1140 
1141   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1142   if (ret == GST_STATE_CHANGE_FAILURE)
1143     goto failure;
1144 
1145   switch (transition) {
1146     case GST_STATE_CHANGE_PAUSED_TO_READY:
1147       /* FIXME: Cleanup everything */
1148       free_play_items (uridecodebin);
1149       /* Free play item */
1150       uridecodebin->posted_about_to_finish = FALSE;
1151       break;
1152     default:
1153       break;
1154   }
1155 
1156   return ret;
1157 
1158   /* ERRORS */
1159 failure:
1160   {
1161     if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
1162       free_play_items (uridecodebin);
1163     return ret;
1164   }
1165 }
1166 
1167 static gboolean
gst_uri_decodebin3_send_event(GstElement * element,GstEvent * event)1168 gst_uri_decodebin3_send_event (GstElement * element, GstEvent * event)
1169 {
1170   GstURIDecodeBin3 *self = GST_URI_DECODE_BIN3 (element);
1171 
1172   if (GST_EVENT_IS_UPSTREAM (event) && self->decodebin)
1173     return gst_element_send_event (self->decodebin, event);
1174 
1175   return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
1176 }
1177