2 * DASH demux plugin for GStreamer
6 * Copyright (C) 2012 Orange
9 * David Corvoysier <david.corvoysier@orange.com>
10 * Hamid Zakari <hamid.zakari@gmail.com>
12 * This library is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU Library General Public
14 * License as published by the Free Software Foundation; either
15 * version 2.1 of the License, or (at your option) any later version.
17 * This library is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * Library General Public License for more details.
22 * You should have received a copy of the GNU Library General Public
23 * License along with this library (COPYING); if not, write to the
24 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25 * Boston, MA 02111-1307, USA.
28 * SECTION:element-dashdemux
30 * DASH demuxer element.
31 * <title>Example launch line</title>
33 * gst-launch playbin2 uri="http://www-itec.uni-klu.ac.at/ftp/datasets/mmsys12/RedBullPlayStreets/redbull_4s/RedBullPlayStreets_4s_isoffmain_DIS_23009_1_v_2_1c2_2011_08_30.mpd"
37 /* Implementation notes:
39 * The following section describes how dashdemux works internally.
43 * dashdemux is a "fake" demux, as unlike traditional demux elements, it
44 * doesn't split data streams contained in an enveloppe to expose them
45 * to downstream decoding elements.
47 * Instead, it parses an XML file called a manifest to identify a set of
48 * individual stream fragments it needs to fetch and expose to the actual
49 * demux elements that will handle them (this behavior is sometimes
50 * referred as the "demux after a demux" scenario).
52 * For a given section of content, several representations corresponding
53 * to different bitrates may be available: dashdemux will select the most
54 * appropriate representation based on local conditions (typically the
55 * available bandwidth and the amount of buffering available, capped by
56 * a maximum allowed bitrate).
58 * The representation selection algorithm can be configured using
59 * specific properties: max bitrate, min/max buffering, bandwidth ratio.
64 * dashdemux has a single sink pad that accepts the data corresponding
65 * to the manifest, typically fetched from an HTTP or file source.
67 * dashdemux exposes the streams it recreates based on the fragments it
68 * fetches through dedicated src pads corresponding to the caps of the
69 * fragments container (ISOBMFF/MP4 or MPEG2TS).
71 * During playback, new representations will typically be exposed as a
72 * new set of pads (see 'Switching between representations' below).
74 * Fragments downloading is performed using a dedicated task that fills
75 * an internal queue. Another task is in charge of popping fragments
76 * from the queue and pushing them downstream.
78 * Switching between representations:
80 * Decodebin supports scenarios allowing to seamlessly switch from one
81 * stream to another inside the same "decoding chain".
83 * To achieve that, it combines the elements it autoplugged in chains
84 * and groups, allowing only one decoding group to be active at a given
85 * time for a given chain.
87 * A chain can signal decodebin that it is complete by sending a
88 * no-more-pads event, but even after that new pads can be added to
89 * create new subgroups, providing that a new no-more-pads event is sent.
91 * We take advantage of that to dynamically create a new decoding group
92 * in order to select a different representation during playback.
94 * Typically, assuming that each fragment contains both audio and video,
95 * the following tree would be created:
98 * |_ group "Representation set 1"
99 * | |_ chain "Qt Demux 0"
100 * | |_ group "Stream 0"
103 * |_ group "Representation set 2"
104 * |_ chain "Qt Demux 1"
105 * |_ group "Stream 1"
109 * Or, if audio and video are contained in separate fragments:
112 * |_ group "Representation set 1"
113 * | |_ chain "Qt Demux 0"
114 * | | |_ group "Stream 0"
115 * | | |_ chain "H264"
116 * | |_ chain "Qt Demux 1"
117 * | |_ group "Stream 1"
119 * |_ group "Representation set 2"
120 * |_ chain "Qt Demux 3"
121 * | |_ group "Stream 2"
123 * |_ chain "Qt Demux 4"
124 * |_ group "Stream 3"
127 * In both cases, when switching from Set 1 to Set 2 an EOS is sent on
128 * each end pad corresponding to Rep 0, triggering the "drain" state to
129 * propagate upstream.
130 * Once both EOS have been processed, the "Set 1" group is completely
131 * drained, and decodebin2 will switch to the "Set 2" group.
133 * Note: nothing can be pushed to the new decoding group before the
134 * old one has been drained, which means that in order to be able to
135 * adapt quickly to bandwidth changes, we will not be able to rely
136 * on downstream buffering, and will instead manage an internal queue.
144 /* FIXME 0.11: suppress warnings for deprecated API such as GStaticRecMutex
145 * with newer GLib versions (>= 2.31.0) */
146 #define GLIB_DISABLE_DEPRECATION_WARNINGS
149 #include <inttypes.h>
150 #include <gst/base/gsttypefindhelper.h>
151 #include "gstdashdemux.h"
153 static GstStaticPadTemplate srctemplate = GST_STATIC_PAD_TEMPLATE ("src%d",
156 GST_STATIC_CAPS_ANY);
158 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
161 GST_STATIC_CAPS ("application/dash+xml"));
163 GST_DEBUG_CATEGORY_STATIC (gst_dash_demux_debug);
164 #define GST_CAT_DEFAULT gst_dash_demux_debug
170 PROP_MIN_BUFFERING_TIME,
171 PROP_MAX_BUFFERING_TIME,
172 PROP_BANDWIDTH_USAGE,
177 /* Default values for properties */
178 #define DEFAULT_MIN_BUFFERING_TIME 5 /* in seconds */
179 #define DEFAULT_MAX_BUFFERING_TIME 30 /* in seconds */
180 #define DEFAULT_BANDWIDTH_USAGE 0.8 /* 0 to 1 */
181 #define DEFAULT_MAX_BITRATE 24000000 /* in bit/s */
183 #define DEFAULT_FAILED_COUNT 3
187 static void gst_dash_demux_set_property (GObject * object, guint prop_id,
188 const GValue * value, GParamSpec * pspec);
189 static void gst_dash_demux_get_property (GObject * object, guint prop_id,
190 GValue * value, GParamSpec * pspec);
191 static void gst_dash_demux_dispose (GObject * obj);
194 static GstStateChangeReturn
195 gst_dash_demux_change_state (GstElement * element, GstStateChange transition);
198 static GstFlowReturn gst_dash_demux_pad (GstPad * pad, GstBuffer * buf);
199 static gboolean gst_dash_demux_sink_event (GstPad * pad, GstEvent * event);
200 static gboolean gst_dash_demux_src_event (GstPad * pad, GstEvent * event);
201 static gboolean gst_dash_demux_src_query (GstPad * pad, GstQuery * query);
202 static void gst_dash_demux_stream_loop (GstDashDemux * demux);
203 static void gst_dash_demux_download_loop (GstDashDemux * demux);
204 static void gst_dash_demux_stop (GstDashDemux * demux);
205 static void gst_dash_demux_pause_stream_task (GstDashDemux * demux);
206 static void gst_dash_demux_resume_stream_task (GstDashDemux * demux);
207 static void gst_dash_demux_resume_download_task (GstDashDemux * demux);
208 static gboolean gst_dash_demux_setup_all_streams (GstDashDemux * demux);
209 static gboolean gst_dash_demux_select_representations (GstDashDemux * demux,
210 guint64 current_bitrate);
211 static gboolean gst_dash_demux_get_next_fragment_set (GstDashDemux * demux);
213 static void gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose);
214 static GstClockTime gst_dash_demux_get_buffering_time (GstDashDemux * demux);
215 static float gst_dash_demux_get_buffering_ratio (GstDashDemux * demux);
216 static GstBuffer *gst_dash_demux_merge_buffer_list (GstFragment * fragment);
219 _do_init (GType type)
221 GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "dashdemux", 0,
222 "dashdemux element");
225 GST_BOILERPLATE_FULL (GstDashDemux, gst_dash_demux, GstElement,
226 GST_TYPE_ELEMENT, _do_init);
229 gst_dash_demux_base_init (gpointer g_class)
231 GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
233 gst_element_class_add_static_pad_template (element_class, &srctemplate);
235 gst_element_class_add_static_pad_template (element_class, &sinktemplate);
237 gst_element_class_set_details_simple (element_class,
240 "Dynamic Adaptive Streaming over HTTP demuxer",
241 "David Corvoysier <david.corvoysier@orange.com>\n\
242 Hamid Zakari <hamid.zakari@gmail.com>\n\
243 Gianluca Gennari <gennarone@gmail.com>");
247 gst_dash_demux_dispose (GObject * obj)
249 GstDashDemux *demux = GST_DASH_DEMUX (obj);
251 if (demux->stream_task) {
252 if (GST_TASK_STATE (demux->stream_task) != GST_TASK_STOPPED) {
253 GST_DEBUG_OBJECT (demux, "Leaving streaming task");
254 gst_task_stop (demux->stream_task);
255 gst_task_join (demux->stream_task);
257 gst_object_unref (demux->stream_task);
258 g_static_rec_mutex_free (&demux->stream_lock);
259 g_mutex_free(demux->stream_timed_lock);
260 demux->stream_task = NULL;
263 if (demux->download_task) {
264 if (GST_TASK_STATE (demux->download_task) != GST_TASK_STOPPED) {
265 GST_DEBUG_OBJECT (demux, "Leaving download task");
266 gst_task_stop (demux->download_task);
267 gst_task_join (demux->download_task);
269 gst_object_unref (demux->download_task);
270 g_static_rec_mutex_free (&demux->download_lock);
271 g_mutex_free(demux->download_timed_lock);
272 demux->download_task = NULL;
275 if (demux->downloader != NULL) {
276 g_object_unref (demux->downloader);
277 demux->downloader = NULL;
280 gst_dash_demux_reset (demux, TRUE);
282 g_queue_free (demux->queue);
284 G_OBJECT_CLASS (parent_class)->dispose (obj);
288 gst_dash_demux_class_init (GstDashDemuxClass * klass)
290 GObjectClass *gobject_class;
291 GstElementClass *gstelement_class;
293 gobject_class = (GObjectClass *) klass;
294 gstelement_class = (GstElementClass *) klass;
296 gobject_class->set_property = gst_dash_demux_set_property;
297 gobject_class->get_property = gst_dash_demux_get_property;
298 gobject_class->dispose = gst_dash_demux_dispose;
300 g_object_class_install_property (gobject_class, PROP_MIN_BUFFERING_TIME,
301 g_param_spec_uint ("min-buffering-time", "Minimum buffering time",
302 "Minimum number of seconds of buffer accumulated before playback",
303 1, G_MAXUINT, DEFAULT_MIN_BUFFERING_TIME,
304 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
306 g_object_class_install_property (gobject_class, PROP_MAX_BUFFERING_TIME,
307 g_param_spec_uint ("max-buffering-time", "Maximum buffering time",
308 "Maximum number of seconds of buffer accumulated during playback",
309 2, G_MAXUINT, DEFAULT_MAX_BUFFERING_TIME,
310 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
312 g_object_class_install_property (gobject_class, PROP_BANDWIDTH_USAGE,
313 g_param_spec_float ("bandwidth-usage",
314 "Bandwidth usage [0..1]",
315 "Percentage of the available bandwidth to use when selecting representations",
316 0, 1, DEFAULT_BANDWIDTH_USAGE,
317 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
319 g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
320 g_param_spec_uint ("max-bitrate", "Max bitrate",
321 "Max of bitrate supported by target decoder",
322 1000, G_MAXUINT, DEFAULT_MAX_BITRATE,
323 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
325 gstelement_class->change_state =
326 GST_DEBUG_FUNCPTR (gst_dash_demux_change_state);
330 gst_dash_demux_init (GstDashDemux * demux, GstDashDemuxClass * klass)
333 demux->sinkpad = gst_pad_new_from_static_template (&sinktemplate, "sink");
334 gst_pad_set_chain_function (demux->sinkpad,
335 GST_DEBUG_FUNCPTR (gst_dash_demux_pad));
336 gst_pad_set_event_function (demux->sinkpad,
337 GST_DEBUG_FUNCPTR (gst_dash_demux_sink_event));
338 gst_element_add_pad (GST_ELEMENT (demux), demux->sinkpad);
341 demux->downloader = gst_uri_downloader_new ();
344 demux->min_buffering_time = DEFAULT_MIN_BUFFERING_TIME * GST_SECOND;
345 demux->max_buffering_time = DEFAULT_MAX_BUFFERING_TIME * GST_SECOND;
346 demux->bandwidth_usage = DEFAULT_BANDWIDTH_USAGE;
347 demux->max_bitrate = DEFAULT_MAX_BITRATE;
349 demux->queue = g_queue_new ();
351 g_static_rec_mutex_init (&demux->download_lock);
352 demux->download_task =
353 gst_task_create ((GstTaskFunction) gst_dash_demux_download_loop, demux);
354 gst_task_set_lock (demux->download_task, &demux->download_lock);
355 demux->download_timed_lock = g_mutex_new ();
358 g_static_rec_mutex_init (&demux->stream_lock);
360 gst_task_create ((GstTaskFunction) gst_dash_demux_stream_loop, demux);
361 gst_task_set_lock (demux->stream_task, &demux->stream_lock);
362 demux->stream_timed_lock = g_mutex_new ();
366 gst_dash_demux_set_property (GObject * object, guint prop_id,
367 const GValue * value, GParamSpec * pspec)
369 GstDashDemux *demux = GST_DASH_DEMUX (object);
372 case PROP_MIN_BUFFERING_TIME:
373 demux->min_buffering_time = g_value_get_uint (value) * GST_SECOND;
375 case PROP_MAX_BUFFERING_TIME:
376 demux->max_buffering_time = g_value_get_uint (value) * GST_SECOND;
378 case PROP_BANDWIDTH_USAGE:
379 demux->bandwidth_usage = g_value_get_float (value);
381 case PROP_MAX_BITRATE:
382 demux->max_bitrate = g_value_get_uint (value);
385 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
391 gst_dash_demux_get_property (GObject * object, guint prop_id, GValue * value,
394 GstDashDemux *demux = GST_DASH_DEMUX (object);
397 case PROP_MIN_BUFFERING_TIME:
398 g_value_set_uint (value, demux->min_buffering_time);
399 demux->min_buffering_time *= GST_SECOND;
401 case PROP_MAX_BUFFERING_TIME:
402 g_value_set_uint (value, demux->max_buffering_time);
403 demux->max_buffering_time *= GST_SECOND;
405 case PROP_BANDWIDTH_USAGE:
406 g_value_set_float (value, demux->bandwidth_usage);
408 case PROP_MAX_BITRATE:
409 g_value_set_uint (value, demux->max_bitrate);
412 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
417 static GstStateChangeReturn
418 gst_dash_demux_change_state (GstElement * element, GstStateChange transition)
420 GstStateChangeReturn ret;
421 GstDashDemux *demux = GST_DASH_DEMUX (element);
423 switch (transition) {
424 case GST_STATE_CHANGE_READY_TO_PAUSED:
425 gst_dash_demux_reset (demux, FALSE);
427 case GST_STATE_CHANGE_PAUSED_TO_PLAYING:
428 /* Start the streaming loop in paused only if we already received
429 the manifest. It might have been stopped if we were in PAUSED
430 state and we filled our queue with enough cached fragments
432 if (demux->client->mpd_node != NULL)
433 gst_dash_demux_resume_stream_task (demux);
439 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
441 switch (transition) {
442 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
443 gst_dash_demux_pause_stream_task (demux);
445 case GST_STATE_CHANGE_PAUSED_TO_READY:
446 demux->cancelled = TRUE;
447 gst_dash_demux_stop (demux);
448 gst_task_join (demux->stream_task);
449 gst_task_join (demux->download_task);
458 gst_dash_demux_clear_queue (GstDashDemux * demux)
460 while (!g_queue_is_empty (demux->queue)) {
461 GList *listfragment = g_queue_pop_head (demux->queue);
463 while (j < g_list_length (listfragment)) {
464 GstFragment *fragment = g_list_nth_data (listfragment, j);
465 g_object_unref (fragment);
468 g_list_free (listfragment);
470 g_queue_clear (demux->queue);
474 gst_dash_demux_src_event (GstPad * pad, GstEvent * event)
478 demux = GST_DASH_DEMUX (gst_pad_get_element_private (pad));
480 switch (event->type) {
486 GstSeekType start_type, stop_type;
489 GstClockTime current_pos, target_pos;
490 guint current_sequence, current_period;
491 GstActiveStream *stream;
492 GstMediaSegment *chunk;
493 GstStreamPeriod *period;
494 guint nb_active_stream;
497 if (gst_mpd_client_is_live (demux->client)) {
498 GST_WARNING_OBJECT (demux, "Received seek event for live stream");
502 gst_event_parse_seek (event, &rate, &format, &flags, &start_type, &start,
505 if (format != GST_FORMAT_TIME)
508 GST_DEBUG_OBJECT (demux,
509 "seek event, rate: %f type: %d start: %" GST_TIME_FORMAT " stop: %"
510 GST_TIME_FORMAT, rate, start_type, GST_TIME_ARGS (start),
511 GST_TIME_ARGS (stop));
513 //GST_MPD_CLIENT_LOCK (demux->client);
515 /* select the requested Period in the Media Presentation */
516 target_pos = (GstClockTime) start;
518 for (list = g_list_first (demux->client->periods); list;
519 list = g_list_next (list)) {
521 current_pos = period->start;
522 current_period = period->number;
523 if (current_pos <= target_pos
524 && target_pos < current_pos + period->duration) {
529 GST_WARNING_OBJECT (demux, "Could not find seeked Period");
532 if (current_period != gst_mpd_client_get_period_index (demux->client)) {
533 GST_DEBUG_OBJECT (demux, "Seeking to Period %d", current_period);
534 /* setup video, audio and subtitle streams, starting from the new Period */
535 if (!gst_mpd_client_set_period_index (demux->client, current_period) ||
536 !gst_dash_demux_setup_all_streams (demux))
540 stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
542 for (list = g_list_first (stream->segments); list;
543 list = g_list_next (list)) {
545 current_pos = chunk->start_time;
546 current_sequence = chunk->number;
547 if (current_pos <= target_pos
548 && target_pos < current_pos + chunk->duration) {
552 //GST_MPD_CLIENT_UNLOCK (demux->client);
555 GST_WARNING_OBJECT (demux, "Could not find seeked fragment");
559 /* We can actually perform the seek */
560 nb_active_stream = gst_mpdparser_get_nb_active_stream (demux->client);
562 if (flags & GST_SEEK_FLAG_FLUSH) {
563 GST_DEBUG_OBJECT (demux, "sending flush start");
565 while (stream_idx < nb_active_stream) {
566 gst_pad_push_event (demux->srcpad[stream_idx],
567 gst_event_new_flush_start ());
573 demux->cancelled = TRUE;
574 gst_dash_demux_stop (demux);
576 /* Wait for streaming to finish */
577 g_static_rec_mutex_lock (&demux->stream_lock);
579 /* Clear the buffering queue */
580 /* FIXME: allow seeking in the buffering queue */
581 gst_dash_demux_clear_queue (demux);
583 //GST_MPD_CLIENT_LOCK (demux->client);
584 GST_DEBUG_OBJECT (demux, "Seeking to sequence %d", current_sequence);
585 /* Update the current sequence on all streams */
586 gst_mpd_client_set_segment_index_for_all_streams (demux->client,
588 /* Calculate offset in the next fragment */
589 demux->position = gst_mpd_client_get_current_position (demux->client);
590 demux->position_shift = start - demux->position;
591 demux->need_segment = TRUE;
592 //GST_MPD_CLIENT_UNLOCK (demux->client);
594 if (flags & GST_SEEK_FLAG_FLUSH) {
595 GST_DEBUG_OBJECT (demux, "Sending flush stop on all pad");
597 while (stream_idx < nb_active_stream) {
598 gst_pad_push_event (demux->srcpad[stream_idx],
599 gst_event_new_flush_stop ());
604 /* Restart the demux */
605 demux->cancelled = FALSE;
606 gst_dash_demux_resume_download_task (demux);
607 gst_dash_demux_resume_stream_task (demux);
608 g_static_rec_mutex_unlock (&demux->stream_lock);
616 return gst_pad_event_default (pad, event);
620 gst_dash_demux_setup_all_streams (GstDashDemux * demux)
622 GList *listLang = NULL;
626 GST_MPD_CLIENT_LOCK (demux->client);
627 /* clean old active stream list, if any */
628 gst_active_streams_free (demux->client);
630 if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_VIDEO, ""))
631 GST_INFO_OBJECT (demux, "No video adaptation set found");
634 gst_mpdparser_get_list_and_nb_of_audio_language (demux->client,
638 GST_INFO_OBJECT (demux, "Number of language is=%d", nb_audio);
640 for (i = 0; i < nb_audio; i++) {
641 lang = (gchar *) g_list_nth_data (listLang, i);
642 if (gst_mpdparser_get_nb_adaptationSet (demux->client) > 1)
643 if (!gst_mpd_client_setup_streaming (demux->client, GST_STREAM_AUDIO,
645 GST_INFO_OBJECT (demux, "No audio adaptation set found");
647 if (gst_mpdparser_get_nb_adaptationSet (demux->client) > nb_audio)
648 if (!gst_mpd_client_setup_streaming (demux->client,
649 GST_STREAM_APPLICATION, lang))
650 GST_INFO_OBJECT (demux, "No application adaptation set found");
652 GST_MPD_CLIENT_UNLOCK (demux->client);
658 gst_dash_demux_sink_event (GstPad * pad, GstEvent * event)
660 GstDashDemux *demux = GST_DASH_DEMUX (gst_pad_get_parent (pad));
662 switch (event->type) {
668 if (demux->manifest == NULL) {
669 GST_WARNING_OBJECT (demux, "Received EOS without a manifest.");
673 GST_DEBUG_OBJECT (demux, "Got EOS on the sink pad: manifest fetched");
676 gst_mpd_client_free (demux->client);
677 demux->client = gst_mpd_client_new ();
679 query = gst_query_new_uri ();
680 res = gst_pad_peer_query (pad, query);
682 gst_query_parse_uri (query, &demux->client->mpd_uri);
683 GST_DEBUG_OBJECT (demux, "Fetched MPD file at URI: %s",
684 demux->client->mpd_uri);
686 GST_WARNING_OBJECT (demux, "MPD URI query failed.");
688 gst_query_unref (query);
690 manifest = (gchar *) GST_BUFFER_DATA (demux->manifest);
691 if (manifest == NULL) {
692 GST_WARNING_OBJECT (demux, "Error validating the manifest.");
693 } else if (!gst_mpd_parse (demux->client, manifest,
694 GST_BUFFER_SIZE (demux->manifest))) {
695 /* In most cases, this will happen if we set a wrong url in the
696 * source element and we have received the 404 HTML response instead of
698 GST_ELEMENT_ERROR (demux, STREAM, DECODE, ("Invalid manifest."),
702 gst_buffer_unref (demux->manifest);
703 demux->manifest = NULL;
705 if (!gst_mpd_client_setup_media_presentation (demux->client)) {
706 GST_ELEMENT_ERROR (demux, STREAM, DECODE,
707 ("Incompatible manifest file."), (NULL));
711 /* setup video, audio and subtitle streams, starting from first Period */
712 if (!gst_mpd_client_set_period_index (demux->client, 0) ||
713 !gst_dash_demux_setup_all_streams (demux))
716 /* start playing from the first segment */
717 gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0);
719 /* Send duration message */
720 if (!gst_mpd_client_is_live (demux->client)) {
721 GstClockTime duration =
722 gst_mpd_client_get_media_presentation_duration (demux->client);
724 if (duration != GST_CLOCK_TIME_NONE) {
725 GST_DEBUG_OBJECT (demux,
726 "Sending duration message : %" GST_TIME_FORMAT,
727 GST_TIME_ARGS (duration));
728 gst_element_post_message (GST_ELEMENT (demux),
729 gst_message_new_duration (GST_OBJECT (demux), GST_FORMAT_TIME,
732 GST_DEBUG_OBJECT (demux,
733 "mediaPresentationDuration unknown, can not send the duration message");
736 gst_dash_demux_resume_download_task (demux);
737 gst_dash_demux_resume_stream_task (demux);
738 gst_event_unref (event);
741 case GST_EVENT_NEWSEGMENT:
742 /* Swallow newsegments, we'll push our own */
743 gst_event_unref (event);
749 return gst_pad_event_default (pad, event);
753 gst_dash_demux_src_query (GstPad * pad, GstQuery * query)
755 GstDashDemux *dashdemux;
756 gboolean ret = FALSE;
761 dashdemux = GST_DASH_DEMUX (gst_pad_get_element_private (pad));
763 switch (query->type) {
764 case GST_QUERY_DURATION:{
765 GstClockTime duration = -1;
768 gst_query_parse_duration (query, &fmt, NULL);
769 if (fmt == GST_FORMAT_TIME) {
771 gst_mpd_client_get_media_presentation_duration (dashdemux->client);
772 if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0) {
773 gst_query_set_duration (query, GST_FORMAT_TIME, duration);
777 GST_DEBUG_OBJECT (dashdemux,
778 "GST_QUERY_DURATION returns %s with duration %" GST_TIME_FORMAT,
779 ret ? "TRUE" : "FALSE", GST_TIME_ARGS (duration));
782 case GST_QUERY_SEEKING:{
786 gst_query_parse_seeking (query, &fmt, NULL, NULL, NULL);
787 GST_DEBUG_OBJECT (dashdemux, "Received GST_QUERY_SEEKING with format %d",
789 if (fmt == GST_FORMAT_TIME) {
790 GstClockTime duration;
793 gst_mpd_client_get_media_presentation_duration (dashdemux->client);
794 if (GST_CLOCK_TIME_IS_VALID (duration) && duration > 0)
797 gst_query_set_seeking (query, fmt,
798 !gst_mpd_client_is_live (dashdemux->client), 0, stop);
800 GST_DEBUG_OBJECT (dashdemux, "GST_QUERY_SEEKING returning with stop : %"
801 GST_TIME_FORMAT, GST_TIME_ARGS (stop));
805 case GST_QUERY_URI: {
807 GST_DEBUG("URI query recevied in DASH demux.....");
809 res = gst_pad_query_default (pad,query);
811 GST_DEBUG("forwarding URI is done successfully!!...");
816 // By default, do not forward queries upstream
825 gst_dash_demux_pad (GstPad * pad, GstBuffer * buf)
827 GstDashDemux *demux = GST_DASH_DEMUX (gst_pad_get_parent (pad));
829 if (demux->manifest == NULL)
830 demux->manifest = buf;
832 demux->manifest = gst_buffer_join (demux->manifest, buf);
834 gst_object_unref (demux);
840 gst_dash_demux_stop (GstDashDemux * demux)
842 gst_uri_downloader_cancel (demux->downloader);
844 if (GST_TASK_STATE (demux->download_task) != GST_TASK_STOPPED) {
845 GST_TASK_SIGNAL (demux->download_task);
846 gst_task_stop (demux->download_task);
848 if (GST_TASK_STATE (demux->stream_task) != GST_TASK_STOPPED) {
849 GST_TASK_SIGNAL (demux->stream_task);
850 gst_task_stop (demux->stream_task);
853 #ifdef DASHDEMUX_MODIFICATION
855 _update_caps(GstDashDemux * demux, guint nb_adaptation_set)
860 /* Create and activate new pads */
862 while (i < nb_adaptation_set) {
863 caps = gst_pad_get_caps(demux->srcpad[i]);
865 caps = gst_caps_make_writable(caps);
866 gst_caps_replace(&caps,demux->output_caps[i]);
869 caps = demux->output_caps[i];
871 gst_pad_use_fixed_caps (demux->srcpad[i]);
872 gst_pad_set_caps (demux->srcpad[i], caps);
873 gst_caps_unref(caps);
879 _add_pads(GstDashDemux * demux, guint nb_adaptation_set)
883 /* Create and activate new pads */
885 while (i < nb_adaptation_set) {
886 demux->srcpad[i] = gst_pad_new_from_static_template (&srctemplate, NULL);
887 gst_pad_set_event_function (demux->srcpad[i],
888 GST_DEBUG_FUNCPTR (gst_dash_demux_src_event));
889 gst_pad_set_query_function (demux->srcpad[i],
890 GST_DEBUG_FUNCPTR (gst_dash_demux_src_query));
891 gst_pad_set_element_private (demux->srcpad[i], demux);
892 gst_pad_set_active (demux->srcpad[i], TRUE);
893 gst_pad_set_caps (demux->srcpad[i], demux->output_caps[i]);
894 gst_caps_unref(demux->output_caps[i]);
895 gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad[i]);
898 /* Send 'no-more-pads' to have decodebin create the new group */
899 gst_element_no_more_pads (GST_ELEMENT (demux));
903 _needs_caps_update (GstDashDemux * demux, GList * fragment)
906 gboolean update_caps = FALSE;
908 while (i < g_list_length (fragment)) {
909 GstFragment *newFragment = g_list_nth_data (fragment, i);
910 if (newFragment == NULL) {
913 GstCaps *srccaps = NULL;
914 demux->output_caps[i] = gst_fragment_get_caps (newFragment);
915 if (G_LIKELY (demux->srcpad[i]))
916 srccaps = gst_pad_get_negotiated_caps (demux->srcpad[i]);
917 if (G_UNLIKELY (!srccaps
918 || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps))
919 || demux->need_segment)) {
922 if (G_LIKELY (srccaps))
923 gst_caps_unref (srccaps);
932 * Called when switching from one set of representations to another, but
933 * only if one of the new representations requires different downstream
934 * elements (see the next function).
936 * This function first creates the new pads, then sends a no-more-pads
937 * event (that will tell decodebin to create a new group), then sends
938 * EOS on the old pads to trigger the group switch.
942 switch_pads (GstDashDemux * demux, guint nb_adaptation_set)
944 GstPad *oldpad[MAX_LANGUAGES];
946 /* Remember old pads */
947 while (i < nb_adaptation_set) {
948 oldpad[i] = demux->srcpad[i];
950 GST_DEBUG_OBJECT (demux,
951 "Switching pads (oldpad:%p)" GST_PTR_FORMAT, oldpad[i]);
955 /* Create and activate new pads */
957 while (i < nb_adaptation_set) {
958 demux->srcpad[i] = gst_pad_new_from_static_template (&srctemplate, NULL);
959 gst_pad_set_event_function (demux->srcpad[i],
960 GST_DEBUG_FUNCPTR (gst_dash_demux_src_event));
961 gst_pad_set_query_function (demux->srcpad[i],
962 GST_DEBUG_FUNCPTR (gst_dash_demux_src_query));
963 gst_pad_set_element_private (demux->srcpad[i], demux);
964 gst_pad_set_active (demux->srcpad[i], TRUE);
965 gst_pad_set_caps (demux->srcpad[i], demux->output_caps[i]);
966 gst_element_add_pad (GST_ELEMENT (demux), demux->srcpad[i]);
969 /* Send 'no-more-pads' to have decodebin create the new group */
970 gst_element_no_more_pads (GST_ELEMENT (demux));
971 /* Push out EOS on all old pads to switch to the new group */
973 while (i < nb_adaptation_set) {
975 gst_pad_push_event (oldpad[i], gst_event_new_eos ());
976 gst_pad_set_active (oldpad[i], FALSE);
977 gst_element_remove_pad (GST_ELEMENT (demux), oldpad[i]);
985 * Figure out if the newly selected representations require a new set
986 * of demuxers and decoders or if we can carry on with the existing ones.
988 * Basically, we look at the list of fragments we need to push downstream,
989 * and compare their caps with those of the corresponding src pads.
991 * As soon as one fragment requires a new set of caps, we need to switch
992 * all decoding pads to recreate a whole decoding group as we cannot
993 * move pads between groups (FIXME: or can we ?).
995 * FIXME: redundant with need_add_header
999 needs_pad_switch (GstDashDemux * demux, GList * fragment)
1002 gboolean switch_pad = FALSE;
1004 while (i < g_list_length (fragment)) {
1005 GstFragment *newFragment = g_list_nth_data (fragment, i);
1006 if (newFragment == NULL) {
1009 GstCaps *srccaps = NULL;
1010 demux->output_caps[i] = gst_fragment_get_caps (newFragment);
1011 if (G_LIKELY (demux->srcpad[i]))
1012 srccaps = gst_pad_get_negotiated_caps (demux->srcpad[i]);
1013 if (G_UNLIKELY (!srccaps
1014 || (!gst_caps_is_equal_fixed (demux->output_caps[i], srccaps))
1015 || demux->need_segment)) {
1018 if (G_LIKELY (srccaps))
1019 gst_caps_unref (srccaps);
1026 /* gst_dash_demux_stream_loop:
1028 * Loop for the "stream' task that pushes fragments to the src pads.
1031 * The task is started as soon as we have received the manifest and
1032 * waits for the first fragment to be downloaded and pushed in the
1033 * queue. Once this fragment has been pushed, the task pauses itself
1034 * until actual playback begins.
1037 * The task pushes fragments downstream at regular intervals based on
1038 * the fragment duration. If it detects a queue underrun, it sends
1039 * a buffering event to tell the main application to pause.
1042 * The task is stopped when we have reached the end of the manifest
1043 * and emptied our queue.
1047 gst_dash_demux_stream_loop (GstDashDemux * demux)
1049 GList *listfragment;
1051 GstBufferList *buffer_list;
1052 guint nb_adaptation_set = 0;
1053 GstActiveStream *stream;
1055 /* Wait until the next scheduled push downstream */
1056 if (g_cond_timed_wait (GST_TASK_GET_COND (demux->stream_task),
1057 demux->stream_timed_lock, &demux->next_push)) {
1061 if (g_queue_is_empty (demux->queue)) {
1062 if (demux->end_of_manifest)
1063 goto end_of_manifest;
1068 if (GST_STATE (demux) == GST_STATE_PLAYING) {
1069 if (!demux->end_of_manifest
1070 && gst_dash_demux_get_buffering_time (demux) <
1071 demux->min_buffering_time) {
1072 /* Warn we are below our threshold: this will eventually pause
1074 gst_element_post_message (GST_ELEMENT (demux),
1075 gst_message_new_buffering (GST_OBJECT (demux),
1076 100 * gst_dash_demux_get_buffering_ratio (demux)));
1079 listfragment = g_queue_pop_head (demux->queue);
1080 nb_adaptation_set = g_list_length (listfragment);
1081 #ifdef DASHDEMUX_MODIFICATION
1082 /* Figure out if we need to create pads or update caps */
1083 gboolean caps_changed = _needs_caps_update (demux, listfragment);
1085 if(demux->srcpad[0] == NULL)
1087 _add_pads(demux,nb_adaptation_set);
1088 demux->need_segment = TRUE;
1090 _update_caps(demux,nb_adaptation_set);
1094 /* Figure out if we need to create/switch pads */
1095 gboolean switch_pad = needs_pad_switch (demux, listfragment);
1097 switch_pads (demux, nb_adaptation_set);
1098 demux->need_segment = TRUE;
1102 for (i = 0; i < nb_adaptation_set; i++) {
1103 GstFragment *fragment = g_list_nth_data (listfragment, i);
1104 stream = gst_mpdparser_get_active_stream_by_index (demux->client, i);
1105 if (demux->need_segment) {
1106 GstClockTime start = fragment->start_time + demux->position_shift;
1107 /* And send a newsegment */
1108 GST_DEBUG_OBJECT (demux, "Sending new-segment. segment start:%"
1109 GST_TIME_FORMAT, GST_TIME_ARGS (start));
1110 gst_pad_push_event (demux->srcpad[i],
1111 gst_event_new_new_segment (FALSE, 1.0, GST_FORMAT_TIME,
1112 start, GST_CLOCK_TIME_NONE, start));
1113 demux->position_shift = 0;
1116 GST_DEBUG_OBJECT (demux, "Pushing fragment #%d", fragment->index);
1117 buffer_list = gst_fragment_get_buffer_list (fragment);
1118 g_object_unref (fragment);
1119 ret = gst_pad_push_list (demux->srcpad[i], buffer_list);
1120 if ((ret != GST_FLOW_OK) && (stream->mimeType == GST_STREAM_VIDEO))
1123 demux->need_segment = FALSE;
1124 g_list_free (listfragment);
1125 GST_STATE_LOCK(demux);
1126 if (GST_STATE (demux) == GST_STATE_PLAYING) {
1127 /* Wait for the duration of a fragment before resuming this task */
1128 g_get_current_time (&demux->next_push);
1129 g_time_val_add (&demux->next_push,
1130 gst_mpd_client_get_next_fragment_duration (demux->client)
1131 / GST_SECOND * G_USEC_PER_SEC);
1132 GST_DEBUG_OBJECT (demux, "Next push scheduled at %s",
1133 g_time_val_to_iso8601 (&demux->next_push));
1135 /* The pipeline is now set up, wait until playback begins */
1136 GST_INFO_OBJECT (demux, "Pausing streaming task");
1137 gst_task_pause (demux->stream_task);
1139 GST_STATE_UNLOCK(demux);
1148 GST_INFO_OBJECT (demux, "Reached end of manifest, sending EOS");
1150 for (i = 0; i < gst_mpdparser_get_nb_active_stream (demux->client); i++) {
1151 gst_pad_push_event (demux->srcpad[i], gst_event_new_eos ());
1153 GST_INFO_OBJECT (demux, "Stopped streaming task");
1154 gst_task_stop (demux->stream_task);
1160 /* FIXME: handle error */
1161 GST_ERROR_OBJECT (demux,
1162 "Error pushing buffer: %s... terminating the demux",
1163 gst_flow_get_name (ret));
1164 gst_dash_demux_stop (demux);
1170 gst_dash_demux_reset (GstDashDemux * demux, gboolean dispose)
1172 demux->end_of_period = FALSE;
1173 demux->end_of_manifest = FALSE;
1174 demux->cancelled = FALSE;
1177 for (i = 0; i < MAX_LANGUAGES; i++)
1178 if (demux->input_caps[i]) {
1179 gst_caps_unref (demux->input_caps[i]);
1180 demux->input_caps[i] = NULL;
1183 if (demux->manifest) {
1184 gst_buffer_unref (demux->manifest);
1185 demux->manifest = NULL;
1187 if (demux->client) {
1188 gst_mpd_client_free (demux->client);
1189 demux->client = NULL;
1192 demux->client = gst_mpd_client_new ();
1195 gst_dash_demux_clear_queue (demux);
1197 demux->last_manifest_update = GST_CLOCK_TIME_NONE;
1198 demux->position = 0;
1199 demux->position_shift = 0;
1200 demux->need_segment = TRUE;
1204 gst_dash_demux_get_buffering_time (GstDashDemux * demux)
1206 GstClockTime buffer_time = 0;
1207 GList *listfragment;
1208 GstFragment *first_fragment, *last_fragment;
1210 if (g_queue_is_empty (demux->queue))
1213 /* get first fragment */
1214 listfragment = g_queue_peek_head (demux->queue);
1215 first_fragment = listfragment->data;
1216 /* get last fragment */
1217 listfragment = g_queue_peek_tail (demux->queue);
1218 last_fragment = listfragment->data;
1220 if (first_fragment && last_fragment) {
1221 buffer_time = last_fragment->stop_time - first_fragment->start_time;
1228 gst_dash_demux_get_buffering_ratio (GstDashDemux * demux)
1230 float buffering_time = gst_dash_demux_get_buffering_time (demux);
1231 if (buffering_time >= demux->min_buffering_time) {
1234 return buffering_time / demux->min_buffering_time;
1238 gst_dash_demux_merge_buffer_list (GstFragment * fragment)
1240 GstBufferList *list;
1241 GstBufferListIterator *it;
1242 GstBuffer *buffer, *ret = NULL;
1243 GstAdapter *adapter;
1246 adapter = gst_adapter_new ();
1247 list = gst_fragment_get_buffer_list (fragment);
1248 it = gst_buffer_list_iterate (list);
1249 while (gst_buffer_list_iterator_next_group (it)) {
1250 while ((buffer = gst_buffer_list_iterator_next (it)) != NULL) {
1251 gst_adapter_push (adapter, gst_buffer_ref (buffer));
1254 gst_buffer_list_iterator_free (it);
1255 gst_buffer_list_unref (list);
1256 size = gst_adapter_available (adapter);
1258 ret = gst_adapter_take_buffer (adapter, size);
1259 GST_DEBUG ("Extracted a buffer of size %d from the fragment", size);
1260 g_object_unref (adapter);
1265 /* gst_dash_demux_download_loop:
1267 * Loop for the "download' task that fetches fragments based on the
1268 * selected representations.
1272 * The task is started from the stream loop.
1276 * It sequentially fetches fragments corresponding to the current
1277 * representations and pushes them into a queue.
1279 * It tries to maintain the number of queued items within a predefined
1280 * range: if the queue is full, it will pause, checking every 100 ms if
1281 * it needs to restart downloading fragments.
1283 * When a new set of fragments has been downloaded, it evaluates the
1284 * download time to check if we can or should switch to a different
1285 * set of representations.
1289 * The task will exit when it encounters an error or when the end of the
1290 * manifest has been reached.
1294 gst_dash_demux_download_loop (GstDashDemux * demux)
1296 GstClock *clock = gst_element_get_clock (GST_ELEMENT (demux));
1297 gint64 update_period = demux->client->mpd_node->minimumUpdatePeriod;
1299 /* Wait until the next scheduled download */
1300 if (g_cond_timed_wait (GST_TASK_GET_COND (demux->download_task),
1301 demux->download_timed_lock, &demux->next_download)) {
1305 if (clock && gst_mpd_client_is_live (demux->client)
1306 && demux->client->mpd_uri != NULL && update_period != -1) {
1307 GstFragment *download;
1309 GstClockTime duration, now = gst_clock_get_time (clock);
1311 /* init reference time for manifest file updates */
1312 if (!GST_CLOCK_TIME_IS_VALID (demux->last_manifest_update))
1313 demux->last_manifest_update = now;
1315 /* update the manifest file */
1316 if (now >= demux->last_manifest_update + update_period * GST_MSECOND) {
1317 GST_DEBUG_OBJECT (demux, "Updating manifest file from URL %s",
1318 demux->client->mpd_uri);
1320 gst_uri_downloader_fetch_uri (demux->downloader,
1321 demux->client->mpd_uri);
1322 if (download == NULL) {
1323 GST_WARNING_OBJECT (demux,
1324 "Failed to update the manifest file from URL %s",
1325 demux->client->mpd_uri);
1327 buffer = gst_dash_demux_merge_buffer_list (download);
1328 g_object_unref (download);
1329 /* parse the manifest file */
1330 if (buffer == NULL) {
1331 GST_WARNING_OBJECT (demux, "Error validating the manifest.");
1332 } else if (!gst_mpd_parse (demux->client,
1333 (gchar *) GST_BUFFER_DATA (buffer), GST_BUFFER_SIZE (buffer))) {
1334 /* In most cases, this will happen if we set a wrong url in the
1335 * source element and we have received the 404 HTML response instead of
1337 GST_WARNING_OBJECT (demux, "Error parsing the manifest.");
1338 gst_buffer_unref (buffer);
1340 GstActiveStream *stream;
1341 guint segment_index;
1343 gst_buffer_unref (buffer);
1344 stream = gst_mpdparser_get_active_stream_by_index (demux->client, 0);
1345 segment_index = gst_mpd_client_get_segment_index (stream);
1346 /* setup video, audio and subtitle streams, starting from first Period */
1347 if (!gst_mpd_client_setup_media_presentation (demux->client) ||
1348 !gst_mpd_client_set_period_index (demux->client,
1349 gst_mpd_client_get_period_index (demux->client))
1350 || !gst_dash_demux_setup_all_streams (demux)) {
1351 GST_DEBUG_OBJECT (demux,
1352 "Error setting up the updated manifest file");
1353 goto end_of_manifest;
1355 /* continue playing from the the next segment */
1356 /* FIXME: support multiple streams with different segment duration */
1357 gst_mpd_client_set_segment_index_for_all_streams (demux->client,
1360 /* Send an updated duration message */
1362 gst_mpd_client_get_media_presentation_duration (demux->client);
1364 if (duration != GST_CLOCK_TIME_NONE) {
1365 GST_DEBUG_OBJECT (demux,
1366 "Sending duration message : %" GST_TIME_FORMAT,
1367 GST_TIME_ARGS (duration));
1368 gst_element_post_message (GST_ELEMENT (demux),
1369 gst_message_new_duration (GST_OBJECT (demux), GST_FORMAT_TIME,
1372 GST_DEBUG_OBJECT (demux,
1373 "mediaPresentationDuration unknown, can not send the duration message");
1375 demux->last_manifest_update += update_period * GST_MSECOND;
1376 GST_DEBUG_OBJECT (demux, "Manifest file successfully updated");
1383 /* Target buffering time MUST at least exceeds mimimum buffering time
1384 * by the duration of a fragment, but SHOULD NOT exceed maximum
1386 GstClockTime target_buffering_time =
1387 demux->min_buffering_time +
1388 gst_mpd_client_get_next_fragment_duration (demux->client);
1389 if (demux->max_buffering_time > target_buffering_time)
1390 target_buffering_time = demux->max_buffering_time;
1391 if (!demux->end_of_manifest
1392 && gst_dash_demux_get_buffering_time (demux) < target_buffering_time) {
1393 if (GST_STATE (demux) != GST_STATE_PLAYING) {
1394 /* Signal our buffering status (this will eventually restart the
1395 * pipeline when we have reached 100 %) */
1396 gst_element_post_message (GST_ELEMENT (demux),
1397 gst_message_new_buffering (GST_OBJECT (demux),
1398 100 * gst_dash_demux_get_buffering_ratio (demux)));
1401 /* try to switch to another set of representations if needed */
1402 gst_dash_demux_select_representations (demux,
1403 demux->bandwidth_usage * demux->dnl_rate *
1404 gst_dash_demux_get_buffering_ratio (demux));
1406 /* fetch the next fragment */
1407 while (!gst_dash_demux_get_next_fragment_set (demux)) {
1408 if (demux->end_of_period) {
1409 GST_INFO_OBJECT (demux, "Reached the end of the Period");
1410 /* setup video, audio and subtitle streams, starting from the next Period */
1411 if (!gst_mpd_client_set_period_index (demux->client,
1412 gst_mpd_client_get_period_index (demux->client) + 1)
1413 || !gst_dash_demux_setup_all_streams (demux)) {
1414 GST_INFO_OBJECT (demux, "Reached the end of the manifest file");
1415 demux->end_of_manifest = TRUE;
1416 if (GST_STATE (demux) != GST_STATE_PLAYING) {
1417 /* Restart the pipeline regardless of the current buffering level */
1418 gst_element_post_message (GST_ELEMENT (demux),
1419 gst_message_new_buffering (GST_OBJECT (demux), 100));
1421 gst_task_start (demux->stream_task);
1422 goto end_of_manifest;
1424 /* start playing from the first segment of the new period */
1425 gst_mpd_client_set_segment_index_for_all_streams (demux->client, 0);
1426 demux->end_of_period = FALSE;
1427 } else if (!demux->cancelled) {
1428 demux->client->update_failed_count++;
1429 if (demux->client->update_failed_count < DEFAULT_FAILED_COUNT) {
1430 GST_WARNING_OBJECT (demux, "Could not fetch the next fragment");
1433 goto error_downloading;
1439 GST_INFO_OBJECT (demux, "Internal buffering : %" PRIu64 " s",
1440 gst_dash_demux_get_buffering_time (demux) / GST_SECOND);
1441 demux->client->update_failed_count = 0;
1443 /* schedule the next download in 100 ms */
1444 g_get_current_time (&demux->next_download);
1445 g_time_val_add (&demux->next_download, 100000);
1455 GST_INFO_OBJECT (demux, "Stopped download task");
1456 gst_task_stop (demux->download_task);
1462 GST_ELEMENT_ERROR (demux, RESOURCE, NOT_FOUND,
1463 ("Could not fetch the next fragment"), (NULL));
1464 gst_dash_demux_stop (demux);
1470 gst_dash_demux_pause_stream_task (GstDashDemux * demux)
1472 /* Send a signal to the stream task so that it pauses itself */
1473 GST_TASK_SIGNAL (demux->stream_task);
1474 /* Pause it explicitly (if it was not in the COND) */
1475 gst_task_pause (demux->stream_task);
1479 gst_dash_demux_resume_stream_task (GstDashDemux * demux)
1481 g_get_current_time (&demux->next_push);
1482 gst_task_start (demux->stream_task);
1486 gst_dash_demux_resume_download_task (GstDashDemux * demux)
1488 g_get_current_time (&demux->next_download);
1489 gst_task_start (demux->download_task);
1492 /* gst_dash_demux_select_representations:
1494 * Select the most appropriate media representations based on a target
1497 * FIXME: all representations are selected against the same bitrate, but
1498 * they will share the same bandwidth. This only works today because the
1499 * audio representations bitrate usage is negligible as compared to the
1500 * video representation one.
1502 * Returns TRUE if a new set of representations has been selected
1505 gst_dash_demux_select_representations (GstDashDemux * demux, guint64 bitrate)
1507 GstActiveStream *stream = NULL;
1508 GList *rep_list = NULL;
1510 gboolean ret = FALSE;
1513 while (i < gst_mpdparser_get_nb_active_stream (demux->client)) {
1514 stream = gst_mpdparser_get_active_stream_by_index (demux->client, i);
1518 /* retrieve representation list */
1519 if (stream->cur_adapt_set)
1520 rep_list = stream->cur_adapt_set->Representations;
1524 /* get representation index with current max_bandwidth */
1526 gst_mpdparser_get_rep_idx_with_max_bandwidth (rep_list, bitrate);
1528 /* if no representation has the required bandwidth, take the lowest one */
1529 if (new_index == -1)
1532 if (new_index != stream->representation_idx) {
1533 GST_MPD_CLIENT_LOCK (demux->client);
1535 gst_mpd_client_setup_representation (demux->client, stream,
1536 g_list_nth_data (rep_list, new_index));
1537 GST_MPD_CLIENT_UNLOCK (demux->client);
1539 GST_INFO_OBJECT (demux, "Switching bitrate to %d",
1540 stream->cur_representation->bandwidth);
1542 GST_WARNING_OBJECT (demux,
1543 "Can not switch representation, aborting...");
1551 static GstFragment *
1552 gst_dash_demux_get_next_header (GstDashDemux * demux, guint stream_idx)
1554 const gchar *initializationURL;
1555 gchar *next_header_uri;
1556 GstFragment *fragment;
1558 if (!gst_mpd_client_get_next_header (demux->client, &initializationURL,
1562 if (strncmp (initializationURL, "http://", 7) != 0) {
1564 g_strconcat (gst_mpdparser_get_baseURL (demux->client),
1565 initializationURL, NULL);
1567 next_header_uri = g_strdup (initializationURL);
1570 GST_INFO_OBJECT (demux, "Fetching header %s", next_header_uri);
1572 fragment = gst_uri_downloader_fetch_uri (demux->downloader, next_header_uri);
1573 g_free (next_header_uri);
1578 static GstBufferListItem
1579 gst_dash_demux_add_buffer_cb (GstBuffer ** buffer,
1580 guint group, guint idx, gpointer user_data)
1582 GstFragment *frag = GST_FRAGMENT (user_data);
1583 /* This buffer still belongs to the original fragment */
1584 /* so we need to increase refcount */
1585 gst_fragment_add_buffer (frag, gst_buffer_ref (*buffer));
1586 return GST_BUFFER_LIST_CONTINUE;
1589 /* Since we cannot add headers after the chunk has been downloaded, we have to recreate a new fragment */
1590 static GstFragment *
1591 gst_dash_demux_prepend_header (GstDashDemux * demux,
1592 GstFragment * frag, GstFragment * header)
1594 GstFragment *res = gst_fragment_new ();
1595 res->name = g_strdup (frag->name);
1596 res->download_start_time = frag->download_start_time;
1597 res->download_stop_time = frag->download_stop_time;
1598 res->start_time = frag->start_time;
1599 res->stop_time = frag->stop_time;
1600 res->index = frag->index;
1601 res->discontinuous = frag->discontinuous;
1603 GstBufferList *list;
1604 list = gst_fragment_get_buffer_list (header);
1605 gst_buffer_list_foreach (list, gst_dash_demux_add_buffer_cb, res);
1606 gst_buffer_list_unref (list);
1607 list = gst_fragment_get_buffer_list (frag);
1608 gst_buffer_list_foreach (list, gst_dash_demux_add_buffer_cb, res);
1609 gst_buffer_list_unref (list);
1611 res->completed = TRUE;
1617 gst_dash_demux_get_video_input_caps (GstDashDemux * demux,
1618 GstActiveStream * stream)
1620 guint width = 0, height = 0;
1621 const gchar *mimeType = NULL;
1622 GstCaps *caps = NULL;
1626 #ifdef DASHDEMUX_MODIFICATION
1627 /* caps need to inlcude resolution */
1628 width = gst_mpd_client_get_video_stream_width (stream);
1629 height = gst_mpd_client_get_video_stream_height (stream);
1631 /* if bitstreamSwitching is true we dont need to swich pads on resolution change */
1632 if (!gst_mpd_client_get_bitstream_switching_flag (stream)) {
1633 width = gst_mpd_client_get_video_stream_width (stream);
1634 height = gst_mpd_client_get_video_stream_height (stream);
1637 mimeType = gst_mpd_client_get_stream_mimeType (stream);
1638 if (mimeType == NULL)
1641 caps = gst_caps_new_simple (mimeType, NULL);
1642 if (width > 0 && height > 0) {
1643 gst_caps_set_simple (caps, "width", G_TYPE_INT, width, "height",
1644 G_TYPE_INT, height, NULL);
1647 /* add ContentProtection to caps */
1648 if ( stream->cur_adapt_set->RepresentationBase->ContentProtection != NULL){
1650 GstDescriptorType *ContentProtectionDesc;
1652 list = g_list_first (stream->cur_adapt_set->RepresentationBase->ContentProtection);
1653 ContentProtectionDesc = (GstDescriptorType *) list->data;
1654 gchar *schemeIdUri = ContentProtectionDesc->schemeIdUri;
1655 gchar *msprPro = ContentProtectionDesc->msprPro;
1657 if ( (schemeIdUri != NULL) && (msprPro != NULL) ){
1658 gst_caps_set_simple (caps, "contentprotection_scheme_iduri", G_TYPE_STRING, schemeIdUri, "mspr:pro", G_TYPE_STRING, msprPro, NULL);
1665 gst_dash_demux_get_audio_input_caps (GstDashDemux * demux,
1666 GstActiveStream * stream)
1668 guint rate = 0, channels = 0;
1669 const gchar *mimeType;
1670 GstCaps *caps = NULL;
1675 /* if bitstreamSwitching is true we dont need to swich pads on rate/channels change */
1676 if (!gst_mpd_client_get_bitstream_switching_flag (stream)) {
1677 channels = gst_mpd_client_get_audio_stream_num_channels (stream);
1678 rate = gst_mpd_client_get_audio_stream_rate (stream);
1680 mimeType = gst_mpd_client_get_stream_mimeType (stream);
1681 if (mimeType == NULL)
1684 caps = gst_caps_new_simple (mimeType, NULL);
1686 gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
1689 gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
1692 /* add ContentProtection to caps */
1693 if ( stream->cur_adapt_set->RepresentationBase->ContentProtection != NULL){
1695 GstDescriptorType *ContentProtectionDesc;
1697 list = g_list_first (stream->cur_adapt_set->RepresentationBase->ContentProtection);
1698 ContentProtectionDesc = (GstDescriptorType *) list->data;
1699 gchar *schemeIdUri = ContentProtectionDesc->schemeIdUri;
1700 gchar *msprPro = ContentProtectionDesc->msprPro;
1702 if ( (schemeIdUri != NULL) && (msprPro != NULL) ){
1703 gst_caps_set_simple (caps, "contentprotection_scheme_iduri", G_TYPE_STRING, schemeIdUri, "mspr:pro", G_TYPE_STRING, msprPro, NULL);
1710 gst_dash_demux_get_application_input_caps (GstDashDemux * demux,
1711 GstActiveStream * stream)
1713 const gchar *mimeType;
1714 GstCaps *caps = NULL;
1719 mimeType = gst_mpd_client_get_stream_mimeType (stream);
1720 if (mimeType == NULL)
1723 caps = gst_caps_new_simple (mimeType, NULL);
1729 gst_dash_demux_get_input_caps (GstDashDemux * demux, GstActiveStream * stream)
1731 switch (stream->mimeType) {
1732 case GST_STREAM_VIDEO:
1733 return gst_dash_demux_get_video_input_caps (demux, stream);
1734 case GST_STREAM_AUDIO:
1735 return gst_dash_demux_get_audio_input_caps (demux, stream);
1736 case GST_STREAM_APPLICATION:
1737 return gst_dash_demux_get_application_input_caps (demux, stream);
1739 return GST_CAPS_NONE;
1744 need_add_header (GstDashDemux * demux)
1746 GstActiveStream *stream;
1748 guint stream_idx = 0;
1749 gboolean switch_caps = FALSE;
1750 while (stream_idx < gst_mpdparser_get_nb_active_stream (demux->client)) {
1752 gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
1755 caps = gst_dash_demux_get_input_caps (demux, stream);
1756 if (!demux->input_caps[stream_idx]
1757 || !gst_caps_is_equal (caps, demux->input_caps[stream_idx])) {
1759 gst_caps_unref (caps);
1762 gst_caps_unref (caps);
1768 /* gst_dash_demux_get_next_fragment_set:
1770 * Get the next set of fragments for the current representations.
1772 * This function uses the generic URI downloader API.
1774 * Returns FALSE if an error occured while downloading fragments
1778 gst_dash_demux_get_next_fragment_set (GstDashDemux * demux)
1780 GstActiveStream *stream;
1781 GstFragment *download, *header;
1782 GList *fragment_set;
1783 gchar *next_fragment_uri;
1784 GstClockTime duration;
1785 GstClockTime timestamp;
1790 guint64 size_buffer = 0;
1792 g_get_current_time (&start);
1793 /* Figure out if we will need to switch pads, thus requiring a new
1794 * header to initialize the new decoding chain
1795 * FIXME: redundant with needs_pad_switch */
1796 gboolean need_header = need_add_header (demux);
1797 guint stream_idx = 0;
1798 fragment_set = NULL;
1799 /* Get the fragment corresponding to each stream index */
1800 while (stream_idx < gst_mpdparser_get_nb_active_stream (demux->client)) {
1801 if (!gst_mpd_client_get_next_fragment (demux->client,
1802 stream_idx, &discont, &next_fragment_uri, &duration, ×tamp)) {
1803 GST_INFO_OBJECT (demux, "This Period doesn't contain more fragments");
1804 demux->end_of_period = TRUE;
1808 GST_INFO_OBJECT (demux, "Fetching next fragment %s", next_fragment_uri);
1810 download = gst_uri_downloader_fetch_uri (demux->downloader,
1812 g_free (next_fragment_uri);
1814 if (download == NULL)
1817 download->start_time = timestamp;
1818 download->stop_time = timestamp + duration;
1821 gst_mpdparser_get_active_stream_by_index (demux->client, stream_idx);
1825 download->index = gst_mpd_client_get_segment_index (stream) - 1;
1827 GstCaps *caps = gst_dash_demux_get_input_caps (demux, stream);
1830 /* Store the new input caps for that stream */
1831 gst_caps_replace (&demux->input_caps[stream_idx], caps);
1832 GST_INFO_OBJECT (demux, "Input source caps: %" GST_PTR_FORMAT,
1833 demux->input_caps[stream_idx]);
1834 /* We need to fetch a new header */
1835 if ((header = gst_dash_demux_get_next_header (demux, stream_idx)) == NULL) {
1836 GST_INFO_OBJECT (demux, "Unable to fetch header");
1838 /* Replace fragment with a new one including the header */
1839 GstFragment *new_fragment =
1840 gst_dash_demux_prepend_header (demux, download, header);
1841 g_object_unref (header);
1842 g_object_unref (download);
1843 download = new_fragment;
1846 gst_caps_unref (caps);
1848 gst_fragment_set_caps (download, demux->input_caps[stream_idx]);
1849 fragment_set = g_list_append (fragment_set, download);
1850 size_buffer += gst_fragment_get_buffer_size (download);
1853 /* Push fragment set into the queue */
1854 g_queue_push_tail (demux->queue, fragment_set);
1855 /* Wake the download task up */
1856 GST_TASK_SIGNAL (demux->download_task);
1857 g_get_current_time (&now);
1858 diff = (GST_TIMEVAL_TO_TIME (now) - GST_TIMEVAL_TO_TIME (start));
1859 demux->dnl_rate = (size_buffer * 8) / ((double) diff / GST_SECOND);
1860 GST_INFO_OBJECT (demux,
1861 "Download rate = %" PRIu64 " Kbits/s (%" PRIu64 " Ko in %.2f s)",
1862 demux->dnl_rate / 1000, size_buffer / 1024, ((double) diff / GST_SECOND));