fdec1bedf6eeb8fc97c83b293b90b8d371ebada7
[platform/upstream/gst-plugins-base.git] / gst / playback / gstdecodebin3.c
1 /* GStreamer
2  *
3  * Copyright (C) <2015> Centricular Ltd
4  *  @author: Edward Hervey <edward@centricular.com>
5  *  @author: Jan Schmidt <jan@centricular.com>
6  *
7  * This library is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU Library General Public
9  * License as published by the Free Software Foundation; either
10  * version 2 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Library General Public License for more details.
16  *
17  * You should have received a copy of the GNU Library General Public
18  * License along with this library; if not, write to the
19  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20  * Boston, MA 02110-1301, USA.
21  */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include <glib.h>
28 #include <glib-object.h>
29 #include <glib/gprintf.h>
30 #include <gst/gst.h>
31 #include <gst/pbutils/pbutils.h>
32
33 #include "gstplayback.h"
34 #include "gstplay-enum.h"
35 #include "gstrawcaps.h"
36
37 /**
38  * SECTION:element-decodebin3
39  * @title: decodebin3
40  *
41  * #GstBin that auto-magically constructs a decoding pipeline using available
42  * decoders and demuxers via auto-plugging. The output is raw audio, video
43  * or subtitle streams.
44  *
45  * decodebin3 differs from the previous decodebin (decodebin2) in important ways:
46  *
47  * * supports publication and selection of stream information via
48  * GstStreamCollection messages and #GST_EVENT_SELECT_STREAM events.
49  *
50  * * dynamically switches stream connections internally, and
51  * reuses decoder elements when stream selections change, so that in
52  * the normal case it maintains 1 decoder of each type (video/audio/subtitle)
53  * and only creates new elements when streams change and an existing decoder
54  * is not capable of handling the new format.
55  *
56  * * supports multiple input pads for the parallel decoding of auxilliary streams
57  * not muxed with the primary stream.
58  *
59  * * does not handle network stream buffering. decodebin3 expects that network stream
60  * buffering is handled upstream, before data is passed to it.
61  *
62  * <emphasis>decodebin3 is still experimental API and a technology preview.
63  * Its behaviour and exposed API is subject to change.</emphasis>
64  *
65  */
66
67 /**
68  * Global design
69  *
70  * 1) From sink pad to elementary streams (GstParseBin)
71  *
72  * The input sink pads are fed to GstParseBin. GstParseBin will feed them
73  * through typefind. When the caps are detected (or changed) we recursively
74  * figure out which demuxer, parser or depayloader is needed until we get to
75  * elementary streams.
76  *
77  * All elementary streams (whether decoded or not, whether exposed or not) are
78  * fed through multiqueue. There is only *one* multiqueue in decodebin3.
79  *
80  * => MultiQueue is the cornerstone.
81  * => No buffering before multiqueue
82  *
83  * 2) Elementary streams
84  *
85  * After GstParseBin, there are 3 main components:
86  *  1) Input Streams (provided by GstParseBin)
87  *  2) Multiqueue slots
88  *  3) Output Streams
89  *
90  * Input Streams correspond to the stream coming from GstParseBin and that gets
91  * fed into a multiqueue slot.
92  *
93  * Output Streams correspond to the combination of a (optional) decoder and an
94  * output ghostpad. Output Streams can be moved from one multiqueue slot to
95  * another, can reconfigure itself (different decoders), and can be
96  * added/removed depending on the configuration (all streams outputted, only one
97  * of each type, ...).
98  *
99  * Multiqueue slots correspond to a pair of sink/src pad from multiqueue. For
100  * each 'active' Input Stream there is a corresponding slot.
101  * Slots might have different streams on input and output (due to internal
102  * buffering).
103  *
104  * Due to internal queuing/buffering/..., all those components (might) behave
105  * asynchronously. Therefore probes will be used on each component source pad to
106  * detect various key-points:
107  *  * EOS :
108  *     the stream is done => Mark that component as done, optionally freeing/removing it
109  *  * STREAM_START :
110  *     a new stream is starting => link it further if needed
111  *
112  * 3) Gradual replacement
113  *
114  * If the caps change at any point in decodebin (input sink pad, demuxer output,
115  * multiqueue output, ..), we gradually replace (if needed) the following elements.
116  *
117  * This is handled by the probes in various locations:
118  *  a) typefind output
119  *  b) multiqueue input (source pad of Input Streams)
120  *  c) multiqueue output (source pad of Multiqueue Slots)
121  *  d) final output (target of source ghostpads)
122  *
123  * When CAPS event arrive at those points, one of three things can happen:
124  * a) There is no elements downstream yet, just create/link-to following elements
125  * b) There are downstream elements, do a ACCEPT_CAPS query
126  *  b.1) The new CAPS are accepted, keep current configuration
127  *  b.2) The new CAPS are not accepted, remove following elements then do a)
128  *
129  *    Components:
130  *
131  *                                                   MultiQ     Output
132  *                     Input(s)                      Slots      Streams
133  *  /-------------------------------------------\   /-----\  /------------- \
134  *
135  * +-------------------------------------------------------------------------+
136  * |                                                                         |
137  * | +---------------------------------------------+                         |
138  * | |   GstParseBin(s)                            |                         |
139  * | |                +--------------+             |  +-----+                |
140  * | |                |              |---[parser]-[|--| Mul |---[ decoder ]-[|
141  * |]--[ typefind ]---|  demuxer(s)  |------------[|  | ti  |                |
142  * | |                |  (if needed) |---[parser]-[|--| qu  |                |
143  * | |                |              |---[parser]-[|--| eu  |---[ decoder ]-[|
144  * | |                +--------------+             |  +------             ^  |
145  * | +---------------------------------------------+        ^             |  |
146  * |                                               ^        |             |  |
147  * +-----------------------------------------------+--------+-------------+--+
148  *                                                 |        |             |
149  *                                                 |        |             |
150  *                                       Probes  --/--------/-------------/
151  *
152  * ATOMIC SWITCHING
153  *
154  * We want to ensure we re-use decoders when switching streams. This takes place
155  * at the multiqueue output level.
156  *
157  * MAIN CONCEPTS
158  *  1) Activating a stream (i.e. linking a slot to an output) is only done within
159  *    the streaming thread in the multiqueue_src_probe() and only if the
160       stream is in the REQUESTED selection.
161  *  2) Deactivating a stream (i.e. unlinking a slot from an output) is also done
162  *    within the stream thread, but only in a purposefully called IDLE probe
163  *    that calls reassign_slot().
164  *
165  * Based on those two principles, 3 "selection" of streams (stream-id) are used:
166  * 1) requested_selection
167  *    All streams within that list should be activated
168  * 2) active_selection
169  *    List of streams that are exposed by decodebin
170  * 3) to_activate
171  *    List of streams that will be moved to requested_selection in the
172  *    reassign_slot() method (i.e. once a stream was deactivated, and the output
173  *    was retargetted)
174  */
175
176
177 GST_DEBUG_CATEGORY_STATIC (decodebin3_debug);
178 #define GST_CAT_DEFAULT decodebin3_debug
179
180 #define GST_TYPE_DECODEBIN3      (gst_decodebin3_get_type ())
181
182 #define EXTRA_DEBUG 1
183
184 #define CUSTOM_FINAL_EOS_QUARK _custom_final_eos_quark_get ()
185 #define CUSTOM_FINAL_EOS_QUARK_DATA "custom-final-eos"
186 static GQuark
187 _custom_final_eos_quark_get (void)
188 {
189   static gsize g_quark;
190
191   if (g_once_init_enter (&g_quark)) {
192     gsize quark =
193         (gsize) g_quark_from_static_string ("decodebin3-custom-final-eos");
194     g_once_init_leave (&g_quark, quark);
195   }
196   return g_quark;
197 }
198
199 typedef struct _GstDecodebin3 GstDecodebin3;
200 typedef struct _GstDecodebin3Class GstDecodebin3Class;
201
202 typedef struct _DecodebinInputStream DecodebinInputStream;
203 typedef struct _DecodebinInput DecodebinInput;
204 typedef struct _DecodebinOutputStream DecodebinOutputStream;
205
206 struct _GstDecodebin3
207 {
208   GstBin bin;
209
210   /* input_lock protects the following variables */
211   GMutex input_lock;
212   /* Main input (static sink pad) */
213   DecodebinInput *main_input;
214   /* Supplementary input (request sink pads) */
215   GList *other_inputs;
216   /* counter for input */
217   guint32 input_counter;
218   /* Current stream group_id (default : GST_GROUP_ID_INVALID) */
219   /* FIXME : Needs to be resetted appropriately (when upstream changes ?) */
220   guint32 current_group_id;
221   /* End of variables protected by input_lock */
222
223   GstElement *multiqueue;
224
225   /* selection_lock protects access to following variables */
226   GMutex selection_lock;
227   GList *input_streams;         /* List of DecodebinInputStream for active collection */
228   GList *output_streams;        /* List of DecodebinOutputStream used for output */
229   GList *slots;                 /* List of MultiQueueSlot */
230   guint slot_id;
231
232   /* Active collection */
233   GstStreamCollection *collection;
234   /* requested selection of stream-id to activate post-multiqueue */
235   GList *requested_selection;
236   /* list of stream-id currently activated in output */
237   GList *active_selection;
238   /* List of stream-id that need to be activated (after a stream switch for ex) */
239   GList *to_activate;
240   /* Pending select streams event */
241   guint32 select_streams_seqnum;
242   /* pending list of streams to select (from downstream) */
243   GList *pending_select_streams;
244   /* TRUE if requested_selection was updated, will become FALSE once
245    * it has fully transitioned to active */
246   gboolean selection_updated;
247   /* End of variables protected by selection_lock */
248
249   /* List of pending collections.
250    * FIXME : Is this really needed ? */
251   GList *pending_collection;
252
253   /* Factories */
254   GMutex factories_lock;
255   guint32 factories_cookie;
256   /* All DECODABLE factories */
257   GList *factories;
258   /* Only DECODER factories */
259   GList *decoder_factories;
260   /* DECODABLE but not DECODER factories */
261   GList *decodable_factories;
262
263   /* counters for pads */
264   guint32 apadcount, vpadcount, tpadcount, opadcount;
265
266   /* Properties */
267   GstCaps *caps;
268 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
269   gboolean force_sw_decoders_for_video;
270   gboolean force_sw_decoders_for_audio;
271 #else
272   gboolean force_sw_decoders;
273 #endif
274 };
275
276 struct _GstDecodebin3Class
277 {
278   GstBinClass class;
279
280   gint (*select_stream) (GstDecodebin3 * dbin,
281     GstStreamCollection * collection, GstStream * stream);
282
283 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
284   gboolean (*request_resource) (GstDecodebin3 * dbin,
285     GstStreamCollection * collection, GstStream * stream);
286 #endif
287 };
288
289 /* Input of decodebin, controls input pad and parsebin */
290 struct _DecodebinInput
291 {
292   GstDecodebin3 *dbin;
293
294   gboolean is_main;
295
296   GstPad *ghost_sink;
297   GstPad *parsebin_sink;
298
299   GstStreamCollection *collection;      /* Active collection */
300
301   guint group_id;
302
303   GstElement *parsebin;
304
305   gulong pad_added_sigid;
306   gulong pad_removed_sigid;
307   gulong drained_sigid;
308
309   /* TRUE if the input got drained
310    * FIXME : When do we reset it if re-used ?
311    */
312   gboolean drained;
313
314   /* HACK : Remove these fields */
315   /* List of PendingPad structures */
316   GList *pending_pads;
317 };
318
319 /* Multiqueue Slots */
320 typedef struct _MultiQueueSlot
321 {
322   guint id;
323
324   GstDecodebin3 *dbin;
325   /* Type of stream handled by this slot */
326   GstStreamType type;
327
328   /* Linked input and output */
329   DecodebinInputStream *input;
330
331   /* pending => last stream received on sink pad */
332   GstStream *pending_stream;
333   /* active => last stream outputted on source pad */
334   GstStream *active_stream;
335
336   GstPad *sink_pad, *src_pad;
337
338   /* id of the MQ src_pad event probe */
339   gulong probe_id;
340
341   gboolean is_drained;
342
343   DecodebinOutputStream *output;
344 } MultiQueueSlot;
345
346 /* Streams that are exposed downstream (i.e. output) */
347 struct _DecodebinOutputStream
348 {
349   GstDecodebin3 *dbin;
350   /* The type of stream handled by this output stream */
351   GstStreamType type;
352
353   /* The slot to which this output stream is currently connected to */
354   MultiQueueSlot *slot;
355
356   GstElement *decoder;          /* Optional */
357   GstPad *decoder_sink, *decoder_src;
358   gboolean linked;
359
360   /* ghostpad */
361   GstPad *src_pad;
362   /* Flag if ghost pad is exposed */
363   gboolean src_exposed;
364
365   /* keyframe dropping probe */
366   gulong drop_probe_id;
367 };
368
369 /* Pending pads from parsebin */
370 typedef struct _PendingPad
371 {
372   GstDecodebin3 *dbin;
373   DecodebinInput *input;
374   GstPad *pad;
375
376   gulong buffer_probe;
377   gulong event_probe;
378   gboolean saw_eos;
379 } PendingPad;
380
381 /* properties */
382 enum
383 {
384   PROP_0,
385   PROP_CAPS,
386 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
387   PROP_FORCE_SW_DECODERS_FOR_VIDEO,
388   PROP_FORCE_SW_DECODERS_FOR_AUDIO,
389 #else
390   PROP_FORCE_SW_DECODERS,
391 #endif
392 };
393
394 /* signals */
395 enum
396 {
397   SIGNAL_SELECT_STREAM,
398   SIGNAL_ABOUT_TO_FINISH,
399 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
400   SIGNAL_REQUEST_RESOURCE,
401 #endif
402   LAST_SIGNAL
403 };
404 static guint gst_decodebin3_signals[LAST_SIGNAL] = { 0 };
405
406 #define SELECTION_LOCK(dbin) G_STMT_START {                             \
407     GST_LOG_OBJECT (dbin,                                               \
408                     "selection locking from thread %p",                 \
409                     g_thread_self ());                                  \
410     g_mutex_lock (&dbin->selection_lock);                               \
411     GST_LOG_OBJECT (dbin,                                               \
412                     "selection locked from thread %p",                  \
413                     g_thread_self ());                                  \
414   } G_STMT_END
415
416 #define SELECTION_UNLOCK(dbin) G_STMT_START {                           \
417     GST_LOG_OBJECT (dbin,                                               \
418                     "selection unlocking from thread %p",               \
419                     g_thread_self ());                                  \
420     g_mutex_unlock (&dbin->selection_lock);                             \
421   } G_STMT_END
422
423 #define INPUT_LOCK(dbin) G_STMT_START {                         \
424     GST_LOG_OBJECT (dbin,                                               \
425                     "input locking from thread %p",                     \
426                     g_thread_self ());                                  \
427     g_mutex_lock (&dbin->input_lock);                           \
428     GST_LOG_OBJECT (dbin,                                               \
429                     "input locked from thread %p",                      \
430                     g_thread_self ());                                  \
431   } G_STMT_END
432
433 #define INPUT_UNLOCK(dbin) G_STMT_START {                               \
434     GST_LOG_OBJECT (dbin,                                               \
435                     "input unlocking from thread %p",           \
436                     g_thread_self ());                                  \
437     g_mutex_unlock (&dbin->input_lock);                         \
438   } G_STMT_END
439
440 GType gst_decodebin3_get_type (void);
441 #define gst_decodebin3_parent_class parent_class
442 G_DEFINE_TYPE (GstDecodebin3, gst_decodebin3, GST_TYPE_BIN);
443
444 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
445
446 #define DEFAULT_FORCE_SW_DECODERS FALSE
447
448 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
449     GST_PAD_SINK,
450     GST_PAD_ALWAYS,
451     GST_STATIC_CAPS_ANY);
452
453 static GstStaticPadTemplate request_sink_template =
454 GST_STATIC_PAD_TEMPLATE ("sink_%u",
455     GST_PAD_SINK,
456     GST_PAD_REQUEST,
457     GST_STATIC_CAPS_ANY);
458
459 static GstStaticPadTemplate video_src_template =
460 GST_STATIC_PAD_TEMPLATE ("video_%u",
461     GST_PAD_SRC,
462     GST_PAD_SOMETIMES,
463     GST_STATIC_CAPS_ANY);
464
465 static GstStaticPadTemplate audio_src_template =
466 GST_STATIC_PAD_TEMPLATE ("audio_%u",
467     GST_PAD_SRC,
468     GST_PAD_SOMETIMES,
469     GST_STATIC_CAPS_ANY);
470
471 static GstStaticPadTemplate text_src_template =
472 GST_STATIC_PAD_TEMPLATE ("text_%u",
473     GST_PAD_SRC,
474     GST_PAD_SOMETIMES,
475     GST_STATIC_CAPS_ANY);
476
477 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
478     GST_PAD_SRC,
479     GST_PAD_SOMETIMES,
480     GST_STATIC_CAPS_ANY);
481
482
483 static void gst_decodebin3_dispose (GObject * object);
484 static void gst_decodebin3_set_property (GObject * object, guint prop_id,
485     const GValue * value, GParamSpec * pspec);
486 static void gst_decodebin3_get_property (GObject * object, guint prop_id,
487     GValue * value, GParamSpec * pspec);
488 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
489 static gboolean gst_decodebin3_request_resource (GstElement * element,
490     GstStreamCollection * collection, GstStream * stream);
491 #endif
492
493 static gboolean parsebin_autoplug_continue_cb (GstElement *
494     parsebin, GstPad * pad, GstCaps * caps, GstDecodebin3 * dbin);
495
496 static gint
497 gst_decodebin3_select_stream (GstDecodebin3 * dbin,
498     GstStreamCollection * collection, GstStream * stream)
499 {
500   GST_LOG_OBJECT (dbin, "default select-stream, returning -1");
501
502   return -1;
503 }
504
505 static GstPad *gst_decodebin3_request_new_pad (GstElement * element,
506     GstPadTemplate * temp, const gchar * name, const GstCaps * caps);
507 static void gst_decodebin3_handle_message (GstBin * bin, GstMessage * message);
508 static GstStateChangeReturn gst_decodebin3_change_state (GstElement * element,
509     GstStateChange transition);
510 static gboolean gst_decodebin3_send_event (GstElement * element,
511     GstEvent * event);
512
513 static void gst_decode_bin_update_factories_list (GstDecodebin3 * dbin);
514 #if 0
515 static gboolean have_factory (GstDecodebin3 * dbin, GstCaps * caps,
516     GstElementFactoryListType ftype);
517 #endif
518
519 static void free_input (GstDecodebin3 * dbin, DecodebinInput * input);
520 static void free_input_async (GstDecodebin3 * dbin, DecodebinInput * input);
521 static DecodebinInput *create_new_input (GstDecodebin3 * dbin, gboolean main);
522 static gboolean set_input_group_id (DecodebinInput * input, guint32 * group_id);
523
524 static void reconfigure_output_stream (DecodebinOutputStream * output,
525     MultiQueueSlot * slot);
526 static void free_output_stream (GstDecodebin3 * dbin,
527     DecodebinOutputStream * output);
528 static DecodebinOutputStream *create_output_stream (GstDecodebin3 * dbin,
529     GstStreamType type);
530
531 static GstPadProbeReturn slot_unassign_probe (GstPad * pad,
532     GstPadProbeInfo * info, MultiQueueSlot * slot);
533 static gboolean reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot);
534 static MultiQueueSlot *get_slot_for_input (GstDecodebin3 * dbin,
535     DecodebinInputStream * input);
536 static void link_input_to_slot (DecodebinInputStream * input,
537     MultiQueueSlot * slot);
538 static void free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot);
539 static void free_multiqueue_slot_async (GstDecodebin3 * dbin,
540     MultiQueueSlot * slot);
541
542 static GstStreamCollection *get_merged_collection (GstDecodebin3 * dbin);
543 static void update_requested_selection (GstDecodebin3 * dbin);
544
545 /* FIXME: Really make all the parser stuff a self-contained helper object */
546 #include "gstdecodebin3-parse.c"
547
548 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
549 static gboolean gst_decodebin3_request_resource (GstElement * element,
550     GstStreamCollection * collection, GstStream * stream)
551 {
552   /* do not consider the resource limit */
553   return TRUE;
554 }
555
556 static gboolean
557 _gst_boolean_accumulator (GSignalInvocationHint * ihint,
558     GValue * return_accu, const GValue * handler_return, gpointer dummy)
559 {
560   gboolean myboolean;
561
562   myboolean = g_value_get_boolean (handler_return);
563   if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
564     g_value_set_boolean (return_accu, myboolean);
565
566   return myboolean;
567 }
568 #endif
569
570 static gboolean
571 _gst_int_accumulator (GSignalInvocationHint * ihint,
572     GValue * return_accu, const GValue * handler_return, gpointer dummy)
573 {
574   gint res = g_value_get_int (handler_return);
575
576   if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
577     g_value_set_int (return_accu, res);
578
579   if (res == -1)
580     return TRUE;
581
582   return FALSE;
583 }
584
585 static void
586 gst_decodebin3_class_init (GstDecodebin3Class * klass)
587 {
588   GObjectClass *gobject_klass = (GObjectClass *) klass;
589   GstElementClass *element_class = (GstElementClass *) klass;
590   GstBinClass *bin_klass = (GstBinClass *) klass;
591
592   gobject_klass->dispose = gst_decodebin3_dispose;
593   gobject_klass->set_property = gst_decodebin3_set_property;
594   gobject_klass->get_property = gst_decodebin3_get_property;
595
596   /* FIXME : ADD PROPERTIES ! */
597   g_object_class_install_property (gobject_klass, PROP_CAPS,
598       g_param_spec_boxed ("caps", "Caps",
599           "The caps on which to stop decoding. (NULL = default)",
600           GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
601 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
602   g_object_class_install_property (gobject_klass, PROP_FORCE_SW_DECODERS_FOR_VIDEO,
603       g_param_spec_boolean ("force-sw-decoders-for-video", "Video Software Decoders Only",
604           "Use only sofware decoders for video to process streams",
605           DEFAULT_FORCE_SW_DECODERS,
606           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
607   g_object_class_install_property (gobject_klass, PROP_FORCE_SW_DECODERS_FOR_AUDIO,
608       g_param_spec_boolean ("force-sw-decoders-for-audio", "Audio Software Decoders Only",
609           "Use only sofware decoders for audio to process streams",
610           DEFAULT_FORCE_SW_DECODERS,
611           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
612 #else
613   /**
614    * GstDecodeBin::force-sw-decoders:
615    *
616    * While auto-plugging, if set to %TRUE, those decoders within
617    * "Hardware" klass will be ignored. Otherwise they will be tried.
618    *
619    * Since: 1.18
620    */
621   g_object_class_install_property (gobject_klass, PROP_FORCE_SW_DECODERS,
622       g_param_spec_boolean ("force-sw-decoders", "Software Decoders Only",
623           "Use only sofware decoders to process streams",
624           DEFAULT_FORCE_SW_DECODERS,
625           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
626 #endif
627   /* FIXME : ADD SIGNALS ! */
628   /**
629    * GstDecodebin3::select-stream
630    * @decodebin: a #GstDecodebin3
631    * @collection: a #GstStreamCollection
632    * @stream: a #GstStream
633    *
634    * This signal is emitted whenever @decodebin needs to decide whether
635    * to expose a @stream of a given @collection.
636    *
637    * Returns: 1 if the stream should be selected, 0 if it shouldn't be selected.
638    * A value of -1 (default) lets @decodebin decide what to do with the stream.
639    * */
640   gst_decodebin3_signals[SIGNAL_SELECT_STREAM] =
641       g_signal_new ("select-stream", G_TYPE_FROM_CLASS (klass),
642       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodebin3Class, select_stream),
643       _gst_int_accumulator, NULL, g_cclosure_marshal_generic,
644       G_TYPE_INT, 2, GST_TYPE_STREAM_COLLECTION, GST_TYPE_STREAM);
645
646   /**
647    * GstDecodebin3::about-to-finish:
648    *
649    * This signal is emitted when the data for the selected URI is
650    * entirely buffered and it is safe to specify anothe URI.
651    */
652   gst_decodebin3_signals[SIGNAL_ABOUT_TO_FINISH] =
653       g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
654       G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_marshal_generic, G_TYPE_NONE,
655       0, G_TYPE_NONE);
656
657 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
658   gst_decodebin3_signals[SIGNAL_REQUEST_RESOURCE] =
659       g_signal_new ("request-resource", G_TYPE_FROM_CLASS (klass),
660       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstDecodebin3Class, request_resource),
661       _gst_boolean_accumulator, NULL, g_cclosure_marshal_generic,
662       G_TYPE_BOOLEAN, 2, GST_TYPE_STREAM_COLLECTION, GST_TYPE_STREAM);
663 #endif
664
665   element_class->request_new_pad =
666       GST_DEBUG_FUNCPTR (gst_decodebin3_request_new_pad);
667   element_class->change_state = GST_DEBUG_FUNCPTR (gst_decodebin3_change_state);
668   element_class->send_event = GST_DEBUG_FUNCPTR (gst_decodebin3_send_event);
669
670   gst_element_class_add_pad_template (element_class,
671       gst_static_pad_template_get (&sink_template));
672   gst_element_class_add_pad_template (element_class,
673       gst_static_pad_template_get (&request_sink_template));
674   gst_element_class_add_pad_template (element_class,
675       gst_static_pad_template_get (&video_src_template));
676   gst_element_class_add_pad_template (element_class,
677       gst_static_pad_template_get (&audio_src_template));
678   gst_element_class_add_pad_template (element_class,
679       gst_static_pad_template_get (&text_src_template));
680   gst_element_class_add_pad_template (element_class,
681       gst_static_pad_template_get (&src_template));
682
683   gst_element_class_set_static_metadata (element_class,
684       "Decoder Bin 3", "Generic/Bin/Decoder",
685       "Autoplug and decode to raw media",
686       "Edward Hervey <edward@centricular.com>");
687
688   bin_klass->handle_message = gst_decodebin3_handle_message;
689
690   klass->select_stream = gst_decodebin3_select_stream;
691
692 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
693   klass->request_resource = gst_decodebin3_request_resource;
694 #endif
695 }
696
697 static void
698 gst_decodebin3_init (GstDecodebin3 * dbin)
699 {
700   /* Create main input */
701   dbin->main_input = create_new_input (dbin, TRUE);
702
703   dbin->multiqueue = gst_element_factory_make ("multiqueue", NULL);
704   g_object_set (dbin->multiqueue, "sync-by-running-time", TRUE,
705       "max-size-buffers", 0, "use-interleave", TRUE, NULL);
706   gst_bin_add ((GstBin *) dbin, dbin->multiqueue);
707
708   dbin->current_group_id = GST_GROUP_ID_INVALID;
709
710   g_mutex_init (&dbin->factories_lock);
711   g_mutex_init (&dbin->selection_lock);
712   g_mutex_init (&dbin->input_lock);
713
714   dbin->caps = gst_static_caps_get (&default_raw_caps);
715 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
716   dbin->force_sw_decoders_for_video = DEFAULT_FORCE_SW_DECODERS;
717   dbin->force_sw_decoders_for_audio = DEFAULT_FORCE_SW_DECODERS;
718 #else
719   dbin->force_sw_decoders = DEFAULT_FORCE_SW_DECODERS;
720 #endif
721
722   GST_OBJECT_FLAG_SET (dbin, GST_BIN_FLAG_STREAMS_AWARE);
723 }
724
725 static void
726 gst_decodebin3_dispose (GObject * object)
727 {
728   GstDecodebin3 *dbin = (GstDecodebin3 *) object;
729   GList *walk, *next;
730
731   if (dbin->factories)
732     gst_plugin_feature_list_free (dbin->factories);
733   if (dbin->decoder_factories)
734     g_list_free (dbin->decoder_factories);
735   if (dbin->decodable_factories)
736     g_list_free (dbin->decodable_factories);
737   g_list_free_full (dbin->requested_selection, g_free);
738   g_list_free (dbin->active_selection);
739   g_list_free (dbin->to_activate);
740   g_list_free (dbin->pending_select_streams);
741   g_clear_object (&dbin->collection);
742
743   free_input (dbin, dbin->main_input);
744
745   for (walk = dbin->other_inputs; walk; walk = next) {
746     DecodebinInput *input = walk->data;
747
748     next = g_list_next (walk);
749
750     free_input (dbin, input);
751     dbin->other_inputs = g_list_delete_link (dbin->other_inputs, walk);
752   }
753
754   G_OBJECT_CLASS (parent_class)->dispose (object);
755 }
756
757 static void
758 gst_decodebin3_set_property (GObject * object, guint prop_id,
759     const GValue * value, GParamSpec * pspec)
760 {
761   GstDecodebin3 *dbin = (GstDecodebin3 *) object;
762
763   /* FIXME : IMPLEMENT */
764   switch (prop_id) {
765     case PROP_CAPS:
766       GST_OBJECT_LOCK (dbin);
767       if (dbin->caps)
768         gst_caps_unref (dbin->caps);
769       dbin->caps = g_value_dup_boxed (value);
770       GST_OBJECT_UNLOCK (dbin);
771       break;
772 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
773     case PROP_FORCE_SW_DECODERS_FOR_VIDEO:
774       dbin->force_sw_decoders_for_video = g_value_get_boolean (value);
775       break;
776     case PROP_FORCE_SW_DECODERS_FOR_AUDIO:
777       dbin->force_sw_decoders_for_audio = g_value_get_boolean (value);
778       break;
779 #else
780     case PROP_FORCE_SW_DECODERS:
781       dbin->force_sw_decoders = g_value_get_boolean (value);
782       break;
783 #endif
784     default:
785       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
786       break;
787   }
788 }
789
790 static void
791 gst_decodebin3_get_property (GObject * object, guint prop_id, GValue * value,
792     GParamSpec * pspec)
793 {
794   GstDecodebin3 *dbin = (GstDecodebin3 *) object;
795
796   /* FIXME : IMPLEMENT */
797   switch (prop_id) {
798     case PROP_CAPS:
799       GST_OBJECT_LOCK (dbin);
800       g_value_set_boxed (value, dbin->caps);
801       GST_OBJECT_UNLOCK (dbin);
802       break;
803 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
804     case PROP_FORCE_SW_DECODERS_FOR_VIDEO:
805       g_value_set_boolean (value, dbin->force_sw_decoders_for_video);
806       break;
807     case PROP_FORCE_SW_DECODERS_FOR_AUDIO:
808       g_value_set_boolean (value, dbin->force_sw_decoders_for_audio);
809       break;
810 #else
811     case PROP_FORCE_SW_DECODERS:
812       g_value_set_boolean (value, dbin->force_sw_decoders);
813       break;
814 #endif
815     default:
816       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
817       break;
818   }
819 }
820
821 static gboolean
822 parsebin_autoplug_continue_cb (GstElement * parsebin, GstPad * pad,
823     GstCaps * caps, GstDecodebin3 * dbin)
824 {
825   GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
826
827   /* If it matches our target caps, expose it */
828   if (gst_caps_can_intersect (caps, dbin->caps))
829     return FALSE;
830
831   return TRUE;
832 }
833
834 /* This method should be called whenever a STREAM_START event
835  * comes out of a given parsebin.
836  * The caller shall replace the group_id if the function returns TRUE */
837 static gboolean
838 set_input_group_id (DecodebinInput * input, guint32 * group_id)
839 {
840   GstDecodebin3 *dbin = input->dbin;
841
842   if (input->group_id != *group_id) {
843     if (input->group_id != GST_GROUP_ID_INVALID)
844       GST_WARNING_OBJECT (dbin,
845           "Group id changed (%" G_GUINT32_FORMAT " -> %" G_GUINT32_FORMAT
846           ") on input %p ", input->group_id, *group_id, input);
847     input->group_id = *group_id;
848   }
849
850   if (*group_id != dbin->current_group_id) {
851     if (dbin->current_group_id == GST_GROUP_ID_INVALID) {
852       GST_DEBUG_OBJECT (dbin, "Setting current group id to %" G_GUINT32_FORMAT,
853           *group_id);
854       dbin->current_group_id = *group_id;
855     }
856     *group_id = dbin->current_group_id;
857     return TRUE;
858   }
859
860   return FALSE;
861 }
862
863 static void
864 parsebin_drained_cb (GstElement * parsebin, DecodebinInput * input)
865 {
866   GstDecodebin3 *dbin = input->dbin;
867   gboolean all_drained;
868   GList *tmp;
869
870   GST_WARNING_OBJECT (dbin, "input %p drained", input);
871   input->drained = TRUE;
872
873   all_drained = dbin->main_input->drained;
874   for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
875     DecodebinInput *data = (DecodebinInput *) tmp->data;
876
877     all_drained &= data->drained;
878   }
879
880   if (all_drained) {
881     GST_WARNING_OBJECT (dbin, "All inputs drained. Posting about-to-finish");
882     g_signal_emit (dbin, gst_decodebin3_signals[SIGNAL_ABOUT_TO_FINISH], 0,
883         NULL);
884   }
885 }
886
887 /* Call with INPUT_LOCK taken */
888 static gboolean
889 ensure_input_parsebin (GstDecodebin3 * dbin, DecodebinInput * input)
890 {
891   gboolean set_state = FALSE;
892
893   if (input->parsebin == NULL) {
894     input->parsebin = gst_element_factory_make ("parsebin", NULL);
895     if (input->parsebin == NULL)
896       goto no_parsebin;
897     input->parsebin = gst_object_ref (input->parsebin);
898     input->parsebin_sink = gst_element_get_static_pad (input->parsebin, "sink");
899     input->pad_added_sigid =
900         g_signal_connect (input->parsebin, "pad-added",
901         (GCallback) parsebin_pad_added_cb, input);
902     input->pad_removed_sigid =
903         g_signal_connect (input->parsebin, "pad-removed",
904         (GCallback) parsebin_pad_removed_cb, input);
905     input->drained_sigid =
906         g_signal_connect (input->parsebin, "drained",
907         (GCallback) parsebin_drained_cb, input);
908     g_signal_connect (input->parsebin, "autoplug-continue",
909         (GCallback) parsebin_autoplug_continue_cb, dbin);
910   }
911
912   if (GST_OBJECT_PARENT (GST_OBJECT (input->parsebin)) != GST_OBJECT (dbin)) {
913     gst_bin_add (GST_BIN (dbin), input->parsebin);
914     set_state = TRUE;
915   }
916
917   gst_ghost_pad_set_target (GST_GHOST_PAD (input->ghost_sink),
918       input->parsebin_sink);
919   if (set_state)
920     gst_element_sync_state_with_parent (input->parsebin);
921
922   return TRUE;
923
924   /* ERRORS */
925 no_parsebin:
926   {
927     gst_element_post_message ((GstElement *) dbin,
928         gst_missing_element_message_new ((GstElement *) dbin, "parsebin"));
929     return FALSE;
930   }
931 }
932
933 static GstPadLinkReturn
934 gst_decodebin3_input_pad_link (GstPad * pad, GstObject * parent, GstPad * peer)
935 {
936   GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
937   GstPadLinkReturn res = GST_PAD_LINK_OK;
938   DecodebinInput *input;
939
940   GST_LOG_OBJECT (parent, "Got link on input pad %" GST_PTR_FORMAT
941       ". Creating parsebin if needed", pad);
942
943   if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
944     goto fail;
945
946   INPUT_LOCK (dbin);
947   if (!ensure_input_parsebin (dbin, input))
948     res = GST_PAD_LINK_REFUSED;
949   INPUT_UNLOCK (dbin);
950
951   return res;
952 fail:
953   GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
954   return GST_PAD_LINK_REFUSED;
955 }
956
957 /* Drop duration query during _input_pad_unlink */
958 static GstPadProbeReturn
959 query_duration_drop_probe (GstPad * pad, GstPadProbeInfo * info,
960     DecodebinInput * input)
961 {
962   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
963
964   if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) {
965     GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
966     if (GST_QUERY_TYPE (query) == GST_QUERY_DURATION) {
967       GST_LOG_OBJECT (pad, "stop forwarding query duration");
968       ret = GST_PAD_PROBE_HANDLED;
969     }
970   }
971
972   return ret;
973 }
974
975 static void
976 gst_decodebin3_input_pad_unlink (GstPad * pad, GstObject * parent)
977 {
978   GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
979   DecodebinInput *input;
980
981   GST_LOG_OBJECT (parent, "Got unlink on input pad %" GST_PTR_FORMAT
982       ". Removing parsebin.", pad);
983
984   if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
985     goto fail;
986
987   INPUT_LOCK (dbin);
988   if (input->parsebin == NULL) {
989     INPUT_UNLOCK (dbin);
990     return;
991   }
992
993   if (GST_OBJECT_PARENT (GST_OBJECT (input->parsebin)) == GST_OBJECT (dbin)) {
994     GstStreamCollection *collection = NULL;
995     gulong probe_id = gst_pad_add_probe (input->parsebin_sink,
996         GST_PAD_PROBE_TYPE_QUERY_UPSTREAM,
997         (GstPadProbeCallback) query_duration_drop_probe, input, NULL);
998
999     /* Clear stream-collection corresponding to current INPUT and post new
1000      * stream-collection message, if needed */
1001     if (input->collection) {
1002       gst_object_unref (input->collection);
1003       input->collection = NULL;
1004     }
1005
1006     SELECTION_LOCK (dbin);
1007     collection = get_merged_collection (dbin);
1008     if (collection && collection != dbin->collection) {
1009       GstMessage *msg;
1010       GST_DEBUG_OBJECT (dbin, "Update Stream Collection");
1011
1012       if (dbin->collection)
1013         gst_object_unref (dbin->collection);
1014       dbin->collection = collection;
1015
1016       msg =
1017           gst_message_new_stream_collection ((GstObject *) dbin,
1018           dbin->collection);
1019
1020       SELECTION_UNLOCK (dbin);
1021       gst_element_post_message (GST_ELEMENT_CAST (dbin), msg);
1022       update_requested_selection (dbin);
1023     } else
1024       SELECTION_UNLOCK (dbin);
1025
1026     gst_bin_remove (GST_BIN (dbin), input->parsebin);
1027     gst_element_set_state (input->parsebin, GST_STATE_NULL);
1028     g_signal_handler_disconnect (input->parsebin, input->pad_removed_sigid);
1029     g_signal_handler_disconnect (input->parsebin, input->pad_added_sigid);
1030     g_signal_handler_disconnect (input->parsebin, input->drained_sigid);
1031     gst_pad_remove_probe (input->parsebin_sink, probe_id);
1032     gst_object_unref (input->parsebin);
1033     gst_object_unref (input->parsebin_sink);
1034
1035     input->parsebin = NULL;
1036     input->parsebin_sink = NULL;
1037
1038     if (!input->is_main) {
1039       dbin->other_inputs = g_list_remove (dbin->other_inputs, input);
1040       free_input_async (dbin, input);
1041     }
1042   }
1043   INPUT_UNLOCK (dbin);
1044   return;
1045
1046 fail:
1047   GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
1048   return;
1049 }
1050
1051 static void
1052 free_input (GstDecodebin3 * dbin, DecodebinInput * input)
1053 {
1054   GST_DEBUG ("Freeing input %p", input);
1055   gst_ghost_pad_set_target (GST_GHOST_PAD (input->ghost_sink), NULL);
1056   gst_element_remove_pad (GST_ELEMENT (dbin), input->ghost_sink);
1057   if (input->parsebin) {
1058     g_signal_handler_disconnect (input->parsebin, input->pad_removed_sigid);
1059     g_signal_handler_disconnect (input->parsebin, input->pad_added_sigid);
1060     g_signal_handler_disconnect (input->parsebin, input->drained_sigid);
1061     gst_element_set_state (input->parsebin, GST_STATE_NULL);
1062     gst_object_unref (input->parsebin);
1063     gst_object_unref (input->parsebin_sink);
1064   }
1065   if (input->collection)
1066     gst_object_unref (input->collection);
1067   g_free (input);
1068 }
1069
1070 static void
1071 free_input_async (GstDecodebin3 * dbin, DecodebinInput * input)
1072 {
1073   GST_LOG_OBJECT (dbin, "pushing input %p on thread pool to free", input);
1074   gst_element_call_async (GST_ELEMENT_CAST (dbin),
1075       (GstElementCallAsyncFunc) free_input, input, NULL);
1076 }
1077
1078 /* Call with INPUT_LOCK taken */
1079 static DecodebinInput *
1080 create_new_input (GstDecodebin3 * dbin, gboolean main)
1081 {
1082   DecodebinInput *input;
1083
1084   input = g_new0 (DecodebinInput, 1);
1085   input->dbin = dbin;
1086   input->is_main = main;
1087   input->group_id = GST_GROUP_ID_INVALID;
1088   if (main)
1089     input->ghost_sink = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
1090   else {
1091     gchar *pad_name = g_strdup_printf ("sink_%u", dbin->input_counter++);
1092     input->ghost_sink = gst_ghost_pad_new_no_target (pad_name, GST_PAD_SINK);
1093     g_free (pad_name);
1094   }
1095   g_object_set_data (G_OBJECT (input->ghost_sink), "decodebin.input", input);
1096   gst_pad_set_link_function (input->ghost_sink, gst_decodebin3_input_pad_link);
1097   gst_pad_set_unlink_function (input->ghost_sink,
1098       gst_decodebin3_input_pad_unlink);
1099
1100   gst_pad_set_active (input->ghost_sink, TRUE);
1101   gst_element_add_pad ((GstElement *) dbin, input->ghost_sink);
1102
1103   return input;
1104
1105 }
1106
1107 static GstPad *
1108 gst_decodebin3_request_new_pad (GstElement * element, GstPadTemplate * temp,
1109     const gchar * name, const GstCaps * caps)
1110 {
1111   GstDecodebin3 *dbin = (GstDecodebin3 *) element;
1112   DecodebinInput *input;
1113   GstPad *res = NULL;
1114
1115   /* We are ignoring names for the time being, not sure it makes any sense
1116    * within the context of decodebin3 ... */
1117   input = create_new_input (dbin, FALSE);
1118   if (input) {
1119     INPUT_LOCK (dbin);
1120     dbin->other_inputs = g_list_append (dbin->other_inputs, input);
1121     res = input->ghost_sink;
1122     INPUT_UNLOCK (dbin);
1123   }
1124
1125   return res;
1126 }
1127
1128 /* Must be called with factories lock! */
1129 static void
1130 gst_decode_bin_update_factories_list (GstDecodebin3 * dbin)
1131 {
1132   guint cookie;
1133
1134   cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1135   if (!dbin->factories || dbin->factories_cookie != cookie) {
1136     GList *tmp;
1137     if (dbin->factories)
1138       gst_plugin_feature_list_free (dbin->factories);
1139     if (dbin->decoder_factories)
1140       g_list_free (dbin->decoder_factories);
1141     if (dbin->decodable_factories)
1142       g_list_free (dbin->decodable_factories);
1143     dbin->factories =
1144         gst_element_factory_list_get_elements
1145         (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1146     dbin->factories =
1147         g_list_sort (dbin->factories, gst_plugin_feature_rank_compare_func);
1148     dbin->factories_cookie = cookie;
1149
1150     /* Filter decoder and other decodables */
1151     dbin->decoder_factories = NULL;
1152     dbin->decodable_factories = NULL;
1153     for (tmp = dbin->factories; tmp; tmp = tmp->next) {
1154       GstElementFactory *fact = (GstElementFactory *) tmp->data;
1155
1156       if (gst_element_factory_list_is_type (fact,
1157               GST_ELEMENT_FACTORY_TYPE_DECODER)) {
1158 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
1159         if  (!(dbin->force_sw_decoders_for_video &&
1160              gst_element_factory_list_is_type (fact, GST_ELEMENT_FACTORY_TYPE_MEDIA_VIDEO) &&
1161              gst_element_factory_list_is_type (fact, GST_ELEMENT_FACTORY_TYPE_HARDWARE)) &&
1162              !(dbin->force_sw_decoders_for_audio &&
1163              gst_element_factory_list_is_type (fact, GST_ELEMENT_FACTORY_TYPE_MEDIA_AUDIO) &&
1164              gst_element_factory_list_is_type (fact, GST_ELEMENT_FACTORY_TYPE_HARDWARE))) {
1165           dbin->decoder_factories =
1166               g_list_append (dbin->decoder_factories, fact);
1167         } else {
1168           GST_WARNING("%s is skipped", GST_OBJECT_NAME(fact));
1169         }
1170 #else
1171         if (!(dbin->force_sw_decoders
1172                 && gst_element_factory_list_is_type (fact,
1173                     GST_ELEMENT_FACTORY_TYPE_HARDWARE))) {
1174           dbin->decoder_factories =
1175               g_list_append (dbin->decoder_factories, fact);
1176         }
1177 #endif
1178       } else {
1179         dbin->decodable_factories =
1180             g_list_append (dbin->decodable_factories, fact);
1181       }
1182     }
1183   }
1184 }
1185
1186 /* Must be called with appropriate lock if list is a protected variable */
1187 static const gchar *
1188 stream_in_list (GList * list, const gchar * sid)
1189 {
1190   GList *tmp;
1191
1192 #if EXTRA_DEBUG
1193   for (tmp = list; tmp; tmp = tmp->next) {
1194     gchar *osid = (gchar *) tmp->data;
1195     GST_DEBUG ("Checking %s against %s", sid, osid);
1196   }
1197 #endif
1198
1199   for (tmp = list; tmp; tmp = tmp->next) {
1200     const gchar *osid = (gchar *) tmp->data;
1201     if (!g_strcmp0 (sid, osid))
1202       return osid;
1203   }
1204
1205   return NULL;
1206 }
1207
1208 static void
1209 update_requested_selection (GstDecodebin3 * dbin)
1210 {
1211   guint i, nb;
1212   GList *tmp = NULL;
1213   GstStreamType used_types = 0;
1214   GstStreamCollection *collection;
1215
1216   /* 1. Is there a pending SELECT_STREAMS we can return straight away since
1217    *  the switch handler will take care of the pending selection */
1218   SELECTION_LOCK (dbin);
1219   if (dbin->pending_select_streams) {
1220     GST_DEBUG_OBJECT (dbin,
1221         "No need to create pending selection, SELECT_STREAMS underway");
1222     goto beach;
1223   }
1224
1225   collection = dbin->collection;
1226   if (G_UNLIKELY (collection == NULL)) {
1227     GST_DEBUG_OBJECT (dbin, "No current GstStreamCollection");
1228     goto beach;
1229   }
1230   nb = gst_stream_collection_get_size (collection);
1231
1232   /* 2. If not, are we in EXPOSE_ALL_MODE ? If so, match everything */
1233   GST_FIXME_OBJECT (dbin, "Implement EXPOSE_ALL_MODE");
1234
1235   /* 3. If not, check if we already have some of the streams in the
1236    * existing active/requested selection */
1237   for (i = 0; i < nb; i++) {
1238     GstStream *stream = gst_stream_collection_get_stream (collection, i);
1239     const gchar *sid = gst_stream_get_stream_id (stream);
1240     gint request = -1;
1241     /* Fire select-stream signal to see if outside components want to
1242      * hint at which streams should be selected */
1243     g_signal_emit (G_OBJECT (dbin),
1244         gst_decodebin3_signals[SIGNAL_SELECT_STREAM], 0, collection, stream,
1245         &request);
1246     GST_DEBUG_OBJECT (dbin, "stream %s , request:%d", sid, request);
1247     if (request == 1 || (request == -1
1248             && (stream_in_list (dbin->requested_selection, sid)
1249                 || stream_in_list (dbin->active_selection, sid)))) {
1250       GstStreamType curtype = gst_stream_get_stream_type (stream);
1251       if (request == 1)
1252         GST_DEBUG_OBJECT (dbin,
1253             "Using stream requested by 'select-stream' signal : %s", sid);
1254       else
1255         GST_DEBUG_OBJECT (dbin,
1256             "Re-using stream already present in requested or active selection : %s",
1257             sid);
1258       tmp = g_list_append (tmp, (gchar *) sid);
1259       used_types |= curtype;
1260     }
1261   }
1262
1263   /* 4. If not, match one stream of each type */
1264   for (i = 0; i < nb; i++) {
1265     GstStream *stream = gst_stream_collection_get_stream (collection, i);
1266     GstStreamType curtype = gst_stream_get_stream_type (stream);
1267     if (!(used_types & curtype)) {
1268       const gchar *sid = gst_stream_get_stream_id (stream);
1269       GST_DEBUG_OBJECT (dbin, "Selecting stream '%s' of type %s",
1270           sid, gst_stream_type_get_name (curtype));
1271       tmp = g_list_append (tmp, (gchar *) sid);
1272       used_types |= curtype;
1273     }
1274   }
1275
1276 beach:
1277   /* Finally set the requested selection */
1278   if (tmp) {
1279     if (dbin->requested_selection) {
1280       GST_FIXME_OBJECT (dbin,
1281           "Replacing non-NULL requested_selection, what should we do ??");
1282       g_list_free_full (dbin->requested_selection, g_free);
1283     }
1284     dbin->requested_selection =
1285         g_list_copy_deep (tmp, (GCopyFunc) g_strdup, NULL);
1286     dbin->selection_updated = TRUE;
1287     g_list_free (tmp);
1288   }
1289   SELECTION_UNLOCK (dbin);
1290 }
1291
1292 /* sort_streams:
1293  * GCompareFunc to use with lists of GstStream.
1294  * Sorts GstStreams by stream type and SELECT flag and stream-id
1295  * First video, then audio, then others.
1296  *
1297  * Return: negative if a<b, 0 if a==b, positive if a>b
1298  */
1299 static gint
1300 sort_streams (GstStream * sa, GstStream * sb)
1301 {
1302   GstStreamType typea, typeb;
1303   GstStreamFlags flaga, flagb;
1304   const gchar *ida, *idb;
1305   gint ret = 0;
1306
1307   typea = gst_stream_get_stream_type (sa);
1308   typeb = gst_stream_get_stream_type (sb);
1309
1310   GST_LOG ("sa(%s), sb(%s)", gst_stream_get_stream_id (sa),
1311       gst_stream_get_stream_id (sb));
1312
1313   /* Sort by stream type. First video, then audio, then others(text, container, unknown) */
1314   if (typea != typeb) {
1315     if (typea & GST_STREAM_TYPE_VIDEO)
1316       ret = -1;
1317     else if (typea & GST_STREAM_TYPE_AUDIO)
1318       ret = (!(typeb & GST_STREAM_TYPE_VIDEO)) ? -1 : 1;
1319     else if (typea & GST_STREAM_TYPE_TEXT)
1320       ret = (!(typeb & GST_STREAM_TYPE_VIDEO)
1321           && !(typeb & GST_STREAM_TYPE_AUDIO)) ? -1 : 1;
1322     else if (typea & GST_STREAM_TYPE_CONTAINER)
1323       ret = (typeb & GST_STREAM_TYPE_UNKNOWN) ? -1 : 1;
1324     else
1325       ret = 1;
1326
1327     if (ret != 0) {
1328       GST_LOG ("Sort by stream-type: %d", ret);
1329       return ret;
1330     }
1331   }
1332
1333   /* Sort by SELECT flag, if stream type is same. */
1334   flaga = gst_stream_get_stream_flags (sa);
1335   flagb = gst_stream_get_stream_flags (sb);
1336
1337   ret =
1338       (flaga & GST_STREAM_FLAG_SELECT) ? ((flagb & GST_STREAM_FLAG_SELECT) ? 0 :
1339       -1) : ((flagb & GST_STREAM_FLAG_SELECT) ? 1 : 0);
1340
1341   if (ret != 0) {
1342     GST_LOG ("Sort by SELECT flag: %d", ret);
1343     return ret;
1344   }
1345
1346   /* Sort by stream-id, if otherwise the same. */
1347   ida = gst_stream_get_stream_id (sa);
1348   idb = gst_stream_get_stream_id (sb);
1349   ret = g_strcmp0 (ida, idb);
1350
1351   GST_LOG ("Sort by stream-id: %d", ret);
1352
1353   return ret;
1354 }
1355
1356 /* Call with INPUT_LOCK taken */
1357 static GstStreamCollection *
1358 get_merged_collection (GstDecodebin3 * dbin)
1359 {
1360   gboolean needs_merge = FALSE;
1361   GstStreamCollection *res = NULL;
1362   GList *tmp;
1363   GList *unsorted_streams = NULL;
1364   guint i, nb_stream;
1365
1366   /* First check if we need to do a merge or just return the only collection */
1367   res = dbin->main_input->collection;
1368
1369   for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
1370     DecodebinInput *input = (DecodebinInput *) tmp->data;
1371     if (input->collection) {
1372       if (res) {
1373         needs_merge = TRUE;
1374         break;
1375       }
1376       res = input->collection;
1377     }
1378   }
1379
1380   if (!needs_merge) {
1381     GST_DEBUG_OBJECT (dbin, "No need to merge, returning %p", res);
1382     return res ? gst_object_ref (res) : NULL;
1383   }
1384
1385   /* We really need to create a new collection */
1386   /* FIXME : Some numbering scheme maybe ?? */
1387   res = gst_stream_collection_new ("decodebin3");
1388   if (dbin->main_input->collection) {
1389     nb_stream = gst_stream_collection_get_size (dbin->main_input->collection);
1390     GST_DEBUG_OBJECT (dbin, "main input %p %d", dbin->main_input, nb_stream);
1391     for (i = 0; i < nb_stream; i++) {
1392       GstStream *stream =
1393           gst_stream_collection_get_stream (dbin->main_input->collection, i);
1394       unsorted_streams = g_list_append (unsorted_streams, stream);
1395     }
1396   }
1397
1398   for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
1399     DecodebinInput *input = (DecodebinInput *) tmp->data;
1400     GST_DEBUG_OBJECT (dbin, "input %p , collection %p", input,
1401         input->collection);
1402     if (input->collection) {
1403       nb_stream = gst_stream_collection_get_size (input->collection);
1404       GST_DEBUG_OBJECT (dbin, "nb_stream : %d", nb_stream);
1405       for (i = 0; i < nb_stream; i++) {
1406         GstStream *stream =
1407             gst_stream_collection_get_stream (input->collection, i);
1408         unsorted_streams = g_list_append (unsorted_streams, stream);
1409       }
1410     }
1411   }
1412
1413   /* re-order streams : video, then audio, then others */
1414   unsorted_streams =
1415       g_list_sort (unsorted_streams, (GCompareFunc) sort_streams);
1416   for (tmp = unsorted_streams; tmp; tmp = tmp->next) {
1417     GstStream *stream = (GstStream *) tmp->data;
1418     GST_DEBUG_OBJECT (dbin, "Adding #stream(%s) to collection",
1419         gst_stream_get_stream_id (stream));
1420     gst_stream_collection_add_stream (res, gst_object_ref (stream));
1421   }
1422
1423   if (unsorted_streams)
1424     g_list_free (unsorted_streams);
1425
1426   return res;
1427 }
1428
1429 /* Call with INPUT_LOCK taken */
1430 static DecodebinInput *
1431 find_message_parsebin (GstDecodebin3 * dbin, GstElement * child)
1432 {
1433   DecodebinInput *input = NULL;
1434   GstElement *parent = gst_object_ref (child);
1435   GList *tmp;
1436
1437   do {
1438     GstElement *next_parent;
1439
1440     GST_DEBUG_OBJECT (dbin, "parent %s",
1441         parent ? GST_ELEMENT_NAME (parent) : "<NONE>");
1442
1443     if (parent == dbin->main_input->parsebin) {
1444       input = dbin->main_input;
1445       break;
1446     }
1447     for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
1448       DecodebinInput *cur = (DecodebinInput *) tmp->data;
1449       if (parent == cur->parsebin) {
1450         input = cur;
1451         break;
1452       }
1453     }
1454     next_parent = (GstElement *) gst_element_get_parent (parent);
1455     gst_object_unref (parent);
1456     parent = next_parent;
1457
1458   } while (parent && parent != (GstElement *) dbin);
1459
1460   if (parent)
1461     gst_object_unref (parent);
1462
1463   return input;
1464 }
1465
1466 static const gchar *
1467 stream_in_collection (GstDecodebin3 * dbin, gchar * sid)
1468 {
1469   guint i, len;
1470
1471   if (dbin->collection == NULL)
1472     return NULL;
1473   len = gst_stream_collection_get_size (dbin->collection);
1474   for (i = 0; i < len; i++) {
1475     GstStream *stream = gst_stream_collection_get_stream (dbin->collection, i);
1476     const gchar *osid = gst_stream_get_stream_id (stream);
1477     if (!g_strcmp0 (sid, osid))
1478       return osid;
1479   }
1480
1481   return NULL;
1482 }
1483
1484 /* Call with INPUT_LOCK taken */
1485 static void
1486 handle_stream_collection (GstDecodebin3 * dbin,
1487     GstStreamCollection * collection, GstElement * child)
1488 {
1489 #ifndef GST_DISABLE_GST_DEBUG
1490   const gchar *upstream_id;
1491   guint i;
1492 #endif
1493   DecodebinInput *input = find_message_parsebin (dbin, child);
1494
1495   if (!input) {
1496     GST_DEBUG_OBJECT (dbin,
1497         "Couldn't find corresponding input, most likely shutting down");
1498     return;
1499   }
1500
1501   /* Replace collection in input */
1502   if (input->collection)
1503     gst_object_unref (input->collection);
1504   input->collection = gst_object_ref (collection);
1505   GST_DEBUG_OBJECT (dbin, "Setting collection %p on input %p", collection,
1506       input);
1507
1508   /* Merge collection if needed */
1509   collection = get_merged_collection (dbin);
1510
1511 #ifndef GST_DISABLE_GST_DEBUG
1512   /* Just some debugging */
1513   upstream_id = gst_stream_collection_get_upstream_id (collection);
1514   GST_DEBUG ("Received Stream Collection. Upstream_id : %s", upstream_id);
1515   GST_DEBUG ("From input %p", input);
1516   GST_DEBUG ("  %d streams", gst_stream_collection_get_size (collection));
1517   for (i = 0; i < gst_stream_collection_get_size (collection); i++) {
1518     GstStream *stream = gst_stream_collection_get_stream (collection, i);
1519     GstTagList *taglist;
1520     GstCaps *caps;
1521
1522     GST_DEBUG ("   Stream '%s'", gst_stream_get_stream_id (stream));
1523     GST_DEBUG ("     type  : %s",
1524         gst_stream_type_get_name (gst_stream_get_stream_type (stream)));
1525     GST_DEBUG ("     flags : 0x%x", gst_stream_get_stream_flags (stream));
1526     taglist = gst_stream_get_tags (stream);
1527     GST_DEBUG ("     tags  : %" GST_PTR_FORMAT, taglist);
1528     caps = gst_stream_get_caps (stream);
1529     GST_DEBUG ("     caps  : %" GST_PTR_FORMAT, caps);
1530     if (taglist)
1531       gst_tag_list_unref (taglist);
1532     if (caps)
1533       gst_caps_unref (caps);
1534   }
1535 #endif
1536
1537   /* Store collection for later usage */
1538   SELECTION_LOCK (dbin);
1539   if (dbin->collection == NULL) {
1540     dbin->collection = collection;
1541   } else {
1542     /* We need to check who emitted this collection (the owner).
1543      * If we already had a collection from that user, this one is an update,
1544      * that is to say that we need to figure out how we are going to re-use
1545      * the streams/slot */
1546     GST_FIXME_OBJECT (dbin, "New collection but already had one ...");
1547     /* FIXME : When do we switch from pending collection to active collection ?
1548      * When all streams from active collection are drained in multiqueue output ? */
1549     gst_object_unref (dbin->collection);
1550     dbin->collection = collection;
1551     /* dbin->pending_collection = */
1552     /*     g_list_append (dbin->pending_collection, collection); */
1553   }
1554   SELECTION_UNLOCK (dbin);
1555 }
1556
1557 static void
1558 gst_decodebin3_handle_message (GstBin * bin, GstMessage * message)
1559 {
1560   GstDecodebin3 *dbin = (GstDecodebin3 *) bin;
1561   gboolean posting_collection = FALSE;
1562
1563   GST_DEBUG_OBJECT (bin, "Got Message %s", GST_MESSAGE_TYPE_NAME (message));
1564
1565   switch (GST_MESSAGE_TYPE (message)) {
1566     case GST_MESSAGE_STREAM_COLLECTION:
1567     {
1568       GstStreamCollection *collection = NULL;
1569       gst_message_parse_stream_collection (message, &collection);
1570       if (collection) {
1571         INPUT_LOCK (dbin);
1572         handle_stream_collection (dbin, collection,
1573             (GstElement *) GST_MESSAGE_SRC (message));
1574         posting_collection = TRUE;
1575         INPUT_UNLOCK (dbin);
1576       }
1577
1578       SELECTION_LOCK (dbin);
1579       if (dbin->collection && collection != dbin->collection) {
1580         /* Replace collection message, we most likely aggregated it */
1581         GstMessage *new_msg;
1582         new_msg =
1583             gst_message_new_stream_collection ((GstObject *) dbin,
1584             dbin->collection);
1585         gst_message_unref (message);
1586         message = new_msg;
1587       }
1588       SELECTION_UNLOCK (dbin);
1589
1590       if (collection)
1591         gst_object_unref (collection);
1592       break;
1593     }
1594     default:
1595       break;
1596   }
1597
1598   GST_BIN_CLASS (parent_class)->handle_message (bin, message);
1599
1600   if (posting_collection) {
1601     /* Figure out a selection for that collection */
1602     update_requested_selection (dbin);
1603   }
1604 }
1605
1606 static DecodebinOutputStream *
1607 find_free_compatible_output (GstDecodebin3 * dbin, GstStream * stream)
1608 {
1609   GList *tmp;
1610   GstStreamType stype = gst_stream_get_stream_type (stream);
1611
1612   for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
1613     DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
1614     if (output->type == stype && output->slot && output->slot->active_stream) {
1615       GstStream *tstream = output->slot->active_stream;
1616       if (!stream_in_list (dbin->requested_selection,
1617               (gchar *) gst_stream_get_stream_id (tstream))) {
1618         return output;
1619       }
1620     }
1621   }
1622
1623   return NULL;
1624 }
1625
1626 /* Give a certain slot, figure out if it should be linked to an
1627  * output stream
1628  * CALL WITH SELECTION LOCK TAKEN !*/
1629 static DecodebinOutputStream *
1630 get_output_for_slot (MultiQueueSlot * slot)
1631 {
1632   GstDecodebin3 *dbin = slot->dbin;
1633   DecodebinOutputStream *output = NULL;
1634   const gchar *stream_id;
1635   GstCaps *caps;
1636   gchar *id_in_list = NULL;
1637
1638   /* If we already have a configured output, just use it */
1639   if (slot->output != NULL)
1640     return slot->output;
1641
1642   /*
1643    * FIXME
1644    *
1645    * This method needs to be split into multiple parts
1646    *
1647    * 1) Figure out whether stream should be exposed or not
1648    *   This is based on autoplug-continue, EXPOSE_ALL_MODE, or presence
1649    *   in the default stream attribution
1650    *
1651    * 2) Figure out whether an output stream should be created, whether
1652    *   we can re-use the output stream already linked to the slot, or
1653    *   whether we need to get re-assigned another (currently used) output
1654    *   stream.
1655    */
1656
1657   stream_id = gst_stream_get_stream_id (slot->active_stream);
1658   caps = gst_stream_get_caps (slot->active_stream);
1659   GST_DEBUG_OBJECT (dbin, "stream %s , %" GST_PTR_FORMAT, stream_id, caps);
1660   gst_caps_unref (caps);
1661
1662   /* 0. Emit autoplug-continue signal for pending caps ? */
1663   GST_FIXME_OBJECT (dbin, "emit autoplug-continue");
1664
1665   /* 1. if in EXPOSE_ALL_MODE, just accept */
1666   GST_FIXME_OBJECT (dbin, "Handle EXPOSE_ALL_MODE");
1667
1668 #if 0
1669   /* FIXME : The idea around this was to avoid activating a stream for
1670    *     which we have no decoder. Unfortunately it is way too
1671    *     expensive. Need to figure out a better solution */
1672   /* 2. Is there a potential decoder (if one is required) */
1673   if (!gst_caps_can_intersect (caps, dbin->caps)
1674       && !have_factory (dbin, (GstCaps *) caps,
1675           GST_ELEMENT_FACTORY_TYPE_DECODER)) {
1676     GST_WARNING_OBJECT (dbin, "Don't have a decoder for %" GST_PTR_FORMAT,
1677         caps);
1678     SELECTION_UNLOCK (dbin);
1679     gst_element_post_message (GST_ELEMENT_CAST (dbin),
1680         gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps));
1681     SELECTION_LOCK (dbin);
1682     return NULL;
1683   }
1684 #endif
1685
1686   /* 3. In default mode check if we should expose */
1687   id_in_list = (gchar *) stream_in_list (dbin->requested_selection, stream_id);
1688   if (id_in_list) {
1689     /* Check if we can steal an existing output stream we could re-use.
1690      * that is:
1691      * * an output stream whose slot->stream is not in requested
1692      * * and is of the same type as this stream
1693      */
1694     output = find_free_compatible_output (dbin, slot->active_stream);
1695     if (output) {
1696       /* Move this output from its current slot to this slot */
1697       dbin->to_activate =
1698           g_list_append (dbin->to_activate, (gchar *) stream_id);
1699       dbin->requested_selection =
1700           g_list_remove (dbin->requested_selection, id_in_list);
1701       g_free (id_in_list);
1702       SELECTION_UNLOCK (dbin);
1703       gst_pad_add_probe (output->slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
1704           (GstPadProbeCallback) slot_unassign_probe, output->slot, NULL);
1705       SELECTION_LOCK (dbin);
1706       return NULL;
1707     }
1708
1709     output = create_output_stream (dbin, slot->type);
1710     output->slot = slot;
1711     GST_DEBUG ("Linking slot %p to new output %p", slot, output);
1712     slot->output = output;
1713     dbin->active_selection =
1714         g_list_append (dbin->active_selection, (gchar *) stream_id);
1715   } else
1716     GST_DEBUG ("Not creating any output for slot %p", slot);
1717
1718   return output;
1719 }
1720
1721 /* Returns SELECTED_STREAMS message if active_selection is equal to
1722  * requested_selection, else NULL.
1723  * Must be called with LOCK taken */
1724 static GstMessage *
1725 is_selection_done (GstDecodebin3 * dbin)
1726 {
1727   GList *tmp;
1728   GstMessage *msg;
1729
1730   if (!dbin->selection_updated)
1731     return NULL;
1732
1733   GST_LOG_OBJECT (dbin, "Checking");
1734
1735   if (dbin->to_activate != NULL) {
1736     GST_DEBUG ("Still have streams to activate");
1737     return NULL;
1738   }
1739   for (tmp = dbin->requested_selection; tmp; tmp = tmp->next) {
1740     GST_DEBUG ("Checking requested stream %s", (gchar *) tmp->data);
1741     if (!stream_in_list (dbin->active_selection, (gchar *) tmp->data)) {
1742       GST_DEBUG ("Not in active selection, returning");
1743       return NULL;
1744     }
1745   }
1746
1747   GST_DEBUG_OBJECT (dbin, "Selection active, creating message");
1748
1749   /* We are completely active */
1750   msg = gst_message_new_streams_selected ((GstObject *) dbin, dbin->collection);
1751   GST_MESSAGE_SEQNUM (msg) = dbin->select_streams_seqnum;
1752   for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
1753     DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
1754     if (output->slot) {
1755       GST_DEBUG_OBJECT (dbin, "Adding stream %s",
1756           gst_stream_get_stream_id (output->slot->active_stream));
1757
1758       gst_message_streams_selected_add (msg, output->slot->active_stream);
1759     } else
1760       GST_WARNING_OBJECT (dbin, "No valid slot for output %p", output);
1761   }
1762   dbin->selection_updated = FALSE;
1763   return msg;
1764 }
1765
1766 /* Must be called with SELECTION_LOCK taken */
1767 static void
1768 check_all_slot_for_eos (GstDecodebin3 * dbin)
1769 {
1770   gboolean all_drained = TRUE;
1771   GList *iter;
1772
1773   GST_DEBUG_OBJECT (dbin, "check slot for eos");
1774
1775   for (iter = dbin->slots; iter; iter = iter->next) {
1776     MultiQueueSlot *slot = iter->data;
1777
1778     if (!slot->output)
1779       continue;
1780
1781     if (slot->is_drained) {
1782       GST_LOG_OBJECT (slot->sink_pad, "slot %p is drained", slot);
1783       continue;
1784     }
1785
1786     all_drained = FALSE;
1787     break;
1788   }
1789
1790   if (all_drained) {
1791     INPUT_LOCK (dbin);
1792     if (!pending_pads_are_eos (dbin->main_input))
1793       all_drained = FALSE;
1794
1795     if (all_drained) {
1796       for (iter = dbin->other_inputs; iter; iter = iter->next) {
1797         if (!pending_pads_are_eos ((DecodebinInput *) iter->data)) {
1798           all_drained = FALSE;
1799           break;
1800         }
1801       }
1802     }
1803     INPUT_UNLOCK (dbin);
1804   }
1805
1806   if (all_drained) {
1807     GST_DEBUG_OBJECT (dbin,
1808         "All active slots are drained, and no pending input, push EOS");
1809
1810     for (iter = dbin->input_streams; iter; iter = iter->next) {
1811       DecodebinInputStream *input = (DecodebinInputStream *) iter->data;
1812       GstPad *peer = gst_pad_get_peer (input->srcpad);
1813
1814       /* Send EOS to all slots */
1815       if (peer) {
1816         GstEvent *stream_start, *eos;
1817
1818         stream_start =
1819             gst_pad_get_sticky_event (input->srcpad, GST_EVENT_STREAM_START, 0);
1820
1821         /* First forward a custom STREAM_START event to reset the EOS status (if any) */
1822         if (stream_start) {
1823           GstStructure *s;
1824           GstEvent *custom_stream_start = gst_event_copy (stream_start);
1825           gst_event_unref (stream_start);
1826           s = (GstStructure *) gst_event_get_structure (custom_stream_start);
1827           gst_structure_set (s, "decodebin3-flushing-stream-start",
1828               G_TYPE_BOOLEAN, TRUE, NULL);
1829           gst_pad_send_event (peer, custom_stream_start);
1830         }
1831
1832         eos = gst_event_new_eos ();
1833         gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (eos),
1834             CUSTOM_FINAL_EOS_QUARK, (gchar *) CUSTOM_FINAL_EOS_QUARK_DATA,
1835             NULL);
1836         gst_pad_send_event (peer, eos);
1837         gst_object_unref (peer);
1838       } else
1839         GST_DEBUG_OBJECT (dbin, "no output");
1840     }
1841   }
1842 }
1843
1844 static GstPadProbeReturn
1845 multiqueue_src_probe (GstPad * pad, GstPadProbeInfo * info,
1846     MultiQueueSlot * slot)
1847 {
1848   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1849   GstDecodebin3 *dbin = slot->dbin;
1850
1851   if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
1852     GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
1853
1854     GST_DEBUG_OBJECT (pad, "Got event %p %s", ev, GST_EVENT_TYPE_NAME (ev));
1855     switch (GST_EVENT_TYPE (ev)) {
1856       case GST_EVENT_STREAM_START:
1857       {
1858         GstStream *stream = NULL;
1859         const GstStructure *s = gst_event_get_structure (ev);
1860
1861         /* Drop STREAM_START events used to cleanup multiqueue */
1862         if (s
1863             && gst_structure_has_field (s,
1864                 "decodebin3-flushing-stream-start")) {
1865           ret = GST_PAD_PROBE_HANDLED;
1866           gst_event_unref (ev);
1867           break;
1868         }
1869
1870         gst_event_parse_stream (ev, &stream);
1871         if (stream == NULL) {
1872           GST_ERROR_OBJECT (pad,
1873               "Got a STREAM_START event without a GstStream");
1874           break;
1875         }
1876         slot->is_drained = FALSE;
1877         GST_DEBUG_OBJECT (pad, "Stream Start '%s'",
1878             gst_stream_get_stream_id (stream));
1879         if (slot->active_stream == NULL) {
1880           slot->active_stream = stream;
1881         } else if (slot->active_stream != stream) {
1882           GST_FIXME_OBJECT (pad, "Handle stream changes (%s => %s) !",
1883               gst_stream_get_stream_id (slot->active_stream),
1884               gst_stream_get_stream_id (stream));
1885           gst_object_unref (slot->active_stream);
1886           slot->active_stream = stream;
1887         } else
1888           gst_object_unref (stream);
1889 #if 0                           /* Disabled because stream-start is pushed for every buffer on every unlinked pad */
1890         {
1891           gboolean is_active, is_requested;
1892           /* Quick check to see if we're in the current selection */
1893           /* FIXME : Re-check all slot<=>output mappings based on requested_selection */
1894           SELECTION_LOCK (dbin);
1895           GST_DEBUG_OBJECT (dbin, "Checking active selection");
1896           is_active = stream_in_list (dbin->active_selection, stream_id);
1897           GST_DEBUG_OBJECT (dbin, "Checking requested selection");
1898           is_requested = stream_in_list (dbin->requested_selection, stream_id);
1899           SELECTION_UNLOCK (dbin);
1900           if (is_active)
1901             GST_DEBUG_OBJECT (pad, "Slot in ACTIVE selection (output:%p)",
1902                 slot->output);
1903           if (is_requested)
1904             GST_DEBUG_OBJECT (pad, "Slot in REQUESTED selection (output:%p)",
1905                 slot->output);
1906           else if (slot->output) {
1907             GST_DEBUG_OBJECT (pad,
1908                 "Slot needs to be deactivated ? It's no longer in requested selection");
1909           } else if (!is_active)
1910             GST_DEBUG_OBJECT (pad,
1911                 "Slot in neither active nor requested selection");
1912         }
1913 #endif
1914       }
1915         break;
1916       case GST_EVENT_CAPS:
1917       {
1918         /* Configure the output slot if needed */
1919         DecodebinOutputStream *output;
1920         GstMessage *msg = NULL;
1921         SELECTION_LOCK (dbin);
1922         output = get_output_for_slot (slot);
1923         if (output) {
1924           reconfigure_output_stream (output, slot);
1925           msg = is_selection_done (dbin);
1926         }
1927         SELECTION_UNLOCK (dbin);
1928         if (msg)
1929           gst_element_post_message ((GstElement *) slot->dbin, msg);
1930       }
1931         break;
1932       case GST_EVENT_EOS:
1933       {
1934         gboolean was_drained = slot->is_drained;
1935         slot->is_drained = TRUE;
1936
1937         /* Custom EOS handling first */
1938         if (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (ev),
1939                 CUSTOM_EOS_QUARK)) {
1940           /* remove custom-eos */
1941           gst_mini_object_set_qdata (GST_MINI_OBJECT_CAST (ev),
1942               CUSTOM_EOS_QUARK, NULL, NULL);
1943           GST_LOG_OBJECT (pad, "Received custom EOS");
1944           ret = GST_PAD_PROBE_HANDLED;
1945           SELECTION_LOCK (dbin);
1946           if (slot->input == NULL) {
1947             GST_DEBUG_OBJECT (pad,
1948                 "Got custom-eos from null input stream, remove output stream");
1949             /* Remove the output */
1950             if (slot->output) {
1951               DecodebinOutputStream *output = slot->output;
1952               dbin->output_streams =
1953                   g_list_remove (dbin->output_streams, output);
1954               free_output_stream (dbin, output);
1955             }
1956             slot->probe_id = 0;
1957             dbin->slots = g_list_remove (dbin->slots, slot);
1958             free_multiqueue_slot_async (dbin, slot);
1959             ret = GST_PAD_PROBE_REMOVE;
1960           } else if (!was_drained) {
1961             check_all_slot_for_eos (dbin);
1962           }
1963           if (ret == GST_PAD_PROBE_HANDLED)
1964             gst_event_unref (ev);
1965           SELECTION_UNLOCK (dbin);
1966           break;
1967         }
1968
1969         GST_FIXME_OBJECT (pad, "EOS on multiqueue source pad. input:%p",
1970             slot->input);
1971         if (slot->input == NULL) {
1972           GstPad *peer;
1973           GST_DEBUG_OBJECT (pad,
1974               "last EOS for input, forwarding and removing slot");
1975           peer = gst_pad_get_peer (pad);
1976           if (peer) {
1977             gst_pad_send_event (peer, ev);
1978             gst_object_unref (peer);
1979           } else {
1980             gst_event_unref (ev);
1981           }
1982           SELECTION_LOCK (dbin);
1983           /* FIXME : Shouldn't we try to re-assign the output instead of just
1984            * removing it ? */
1985           /* Remove the output */
1986           if (slot->output) {
1987             DecodebinOutputStream *output = slot->output;
1988             dbin->output_streams = g_list_remove (dbin->output_streams, output);
1989             free_output_stream (dbin, output);
1990           }
1991           slot->probe_id = 0;
1992           dbin->slots = g_list_remove (dbin->slots, slot);
1993           SELECTION_UNLOCK (dbin);
1994
1995           free_multiqueue_slot_async (dbin, slot);
1996           ret = GST_PAD_PROBE_REMOVE;
1997         } else if (gst_mini_object_get_qdata (GST_MINI_OBJECT_CAST (ev),
1998                 CUSTOM_FINAL_EOS_QUARK)) {
1999           GST_DEBUG_OBJECT (pad, "Got final eos, propagating downstream");
2000         } else {
2001           GST_DEBUG_OBJECT (pad, "Got regular eos (all_inputs_are_eos)");
2002           /* drop current event as eos will be sent in check_all_slot_for_eos
2003            * when all output streams are also eos */
2004           ret = GST_PAD_PROBE_DROP;
2005           SELECTION_LOCK (dbin);
2006           check_all_slot_for_eos (dbin);
2007           SELECTION_UNLOCK (dbin);
2008         }
2009       }
2010         break;
2011       default:
2012         break;
2013     }
2014   } else if (GST_IS_QUERY (GST_PAD_PROBE_INFO_DATA (info))) {
2015     GstQuery *query = GST_PAD_PROBE_INFO_QUERY (info);
2016     switch (GST_QUERY_TYPE (query)) {
2017       case GST_QUERY_CAPS:
2018       {
2019         GST_DEBUG_OBJECT (pad, "Intercepting CAPS query");
2020         gst_query_set_caps_result (query, GST_CAPS_ANY);
2021         ret = GST_PAD_PROBE_HANDLED;
2022       }
2023         break;
2024
2025       case GST_QUERY_ACCEPT_CAPS:
2026       {
2027         GST_DEBUG_OBJECT (pad, "Intercepting Accept Caps query");
2028         /* If the current decoder doesn't accept caps, we'll reconfigure
2029          * on the actual caps event. So accept any caps. */
2030         gst_query_set_accept_caps_result (query, TRUE);
2031         ret = GST_PAD_PROBE_HANDLED;
2032       }
2033       default:
2034         break;
2035     }
2036   }
2037
2038   return ret;
2039 }
2040
2041 /* Create a new multiqueue slot for the given type
2042  *
2043  * It is up to the caller to know whether that slot is needed or not
2044  * (and release it when no longer needed) */
2045 static MultiQueueSlot *
2046 create_new_slot (GstDecodebin3 * dbin, GstStreamType type)
2047 {
2048   MultiQueueSlot *slot;
2049   GstIterator *it = NULL;
2050   GValue item = { 0, };
2051
2052   GST_DEBUG_OBJECT (dbin, "Creating new slot for type %s",
2053       gst_stream_type_get_name (type));
2054   slot = g_new0 (MultiQueueSlot, 1);
2055   slot->dbin = dbin;
2056
2057   slot->id = dbin->slot_id++;
2058
2059   slot->type = type;
2060   slot->sink_pad = gst_element_get_request_pad (dbin->multiqueue, "sink_%u");
2061   if (slot->sink_pad == NULL)
2062     goto fail;
2063
2064   it = gst_pad_iterate_internal_links (slot->sink_pad);
2065   if (!it || (gst_iterator_next (it, &item)) != GST_ITERATOR_OK
2066       || ((slot->src_pad = g_value_dup_object (&item)) == NULL)) {
2067     GST_ERROR ("Couldn't get srcpad from multiqueue for sink pad %s:%s",
2068         GST_DEBUG_PAD_NAME (slot->src_pad));
2069     goto fail;
2070   }
2071   gst_iterator_free (it);
2072   g_value_reset (&item);
2073
2074   g_object_set (slot->sink_pad, "group-id", (guint) type, NULL);
2075
2076   /* Add event probe */
2077   slot->probe_id =
2078       gst_pad_add_probe (slot->src_pad,
2079       GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM | GST_PAD_PROBE_TYPE_QUERY_DOWNSTREAM,
2080       (GstPadProbeCallback) multiqueue_src_probe, slot, NULL);
2081
2082   GST_DEBUG ("Created new slot %u (%p) (%s:%s)", slot->id, slot,
2083       GST_DEBUG_PAD_NAME (slot->src_pad));
2084
2085   dbin->slots = g_list_append (dbin->slots, slot);
2086
2087   return slot;
2088
2089   /* ERRORS */
2090 fail:
2091   {
2092     if (slot->sink_pad)
2093       gst_element_release_request_pad (dbin->multiqueue, slot->sink_pad);
2094     g_free (slot);
2095     return NULL;
2096   }
2097 }
2098
2099 /* Must be called with SELECTION_LOCK */
2100 static MultiQueueSlot *
2101 get_slot_for_input (GstDecodebin3 * dbin, DecodebinInputStream * input)
2102 {
2103   GList *tmp;
2104   MultiQueueSlot *empty_slot = NULL;
2105   GstStreamType input_type = 0;
2106   gchar *stream_id = NULL;
2107
2108   GST_DEBUG_OBJECT (dbin, "input %p (stream %p %s)",
2109       input, input->active_stream,
2110       input->
2111       active_stream ? gst_stream_get_stream_id (input->active_stream) : "");
2112
2113   if (input->active_stream) {
2114     input_type = gst_stream_get_stream_type (input->active_stream);
2115     stream_id = (gchar *) gst_stream_get_stream_id (input->active_stream);
2116   }
2117
2118   /* Go over existing slots and check if there is already one for it */
2119   for (tmp = dbin->slots; tmp; tmp = tmp->next) {
2120     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2121     /* Already used input, return that one */
2122     if (slot->input == input) {
2123       GST_DEBUG_OBJECT (dbin, "Returning already specified slot %d", slot->id);
2124       return slot;
2125     }
2126   }
2127
2128   /* Go amongst all unused slots of the right type and try to find a candidate */
2129   for (tmp = dbin->slots; tmp; tmp = tmp->next) {
2130     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2131     if (slot->input == NULL && input_type == slot->type) {
2132       /* Remember this empty slot for later */
2133       empty_slot = slot;
2134       /* Check if available slot is of the same stream_id */
2135       GST_LOG_OBJECT (dbin, "Checking candidate slot %d (active_stream:%p)",
2136           slot->id, slot->active_stream);
2137       if (stream_id && slot->active_stream) {
2138         gchar *ostream_id =
2139             (gchar *) gst_stream_get_stream_id (slot->active_stream);
2140         GST_DEBUG_OBJECT (dbin, "Checking slot %d %s against %s", slot->id,
2141             ostream_id, stream_id);
2142         if (!g_strcmp0 (stream_id, ostream_id))
2143           break;
2144       }
2145     }
2146   }
2147
2148   if (empty_slot) {
2149     GST_DEBUG_OBJECT (dbin, "Re-using existing unused slot %d", empty_slot->id);
2150     empty_slot->input = input;
2151     return empty_slot;
2152   }
2153
2154   if (input_type)
2155     return create_new_slot (dbin, input_type);
2156
2157   return NULL;
2158 }
2159
2160 static void
2161 link_input_to_slot (DecodebinInputStream * input, MultiQueueSlot * slot)
2162 {
2163   if (slot->input != NULL && slot->input != input) {
2164     GST_ERROR_OBJECT (slot->dbin,
2165         "Trying to link input to an already used slot");
2166     return;
2167   }
2168   gst_pad_link_full (input->srcpad, slot->sink_pad, GST_PAD_LINK_CHECK_NOTHING);
2169   slot->pending_stream = input->active_stream;
2170   slot->input = input;
2171 }
2172
2173 #if 0
2174 static gboolean
2175 have_factory (GstDecodebin3 * dbin, GstCaps * caps,
2176     GstElementFactoryListType ftype)
2177 {
2178   gboolean ret = FALSE;
2179   GList *res;
2180
2181   g_mutex_lock (&dbin->factories_lock);
2182   gst_decode_bin_update_factories_list (dbin);
2183   if (ftype == GST_ELEMENT_FACTORY_TYPE_DECODER)
2184     res =
2185         gst_element_factory_list_filter (dbin->decoder_factories,
2186         caps, GST_PAD_SINK, TRUE);
2187   else
2188     res =
2189         gst_element_factory_list_filter (dbin->decodable_factories,
2190         caps, GST_PAD_SINK, TRUE);
2191   g_mutex_unlock (&dbin->factories_lock);
2192
2193   if (res) {
2194     ret = TRUE;
2195     gst_plugin_feature_list_free (res);
2196   }
2197
2198   return ret;
2199 }
2200 #endif
2201
2202 static GstElement *
2203 create_element (GstDecodebin3 * dbin, GstStream * stream,
2204     GstElementFactoryListType ftype)
2205 {
2206   GList *res;
2207   GstElement *element = NULL;
2208   GstCaps *caps;
2209
2210   g_mutex_lock (&dbin->factories_lock);
2211   gst_decode_bin_update_factories_list (dbin);
2212   caps = gst_stream_get_caps (stream);
2213   if (ftype == GST_ELEMENT_FACTORY_TYPE_DECODER)
2214     res =
2215         gst_element_factory_list_filter (dbin->decoder_factories,
2216         caps, GST_PAD_SINK, TRUE);
2217   else
2218     res =
2219         gst_element_factory_list_filter (dbin->decodable_factories,
2220         caps, GST_PAD_SINK, TRUE);
2221   g_mutex_unlock (&dbin->factories_lock);
2222
2223   if (res) {
2224 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
2225     if (gst_element_factory_list_is_type (res->data,
2226               GST_ELEMENT_FACTORY_TYPE_HARDWARE)) {
2227         gboolean result = FALSE;
2228         g_signal_emit (G_OBJECT (dbin),
2229             gst_decodebin3_signals[SIGNAL_REQUEST_RESOURCE], 0, dbin->collection, stream,
2230             &result);
2231         if (!result) {
2232           GST_WARNING_OBJECT (dbin, "Failed to get HW resource.");
2233           gst_plugin_feature_list_free (res);
2234           gst_caps_unref (caps);
2235           return NULL;
2236         }
2237     }
2238 #endif
2239     element =
2240         gst_element_factory_create ((GstElementFactory *) res->data, NULL);
2241     GST_DEBUG ("Created element '%s'", GST_ELEMENT_NAME (element));
2242     gst_plugin_feature_list_free (res);
2243   } else {
2244     GST_DEBUG ("Could not find an element for caps %" GST_PTR_FORMAT, caps);
2245   }
2246
2247   gst_caps_unref (caps);
2248   return element;
2249 }
2250
2251 /* FIXME : VERY NAIVE. ASSUMING FIRST ONE WILL WORK */
2252 static GstElement *
2253 create_decoder (GstDecodebin3 * dbin, GstStream * stream)
2254 {
2255   return create_element (dbin, stream, GST_ELEMENT_FACTORY_TYPE_DECODER);
2256 }
2257
2258 static GstPadProbeReturn
2259 keyframe_waiter_probe (GstPad * pad, GstPadProbeInfo * info,
2260     DecodebinOutputStream * output)
2261 {
2262   GstBuffer *buf = GST_PAD_PROBE_INFO_BUFFER (info);
2263   /* If we have a keyframe, remove the probe and let all data through */
2264   /* FIXME : HANDLE HEADER BUFFER ?? */
2265   if (!GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_DELTA_UNIT) ||
2266       GST_BUFFER_FLAG_IS_SET (buf, GST_BUFFER_FLAG_HEADER)) {
2267     GST_DEBUG_OBJECT (pad,
2268         "Buffer is keyframe or header, letting through and removing probe");
2269     output->drop_probe_id = 0;
2270     return GST_PAD_PROBE_REMOVE;
2271   }
2272   GST_DEBUG_OBJECT (pad, "Buffer is not a keyframe, dropping");
2273   return GST_PAD_PROBE_DROP;
2274 }
2275
2276 static void
2277 reconfigure_output_stream (DecodebinOutputStream * output,
2278     MultiQueueSlot * slot)
2279 {
2280   GstDecodebin3 *dbin = output->dbin;
2281   GstCaps *new_caps = (GstCaps *) gst_stream_get_caps (slot->active_stream);
2282   gboolean needs_decoder;
2283
2284   needs_decoder = gst_caps_can_intersect (new_caps, dbin->caps) != TRUE;
2285
2286   GST_DEBUG_OBJECT (dbin,
2287       "Reconfiguring output %p to slot %p, needs_decoder:%d", output, slot,
2288       needs_decoder);
2289
2290   /* FIXME : Maybe make the output un-hook itself automatically ? */
2291   if (output->slot != NULL && output->slot != slot) {
2292     GST_WARNING_OBJECT (dbin,
2293         "Output still linked to another slot (%p)", output->slot);
2294     gst_caps_unref (new_caps);
2295     return;
2296   }
2297
2298   /* Check if existing config is reusable as-is by checking if
2299    * the existing decoder accepts the new caps, if not delete
2300    * it and create a new one */
2301   if (output->decoder) {
2302     gboolean can_reuse_decoder;
2303
2304     if (needs_decoder) {
2305       can_reuse_decoder =
2306           gst_pad_query_accept_caps (output->decoder_sink, new_caps);
2307     } else
2308       can_reuse_decoder = FALSE;
2309
2310     if (can_reuse_decoder) {
2311       if (output->type & GST_STREAM_TYPE_VIDEO && output->drop_probe_id == 0) {
2312         GST_DEBUG_OBJECT (dbin, "Adding keyframe-waiter probe");
2313         output->drop_probe_id =
2314             gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER,
2315             (GstPadProbeCallback) keyframe_waiter_probe, output, NULL);
2316       }
2317       GST_DEBUG_OBJECT (dbin, "Reusing existing decoder for slot %p", slot);
2318       if (output->linked == FALSE) {
2319         gst_pad_link_full (slot->src_pad, output->decoder_sink,
2320             GST_PAD_LINK_CHECK_NOTHING);
2321         output->linked = TRUE;
2322       }
2323       gst_caps_unref (new_caps);
2324       return;
2325     }
2326
2327     GST_DEBUG_OBJECT (dbin, "Removing old decoder for slot %p", slot);
2328
2329     if (output->linked)
2330       gst_pad_unlink (slot->src_pad, output->decoder_sink);
2331     output->linked = FALSE;
2332     if (output->drop_probe_id) {
2333       gst_pad_remove_probe (slot->src_pad, output->drop_probe_id);
2334       output->drop_probe_id = 0;
2335     }
2336
2337     if (!gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad, NULL)) {
2338       GST_ERROR_OBJECT (dbin, "Could not release decoder pad");
2339       gst_caps_unref (new_caps);
2340       goto cleanup;
2341     }
2342
2343     gst_element_set_locked_state (output->decoder, TRUE);
2344     gst_element_set_state (output->decoder, GST_STATE_NULL);
2345
2346     gst_bin_remove ((GstBin *) dbin, output->decoder);
2347     output->decoder = NULL;
2348   }
2349
2350   gst_caps_unref (new_caps);
2351
2352   gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
2353   gst_object_replace ((GstObject **) & output->decoder_src, NULL);
2354
2355   /* If a decoder is required, create one */
2356   if (needs_decoder) {
2357     /* If we don't have a decoder yet, instantiate one */
2358     output->decoder = create_decoder (dbin, slot->active_stream);
2359     if (output->decoder == NULL) {
2360       GstCaps *caps;
2361
2362       SELECTION_UNLOCK (dbin);
2363       /* FIXME : Should we be smarter if there's a missing decoder ?
2364        * Should we deactivate that stream ? */
2365       caps = gst_stream_get_caps (slot->active_stream);
2366       gst_element_post_message (GST_ELEMENT_CAST (dbin),
2367           gst_missing_decoder_message_new (GST_ELEMENT_CAST (dbin), caps));
2368       gst_caps_unref (caps);
2369       SELECTION_LOCK (dbin);
2370       goto cleanup;
2371     }
2372     if (!gst_bin_add ((GstBin *) dbin, output->decoder)) {
2373       GST_ERROR_OBJECT (dbin, "could not add decoder to pipeline");
2374       goto cleanup;
2375     }
2376     output->decoder_sink = gst_element_get_static_pad (output->decoder, "sink");
2377     output->decoder_src = gst_element_get_static_pad (output->decoder, "src");
2378     if (output->type & GST_STREAM_TYPE_VIDEO) {
2379       GST_DEBUG_OBJECT (dbin, "Adding keyframe-waiter probe");
2380       output->drop_probe_id =
2381           gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_BUFFER,
2382           (GstPadProbeCallback) keyframe_waiter_probe, output, NULL);
2383     }
2384     if (gst_pad_link_full (slot->src_pad, output->decoder_sink,
2385             GST_PAD_LINK_CHECK_NOTHING) != GST_PAD_LINK_OK) {
2386       GST_ERROR_OBJECT (dbin, "could not link to %s:%s",
2387           GST_DEBUG_PAD_NAME (output->decoder_sink));
2388       goto cleanup;
2389     }
2390   } else {
2391     output->decoder_src = gst_object_ref (slot->src_pad);
2392     output->decoder_sink = NULL;
2393   }
2394   output->linked = TRUE;
2395   if (!gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad,
2396           output->decoder_src)) {
2397     GST_ERROR_OBJECT (dbin, "Could not expose decoder pad");
2398     goto cleanup;
2399   }
2400   if (output->src_exposed == FALSE) {
2401     output->src_exposed = TRUE;
2402     gst_element_add_pad (GST_ELEMENT_CAST (dbin), output->src_pad);
2403   }
2404
2405   if (output->decoder)
2406     gst_element_sync_state_with_parent (output->decoder);
2407
2408   output->slot = slot;
2409   return;
2410
2411 cleanup:
2412   {
2413     GST_DEBUG_OBJECT (dbin, "Cleanup");
2414     if (output->decoder_sink) {
2415       gst_object_unref (output->decoder_sink);
2416       output->decoder_sink = NULL;
2417     }
2418     if (output->decoder_src) {
2419       gst_object_unref (output->decoder_src);
2420       output->decoder_src = NULL;
2421     }
2422     if (output->decoder) {
2423       gst_element_set_state (output->decoder, GST_STATE_NULL);
2424       gst_bin_remove ((GstBin *) dbin, output->decoder);
2425       output->decoder = NULL;
2426     }
2427   }
2428 }
2429
2430 static GstPadProbeReturn
2431 idle_reconfigure (GstPad * pad, GstPadProbeInfo * info, MultiQueueSlot * slot)
2432 {
2433   GstMessage *msg = NULL;
2434   DecodebinOutputStream *output;
2435
2436   SELECTION_LOCK (slot->dbin);
2437   output = get_output_for_slot (slot);
2438
2439   GST_DEBUG_OBJECT (pad, "output : %p", output);
2440
2441   if (output) {
2442     reconfigure_output_stream (output, slot);
2443     msg = is_selection_done (slot->dbin);
2444   }
2445   SELECTION_UNLOCK (slot->dbin);
2446   if (msg)
2447     gst_element_post_message ((GstElement *) slot->dbin, msg);
2448
2449   return GST_PAD_PROBE_REMOVE;
2450 }
2451
2452 static MultiQueueSlot *
2453 find_slot_for_stream_id (GstDecodebin3 * dbin, const gchar * sid)
2454 {
2455   GList *tmp;
2456
2457   for (tmp = dbin->slots; tmp; tmp = tmp->next) {
2458     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2459     const gchar *stream_id;
2460     if (slot->active_stream) {
2461       stream_id = gst_stream_get_stream_id (slot->active_stream);
2462       if (!g_strcmp0 (sid, stream_id))
2463         return slot;
2464     }
2465     if (slot->pending_stream && slot->pending_stream != slot->active_stream) {
2466       stream_id = gst_stream_get_stream_id (slot->pending_stream);
2467       if (!g_strcmp0 (sid, stream_id))
2468         return slot;
2469     }
2470   }
2471
2472   return NULL;
2473 }
2474
2475 /* This function handles the reassignment of a slot. Call this from
2476  * the streaming thread of a slot. */
2477 static gboolean
2478 reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
2479 {
2480   DecodebinOutputStream *output;
2481   MultiQueueSlot *target_slot = NULL;
2482   GList *tmp;
2483   const gchar *sid, *tsid;
2484
2485   SELECTION_LOCK (dbin);
2486   output = slot->output;
2487
2488   if (G_UNLIKELY (slot->active_stream == NULL)) {
2489     GST_DEBUG_OBJECT (slot->src_pad,
2490         "Called on inactive slot (active_stream == NULL)");
2491     SELECTION_UNLOCK (dbin);
2492     return FALSE;
2493   }
2494
2495   if (G_UNLIKELY (output == NULL)) {
2496     GST_DEBUG_OBJECT (slot->src_pad,
2497         "Slot doesn't have any output to be removed");
2498     SELECTION_UNLOCK (dbin);
2499     return FALSE;
2500   }
2501
2502   sid = gst_stream_get_stream_id (slot->active_stream);
2503   GST_DEBUG_OBJECT (slot->src_pad, "slot %s %p", sid, slot);
2504
2505   /* Recheck whether this stream is still in the list of streams to deactivate */
2506   if (stream_in_list (dbin->requested_selection, sid)) {
2507     /* Stream is in the list of requested streams, don't remove */
2508     SELECTION_UNLOCK (dbin);
2509     GST_DEBUG_OBJECT (slot->src_pad,
2510         "Stream '%s' doesn't need to be deactivated", sid);
2511     return FALSE;
2512   }
2513
2514   /* Unlink slot from output */
2515   /* FIXME : Handle flushing ? */
2516   /* FIXME : Handle outputs without decoders */
2517   GST_DEBUG_OBJECT (slot->src_pad, "Unlinking from decoder %p",
2518       output->decoder_sink);
2519   if (output->decoder_sink)
2520     gst_pad_unlink (slot->src_pad, output->decoder_sink);
2521   output->linked = FALSE;
2522   slot->output = NULL;
2523   output->slot = NULL;
2524   /* Remove sid from active selection */
2525   for (tmp = dbin->active_selection; tmp; tmp = tmp->next)
2526     if (!g_strcmp0 (sid, tmp->data)) {
2527       dbin->active_selection = g_list_delete_link (dbin->active_selection, tmp);
2528       break;
2529     }
2530
2531   /* Can we re-assign this output to a requested stream ? */
2532   GST_DEBUG_OBJECT (slot->src_pad, "Attempting to re-assing output stream");
2533   for (tmp = dbin->to_activate; tmp; tmp = tmp->next) {
2534     MultiQueueSlot *tslot = find_slot_for_stream_id (dbin, tmp->data);
2535     GST_LOG_OBJECT (tslot->src_pad, "Checking slot %p (output:%p , stream:%s)",
2536         tslot, tslot->output, gst_stream_get_stream_id (tslot->active_stream));
2537     if (tslot && tslot->type == output->type && tslot->output == NULL) {
2538       GST_DEBUG_OBJECT (tslot->src_pad, "Using as reassigned slot");
2539       target_slot = tslot;
2540       tsid = tmp->data;
2541       /* Pass target stream id to requested selection */
2542       dbin->requested_selection =
2543           g_list_append (dbin->requested_selection, g_strdup (tmp->data));
2544       dbin->to_activate = g_list_remove (dbin->to_activate, tmp->data);
2545       break;
2546     }
2547   }
2548
2549   if (target_slot) {
2550     GST_DEBUG_OBJECT (slot->src_pad, "Assigning output to slot %p '%s'",
2551         target_slot, tsid);
2552     target_slot->output = output;
2553     output->slot = target_slot;
2554     dbin->active_selection =
2555         g_list_append (dbin->active_selection, (gchar *) tsid);
2556     SELECTION_UNLOCK (dbin);
2557
2558     /* Wakeup the target slot so that it retries to send events/buffers
2559      * thereby triggering the output reconfiguration codepath */
2560     gst_pad_add_probe (target_slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
2561         (GstPadProbeCallback) idle_reconfigure, target_slot, NULL);
2562     /* gst_pad_send_event (target_slot->src_pad, gst_event_new_reconfigure ()); */
2563   } else {
2564     GstMessage *msg;
2565
2566     dbin->output_streams = g_list_remove (dbin->output_streams, output);
2567     free_output_stream (dbin, output);
2568     msg = is_selection_done (slot->dbin);
2569     SELECTION_UNLOCK (dbin);
2570
2571     if (msg)
2572       gst_element_post_message ((GstElement *) slot->dbin, msg);
2573   }
2574
2575   return TRUE;
2576 }
2577
2578 /* Idle probe called when a slot should be unassigned from its output stream.
2579  * This is needed to ensure nothing is flowing when unlinking the slot.
2580  *
2581  * Also, this method will search for a pending stream which could re-use
2582  * the output stream. */
2583 static GstPadProbeReturn
2584 slot_unassign_probe (GstPad * pad, GstPadProbeInfo * info,
2585     MultiQueueSlot * slot)
2586 {
2587   GstDecodebin3 *dbin = slot->dbin;
2588
2589   reassign_slot (dbin, slot);
2590
2591   return GST_PAD_PROBE_REMOVE;
2592 }
2593
2594 static gboolean
2595 handle_stream_switch (GstDecodebin3 * dbin, GList * select_streams,
2596     guint32 seqnum)
2597 {
2598   gboolean ret = TRUE;
2599   GList *tmp;
2600   /* List of slots to (de)activate. */
2601   GList *to_deactivate = NULL;
2602   GList *to_activate = NULL;
2603   /* List of unknown stream id, most likely means the event
2604    * should be sent upstream so that elements can expose the requested stream */
2605   GList *unknown = NULL;
2606   GList *to_reassign = NULL;
2607   GList *future_request_streams = NULL;
2608   GList *pending_streams = NULL;
2609   GList *slots_to_reassign = NULL;
2610
2611   SELECTION_LOCK (dbin);
2612   if (G_UNLIKELY (seqnum != dbin->select_streams_seqnum)) {
2613     GST_DEBUG_OBJECT (dbin, "New SELECT_STREAMS has arrived in the meantime");
2614     SELECTION_UNLOCK (dbin);
2615     return TRUE;
2616   }
2617   /* Remove pending select_streams */
2618   g_list_free (dbin->pending_select_streams);
2619   dbin->pending_select_streams = NULL;
2620
2621   /* COMPARE the requested streams to the active and requested streams
2622    * on multiqueue. */
2623
2624   /* First check the slots to activate and which ones are unknown */
2625   for (tmp = select_streams; tmp; tmp = tmp->next) {
2626     const gchar *sid = (const gchar *) tmp->data;
2627     MultiQueueSlot *slot;
2628     GST_DEBUG_OBJECT (dbin, "Checking stream '%s'", sid);
2629     slot = find_slot_for_stream_id (dbin, sid);
2630     /* Find the corresponding slot */
2631     if (slot == NULL) {
2632       if (stream_in_collection (dbin, (gchar *) sid)) {
2633         pending_streams = g_list_append (pending_streams, (gchar *) sid);
2634       } else {
2635         GST_DEBUG_OBJECT (dbin, "We don't have a slot for stream '%s'", sid);
2636         unknown = g_list_append (unknown, (gchar *) sid);
2637       }
2638     } else if (slot->output == NULL) {
2639       GST_DEBUG_OBJECT (dbin, "We need to activate slot %p for stream '%s')",
2640           slot, sid);
2641       to_activate = g_list_append (to_activate, slot);
2642     } else {
2643       GST_DEBUG_OBJECT (dbin,
2644           "Stream '%s' from slot %p is already active on output %p", sid, slot,
2645           slot->output);
2646       future_request_streams =
2647           g_list_append (future_request_streams, (gchar *) sid);
2648     }
2649   }
2650
2651   for (tmp = dbin->slots; tmp; tmp = tmp->next) {
2652     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2653     /* For slots that have an output, check if it's part of the streams to
2654      * be active */
2655     if (slot->output) {
2656       gboolean slot_to_deactivate = TRUE;
2657
2658       if (slot->active_stream) {
2659         if (stream_in_list (select_streams,
2660                 gst_stream_get_stream_id (slot->active_stream)))
2661           slot_to_deactivate = FALSE;
2662       }
2663       if (slot_to_deactivate && slot->pending_stream
2664           && slot->pending_stream != slot->active_stream) {
2665         if (stream_in_list (select_streams,
2666                 gst_stream_get_stream_id (slot->pending_stream)))
2667           slot_to_deactivate = FALSE;
2668       }
2669       if (slot_to_deactivate) {
2670         GST_DEBUG_OBJECT (dbin,
2671             "Slot %p (%s) should be deactivated, no longer used", slot,
2672             slot->
2673             active_stream ? gst_stream_get_stream_id (slot->active_stream) :
2674             "NULL");
2675         to_deactivate = g_list_append (to_deactivate, slot);
2676       }
2677     }
2678   }
2679
2680   if (to_deactivate != NULL) {
2681     GST_DEBUG_OBJECT (dbin, "Check if we can reassign slots");
2682     /* We need to compare what needs to be activated and deactivated in order
2683      * to determine whether there are outputs that can be transferred */
2684     /* Take the stream-id of the slots that are to be activated, for which there
2685      * is a slot of the same type that needs to be deactivated */
2686     tmp = to_deactivate;
2687     while (tmp) {
2688       MultiQueueSlot *slot_to_deactivate = (MultiQueueSlot *) tmp->data;
2689       gboolean removeit = FALSE;
2690       GList *tmp2, *next;
2691       GST_DEBUG_OBJECT (dbin,
2692           "Checking if slot to deactivate (%p) has a candidate slot to activate",
2693           slot_to_deactivate);
2694       for (tmp2 = to_activate; tmp2; tmp2 = tmp2->next) {
2695         MultiQueueSlot *slot_to_activate = (MultiQueueSlot *) tmp2->data;
2696         GST_DEBUG_OBJECT (dbin, "Comparing to slot %p", slot_to_activate);
2697         if (slot_to_activate->type == slot_to_deactivate->type) {
2698           GST_DEBUG_OBJECT (dbin, "Re-using");
2699           to_reassign = g_list_append (to_reassign, (gchar *)
2700               gst_stream_get_stream_id (slot_to_activate->active_stream));
2701           slots_to_reassign =
2702               g_list_append (slots_to_reassign, slot_to_deactivate);
2703           to_activate = g_list_remove (to_activate, slot_to_activate);
2704           removeit = TRUE;
2705           break;
2706         }
2707       }
2708       next = tmp->next;
2709       if (removeit)
2710         to_deactivate = g_list_delete_link (to_deactivate, tmp);
2711       tmp = next;
2712     }
2713   }
2714
2715   for (tmp = to_deactivate; tmp; tmp = tmp->next) {
2716     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2717     GST_DEBUG_OBJECT (dbin,
2718         "Really need to deactivate slot %p, but no available alternative",
2719         slot);
2720
2721     slots_to_reassign = g_list_append (slots_to_reassign, slot);
2722   }
2723
2724   /* The only slots left to activate are the ones that won't be reassigned and
2725    * therefore really need to have a new output created */
2726   for (tmp = to_activate; tmp; tmp = tmp->next) {
2727     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2728     if (slot->active_stream)
2729       future_request_streams =
2730           g_list_append (future_request_streams,
2731           (gchar *) gst_stream_get_stream_id (slot->active_stream));
2732     else if (slot->pending_stream)
2733       future_request_streams =
2734           g_list_append (future_request_streams,
2735           (gchar *) gst_stream_get_stream_id (slot->pending_stream));
2736     else
2737       GST_ERROR_OBJECT (dbin, "No stream for slot %p !!", slot);
2738   }
2739
2740   if (to_activate == NULL && pending_streams != NULL) {
2741     GST_DEBUG_OBJECT (dbin, "Stream switch requested for future collection");
2742     if (dbin->requested_selection)
2743       g_list_free_full (dbin->requested_selection, g_free);
2744     dbin->requested_selection =
2745         g_list_copy_deep (select_streams, (GCopyFunc) g_strdup, NULL);
2746     g_list_free (to_deactivate);
2747     g_list_free (pending_streams);
2748     to_deactivate = NULL;
2749     pending_streams = NULL;
2750   } else {
2751     if (dbin->requested_selection)
2752       g_list_free_full (dbin->requested_selection, g_free);
2753     dbin->requested_selection =
2754         g_list_copy_deep (future_request_streams, (GCopyFunc) g_strdup, NULL);
2755     dbin->requested_selection =
2756         g_list_concat (dbin->requested_selection,
2757         g_list_copy_deep (pending_streams, (GCopyFunc) g_strdup, NULL));
2758     if (dbin->to_activate)
2759       g_list_free (dbin->to_activate);
2760     dbin->to_activate = g_list_copy (to_reassign);
2761   }
2762
2763   dbin->selection_updated = TRUE;
2764   SELECTION_UNLOCK (dbin);
2765
2766   if (unknown) {
2767     GST_FIXME_OBJECT (dbin, "Got request for an unknown stream");
2768     g_list_free (unknown);
2769   }
2770
2771   if (to_activate && !slots_to_reassign) {
2772     for (tmp = to_activate; tmp; tmp = tmp->next) {
2773       MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2774       gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
2775           (GstPadProbeCallback) idle_reconfigure, slot, NULL);
2776     }
2777   }
2778
2779   /* For all streams to deactivate, add an idle probe where we will do
2780    * the unassignment and switch over */
2781   for (tmp = slots_to_reassign; tmp; tmp = tmp->next) {
2782     MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
2783     gst_pad_add_probe (slot->src_pad, GST_PAD_PROBE_TYPE_IDLE,
2784         (GstPadProbeCallback) slot_unassign_probe, slot, NULL);
2785   }
2786
2787   if (to_deactivate)
2788     g_list_free (to_deactivate);
2789   if (to_activate)
2790     g_list_free (to_activate);
2791   if (to_reassign)
2792     g_list_free (to_reassign);
2793   if (future_request_streams)
2794     g_list_free (future_request_streams);
2795   if (pending_streams)
2796     g_list_free (pending_streams);
2797   if (slots_to_reassign)
2798     g_list_free (slots_to_reassign);
2799
2800   return ret;
2801 }
2802
2803 static GstPadProbeReturn
2804 ghost_pad_event_probe (GstPad * pad, GstPadProbeInfo * info,
2805     DecodebinOutputStream * output)
2806 {
2807   GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2808   GstDecodebin3 *dbin = output->dbin;
2809   GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
2810
2811   GST_DEBUG_OBJECT (pad, "Got event %p %s", event, GST_EVENT_TYPE_NAME (event));
2812
2813   switch (GST_EVENT_TYPE (event)) {
2814     case GST_EVENT_SELECT_STREAMS:
2815     {
2816       GstPad *peer;
2817       GList *streams = NULL;
2818       guint32 seqnum = gst_event_get_seqnum (event);
2819
2820       SELECTION_LOCK (dbin);
2821       if (seqnum == dbin->select_streams_seqnum) {
2822         SELECTION_UNLOCK (dbin);
2823         GST_DEBUG_OBJECT (pad,
2824             "Already handled/handling that SELECT_STREAMS event");
2825         gst_event_unref (event);
2826         ret = GST_PAD_PROBE_HANDLED;
2827         break;
2828       }
2829       dbin->select_streams_seqnum = seqnum;
2830       if (dbin->pending_select_streams != NULL) {
2831         GST_LOG_OBJECT (dbin, "Replacing pending select streams");
2832         g_list_free (dbin->pending_select_streams);
2833         dbin->pending_select_streams = NULL;
2834       }
2835       gst_event_parse_select_streams (event, &streams);
2836       dbin->pending_select_streams = g_list_copy (streams);
2837       SELECTION_UNLOCK (dbin);
2838
2839       /* Send event upstream */
2840       if ((peer = gst_pad_get_peer (pad))) {
2841         gst_pad_send_event (peer, event);
2842         gst_object_unref (peer);
2843       } else {
2844         gst_event_unref (event);
2845       }
2846       /* Finally handle the switch */
2847       if (streams) {
2848         handle_stream_switch (dbin, streams, seqnum);
2849         g_list_free_full (streams, g_free);
2850       }
2851       ret = GST_PAD_PROBE_HANDLED;
2852     }
2853       break;
2854     default:
2855       break;
2856   }
2857
2858   return ret;
2859 }
2860
2861 static gboolean
2862 gst_decodebin3_send_event (GstElement * element, GstEvent * event)
2863 {
2864   GST_DEBUG_OBJECT (element, "event %s", GST_EVENT_TYPE_NAME (event));
2865   if (GST_EVENT_TYPE (event) == GST_EVENT_SELECT_STREAMS) {
2866     GstDecodebin3 *dbin = (GstDecodebin3 *) element;
2867     GList *streams = NULL;
2868     guint32 seqnum = gst_event_get_seqnum (event);
2869
2870     SELECTION_LOCK (dbin);
2871     if (seqnum == dbin->select_streams_seqnum) {
2872       SELECTION_UNLOCK (dbin);
2873       GST_DEBUG_OBJECT (dbin,
2874           "Already handled/handling that SELECT_STREAMS event");
2875       return TRUE;
2876     }
2877     dbin->select_streams_seqnum = seqnum;
2878     if (dbin->pending_select_streams != NULL) {
2879       GST_LOG_OBJECT (dbin, "Replacing pending select streams");
2880       g_list_free (dbin->pending_select_streams);
2881       dbin->pending_select_streams = NULL;
2882     }
2883     gst_event_parse_select_streams (event, &streams);
2884     dbin->pending_select_streams = g_list_copy (streams);
2885     SELECTION_UNLOCK (dbin);
2886
2887     /* FIXME : We don't have an upstream ?? */
2888 #if 0
2889     /* Send event upstream */
2890     if ((peer = gst_pad_get_peer (pad))) {
2891       gst_pad_send_event (peer, event);
2892       gst_object_unref (peer);
2893     }
2894 #endif
2895     /* Finally handle the switch */
2896     if (streams) {
2897       handle_stream_switch (dbin, streams, seqnum);
2898       g_list_free_full (streams, g_free);
2899     }
2900
2901     gst_event_unref (event);
2902     return TRUE;
2903   }
2904   return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
2905 }
2906
2907
2908 static void
2909 free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
2910 {
2911   if (slot->probe_id)
2912     gst_pad_remove_probe (slot->src_pad, slot->probe_id);
2913   if (slot->input) {
2914     if (slot->input->srcpad)
2915       gst_pad_unlink (slot->input->srcpad, slot->sink_pad);
2916   }
2917
2918   gst_element_release_request_pad (dbin->multiqueue, slot->sink_pad);
2919   gst_object_replace ((GstObject **) & slot->sink_pad, NULL);
2920   gst_object_replace ((GstObject **) & slot->src_pad, NULL);
2921   gst_object_replace ((GstObject **) & slot->active_stream, NULL);
2922   g_free (slot);
2923 }
2924
2925 static void
2926 free_multiqueue_slot_async (GstDecodebin3 * dbin, MultiQueueSlot * slot)
2927 {
2928   GST_LOG_OBJECT (dbin, "pushing multiqueue slot on thread pool to free");
2929   gst_element_call_async (GST_ELEMENT_CAST (dbin),
2930       (GstElementCallAsyncFunc) free_multiqueue_slot, slot, NULL);
2931 }
2932
2933 /* Create a DecodebinOutputStream for a given type
2934  * Note: It will be empty initially, it needs to be configured
2935  * afterwards */
2936 static DecodebinOutputStream *
2937 create_output_stream (GstDecodebin3 * dbin, GstStreamType type)
2938 {
2939   DecodebinOutputStream *res = g_new0 (DecodebinOutputStream, 1);
2940   gchar *pad_name;
2941   const gchar *prefix;
2942   GstStaticPadTemplate *templ;
2943   GstPadTemplate *ptmpl;
2944   guint32 *counter;
2945   GstPad *internal_pad;
2946
2947   GST_DEBUG_OBJECT (dbin, "Created new output stream %p for type %s",
2948       res, gst_stream_type_get_name (type));
2949
2950   res->type = type;
2951   res->dbin = dbin;
2952
2953   if (type & GST_STREAM_TYPE_VIDEO) {
2954     templ = &video_src_template;
2955     counter = &dbin->vpadcount;
2956     prefix = "video";
2957   } else if (type & GST_STREAM_TYPE_AUDIO) {
2958     templ = &audio_src_template;
2959     counter = &dbin->apadcount;
2960     prefix = "audio";
2961   } else if (type & GST_STREAM_TYPE_TEXT) {
2962     templ = &text_src_template;
2963     counter = &dbin->tpadcount;
2964     prefix = "text";
2965   } else {
2966     templ = &src_template;
2967     counter = &dbin->opadcount;
2968     prefix = "src";
2969   }
2970
2971   pad_name = g_strdup_printf ("%s_%u", prefix, *counter);
2972   *counter += 1;
2973   ptmpl = gst_static_pad_template_get (templ);
2974   res->src_pad = gst_ghost_pad_new_no_target_from_template (pad_name, ptmpl);
2975   gst_object_unref (ptmpl);
2976   g_free (pad_name);
2977   gst_pad_set_active (res->src_pad, TRUE);
2978   /* Put an event probe on the internal proxy pad to detect upstream
2979    * events */
2980   internal_pad =
2981       (GstPad *) gst_proxy_pad_get_internal ((GstProxyPad *) res->src_pad);
2982   gst_pad_add_probe (internal_pad, GST_PAD_PROBE_TYPE_EVENT_UPSTREAM,
2983       (GstPadProbeCallback) ghost_pad_event_probe, res, NULL);
2984   gst_object_unref (internal_pad);
2985
2986   dbin->output_streams = g_list_append (dbin->output_streams, res);
2987
2988   return res;
2989 }
2990
2991 static void
2992 free_output_stream (GstDecodebin3 * dbin, DecodebinOutputStream * output)
2993 {
2994   if (output->slot) {
2995     if (output->decoder_sink && output->decoder)
2996       gst_pad_unlink (output->slot->src_pad, output->decoder_sink);
2997
2998     output->slot->output = NULL;
2999     output->slot = NULL;
3000   }
3001   gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
3002   gst_ghost_pad_set_target ((GstGhostPad *) output->src_pad, NULL);
3003   gst_object_replace ((GstObject **) & output->decoder_src, NULL);
3004   if (output->src_exposed) {
3005     gst_element_remove_pad ((GstElement *) dbin, output->src_pad);
3006   }
3007   if (output->decoder) {
3008     gst_element_set_locked_state (output->decoder, TRUE);
3009     gst_element_set_state (output->decoder, GST_STATE_NULL);
3010     gst_bin_remove ((GstBin *) dbin, output->decoder);
3011   }
3012   g_free (output);
3013 }
3014
3015 static GstStateChangeReturn
3016 gst_decodebin3_change_state (GstElement * element, GstStateChange transition)
3017 {
3018   GstDecodebin3 *dbin = (GstDecodebin3 *) element;
3019   GstStateChangeReturn ret;
3020
3021   /* Upwards */
3022   switch (transition) {
3023     default:
3024       break;
3025   }
3026   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3027   if (ret == GST_STATE_CHANGE_FAILURE)
3028     goto beach;
3029
3030   switch (transition) {
3031     case GST_STATE_CHANGE_PAUSED_TO_READY:
3032     {
3033       GList *tmp;
3034
3035       /* Free output streams */
3036       for (tmp = dbin->output_streams; tmp; tmp = tmp->next) {
3037         DecodebinOutputStream *output = (DecodebinOutputStream *) tmp->data;
3038         free_output_stream (dbin, output);
3039       }
3040       g_list_free (dbin->output_streams);
3041       dbin->output_streams = NULL;
3042       /* Free multiqueue slots */
3043       for (tmp = dbin->slots; tmp; tmp = tmp->next) {
3044         MultiQueueSlot *slot = (MultiQueueSlot *) tmp->data;
3045         free_multiqueue_slot (dbin, slot);
3046       }
3047       g_list_free (dbin->slots);
3048       dbin->slots = NULL;
3049       dbin->current_group_id = GST_GROUP_ID_INVALID;
3050       /* Free inputs */
3051     }
3052       break;
3053     default:
3054       break;
3055   }
3056 beach:
3057   return ret;
3058 }
3059
3060 gboolean
3061 gst_decodebin3_plugin_init (GstPlugin * plugin)
3062 {
3063   GST_DEBUG_CATEGORY_INIT (decodebin3_debug, "decodebin3", 0, "decoder bin");
3064
3065   return gst_element_register (plugin, "decodebin3", GST_RANK_NONE,
3066       GST_TYPE_DECODEBIN3);
3067 }