3 * Copyright (C) <2015> Centricular Ltd
4 * @author: Edward Hervey <edward@centricular.com>
5 * @author: Jan Schmidt <jan@centricular.com>
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.
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.
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.
28 #include <glib-object.h>
29 #include <glib/gprintf.h>
31 #include <gst/pbutils/pbutils.h>
33 #include "gstplayback.h"
34 #include "gstplay-enum.h"
35 #include "gstrawcaps.h"
38 * SECTION:element-decodebin3
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.
45 * decodebin3 differs from the previous decodebin (decodebin2) in important ways:
47 * * supports publication and selection of stream information via
48 * GstStreamCollection messages and #GST_EVENT_SELECT_STREAM events.
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.
56 * * supports multiple input pads for the parallel decoding of auxilliary streams
57 * not muxed with the primary stream.
59 * * does not handle network stream buffering. decodebin3 expects that network stream
60 * buffering is handled upstream, before data is passed to it.
62 * <emphasis>decodebin3 is still experimental API and a technology preview.
63 * Its behaviour and exposed API is subject to change.</emphasis>
70 * 1) From sink pad to elementary streams (GstParseBin)
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
77 * All elementary streams (whether decoded or not, whether exposed or not) are
78 * fed through multiqueue. There is only *one* multiqueue in decodebin3.
80 * => MultiQueue is the cornerstone.
81 * => No buffering before multiqueue
83 * 2) Elementary streams
85 * After GstParseBin, there are 3 main components:
86 * 1) Input Streams (provided by GstParseBin)
90 * Input Streams correspond to the stream coming from GstParseBin and that gets
91 * fed into a multiqueue slot.
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
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
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:
108 * the stream is done => Mark that component as done, optionally freeing/removing it
110 * a new stream is starting => link it further if needed
112 * 3) Gradual replacement
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.
117 * This is handled by the probes in various locations:
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)
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)
132 * Input(s) Slots Streams
133 * /-------------------------------------------\ /-----\ /------------- \
135 * +-------------------------------------------------------------------------+
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 * | +---------------------------------------------+ ^ | |
147 * +-----------------------------------------------+--------+-------------+--+
150 * Probes --/--------/-------------/
154 * We want to ensure we re-use decoders when switching streams. This takes place
155 * at the multiqueue output level.
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().
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
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
177 GST_DEBUG_CATEGORY_STATIC (decodebin3_debug);
178 #define GST_CAT_DEFAULT decodebin3_debug
180 #define GST_TYPE_DECODEBIN3 (gst_decodebin3_get_type ())
182 #define EXTRA_DEBUG 1
184 #define CUSTOM_FINAL_EOS_QUARK _custom_final_eos_quark_get ()
185 #define CUSTOM_FINAL_EOS_QUARK_DATA "custom-final-eos"
187 _custom_final_eos_quark_get (void)
189 static gsize g_quark;
191 if (g_once_init_enter (&g_quark)) {
193 (gsize) g_quark_from_static_string ("decodebin3-custom-final-eos");
194 g_once_init_leave (&g_quark, quark);
199 typedef struct _GstDecodebin3 GstDecodebin3;
200 typedef struct _GstDecodebin3Class GstDecodebin3Class;
202 typedef struct _DecodebinInputStream DecodebinInputStream;
203 typedef struct _DecodebinInput DecodebinInput;
204 typedef struct _DecodebinOutputStream DecodebinOutputStream;
206 struct _GstDecodebin3
210 /* input_lock protects the following variables */
212 /* Main input (static sink pad) */
213 DecodebinInput *main_input;
214 /* Supplementary input (request sink pads) */
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 */
223 GstElement *multiqueue;
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 */
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) */
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 */
249 /* List of pending collections.
250 * FIXME : Is this really needed ? */
251 GList *pending_collection;
254 GMutex factories_lock;
255 guint32 factories_cookie;
256 /* All DECODABLE factories */
258 /* Only DECODER factories */
259 GList *decoder_factories;
260 /* DECODABLE but not DECODER factories */
261 GList *decodable_factories;
263 /* counters for pads */
264 guint32 apadcount, vpadcount, tpadcount, opadcount;
268 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
269 gboolean force_sw_decoders_for_video;
270 gboolean force_sw_decoders_for_audio;
272 gboolean force_sw_decoders;
276 struct _GstDecodebin3Class
280 gint (*select_stream) (GstDecodebin3 * dbin,
281 GstStreamCollection * collection, GstStream * stream);
283 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
284 gboolean (*request_resource) (GstDecodebin3 * dbin,
285 GstStreamCollection * collection, GstStream * stream);
289 /* Input of decodebin, controls input pad and parsebin */
290 struct _DecodebinInput
297 GstPad *parsebin_sink;
299 GstStreamCollection *collection; /* Active collection */
303 GstElement *parsebin;
305 gulong pad_added_sigid;
306 gulong pad_removed_sigid;
307 gulong drained_sigid;
309 /* TRUE if the input got drained
310 * FIXME : When do we reset it if re-used ?
314 /* HACK : Remove these fields */
315 /* List of PendingPad structures */
319 /* Multiqueue Slots */
320 typedef struct _MultiQueueSlot
325 /* Type of stream handled by this slot */
328 /* Linked input and output */
329 DecodebinInputStream *input;
331 /* pending => last stream received on sink pad */
332 GstStream *pending_stream;
333 /* active => last stream outputted on source pad */
334 GstStream *active_stream;
336 GstPad *sink_pad, *src_pad;
338 /* id of the MQ src_pad event probe */
343 DecodebinOutputStream *output;
346 /* Streams that are exposed downstream (i.e. output) */
347 struct _DecodebinOutputStream
350 /* The type of stream handled by this output stream */
353 /* The slot to which this output stream is currently connected to */
354 MultiQueueSlot *slot;
356 GstElement *decoder; /* Optional */
357 GstPad *decoder_sink, *decoder_src;
362 /* Flag if ghost pad is exposed */
363 gboolean src_exposed;
365 /* keyframe dropping probe */
366 gulong drop_probe_id;
369 /* Pending pads from parsebin */
370 typedef struct _PendingPad
373 DecodebinInput *input;
386 #ifdef TIZEN_FEATURE_FORCE_SW_DECODER
387 PROP_FORCE_SW_DECODERS_FOR_VIDEO,
388 PROP_FORCE_SW_DECODERS_FOR_AUDIO,
390 PROP_FORCE_SW_DECODERS,
397 SIGNAL_SELECT_STREAM,
398 SIGNAL_ABOUT_TO_FINISH,
399 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
400 SIGNAL_REQUEST_RESOURCE,
404 static guint gst_decodebin3_signals[LAST_SIGNAL] = { 0 };
406 #define SELECTION_LOCK(dbin) G_STMT_START { \
407 GST_LOG_OBJECT (dbin, \
408 "selection locking from thread %p", \
410 g_mutex_lock (&dbin->selection_lock); \
411 GST_LOG_OBJECT (dbin, \
412 "selection locked from thread %p", \
416 #define SELECTION_UNLOCK(dbin) G_STMT_START { \
417 GST_LOG_OBJECT (dbin, \
418 "selection unlocking from thread %p", \
420 g_mutex_unlock (&dbin->selection_lock); \
423 #define INPUT_LOCK(dbin) G_STMT_START { \
424 GST_LOG_OBJECT (dbin, \
425 "input locking from thread %p", \
427 g_mutex_lock (&dbin->input_lock); \
428 GST_LOG_OBJECT (dbin, \
429 "input locked from thread %p", \
433 #define INPUT_UNLOCK(dbin) G_STMT_START { \
434 GST_LOG_OBJECT (dbin, \
435 "input unlocking from thread %p", \
437 g_mutex_unlock (&dbin->input_lock); \
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);
444 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
446 #define DEFAULT_FORCE_SW_DECODERS FALSE
448 static GstStaticPadTemplate sink_template = GST_STATIC_PAD_TEMPLATE ("sink",
451 GST_STATIC_CAPS_ANY);
453 static GstStaticPadTemplate request_sink_template =
454 GST_STATIC_PAD_TEMPLATE ("sink_%u",
457 GST_STATIC_CAPS_ANY);
459 static GstStaticPadTemplate video_src_template =
460 GST_STATIC_PAD_TEMPLATE ("video_%u",
463 GST_STATIC_CAPS_ANY);
465 static GstStaticPadTemplate audio_src_template =
466 GST_STATIC_PAD_TEMPLATE ("audio_%u",
469 GST_STATIC_CAPS_ANY);
471 static GstStaticPadTemplate text_src_template =
472 GST_STATIC_PAD_TEMPLATE ("text_%u",
475 GST_STATIC_CAPS_ANY);
477 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
480 GST_STATIC_CAPS_ANY);
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);
493 static gboolean parsebin_autoplug_continue_cb (GstElement *
494 parsebin, GstPad * pad, GstCaps * caps, GstDecodebin3 * dbin);
497 gst_decodebin3_select_stream (GstDecodebin3 * dbin,
498 GstStreamCollection * collection, GstStream * stream)
500 GST_LOG_OBJECT (dbin, "default select-stream, returning -1");
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,
513 static void gst_decode_bin_update_factories_list (GstDecodebin3 * dbin);
515 static gboolean have_factory (GstDecodebin3 * dbin, GstCaps * caps,
516 GstElementFactoryListType ftype);
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);
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,
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);
542 static GstStreamCollection *get_merged_collection (GstDecodebin3 * dbin);
543 static void update_requested_selection (GstDecodebin3 * dbin);
545 /* FIXME: Really make all the parser stuff a self-contained helper object */
546 #include "gstdecodebin3-parse.c"
548 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
549 static gboolean gst_decodebin3_request_resource (GstElement * element,
550 GstStreamCollection * collection, GstStream * stream)
552 /* do not consider the resource limit */
557 _gst_boolean_accumulator (GSignalInvocationHint * ihint,
558 GValue * return_accu, const GValue * handler_return, gpointer dummy)
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);
571 _gst_int_accumulator (GSignalInvocationHint * ihint,
572 GValue * return_accu, const GValue * handler_return, gpointer dummy)
574 gint res = g_value_get_int (handler_return);
576 if (!(ihint->run_type & G_SIGNAL_RUN_CLEANUP))
577 g_value_set_int (return_accu, res);
586 gst_decodebin3_class_init (GstDecodebin3Class * klass)
588 GObjectClass *gobject_klass = (GObjectClass *) klass;
589 GstElementClass *element_class = (GstElementClass *) klass;
590 GstBinClass *bin_klass = (GstBinClass *) klass;
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;
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));
614 * GstDecodeBin::force-sw-decoders:
616 * While auto-plugging, if set to %TRUE, those decoders within
617 * "Hardware" klass will be ignored. Otherwise they will be tried.
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));
627 /* FIXME : ADD SIGNALS ! */
629 * GstDecodebin3::select-stream
630 * @decodebin: a #GstDecodebin3
631 * @collection: a #GstStreamCollection
632 * @stream: a #GstStream
634 * This signal is emitted whenever @decodebin needs to decide whether
635 * to expose a @stream of a given @collection.
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.
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);
647 * GstDecodebin3::about-to-finish:
649 * This signal is emitted when the data for the selected URI is
650 * entirely buffered and it is safe to specify anothe URI.
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,
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);
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);
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));
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>");
688 bin_klass->handle_message = gst_decodebin3_handle_message;
690 klass->select_stream = gst_decodebin3_select_stream;
692 #ifdef TIZEN_FEATURE_RESOURCE_MANAGER
693 klass->request_resource = gst_decodebin3_request_resource;
698 gst_decodebin3_init (GstDecodebin3 * dbin)
700 /* Create main input */
701 dbin->main_input = create_new_input (dbin, TRUE);
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);
708 dbin->current_group_id = GST_GROUP_ID_INVALID;
710 g_mutex_init (&dbin->factories_lock);
711 g_mutex_init (&dbin->selection_lock);
712 g_mutex_init (&dbin->input_lock);
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;
719 dbin->force_sw_decoders = DEFAULT_FORCE_SW_DECODERS;
722 GST_OBJECT_FLAG_SET (dbin, GST_BIN_FLAG_STREAMS_AWARE);
726 gst_decodebin3_dispose (GObject * object)
728 GstDecodebin3 *dbin = (GstDecodebin3 *) object;
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);
743 free_input (dbin, dbin->main_input);
745 for (walk = dbin->other_inputs; walk; walk = next) {
746 DecodebinInput *input = walk->data;
748 next = g_list_next (walk);
750 free_input (dbin, input);
751 dbin->other_inputs = g_list_delete_link (dbin->other_inputs, walk);
754 G_OBJECT_CLASS (parent_class)->dispose (object);
758 gst_decodebin3_set_property (GObject * object, guint prop_id,
759 const GValue * value, GParamSpec * pspec)
761 GstDecodebin3 *dbin = (GstDecodebin3 *) object;
763 /* FIXME : IMPLEMENT */
766 GST_OBJECT_LOCK (dbin);
768 gst_caps_unref (dbin->caps);
769 dbin->caps = g_value_dup_boxed (value);
770 GST_OBJECT_UNLOCK (dbin);
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);
776 case PROP_FORCE_SW_DECODERS_FOR_AUDIO:
777 dbin->force_sw_decoders_for_audio = g_value_get_boolean (value);
780 case PROP_FORCE_SW_DECODERS:
781 dbin->force_sw_decoders = g_value_get_boolean (value);
785 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
791 gst_decodebin3_get_property (GObject * object, guint prop_id, GValue * value,
794 GstDecodebin3 *dbin = (GstDecodebin3 *) object;
796 /* FIXME : IMPLEMENT */
799 GST_OBJECT_LOCK (dbin);
800 g_value_set_boxed (value, dbin->caps);
801 GST_OBJECT_UNLOCK (dbin);
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);
807 case PROP_FORCE_SW_DECODERS_FOR_AUDIO:
808 g_value_set_boolean (value, dbin->force_sw_decoders_for_audio);
811 case PROP_FORCE_SW_DECODERS:
812 g_value_set_boolean (value, dbin->force_sw_decoders);
816 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
822 parsebin_autoplug_continue_cb (GstElement * parsebin, GstPad * pad,
823 GstCaps * caps, GstDecodebin3 * dbin)
825 GST_DEBUG_OBJECT (pad, "caps %" GST_PTR_FORMAT, caps);
827 /* If it matches our target caps, expose it */
828 if (gst_caps_can_intersect (caps, dbin->caps))
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 */
838 set_input_group_id (DecodebinInput * input, guint32 * group_id)
840 GstDecodebin3 *dbin = input->dbin;
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;
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,
854 dbin->current_group_id = *group_id;
856 *group_id = dbin->current_group_id;
864 parsebin_drained_cb (GstElement * parsebin, DecodebinInput * input)
866 GstDecodebin3 *dbin = input->dbin;
867 gboolean all_drained;
870 GST_WARNING_OBJECT (dbin, "input %p drained", input);
871 input->drained = TRUE;
873 all_drained = dbin->main_input->drained;
874 for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
875 DecodebinInput *data = (DecodebinInput *) tmp->data;
877 all_drained &= data->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,
887 /* Call with INPUT_LOCK taken */
889 ensure_input_parsebin (GstDecodebin3 * dbin, DecodebinInput * input)
891 gboolean set_state = FALSE;
893 if (input->parsebin == NULL) {
894 input->parsebin = gst_element_factory_make ("parsebin", NULL);
895 if (input->parsebin == NULL)
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);
912 if (GST_OBJECT_PARENT (GST_OBJECT (input->parsebin)) != GST_OBJECT (dbin)) {
913 gst_bin_add (GST_BIN (dbin), input->parsebin);
917 gst_ghost_pad_set_target (GST_GHOST_PAD (input->ghost_sink),
918 input->parsebin_sink);
920 gst_element_sync_state_with_parent (input->parsebin);
927 gst_element_post_message ((GstElement *) dbin,
928 gst_missing_element_message_new ((GstElement *) dbin, "parsebin"));
933 static GstPadLinkReturn
934 gst_decodebin3_input_pad_link (GstPad * pad, GstObject * parent, GstPad * peer)
936 GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
937 GstPadLinkReturn res = GST_PAD_LINK_OK;
938 DecodebinInput *input;
940 GST_LOG_OBJECT (parent, "Got link on input pad %" GST_PTR_FORMAT
941 ". Creating parsebin if needed", pad);
943 if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
947 if (!ensure_input_parsebin (dbin, input))
948 res = GST_PAD_LINK_REFUSED;
953 GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
954 return GST_PAD_LINK_REFUSED;
957 /* Drop duration query during _input_pad_unlink */
958 static GstPadProbeReturn
959 query_duration_drop_probe (GstPad * pad, GstPadProbeInfo * info,
960 DecodebinInput * input)
962 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
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;
976 gst_decodebin3_input_pad_unlink (GstPad * pad, GstObject * parent)
978 GstDecodebin3 *dbin = (GstDecodebin3 *) parent;
979 DecodebinInput *input;
981 GST_LOG_OBJECT (parent, "Got unlink on input pad %" GST_PTR_FORMAT
982 ". Removing parsebin.", pad);
984 if ((input = g_object_get_data (G_OBJECT (pad), "decodebin.input")) == NULL)
988 if (input->parsebin == NULL) {
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);
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;
1006 SELECTION_LOCK (dbin);
1007 collection = get_merged_collection (dbin);
1008 if (collection && collection != dbin->collection) {
1010 GST_DEBUG_OBJECT (dbin, "Update Stream Collection");
1012 if (dbin->collection)
1013 gst_object_unref (dbin->collection);
1014 dbin->collection = collection;
1017 gst_message_new_stream_collection ((GstObject *) dbin,
1020 SELECTION_UNLOCK (dbin);
1021 gst_element_post_message (GST_ELEMENT_CAST (dbin), msg);
1022 update_requested_selection (dbin);
1024 SELECTION_UNLOCK (dbin);
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);
1035 input->parsebin = NULL;
1036 input->parsebin_sink = NULL;
1038 if (!input->is_main) {
1039 dbin->other_inputs = g_list_remove (dbin->other_inputs, input);
1040 free_input_async (dbin, input);
1043 INPUT_UNLOCK (dbin);
1047 GST_ERROR_OBJECT (parent, "Failed to retrieve input state from ghost pad");
1052 free_input (GstDecodebin3 * dbin, DecodebinInput * input)
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);
1065 if (input->collection)
1066 gst_object_unref (input->collection);
1071 free_input_async (GstDecodebin3 * dbin, DecodebinInput * input)
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);
1078 /* Call with INPUT_LOCK taken */
1079 static DecodebinInput *
1080 create_new_input (GstDecodebin3 * dbin, gboolean main)
1082 DecodebinInput *input;
1084 input = g_new0 (DecodebinInput, 1);
1086 input->is_main = main;
1087 input->group_id = GST_GROUP_ID_INVALID;
1089 input->ghost_sink = gst_ghost_pad_new_no_target ("sink", GST_PAD_SINK);
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);
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);
1100 gst_pad_set_active (input->ghost_sink, TRUE);
1101 gst_element_add_pad ((GstElement *) dbin, input->ghost_sink);
1108 gst_decodebin3_request_new_pad (GstElement * element, GstPadTemplate * temp,
1109 const gchar * name, const GstCaps * caps)
1111 GstDecodebin3 *dbin = (GstDecodebin3 *) element;
1112 DecodebinInput *input;
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);
1120 dbin->other_inputs = g_list_append (dbin->other_inputs, input);
1121 res = input->ghost_sink;
1122 INPUT_UNLOCK (dbin);
1128 /* Must be called with factories lock! */
1130 gst_decode_bin_update_factories_list (GstDecodebin3 * dbin)
1134 cookie = gst_registry_get_feature_list_cookie (gst_registry_get ());
1135 if (!dbin->factories || dbin->factories_cookie != cookie) {
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);
1144 gst_element_factory_list_get_elements
1145 (GST_ELEMENT_FACTORY_TYPE_DECODABLE, GST_RANK_MARGINAL);
1147 g_list_sort (dbin->factories, gst_plugin_feature_rank_compare_func);
1148 dbin->factories_cookie = cookie;
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;
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);
1168 GST_WARNING("%s is skipped", GST_OBJECT_NAME(fact));
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);
1179 dbin->decodable_factories =
1180 g_list_append (dbin->decodable_factories, fact);
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)
1193 for (tmp = list; tmp; tmp = tmp->next) {
1194 gchar *osid = (gchar *) tmp->data;
1195 GST_DEBUG ("Checking %s against %s", sid, osid);
1199 for (tmp = list; tmp; tmp = tmp->next) {
1200 const gchar *osid = (gchar *) tmp->data;
1201 if (!g_strcmp0 (sid, osid))
1209 update_requested_selection (GstDecodebin3 * dbin)
1213 GstStreamType used_types = 0;
1214 GstStreamCollection *collection;
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");
1225 collection = dbin->collection;
1226 if (G_UNLIKELY (collection == NULL)) {
1227 GST_DEBUG_OBJECT (dbin, "No current GstStreamCollection");
1230 nb = gst_stream_collection_get_size (collection);
1232 /* 2. If not, are we in EXPOSE_ALL_MODE ? If so, match everything */
1233 GST_FIXME_OBJECT (dbin, "Implement EXPOSE_ALL_MODE");
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);
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,
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);
1252 GST_DEBUG_OBJECT (dbin,
1253 "Using stream requested by 'select-stream' signal : %s", sid);
1255 GST_DEBUG_OBJECT (dbin,
1256 "Re-using stream already present in requested or active selection : %s",
1258 tmp = g_list_append (tmp, (gchar *) sid);
1259 used_types |= curtype;
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;
1277 /* Finally set the requested selection */
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);
1284 dbin->requested_selection =
1285 g_list_copy_deep (tmp, (GCopyFunc) g_strdup, NULL);
1286 dbin->selection_updated = TRUE;
1289 SELECTION_UNLOCK (dbin);
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.
1297 * Return: negative if a<b, 0 if a==b, positive if a>b
1300 sort_streams (GstStream * sa, GstStream * sb)
1302 GstStreamType typea, typeb;
1303 GstStreamFlags flaga, flagb;
1304 const gchar *ida, *idb;
1307 typea = gst_stream_get_stream_type (sa);
1308 typeb = gst_stream_get_stream_type (sb);
1310 GST_LOG ("sa(%s), sb(%s)", gst_stream_get_stream_id (sa),
1311 gst_stream_get_stream_id (sb));
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)
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;
1328 GST_LOG ("Sort by stream-type: %d", ret);
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);
1338 (flaga & GST_STREAM_FLAG_SELECT) ? ((flagb & GST_STREAM_FLAG_SELECT) ? 0 :
1339 -1) : ((flagb & GST_STREAM_FLAG_SELECT) ? 1 : 0);
1342 GST_LOG ("Sort by SELECT flag: %d", ret);
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);
1351 GST_LOG ("Sort by stream-id: %d", ret);
1356 /* Call with INPUT_LOCK taken */
1357 static GstStreamCollection *
1358 get_merged_collection (GstDecodebin3 * dbin)
1360 gboolean needs_merge = FALSE;
1361 GstStreamCollection *res = NULL;
1363 GList *unsorted_streams = NULL;
1366 /* First check if we need to do a merge or just return the only collection */
1367 res = dbin->main_input->collection;
1369 for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
1370 DecodebinInput *input = (DecodebinInput *) tmp->data;
1371 if (input->collection) {
1376 res = input->collection;
1381 GST_DEBUG_OBJECT (dbin, "No need to merge, returning %p", res);
1382 return res ? gst_object_ref (res) : NULL;
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++) {
1393 gst_stream_collection_get_stream (dbin->main_input->collection, i);
1394 unsorted_streams = g_list_append (unsorted_streams, stream);
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,
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++) {
1407 gst_stream_collection_get_stream (input->collection, i);
1408 unsorted_streams = g_list_append (unsorted_streams, stream);
1413 /* re-order streams : video, then audio, then others */
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));
1423 if (unsorted_streams)
1424 g_list_free (unsorted_streams);
1429 /* Call with INPUT_LOCK taken */
1430 static DecodebinInput *
1431 find_message_parsebin (GstDecodebin3 * dbin, GstElement * child)
1433 DecodebinInput *input = NULL;
1434 GstElement *parent = gst_object_ref (child);
1438 GstElement *next_parent;
1440 GST_DEBUG_OBJECT (dbin, "parent %s",
1441 parent ? GST_ELEMENT_NAME (parent) : "<NONE>");
1443 if (parent == dbin->main_input->parsebin) {
1444 input = dbin->main_input;
1447 for (tmp = dbin->other_inputs; tmp; tmp = tmp->next) {
1448 DecodebinInput *cur = (DecodebinInput *) tmp->data;
1449 if (parent == cur->parsebin) {
1454 next_parent = (GstElement *) gst_element_get_parent (parent);
1455 gst_object_unref (parent);
1456 parent = next_parent;
1458 } while (parent && parent != (GstElement *) dbin);
1461 gst_object_unref (parent);
1466 static const gchar *
1467 stream_in_collection (GstDecodebin3 * dbin, gchar * sid)
1471 if (dbin->collection == 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))
1484 /* Call with INPUT_LOCK taken */
1486 handle_stream_collection (GstDecodebin3 * dbin,
1487 GstStreamCollection * collection, GstElement * child)
1489 #ifndef GST_DISABLE_GST_DEBUG
1490 const gchar *upstream_id;
1493 DecodebinInput *input = find_message_parsebin (dbin, child);
1496 GST_DEBUG_OBJECT (dbin,
1497 "Couldn't find corresponding input, most likely shutting down");
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,
1508 /* Merge collection if needed */
1509 collection = get_merged_collection (dbin);
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;
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);
1531 gst_tag_list_unref (taglist);
1533 gst_caps_unref (caps);
1537 /* Store collection for later usage */
1538 SELECTION_LOCK (dbin);
1539 if (dbin->collection == NULL) {
1540 dbin->collection = collection;
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); */
1554 SELECTION_UNLOCK (dbin);
1558 gst_decodebin3_handle_message (GstBin * bin, GstMessage * message)
1560 GstDecodebin3 *dbin = (GstDecodebin3 *) bin;
1561 gboolean posting_collection = FALSE;
1563 GST_DEBUG_OBJECT (bin, "Got Message %s", GST_MESSAGE_TYPE_NAME (message));
1565 switch (GST_MESSAGE_TYPE (message)) {
1566 case GST_MESSAGE_STREAM_COLLECTION:
1568 GstStreamCollection *collection = NULL;
1569 gst_message_parse_stream_collection (message, &collection);
1572 handle_stream_collection (dbin, collection,
1573 (GstElement *) GST_MESSAGE_SRC (message));
1574 posting_collection = TRUE;
1575 INPUT_UNLOCK (dbin);
1578 SELECTION_LOCK (dbin);
1579 if (dbin->collection && collection != dbin->collection) {
1580 /* Replace collection message, we most likely aggregated it */
1581 GstMessage *new_msg;
1583 gst_message_new_stream_collection ((GstObject *) dbin,
1585 gst_message_unref (message);
1588 SELECTION_UNLOCK (dbin);
1591 gst_object_unref (collection);
1598 GST_BIN_CLASS (parent_class)->handle_message (bin, message);
1600 if (posting_collection) {
1601 /* Figure out a selection for that collection */
1602 update_requested_selection (dbin);
1606 static DecodebinOutputStream *
1607 find_free_compatible_output (GstDecodebin3 * dbin, GstStream * stream)
1610 GstStreamType stype = gst_stream_get_stream_type (stream);
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))) {
1626 /* Give a certain slot, figure out if it should be linked to an
1628 * CALL WITH SELECTION LOCK TAKEN !*/
1629 static DecodebinOutputStream *
1630 get_output_for_slot (MultiQueueSlot * slot)
1632 GstDecodebin3 *dbin = slot->dbin;
1633 DecodebinOutputStream *output = NULL;
1634 const gchar *stream_id;
1636 gchar *id_in_list = NULL;
1638 /* If we already have a configured output, just use it */
1639 if (slot->output != NULL)
1640 return slot->output;
1645 * This method needs to be split into multiple parts
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
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
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);
1662 /* 0. Emit autoplug-continue signal for pending caps ? */
1663 GST_FIXME_OBJECT (dbin, "emit autoplug-continue");
1665 /* 1. if in EXPOSE_ALL_MODE, just accept */
1666 GST_FIXME_OBJECT (dbin, "Handle EXPOSE_ALL_MODE");
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,
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);
1686 /* 3. In default mode check if we should expose */
1687 id_in_list = (gchar *) stream_in_list (dbin->requested_selection, stream_id);
1689 /* Check if we can steal an existing output stream we could re-use.
1691 * * an output stream whose slot->stream is not in requested
1692 * * and is of the same type as this stream
1694 output = find_free_compatible_output (dbin, slot->active_stream);
1696 /* Move this output from its current slot to this slot */
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);
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);
1716 GST_DEBUG ("Not creating any output for slot %p", slot);
1721 /* Returns SELECTED_STREAMS message if active_selection is equal to
1722 * requested_selection, else NULL.
1723 * Must be called with LOCK taken */
1725 is_selection_done (GstDecodebin3 * dbin)
1730 if (!dbin->selection_updated)
1733 GST_LOG_OBJECT (dbin, "Checking");
1735 if (dbin->to_activate != NULL) {
1736 GST_DEBUG ("Still have streams to activate");
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");
1747 GST_DEBUG_OBJECT (dbin, "Selection active, creating message");
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;
1755 GST_DEBUG_OBJECT (dbin, "Adding stream %s",
1756 gst_stream_get_stream_id (output->slot->active_stream));
1758 gst_message_streams_selected_add (msg, output->slot->active_stream);
1760 GST_WARNING_OBJECT (dbin, "No valid slot for output %p", output);
1762 dbin->selection_updated = FALSE;
1766 /* Must be called with SELECTION_LOCK taken */
1768 check_all_slot_for_eos (GstDecodebin3 * dbin)
1770 gboolean all_drained = TRUE;
1773 GST_DEBUG_OBJECT (dbin, "check slot for eos");
1775 for (iter = dbin->slots; iter; iter = iter->next) {
1776 MultiQueueSlot *slot = iter->data;
1781 if (slot->is_drained) {
1782 GST_LOG_OBJECT (slot->sink_pad, "slot %p is drained", slot);
1786 all_drained = FALSE;
1792 if (!pending_pads_are_eos (dbin->main_input))
1793 all_drained = FALSE;
1796 for (iter = dbin->other_inputs; iter; iter = iter->next) {
1797 if (!pending_pads_are_eos ((DecodebinInput *) iter->data)) {
1798 all_drained = FALSE;
1803 INPUT_UNLOCK (dbin);
1807 GST_DEBUG_OBJECT (dbin,
1808 "All active slots are drained, and no pending input, push EOS");
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);
1814 /* Send EOS to all slots */
1816 GstEvent *stream_start, *eos;
1819 gst_pad_get_sticky_event (input->srcpad, GST_EVENT_STREAM_START, 0);
1821 /* First forward a custom STREAM_START event to reset the EOS status (if any) */
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);
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,
1836 gst_pad_send_event (peer, eos);
1837 gst_object_unref (peer);
1839 GST_DEBUG_OBJECT (dbin, "no output");
1844 static GstPadProbeReturn
1845 multiqueue_src_probe (GstPad * pad, GstPadProbeInfo * info,
1846 MultiQueueSlot * slot)
1848 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
1849 GstDecodebin3 *dbin = slot->dbin;
1851 if (GST_IS_EVENT (GST_PAD_PROBE_INFO_DATA (info))) {
1852 GstEvent *ev = GST_PAD_PROBE_INFO_EVENT (info);
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:
1858 GstStream *stream = NULL;
1859 const GstStructure *s = gst_event_get_structure (ev);
1861 /* Drop STREAM_START events used to cleanup multiqueue */
1863 && gst_structure_has_field (s,
1864 "decodebin3-flushing-stream-start")) {
1865 ret = GST_PAD_PROBE_HANDLED;
1866 gst_event_unref (ev);
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");
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;
1888 gst_object_unref (stream);
1889 #if 0 /* Disabled because stream-start is pushed for every buffer on every unlinked pad */
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);
1901 GST_DEBUG_OBJECT (pad, "Slot in ACTIVE selection (output:%p)",
1904 GST_DEBUG_OBJECT (pad, "Slot in REQUESTED selection (output:%p)",
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");
1916 case GST_EVENT_CAPS:
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);
1924 reconfigure_output_stream (output, slot);
1925 msg = is_selection_done (dbin);
1927 SELECTION_UNLOCK (dbin);
1929 gst_element_post_message ((GstElement *) slot->dbin, msg);
1934 gboolean was_drained = slot->is_drained;
1935 slot->is_drained = TRUE;
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 */
1951 DecodebinOutputStream *output = slot->output;
1952 dbin->output_streams =
1953 g_list_remove (dbin->output_streams, output);
1954 free_output_stream (dbin, output);
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);
1963 if (ret == GST_PAD_PROBE_HANDLED)
1964 gst_event_unref (ev);
1965 SELECTION_UNLOCK (dbin);
1969 GST_FIXME_OBJECT (pad, "EOS on multiqueue source pad. input:%p",
1971 if (slot->input == NULL) {
1973 GST_DEBUG_OBJECT (pad,
1974 "last EOS for input, forwarding and removing slot");
1975 peer = gst_pad_get_peer (pad);
1977 gst_pad_send_event (peer, ev);
1978 gst_object_unref (peer);
1980 gst_event_unref (ev);
1982 SELECTION_LOCK (dbin);
1983 /* FIXME : Shouldn't we try to re-assign the output instead of just
1985 /* Remove the output */
1987 DecodebinOutputStream *output = slot->output;
1988 dbin->output_streams = g_list_remove (dbin->output_streams, output);
1989 free_output_stream (dbin, output);
1992 dbin->slots = g_list_remove (dbin->slots, slot);
1993 SELECTION_UNLOCK (dbin);
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");
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);
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:
2019 GST_DEBUG_OBJECT (pad, "Intercepting CAPS query");
2020 gst_query_set_caps_result (query, GST_CAPS_ANY);
2021 ret = GST_PAD_PROBE_HANDLED;
2025 case GST_QUERY_ACCEPT_CAPS:
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;
2041 /* Create a new multiqueue slot for the given type
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)
2048 MultiQueueSlot *slot;
2049 GstIterator *it = NULL;
2050 GValue item = { 0, };
2052 GST_DEBUG_OBJECT (dbin, "Creating new slot for type %s",
2053 gst_stream_type_get_name (type));
2054 slot = g_new0 (MultiQueueSlot, 1);
2057 slot->id = dbin->slot_id++;
2060 slot->sink_pad = gst_element_get_request_pad (dbin->multiqueue, "sink_%u");
2061 if (slot->sink_pad == NULL)
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));
2071 gst_iterator_free (it);
2072 g_value_reset (&item);
2074 g_object_set (slot->sink_pad, "group-id", (guint) type, NULL);
2076 /* Add event probe */
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);
2082 GST_DEBUG ("Created new slot %u (%p) (%s:%s)", slot->id, slot,
2083 GST_DEBUG_PAD_NAME (slot->src_pad));
2085 dbin->slots = g_list_append (dbin->slots, slot);
2093 gst_element_release_request_pad (dbin->multiqueue, slot->sink_pad);
2099 /* Must be called with SELECTION_LOCK */
2100 static MultiQueueSlot *
2101 get_slot_for_input (GstDecodebin3 * dbin, DecodebinInputStream * input)
2104 MultiQueueSlot *empty_slot = NULL;
2105 GstStreamType input_type = 0;
2106 gchar *stream_id = NULL;
2108 GST_DEBUG_OBJECT (dbin, "input %p (stream %p %s)",
2109 input, input->active_stream,
2111 active_stream ? gst_stream_get_stream_id (input->active_stream) : "");
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);
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);
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 */
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) {
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))
2149 GST_DEBUG_OBJECT (dbin, "Re-using existing unused slot %d", empty_slot->id);
2150 empty_slot->input = input;
2155 return create_new_slot (dbin, input_type);
2161 link_input_to_slot (DecodebinInputStream * input, MultiQueueSlot * slot)
2163 if (slot->input != NULL && slot->input != input) {
2164 GST_ERROR_OBJECT (slot->dbin,
2165 "Trying to link input to an already used slot");
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;
2175 have_factory (GstDecodebin3 * dbin, GstCaps * caps,
2176 GstElementFactoryListType ftype)
2178 gboolean ret = FALSE;
2181 g_mutex_lock (&dbin->factories_lock);
2182 gst_decode_bin_update_factories_list (dbin);
2183 if (ftype == GST_ELEMENT_FACTORY_TYPE_DECODER)
2185 gst_element_factory_list_filter (dbin->decoder_factories,
2186 caps, GST_PAD_SINK, TRUE);
2189 gst_element_factory_list_filter (dbin->decodable_factories,
2190 caps, GST_PAD_SINK, TRUE);
2191 g_mutex_unlock (&dbin->factories_lock);
2195 gst_plugin_feature_list_free (res);
2203 create_element (GstDecodebin3 * dbin, GstStream * stream,
2204 GstElementFactoryListType ftype)
2207 GstElement *element = NULL;
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)
2215 gst_element_factory_list_filter (dbin->decoder_factories,
2216 caps, GST_PAD_SINK, TRUE);
2219 gst_element_factory_list_filter (dbin->decodable_factories,
2220 caps, GST_PAD_SINK, TRUE);
2221 g_mutex_unlock (&dbin->factories_lock);
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,
2232 GST_WARNING_OBJECT (dbin, "Failed to get HW resource.");
2233 gst_plugin_feature_list_free (res);
2234 gst_caps_unref (caps);
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);
2244 GST_DEBUG ("Could not find an element for caps %" GST_PTR_FORMAT, caps);
2247 gst_caps_unref (caps);
2251 /* FIXME : VERY NAIVE. ASSUMING FIRST ONE WILL WORK */
2253 create_decoder (GstDecodebin3 * dbin, GstStream * stream)
2255 return create_element (dbin, stream, GST_ELEMENT_FACTORY_TYPE_DECODER);
2258 static GstPadProbeReturn
2259 keyframe_waiter_probe (GstPad * pad, GstPadProbeInfo * info,
2260 DecodebinOutputStream * output)
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;
2272 GST_DEBUG_OBJECT (pad, "Buffer is not a keyframe, dropping");
2273 return GST_PAD_PROBE_DROP;
2277 reconfigure_output_stream (DecodebinOutputStream * output,
2278 MultiQueueSlot * slot)
2280 GstDecodebin3 *dbin = output->dbin;
2281 GstCaps *new_caps = (GstCaps *) gst_stream_get_caps (slot->active_stream);
2282 gboolean needs_decoder;
2284 needs_decoder = gst_caps_can_intersect (new_caps, dbin->caps) != TRUE;
2286 GST_DEBUG_OBJECT (dbin,
2287 "Reconfiguring output %p to slot %p, needs_decoder:%d", output, slot,
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);
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;
2304 if (needs_decoder) {
2306 gst_pad_query_accept_caps (output->decoder_sink, new_caps);
2308 can_reuse_decoder = FALSE;
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);
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;
2323 gst_caps_unref (new_caps);
2327 GST_DEBUG_OBJECT (dbin, "Removing old decoder for slot %p", slot);
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;
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);
2343 gst_element_set_locked_state (output->decoder, TRUE);
2344 gst_element_set_state (output->decoder, GST_STATE_NULL);
2346 gst_bin_remove ((GstBin *) dbin, output->decoder);
2347 output->decoder = NULL;
2350 gst_caps_unref (new_caps);
2352 gst_object_replace ((GstObject **) & output->decoder_sink, NULL);
2353 gst_object_replace ((GstObject **) & output->decoder_src, NULL);
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) {
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);
2372 if (!gst_bin_add ((GstBin *) dbin, output->decoder)) {
2373 GST_ERROR_OBJECT (dbin, "could not add decoder to pipeline");
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);
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));
2391 output->decoder_src = gst_object_ref (slot->src_pad);
2392 output->decoder_sink = NULL;
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");
2400 if (output->src_exposed == FALSE) {
2401 output->src_exposed = TRUE;
2402 gst_element_add_pad (GST_ELEMENT_CAST (dbin), output->src_pad);
2405 if (output->decoder)
2406 gst_element_sync_state_with_parent (output->decoder);
2408 output->slot = slot;
2413 GST_DEBUG_OBJECT (dbin, "Cleanup");
2414 if (output->decoder_sink) {
2415 gst_object_unref (output->decoder_sink);
2416 output->decoder_sink = NULL;
2418 if (output->decoder_src) {
2419 gst_object_unref (output->decoder_src);
2420 output->decoder_src = NULL;
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;
2430 static GstPadProbeReturn
2431 idle_reconfigure (GstPad * pad, GstPadProbeInfo * info, MultiQueueSlot * slot)
2433 GstMessage *msg = NULL;
2434 DecodebinOutputStream *output;
2436 SELECTION_LOCK (slot->dbin);
2437 output = get_output_for_slot (slot);
2439 GST_DEBUG_OBJECT (pad, "output : %p", output);
2442 reconfigure_output_stream (output, slot);
2443 msg = is_selection_done (slot->dbin);
2445 SELECTION_UNLOCK (slot->dbin);
2447 gst_element_post_message ((GstElement *) slot->dbin, msg);
2449 return GST_PAD_PROBE_REMOVE;
2452 static MultiQueueSlot *
2453 find_slot_for_stream_id (GstDecodebin3 * dbin, const gchar * sid)
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))
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))
2475 /* This function handles the reassignment of a slot. Call this from
2476 * the streaming thread of a slot. */
2478 reassign_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
2480 DecodebinOutputStream *output;
2481 MultiQueueSlot *target_slot = NULL;
2483 const gchar *sid, *tsid;
2485 SELECTION_LOCK (dbin);
2486 output = slot->output;
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);
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);
2502 sid = gst_stream_get_stream_id (slot->active_stream);
2503 GST_DEBUG_OBJECT (slot->src_pad, "slot %s %p", sid, slot);
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);
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);
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;
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);
2550 GST_DEBUG_OBJECT (slot->src_pad, "Assigning output to slot %p '%s'",
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);
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 ()); */
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);
2572 gst_element_post_message ((GstElement *) slot->dbin, msg);
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.
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)
2587 GstDecodebin3 *dbin = slot->dbin;
2589 reassign_slot (dbin, slot);
2591 return GST_PAD_PROBE_REMOVE;
2595 handle_stream_switch (GstDecodebin3 * dbin, GList * select_streams,
2598 gboolean ret = TRUE;
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;
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);
2617 /* Remove pending select_streams */
2618 g_list_free (dbin->pending_select_streams);
2619 dbin->pending_select_streams = NULL;
2621 /* COMPARE the requested streams to the active and requested streams
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 */
2632 if (stream_in_collection (dbin, (gchar *) sid)) {
2633 pending_streams = g_list_append (pending_streams, (gchar *) sid);
2635 GST_DEBUG_OBJECT (dbin, "We don't have a slot for stream '%s'", sid);
2636 unknown = g_list_append (unknown, (gchar *) sid);
2638 } else if (slot->output == NULL) {
2639 GST_DEBUG_OBJECT (dbin, "We need to activate slot %p for stream '%s')",
2641 to_activate = g_list_append (to_activate, slot);
2643 GST_DEBUG_OBJECT (dbin,
2644 "Stream '%s' from slot %p is already active on output %p", sid, slot,
2646 future_request_streams =
2647 g_list_append (future_request_streams, (gchar *) sid);
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
2656 gboolean slot_to_deactivate = TRUE;
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;
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;
2669 if (slot_to_deactivate) {
2670 GST_DEBUG_OBJECT (dbin,
2671 "Slot %p (%s) should be deactivated, no longer used", slot,
2673 active_stream ? gst_stream_get_stream_id (slot->active_stream) :
2675 to_deactivate = g_list_append (to_deactivate, slot);
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;
2688 MultiQueueSlot *slot_to_deactivate = (MultiQueueSlot *) tmp->data;
2689 gboolean removeit = FALSE;
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));
2702 g_list_append (slots_to_reassign, slot_to_deactivate);
2703 to_activate = g_list_remove (to_activate, slot_to_activate);
2710 to_deactivate = g_list_delete_link (to_deactivate, tmp);
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",
2721 slots_to_reassign = g_list_append (slots_to_reassign, slot);
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));
2737 GST_ERROR_OBJECT (dbin, "No stream for slot %p !!", slot);
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;
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);
2763 dbin->selection_updated = TRUE;
2764 SELECTION_UNLOCK (dbin);
2767 GST_FIXME_OBJECT (dbin, "Got request for an unknown stream");
2768 g_list_free (unknown);
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);
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);
2788 g_list_free (to_deactivate);
2790 g_list_free (to_activate);
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);
2803 static GstPadProbeReturn
2804 ghost_pad_event_probe (GstPad * pad, GstPadProbeInfo * info,
2805 DecodebinOutputStream * output)
2807 GstPadProbeReturn ret = GST_PAD_PROBE_OK;
2808 GstDecodebin3 *dbin = output->dbin;
2809 GstEvent *event = GST_PAD_PROBE_INFO_EVENT (info);
2811 GST_DEBUG_OBJECT (pad, "Got event %p %s", event, GST_EVENT_TYPE_NAME (event));
2813 switch (GST_EVENT_TYPE (event)) {
2814 case GST_EVENT_SELECT_STREAMS:
2817 GList *streams = NULL;
2818 guint32 seqnum = gst_event_get_seqnum (event);
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;
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;
2835 gst_event_parse_select_streams (event, &streams);
2836 dbin->pending_select_streams = g_list_copy (streams);
2837 SELECTION_UNLOCK (dbin);
2839 /* Send event upstream */
2840 if ((peer = gst_pad_get_peer (pad))) {
2841 gst_pad_send_event (peer, event);
2842 gst_object_unref (peer);
2844 gst_event_unref (event);
2846 /* Finally handle the switch */
2848 handle_stream_switch (dbin, streams, seqnum);
2849 g_list_free_full (streams, g_free);
2851 ret = GST_PAD_PROBE_HANDLED;
2862 gst_decodebin3_send_event (GstElement * element, GstEvent * event)
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);
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");
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;
2883 gst_event_parse_select_streams (event, &streams);
2884 dbin->pending_select_streams = g_list_copy (streams);
2885 SELECTION_UNLOCK (dbin);
2887 /* FIXME : We don't have an upstream ?? */
2889 /* Send event upstream */
2890 if ((peer = gst_pad_get_peer (pad))) {
2891 gst_pad_send_event (peer, event);
2892 gst_object_unref (peer);
2895 /* Finally handle the switch */
2897 handle_stream_switch (dbin, streams, seqnum);
2898 g_list_free_full (streams, g_free);
2901 gst_event_unref (event);
2904 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);
2909 free_multiqueue_slot (GstDecodebin3 * dbin, MultiQueueSlot * slot)
2912 gst_pad_remove_probe (slot->src_pad, slot->probe_id);
2914 if (slot->input->srcpad)
2915 gst_pad_unlink (slot->input->srcpad, slot->sink_pad);
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);
2926 free_multiqueue_slot_async (GstDecodebin3 * dbin, MultiQueueSlot * slot)
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);
2933 /* Create a DecodebinOutputStream for a given type
2934 * Note: It will be empty initially, it needs to be configured
2936 static DecodebinOutputStream *
2937 create_output_stream (GstDecodebin3 * dbin, GstStreamType type)
2939 DecodebinOutputStream *res = g_new0 (DecodebinOutputStream, 1);
2941 const gchar *prefix;
2942 GstStaticPadTemplate *templ;
2943 GstPadTemplate *ptmpl;
2945 GstPad *internal_pad;
2947 GST_DEBUG_OBJECT (dbin, "Created new output stream %p for type %s",
2948 res, gst_stream_type_get_name (type));
2953 if (type & GST_STREAM_TYPE_VIDEO) {
2954 templ = &video_src_template;
2955 counter = &dbin->vpadcount;
2957 } else if (type & GST_STREAM_TYPE_AUDIO) {
2958 templ = &audio_src_template;
2959 counter = &dbin->apadcount;
2961 } else if (type & GST_STREAM_TYPE_TEXT) {
2962 templ = &text_src_template;
2963 counter = &dbin->tpadcount;
2966 templ = &src_template;
2967 counter = &dbin->opadcount;
2971 pad_name = g_strdup_printf ("%s_%u", prefix, *counter);
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);
2977 gst_pad_set_active (res->src_pad, TRUE);
2978 /* Put an event probe on the internal proxy pad to detect upstream
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);
2986 dbin->output_streams = g_list_append (dbin->output_streams, res);
2992 free_output_stream (GstDecodebin3 * dbin, DecodebinOutputStream * output)
2995 if (output->decoder_sink && output->decoder)
2996 gst_pad_unlink (output->slot->src_pad, output->decoder_sink);
2998 output->slot->output = NULL;
2999 output->slot = NULL;
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);
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);
3015 static GstStateChangeReturn
3016 gst_decodebin3_change_state (GstElement * element, GstStateChange transition)
3018 GstDecodebin3 *dbin = (GstDecodebin3 *) element;
3019 GstStateChangeReturn ret;
3022 switch (transition) {
3026 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
3027 if (ret == GST_STATE_CHANGE_FAILURE)
3030 switch (transition) {
3031 case GST_STATE_CHANGE_PAUSED_TO_READY:
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);
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);
3047 g_list_free (dbin->slots);
3049 dbin->current_group_id = GST_GROUP_ID_INVALID;
3061 gst_decodebin3_plugin_init (GstPlugin * plugin)
3063 GST_DEBUG_CATEGORY_INIT (decodebin3_debug, "decodebin3", 0, "decoder bin");
3065 return gst_element_register (plugin, "decodebin3", GST_RANK_NONE,
3066 GST_TYPE_DECODEBIN3);