2 * Copyright (C) <2007> Wim Taymans <wim.taymans@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
22 * * BUFFERING MESSAGES
23 * ** How/Where do we deal with buffering messages from a new/prerolling
24 * source ? Ideally we want to re-use the same sourcebin ?
25 * ** Remember last buffering messages per source handler, if the SourceEntry
26 * group_id is the one being currently outputted on the source ghostpads,
27 * post the (last) buffering messages.
28 * If no group_id is being outputted (still prerolling), then output
29 * the messages directly
32 * ** URIDECODEBIN3 is not async-aware.
35 * ** Correlate group_id and URI to know when/which stream is being outputted/started
39 * SECTION:element-uridecodebin3
40 * @title: uridecodebin3
42 * Decodes data from a URI into raw media. It selects a source element that can
43 * handle the given #GstURIDecodeBin3:uri scheme and connects it to a decodebin.
53 #include <gst/gst-i18n-plugin.h>
54 #include <gst/pbutils/missing-plugins.h>
56 #include "gstplay-enum.h"
57 #include "gstrawcaps.h"
58 #include "gstplaybackelements.h"
59 #include "gstplaybackutils.h"
61 #define GST_TYPE_URI_DECODE_BIN3 \
62 (gst_uri_decode_bin3_get_type())
63 #define GST_URI_DECODE_BIN3(obj) \
64 (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_URI_DECODE_BIN3,GstURIDecodeBin3))
65 #define GST_URI_DECODE_BIN3_CLASS(klass) \
66 (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_URI_DECODE_BIN3,GstURIDecodeBin3Class))
67 #define GST_IS_URI_DECODE_BIN3(obj) \
68 (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_URI_DECODE_BIN3))
69 #define GST_IS_URI_DECODE_BIN3_CLASS(klass) \
70 (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_URI_DECODE_BIN3))
71 #define GST_URI_DECODE_BIN3_CAST(obj) ((GstURIDecodeBin3 *) (obj))
73 typedef struct _GstSourceGroup GstSourceGroup;
74 typedef struct _GstURIDecodeBin3 GstURIDecodeBin3;
75 typedef struct _GstURIDecodeBin3Class GstURIDecodeBin3Class;
77 #define GST_URI_DECODE_BIN3_LOCK(dec) (g_mutex_lock(&((GstURIDecodeBin3*)(dec))->lock))
78 #define GST_URI_DECODE_BIN3_UNLOCK(dec) (g_mutex_unlock(&((GstURIDecodeBin3*)(dec))->lock))
80 typedef struct _GstPlayItem GstPlayItem;
81 typedef struct _GstSourceItem GstSourceItem;
82 typedef struct _GstSourceHandler GstSourceHandler;
83 typedef struct _OutputPad OutputPad;
85 /* A structure describing a play item, which travels through the elements
89 GstURIDecodeBin3 *uridecodebin;
92 GstSourceItem *main_item;
95 /* FIXME : Replace by a list later */
96 GstSourceItem *sub_item;
98 /* The group_id used to identify this play item via STREAM_START events
99 * This is the group_id which will be used externally (i.e. rewritten
100 * to outgoing STREAM_START events and in emitted signals).
101 * The urisourcebin-specific group_id is located in GstSourceItem */
104 /* Is this play item the one being currently outputted by decodebin3
105 * and on our source ghostpads */
106 gboolean currently_outputted;
109 struct _GstSourceItem
111 /* The GstPlayItem to which this GstSourceItem belongs to */
112 GstPlayItem *play_item;
116 /* The urisourcebin controlling this uri
118 GstSourceHandler *handler;
120 /* The groupid created by urisourcebin for this uri */
121 guint internal_groupid;
123 /* FIXME : Add tag lists and other uri-specific items here ? */
126 /* Structure wrapping everything related to a urisourcebin */
127 struct _GstSourceHandler
129 GstURIDecodeBin3 *uridecodebin;
131 GstElement *urisourcebin;
133 /* Signal handlers */
135 gulong pad_removed_id;
136 gulong source_setup_id;
137 gulong about_to_finish_id;
139 /* TRUE if the controlled urisourcebin was added to uridecodebin */
142 /* whether urisourcebin is drained or not.
143 * Reset if/when setting a new URI */
146 /* Whether urisourcebin posted EOS on all pads and
147 * there is no pending entry */
150 /* TRUE if the urisourcebin handles main item */
151 gboolean is_main_source;
153 /* buffering message stored for after switching */
154 GstMessage *pending_buffering_msg;
157 /* Controls an output source pad */
160 GstURIDecodeBin3 *uridecodebin;
165 /* Downstream event probe id */
168 /* TRUE if the pad saw EOS. Reset to FALSE on STREAM_START */
171 /* The last seen (i.e. current) group_id
172 * Can be (guint)-1 if no group_id was seen yet */
173 guint current_group_id;
179 * uridecodebin3 element struct
181 struct _GstURIDecodeBin3
183 GstBin parent_instance;
185 GMutex lock; /* lock for constructing */
189 guint64 connection_speed; /* In bits/sec (0 = unknown) */
191 guint64 buffer_duration; /* When buffering, buffer duration (ns) */
192 guint buffer_size; /* When buffering, buffer size (bytes) */
194 gboolean use_buffering;
195 guint64 ring_buffer_max_size;
197 GList *play_items; /* List of GstPlayItem ordered by time of
198 * creation. Head of list is therefore the
199 * current (or pending if initial) one being
201 GstPlayItem *current; /* Currently active GstPlayItem. Can be NULL
202 * if no entry is active yet (i.e. no source
206 * FIXME : Replace by a more modular system later on */
207 GstSourceHandler *main_handler;
208 GstSourceHandler *sub_handler;
211 * FIXME : Switch to a playlist-based API */
213 gboolean uri_changed; /* TRUE if uri changed */
215 gboolean suburi_changed; /* TRUE if suburi changed */
217 /* A global decodebin3 that's used to actually do decoding */
218 GstElement *decodebin;
221 gulong db_pad_added_id;
222 gulong db_pad_removed_id;
223 gulong db_select_stream_id;
224 gulong db_about_to_finish_id;
226 GList *output_pads; /* List of OutputPad */
228 GList *source_handlers; /* List of SourceHandler */
230 /* Whether we already signalled about-to-finish or not
231 * FIXME: Track this by group-id ! */
232 gboolean posted_about_to_finish;
236 gst_uridecodebin3_select_stream (GstURIDecodeBin3 * dbin,
237 GstStreamCollection * collection, GstStream * stream)
239 GST_LOG_OBJECT (dbin, "default select-stream, returning -1");
244 struct _GstURIDecodeBin3Class
246 GstBinClass parent_class;
248 gint (*select_stream) (GstURIDecodeBin3 * dbin,
249 GstStreamCollection * collection, GstStream * stream);
252 GST_DEBUG_CATEGORY_STATIC (gst_uri_decode_bin3_debug);
253 #define GST_CAT_DEFAULT gst_uri_decode_bin3_debug
258 SIGNAL_SELECT_STREAM,
260 SIGNAL_ABOUT_TO_FINISH,
265 static GstStaticCaps raw_audio_caps = GST_STATIC_CAPS ("audio/x-raw(ANY)");
266 static GstStaticCaps raw_video_caps = GST_STATIC_CAPS ("video/x-raw(ANY)");
270 #define DEFAULT_PROP_URI NULL
271 #define DEFAULT_PROP_SUBURI NULL
272 #define DEFAULT_CONNECTION_SPEED 0
273 #define DEFAULT_CAPS (gst_static_caps_get (&default_raw_caps))
274 #define DEFAULT_BUFFER_DURATION -1
275 #define DEFAULT_BUFFER_SIZE -1
276 #define DEFAULT_DOWNLOAD FALSE
277 #define DEFAULT_USE_BUFFERING FALSE
278 #define DEFAULT_RING_BUFFER_MAX_SIZE 0
288 PROP_CONNECTION_SPEED,
290 PROP_BUFFER_DURATION,
293 PROP_RING_BUFFER_MAX_SIZE,
297 static guint gst_uri_decode_bin3_signals[LAST_SIGNAL] = { 0 };
299 static GstStaticCaps default_raw_caps = GST_STATIC_CAPS (DEFAULT_RAW_CAPS);
301 static GstStaticPadTemplate video_src_template =
302 GST_STATIC_PAD_TEMPLATE ("video_%u",
305 GST_STATIC_CAPS_ANY);
307 static GstStaticPadTemplate audio_src_template =
308 GST_STATIC_PAD_TEMPLATE ("audio_%u",
311 GST_STATIC_CAPS_ANY);
313 static GstStaticPadTemplate text_src_template =
314 GST_STATIC_PAD_TEMPLATE ("text_%u",
317 GST_STATIC_CAPS_ANY);
319 static GstStaticPadTemplate src_template = GST_STATIC_PAD_TEMPLATE ("src_%u",
322 GST_STATIC_CAPS_ANY);
324 GType gst_uri_decode_bin3_get_type (void);
325 #define gst_uri_decode_bin3_parent_class parent_class
326 G_DEFINE_TYPE (GstURIDecodeBin3, gst_uri_decode_bin3, GST_TYPE_BIN);
329 GST_DEBUG_CATEGORY_INIT (gst_uri_decode_bin3_debug, "uridecodebin3", 0, "URI decoder element 3"); \
330 playback_element_init (plugin);
331 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (uridecodebin3, "uridecodebin3",
332 GST_RANK_NONE, GST_TYPE_URI_DECODE_BIN3, _do_init);
334 #define REMOVE_SIGNAL(obj,id) \
336 g_signal_handler_disconnect (obj, id); \
340 static void gst_uri_decode_bin3_set_property (GObject * object, guint prop_id,
341 const GValue * value, GParamSpec * pspec);
342 static void gst_uri_decode_bin3_get_property (GObject * object, guint prop_id,
343 GValue * value, GParamSpec * pspec);
344 static void gst_uri_decode_bin3_finalize (GObject * obj);
345 static GstSourceHandler *new_source_handler (GstURIDecodeBin3 * uridecodebin,
348 static GstStateChangeReturn gst_uri_decode_bin3_change_state (GstElement *
349 element, GstStateChange transition);
350 static gboolean gst_uri_decodebin3_send_event (GstElement * element,
354 _gst_int_accumulator (GSignalInvocationHint * ihint,
355 GValue * return_accu, const GValue * handler_return, gpointer dummy)
357 gint res = g_value_get_int (handler_return);
359 g_value_set_int (return_accu, res);
369 gst_uri_decode_bin3_class_init (GstURIDecodeBin3Class * klass)
371 GObjectClass *gobject_class;
372 GstElementClass *gstelement_class;
374 gobject_class = G_OBJECT_CLASS (klass);
375 gstelement_class = GST_ELEMENT_CLASS (klass);
377 gobject_class->set_property = gst_uri_decode_bin3_set_property;
378 gobject_class->get_property = gst_uri_decode_bin3_get_property;
379 gobject_class->finalize = gst_uri_decode_bin3_finalize;
381 g_object_class_install_property (gobject_class, PROP_URI,
382 g_param_spec_string ("uri", "URI", "URI to decode",
383 DEFAULT_PROP_URI, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
385 g_object_class_install_property (gobject_class, PROP_CURRENT_URI,
386 g_param_spec_string ("current-uri", "Current URI",
387 "The currently playing URI", NULL,
388 G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
390 g_object_class_install_property (gobject_class, PROP_SUBURI,
391 g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
392 NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
394 g_object_class_install_property (gobject_class, PROP_CURRENT_SUBURI,
395 g_param_spec_string ("current-suburi", "Current .sub-URI",
396 "The currently playing URI of a subtitle",
397 NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
399 g_object_class_install_property (gobject_class, PROP_SOURCE,
400 g_param_spec_object ("source", "Source", "Source object used",
401 GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
403 g_object_class_install_property (gobject_class, PROP_CONNECTION_SPEED,
404 g_param_spec_uint64 ("connection-speed", "Connection Speed",
405 "Network connection speed in kbps (0 = unknown)",
406 0, G_MAXUINT64 / 1000, DEFAULT_CONNECTION_SPEED,
407 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
409 g_object_class_install_property (gobject_class, PROP_BUFFER_SIZE,
410 g_param_spec_int ("buffer-size", "Buffer size (bytes)",
411 "Buffer size when buffering streams (-1 default value)",
412 -1, G_MAXINT, DEFAULT_BUFFER_SIZE,
413 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
415 g_object_class_install_property (gobject_class, PROP_BUFFER_DURATION,
416 g_param_spec_int64 ("buffer-duration", "Buffer duration (ns)",
417 "Buffer duration when buffering streams (-1 default value)",
418 -1, G_MAXINT64, DEFAULT_BUFFER_DURATION,
419 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
422 * GstURIDecodeBin3::download:
424 * For certain media type, enable download buffering.
426 g_object_class_install_property (gobject_class, PROP_DOWNLOAD,
427 g_param_spec_boolean ("download", "Download",
428 "Attempt download buffering when buffering network streams",
429 DEFAULT_DOWNLOAD, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
431 * GstURIDecodeBin3::use-buffering:
433 * Emit BUFFERING messages based on low-/high-percent thresholds of the
434 * demuxed or parsed data.
435 * When download buffering is activated and used for the current media
436 * type, this property does nothing. Otherwise perform buffering on the
437 * demuxed or parsed media.
439 g_object_class_install_property (gobject_class, PROP_USE_BUFFERING,
440 g_param_spec_boolean ("use-buffering", "Use Buffering",
441 "Perform buffering on demuxed/parsed media",
442 DEFAULT_USE_BUFFERING, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
445 * GstURIDecodeBin3::ring-buffer-max-size
447 * The maximum size of the ring buffer in kilobytes. If set to 0, the ring
448 * buffer is disabled. Default is 0.
450 g_object_class_install_property (gobject_class, PROP_RING_BUFFER_MAX_SIZE,
451 g_param_spec_uint64 ("ring-buffer-max-size",
452 "Max. ring buffer size (bytes)",
453 "Max. amount of data in the ring buffer (bytes, 0 = ring buffer disabled)",
454 0, G_MAXUINT, DEFAULT_RING_BUFFER_MAX_SIZE,
455 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
457 g_object_class_install_property (gobject_class, PROP_CAPS,
458 g_param_spec_boxed ("caps", "Caps",
459 "The caps on which to stop decoding. (NULL = default)",
460 GST_TYPE_CAPS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
463 * GstURIDecodebin3::select-stream
464 * @decodebin: a #GstURIDecodebin3
465 * @collection: a #GstStreamCollection
466 * @stream: a #GstStream
468 * This signal is emitted whenever @decodebin needs to decide whether
469 * to expose a @stream of a given @collection.
471 * Note that the prefered way to select streams is to listen to
472 * GST_MESSAGE_STREAM_COLLECTION on the bus and send a
473 * GST_EVENT_SELECT_STREAMS with the streams the user wants.
475 * Returns: 1 if the stream should be selected, 0 if it shouldn't be selected.
476 * A value of -1 (default) lets @decodebin decide what to do with the stream.
478 gst_uri_decode_bin3_signals[SIGNAL_SELECT_STREAM] =
479 g_signal_new ("select-stream", G_TYPE_FROM_CLASS (klass),
480 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstURIDecodeBin3Class, select_stream),
481 _gst_int_accumulator, NULL, NULL, G_TYPE_INT, 2,
482 GST_TYPE_STREAM_COLLECTION, GST_TYPE_STREAM);
485 * GstURIDecodeBin3::source-setup:
486 * @bin: the uridecodebin.
487 * @source: source element
489 * This signal is emitted after a source element has been created, so
490 * it can be configured by setting additional properties (e.g. set a
491 * proxy server for an http source, or set the device and read speed for
492 * an audio cd source).
494 gst_uri_decode_bin3_signals[SIGNAL_SOURCE_SETUP] =
495 g_signal_new ("source-setup", G_TYPE_FROM_CLASS (klass),
496 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 1, GST_TYPE_ELEMENT);
498 * GstURIDecodeBin3::about-to-finish:
500 * This signal is emitted when the data for the selected URI is
501 * entirely buffered and it is safe to specify another URI.
503 gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH] =
504 g_signal_new ("about-to-finish", G_TYPE_FROM_CLASS (klass),
505 G_SIGNAL_RUN_LAST, 0, NULL, NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
508 gst_element_class_add_static_pad_template (gstelement_class,
509 &video_src_template);
510 gst_element_class_add_static_pad_template (gstelement_class,
511 &audio_src_template);
512 gst_element_class_add_static_pad_template (gstelement_class,
514 gst_element_class_add_static_pad_template (gstelement_class, &src_template);
515 gst_element_class_set_static_metadata (gstelement_class,
516 "URI Decoder", "Generic/Bin/Decoder",
517 "Autoplug and decode an URI to raw media",
518 "Edward Hervey <edward@centricular.com>, Jan Schmidt <jan@centricular.com>");
520 gstelement_class->change_state = gst_uri_decode_bin3_change_state;
521 gstelement_class->send_event =
522 GST_DEBUG_FUNCPTR (gst_uri_decodebin3_send_event);
524 klass->select_stream = gst_uridecodebin3_select_stream;
527 static GstPadProbeReturn
528 db_src_probe (GstPad * pad, GstPadProbeInfo * info, OutputPad * output)
530 /* FIXME : IMPLEMENT */
532 /* EOS : Mark pad as EOS */
534 /* STREAM_START : Store group_id and check if currently active
535 * PlayEntry changed */
537 return GST_PAD_PROBE_OK;
541 add_output_pad (GstURIDecodeBin3 * dec, GstPad * target_pad)
545 GstEvent *stream_start;
547 output = g_slice_new0 (OutputPad);
549 GST_LOG_OBJECT (dec, "Created output %p", output);
551 output->uridecodebin = dec;
552 output->target_pad = target_pad;
553 output->current_group_id = (guint) - 1;
554 pad_name = gst_pad_get_name (target_pad);
555 output->ghost_pad = gst_ghost_pad_new (pad_name, target_pad);
558 gst_pad_set_active (output->ghost_pad, TRUE);
560 stream_start = gst_pad_get_sticky_event (target_pad,
561 GST_EVENT_STREAM_START, 0);
563 gst_pad_store_sticky_event (output->ghost_pad, stream_start);
564 gst_event_unref (stream_start);
566 GST_WARNING_OBJECT (target_pad,
567 "Exposing pad without stored stream-start event");
570 gst_element_add_pad (GST_ELEMENT (dec), output->ghost_pad);
573 gst_pad_add_probe (output->target_pad,
574 GST_PAD_PROBE_TYPE_EVENT_DOWNSTREAM, (GstPadProbeCallback) db_src_probe,
577 /* FIXME: LOCK TO PROTECT PAD LIST */
578 dec->output_pads = g_list_append (dec->output_pads, output);
584 db_pad_added_cb (GstElement * element, GstPad * pad, GstURIDecodeBin3 * dec)
586 GST_DEBUG_OBJECT (dec, "Wrapping new pad %s:%s", GST_DEBUG_PAD_NAME (pad));
588 if (GST_PAD_IS_SRC (pad))
589 add_output_pad (dec, pad);
593 db_pad_removed_cb (GstElement * element, GstPad * pad, GstURIDecodeBin3 * dec)
596 OutputPad *output = NULL;
598 if (!GST_PAD_IS_SRC (pad))
601 GST_DEBUG_OBJECT (dec, "pad %s:%s", GST_DEBUG_PAD_NAME (pad));
602 /* FIXME: LOCK for list access */
604 for (tmp = dec->output_pads; tmp; tmp = tmp->next) {
605 OutputPad *cand = (OutputPad *) tmp->data;
607 if (cand->target_pad == pad) {
609 dec->output_pads = g_list_delete_link (dec->output_pads, tmp);
615 GST_LOG_OBJECT (element, "Removing output %p", output);
616 /* Remove source ghost pad */
617 gst_ghost_pad_set_target ((GstGhostPad *) output->ghost_pad, NULL);
618 gst_element_remove_pad ((GstElement *) dec, output->ghost_pad);
620 /* FIXME : Update global/current PlayEntry group_id (did we switch ?) */
622 /* Remove event probe */
623 gst_pad_remove_probe (output->target_pad, output->probe_id);
625 g_slice_free (OutputPad, output);
630 db_select_stream_cb (GstElement * decodebin,
631 GstStreamCollection * collection, GstStream * stream,
632 GstURIDecodeBin3 * uridecodebin)
636 g_signal_emit (uridecodebin,
637 gst_uri_decode_bin3_signals[SIGNAL_SELECT_STREAM], 0, collection, stream,
643 db_about_to_finish_cb (GstElement * decodebin, GstURIDecodeBin3 * uridecodebin)
645 if (!uridecodebin->posted_about_to_finish) {
646 uridecodebin->posted_about_to_finish = TRUE;
647 g_signal_emit (uridecodebin,
648 gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
653 gst_uri_decode_bin3_init (GstURIDecodeBin3 * dec)
655 g_mutex_init (&dec->lock);
657 dec->uri = DEFAULT_PROP_URI;
658 dec->suburi = DEFAULT_PROP_SUBURI;
659 dec->connection_speed = DEFAULT_CONNECTION_SPEED;
660 dec->caps = DEFAULT_CAPS;
661 dec->buffer_duration = DEFAULT_BUFFER_DURATION;
662 dec->buffer_size = DEFAULT_BUFFER_SIZE;
663 dec->download = DEFAULT_DOWNLOAD;
664 dec->use_buffering = DEFAULT_USE_BUFFERING;
665 dec->ring_buffer_max_size = DEFAULT_RING_BUFFER_MAX_SIZE;
667 dec->decodebin = gst_element_factory_make ("decodebin3", NULL);
668 gst_bin_add (GST_BIN_CAST (dec), dec->decodebin);
669 dec->db_pad_added_id =
670 g_signal_connect (dec->decodebin, "pad-added",
671 G_CALLBACK (db_pad_added_cb), dec);
672 dec->db_pad_removed_id =
673 g_signal_connect (dec->decodebin, "pad-removed",
674 G_CALLBACK (db_pad_removed_cb), dec);
675 dec->db_select_stream_id =
676 g_signal_connect (dec->decodebin, "select-stream",
677 G_CALLBACK (db_select_stream_cb), dec);
678 dec->db_about_to_finish_id =
679 g_signal_connect (dec->decodebin, "about-to-finish",
680 G_CALLBACK (db_about_to_finish_cb), dec);
682 GST_OBJECT_FLAG_SET (dec, GST_ELEMENT_FLAG_SOURCE);
683 gst_bin_set_suppressed_flags (GST_BIN (dec),
684 GST_ELEMENT_FLAG_SOURCE | GST_ELEMENT_FLAG_SINK);
688 gst_uri_decode_bin3_finalize (GObject * obj)
690 GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (obj);
692 g_mutex_clear (&dec->lock);
694 g_free (dec->suburi);
696 G_OBJECT_CLASS (parent_class)->finalize (obj);
699 static GstStateChangeReturn
700 activate_source_item (GstSourceItem * item)
702 GstSourceHandler *handler = item->handler;
704 if (handler == NULL) {
705 GST_WARNING ("Can't activate item without a handler");
706 return GST_STATE_CHANGE_FAILURE;
709 g_object_set (handler->urisourcebin, "uri", item->uri, NULL);
710 if (!handler->active) {
711 gst_bin_add ((GstBin *) handler->uridecodebin, handler->urisourcebin);
712 /* if (!gst_element_sync_state_with_parent (handler->urisourcebin)) */
713 /* return GST_STATE_CHANGE_FAILURE; */
714 handler->active = TRUE;
717 return GST_STATE_CHANGE_SUCCESS;
721 src_pad_added_cb (GstElement * element, GstPad * pad,
722 GstSourceHandler * handler)
724 GstURIDecodeBin3 *uridecodebin;
725 GstPad *sinkpad = NULL;
726 GstPadLinkReturn res;
727 GstPlayItem *current_play_item;
728 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
730 uridecodebin = handler->uridecodebin;
731 current_play_item = uridecodebin->current;
733 GST_DEBUG_OBJECT (uridecodebin,
734 "New pad %" GST_PTR_FORMAT " from source %" GST_PTR_FORMAT, pad, element);
736 /* FIXME: Add probe to unify group_id and detect EOS */
738 /* Try to link to main sink pad only if it's from a main handler */
739 if (handler->is_main_source) {
740 sinkpad = gst_element_get_static_pad (uridecodebin->decodebin, "sink");
741 if (gst_pad_is_linked (sinkpad)) {
742 gst_object_unref (sinkpad);
749 gst_element_request_pad_simple (uridecodebin->decodebin, "sink_%u");
752 GST_DEBUG_OBJECT (uridecodebin,
753 "Linking %" GST_PTR_FORMAT " to %" GST_PTR_FORMAT, pad, sinkpad);
754 res = gst_pad_link (pad, sinkpad);
755 gst_object_unref (sinkpad);
756 if (GST_PAD_LINK_FAILED (res))
760 /* Activate sub_item after the main source activation was finished */
761 if (handler->is_main_source && current_play_item->sub_item
762 && !current_play_item->sub_item->handler) {
763 current_play_item->sub_item->handler =
764 new_source_handler (uridecodebin, FALSE);
765 ret = activate_source_item (current_play_item->sub_item);
766 if (ret == GST_STATE_CHANGE_FAILURE)
767 goto sub_item_activation_failed;
774 GST_ERROR_OBJECT (uridecodebin,
775 "failed to link pad %s:%s to decodebin, reason %s (%d)",
776 GST_DEBUG_PAD_NAME (pad), gst_pad_link_get_name (res), res);
779 sub_item_activation_failed:
781 GST_ERROR_OBJECT (uridecodebin,
782 "failed to activate subtitle playback item");
788 src_pad_removed_cb (GstElement * element, GstPad * pad,
789 GstSourceHandler * handler)
791 GstURIDecodeBin3 *uridecodebin = handler->uridecodebin;
792 GstPad *peer_pad = gst_pad_get_peer (pad);
795 GstPadTemplate *templ = gst_pad_get_pad_template (peer_pad);
797 GST_DEBUG_OBJECT (uridecodebin,
798 "Source %" GST_PTR_FORMAT " removed pad %" GST_PTR_FORMAT " peer %"
799 GST_PTR_FORMAT, element, pad, peer_pad);
802 if (GST_PAD_TEMPLATE_PRESENCE (templ) == GST_PAD_REQUEST) {
803 GST_DEBUG_OBJECT (uridecodebin,
804 "Releasing decodebin pad %" GST_PTR_FORMAT, peer_pad);
805 gst_element_release_request_pad (uridecodebin->decodebin, peer_pad);
807 gst_object_unref (templ);
810 gst_object_unref (peer_pad);
815 src_source_setup_cb (GstElement * element, GstElement * source,
816 GstSourceHandler * handler)
818 g_signal_emit (handler->uridecodebin,
819 gst_uri_decode_bin3_signals[SIGNAL_SOURCE_SETUP], 0, source, NULL);
823 src_about_to_finish_cb (GstElement * element, GstSourceHandler * handler)
825 /* FIXME : check if all sources are done */
826 if (!handler->uridecodebin->posted_about_to_finish) {
827 handler->uridecodebin->posted_about_to_finish = TRUE;
828 g_signal_emit (handler->uridecodebin,
829 gst_uri_decode_bin3_signals[SIGNAL_ABOUT_TO_FINISH], 0, NULL);
833 static GstSourceHandler *
834 new_source_handler (GstURIDecodeBin3 * uridecodebin, gboolean is_main)
836 GstSourceHandler *handler;
838 handler = g_slice_new0 (GstSourceHandler);
840 handler->uridecodebin = uridecodebin;
841 handler->is_main_source = is_main;
842 handler->urisourcebin = gst_element_factory_make ("urisourcebin", NULL);
843 /* Set pending properties */
844 g_object_set (handler->urisourcebin,
845 "connection-speed", uridecodebin->connection_speed / 1000,
846 "download", uridecodebin->download,
847 "use-buffering", uridecodebin->use_buffering,
848 "buffer-duration", uridecodebin->buffer_duration,
849 "buffer-size", uridecodebin->buffer_size,
850 "ring-buffer-max-size", uridecodebin->ring_buffer_max_size, NULL);
852 handler->pad_added_id =
853 g_signal_connect (handler->urisourcebin, "pad-added",
854 (GCallback) src_pad_added_cb, handler);
855 handler->pad_removed_id =
856 g_signal_connect (handler->urisourcebin, "pad-removed",
857 (GCallback) src_pad_removed_cb, handler);
858 handler->source_setup_id =
859 g_signal_connect (handler->urisourcebin, "source-setup",
860 (GCallback) src_source_setup_cb, handler);
861 handler->about_to_finish_id =
862 g_signal_connect (handler->urisourcebin, "about-to-finish",
863 (GCallback) src_about_to_finish_cb, handler);
865 uridecodebin->source_handlers =
866 g_list_append (uridecodebin->source_handlers, handler);
872 gst_uri_decode_bin3_set_property (GObject * object, guint prop_id,
873 const GValue * value, GParamSpec * pspec)
875 GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (object);
881 dec->uri = g_value_dup_string (value);
885 g_free (dec->suburi);
886 dec->suburi = g_value_dup_string (value);
888 case PROP_CONNECTION_SPEED:
889 GST_URI_DECODE_BIN3_LOCK (dec);
890 dec->connection_speed = g_value_get_uint64 (value) * 1000;
891 GST_URI_DECODE_BIN3_UNLOCK (dec);
893 case PROP_BUFFER_SIZE:
894 dec->buffer_size = g_value_get_int (value);
896 case PROP_BUFFER_DURATION:
897 dec->buffer_duration = g_value_get_int64 (value);
900 dec->download = g_value_get_boolean (value);
902 case PROP_USE_BUFFERING:
903 dec->use_buffering = g_value_get_boolean (value);
905 case PROP_RING_BUFFER_MAX_SIZE:
906 dec->ring_buffer_max_size = g_value_get_uint64 (value);
909 GST_OBJECT_LOCK (dec);
911 gst_caps_unref (dec->caps);
912 dec->caps = g_value_dup_boxed (value);
913 GST_OBJECT_UNLOCK (dec);
916 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
922 gst_uri_decode_bin3_get_property (GObject * object, guint prop_id,
923 GValue * value, GParamSpec * pspec)
925 GstURIDecodeBin3 *dec = GST_URI_DECODE_BIN3 (object);
930 g_value_set_string (value, dec->uri);
933 case PROP_CURRENT_URI:
935 if (dec->current && dec->current->main_item) {
936 g_value_set_string (value, dec->current->main_item->uri);
938 g_value_set_string (value, NULL);
944 g_value_set_string (value, dec->suburi);
947 case PROP_CURRENT_SUBURI:
949 if (dec->current && dec->current->sub_item) {
950 g_value_set_string (value, dec->current->sub_item->uri);
952 g_value_set_string (value, NULL);
958 GST_OBJECT_LOCK (dec);
959 g_value_set_object (value, dec->source);
960 GST_OBJECT_UNLOCK (dec);
963 case PROP_CONNECTION_SPEED:
964 GST_URI_DECODE_BIN3_LOCK (dec);
965 g_value_set_uint64 (value, dec->connection_speed / 1000);
966 GST_URI_DECODE_BIN3_UNLOCK (dec);
968 case PROP_BUFFER_SIZE:
969 GST_OBJECT_LOCK (dec);
970 g_value_set_int (value, dec->buffer_size);
971 GST_OBJECT_UNLOCK (dec);
973 case PROP_BUFFER_DURATION:
974 GST_OBJECT_LOCK (dec);
975 g_value_set_int64 (value, dec->buffer_duration);
976 GST_OBJECT_UNLOCK (dec);
979 g_value_set_boolean (value, dec->download);
981 case PROP_USE_BUFFERING:
982 g_value_set_boolean (value, dec->use_buffering);
984 case PROP_RING_BUFFER_MAX_SIZE:
985 g_value_set_uint64 (value, dec->ring_buffer_max_size);
988 GST_OBJECT_LOCK (dec);
989 g_value_set_boxed (value, dec->caps);
990 GST_OBJECT_UNLOCK (dec);
993 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
999 free_source_handler (GstURIDecodeBin3 * uridecodebin,
1000 GstSourceHandler * handler)
1002 GST_LOG_OBJECT (uridecodebin, "source handler %p", handler);
1003 if (handler->active) {
1004 GST_LOG_OBJECT (uridecodebin, "Removing %" GST_PTR_FORMAT,
1005 handler->urisourcebin);
1006 gst_element_set_state (handler->urisourcebin, GST_STATE_NULL);
1007 gst_bin_remove ((GstBin *) uridecodebin, handler->urisourcebin);
1009 uridecodebin->source_handlers =
1010 g_list_remove (uridecodebin->source_handlers, handler);
1011 g_slice_free (GstSourceHandler, handler);
1014 static GstSourceItem *
1015 new_source_item (GstURIDecodeBin3 * dec, GstPlayItem * item, gchar * uri)
1017 GstSourceItem *sourceitem = g_slice_new0 (GstSourceItem);
1019 sourceitem->play_item = item;
1020 sourceitem->uri = uri;
1026 free_source_item (GstURIDecodeBin3 * uridecodebin, GstSourceItem * item)
1028 GST_LOG_OBJECT (uridecodebin, "source item %p", item);
1030 free_source_handler (uridecodebin, item->handler);
1031 g_slice_free (GstSourceItem, item);
1034 static GstPlayItem *
1035 new_play_item (GstURIDecodeBin3 * dec, gchar * uri, gchar * suburi)
1037 GstPlayItem *item = g_slice_new0 (GstPlayItem);
1039 item->uridecodebin = dec;
1040 item->main_item = new_source_item (dec, item, uri);
1042 item->sub_item = new_source_item (dec, item, suburi);
1048 free_play_item (GstURIDecodeBin3 * dec, GstPlayItem * item)
1050 GST_LOG_OBJECT (dec, "play item %p", item);
1051 if (item->main_item)
1052 free_source_item (dec, item->main_item);
1054 free_source_item (dec, item->sub_item);
1056 g_slice_free (GstPlayItem, item);
1059 /* Sync source handlers for the given play item. Might require creating/removing some
1060 * and/or configure the handlers accordingly */
1061 static GstStateChangeReturn
1062 assign_handlers_to_item (GstURIDecodeBin3 * dec, GstPlayItem * item)
1064 GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
1066 /* FIXME : Go over existing handlers to see if we can assign some to the
1069 /* Create missing handlers */
1070 if (item->main_item->handler == NULL) {
1071 item->main_item->handler = new_source_handler (dec, TRUE);
1072 ret = activate_source_item (item->main_item);
1073 if (ret == GST_STATE_CHANGE_FAILURE)
1080 /* Called to activate the next play item */
1081 static GstStateChangeReturn
1082 activate_next_play_item (GstURIDecodeBin3 * dec)
1085 GstStateChangeReturn ret;
1087 /* If there is no current play entry, create one from the uri/suburi
1088 * FIXME : Use a playlist API in the future */
1089 item = new_play_item (dec, dec->uri, dec->suburi);
1091 ret = assign_handlers_to_item (dec, item);
1092 if (ret == GST_STATE_CHANGE_FAILURE) {
1093 free_play_item (dec, item);
1097 dec->play_items = g_list_append (dec->play_items, item);
1098 dec->current = dec->play_items->data;
1104 free_play_items (GstURIDecodeBin3 * dec)
1108 for (tmp = dec->play_items; tmp; tmp = tmp->next) {
1109 GstPlayItem *item = (GstPlayItem *) tmp->data;
1110 free_play_item (dec, item);
1113 g_list_free (dec->play_items);
1114 dec->play_items = NULL;
1115 dec->current = NULL;
1118 static GstStateChangeReturn
1119 gst_uri_decode_bin3_change_state (GstElement * element,
1120 GstStateChange transition)
1122 GstStateChangeReturn ret;
1123 GstURIDecodeBin3 *uridecodebin = (GstURIDecodeBin3 *) element;
1125 switch (transition) {
1126 case GST_STATE_CHANGE_NULL_TO_READY:
1127 g_object_set (uridecodebin->decodebin, "caps", uridecodebin->caps, NULL);
1129 case GST_STATE_CHANGE_READY_TO_PAUSED:
1130 ret = activate_next_play_item (uridecodebin);
1131 if (ret == GST_STATE_CHANGE_FAILURE)
1137 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
1138 if (ret == GST_STATE_CHANGE_FAILURE)
1141 switch (transition) {
1142 case GST_STATE_CHANGE_PAUSED_TO_READY:
1143 /* FIXME: Cleanup everything */
1144 free_play_items (uridecodebin);
1145 /* Free play item */
1146 uridecodebin->posted_about_to_finish = FALSE;
1157 if (transition == GST_STATE_CHANGE_READY_TO_PAUSED)
1158 free_play_items (uridecodebin);
1164 gst_uri_decodebin3_send_event (GstElement * element, GstEvent * event)
1166 GstURIDecodeBin3 *self = GST_URI_DECODE_BIN3 (element);
1168 if (GST_EVENT_IS_UPSTREAM (event) && self->decodebin)
1169 return gst_element_send_event (self->decodebin, event);
1171 return GST_ELEMENT_CLASS (parent_class)->send_event (element, event);