Move files from gst-plugins-ugly into the "subprojects/gst-plugins-ugly/" subdir
[platform/upstream/gstreamer.git] / subprojects / gst-plugins-bad / ext / dash / gstdashdemux.c
1 /*
2  * DASH demux plugin for GStreamer
3  *
4  * gstdashdemux.c
5  *
6  * Copyright (C) 2012 Orange
7  *
8  * Authors:
9  *   David Corvoysier <david.corvoysier@orange.com>
10  *   Hamid Zakari <hamid.zakari@gmail.com>
11  *
12  * Copyright (C) 2013 Smart TV Alliance
13  *  Author: Thiago Sousa Santos <thiago.sousa.santos@collabora.com>, Collabora Ltd.
14  *
15  * This library is free software; you can redistribute it and/or
16  * modify it under the terms of the GNU Library General Public
17  * License as published by the Free Software Foundation; either
18  * version 2.1 of the License, or (at your option) any later version.
19  *
20  * This library is distributed in the hope that it will be useful,
21  * but WITHOUT ANY WARRANTY; without even the implied warranty of
22  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  * Library General Public License for more details.
24  *
25  * You should have received a copy of the GNU Library General Public
26  * License along with this library (COPYING); if not, write to the
27  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
28  * Boston, MA 02111-1307, USA.
29  */
30 /**
31  * SECTION:element-dashdemux
32  * @title: dashdemux
33  *
34  * DASH demuxer element.
35  * ## Example launch line
36  * |[
37  * gst-launch-1.0 playbin 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"
38  * ]|
39  */
40
41 /* Implementation notes:
42  *
43  * The following section describes how dashdemux works internally.
44  *
45  * Introduction:
46  *
47  * dashdemux is a "fake" demux, as unlike traditional demux elements, it
48  * doesn't split data streams contained in an envelope to expose them to
49  * downstream decoding elements.
50  *
51  * Instead, it parses an XML file called a manifest to identify a set of
52  * individual stream fragments it needs to fetch and expose to the actual
53  * demux elements that will handle them (this behavior is sometimes
54  * referred as the "demux after a demux" scenario).
55  *
56  * For a given section of content, several representations corresponding
57  * to different bitrates may be available: dashdemux will select the most
58  * appropriate representation based on local conditions (typically the
59  * available bandwidth and the amount of buffering available, capped by
60  * a maximum allowed bitrate).
61  *
62  * The representation selection algorithm can be configured using
63  * specific properties: max bitrate, min/max buffering, bandwidth ratio.
64  *
65  *
66  * General Design:
67  *
68  * dashdemux has a single sink pad that accepts the data corresponding
69  * to the manifest, typically fetched from an HTTP or file source.
70  *
71  * dashdemux exposes the streams it recreates based on the fragments it
72  * fetches through dedicated src pads corresponding to the caps of the
73  * fragments container (ISOBMFF/MP4 or MPEG2TS).
74  *
75  * During playback, new representations will typically be exposed as a
76  * new set of pads (see 'Switching between representations' below).
77  *
78  * Fragments downloading is performed using a dedicated task that fills
79  * an internal queue. Another task is in charge of popping fragments
80  * from the queue and pushing them downstream.
81  *
82  * Switching between representations:
83  *
84  * Decodebin supports scenarios allowing to seamlessly switch from one
85  * stream to another inside the same "decoding chain".
86  *
87  * To achieve that, it combines the elements it autoplugged in chains
88  *  and groups, allowing only one decoding group to be active at a given
89  * time for a given chain.
90  *
91  * A chain can signal decodebin that it is complete by sending a
92  * no-more-pads event, but even after that new pads can be added to
93  * create new subgroups, providing that a new no-more-pads event is sent.
94  *
95  * We take advantage of that to dynamically create a new decoding group
96  * in order to select a different representation during playback.
97  *
98  * Typically, assuming that each fragment contains both audio and video,
99  * the following tree would be created:
100  *
101  * chain "DASH Demux"
102  * |_ group "Representation set 1"
103  * |   |_ chain "Qt Demux 0"
104  * |       |_ group "Stream 0"
105  * |           |_ chain "H264"
106  * |           |_ chain "AAC"
107  * |_ group "Representation set 2"
108  *     |_ chain "Qt Demux 1"
109  *         |_ group "Stream 1"
110  *             |_ chain "H264"
111  *             |_ chain "AAC"
112  *
113  * Or, if audio and video are contained in separate fragments:
114  *
115  * chain "DASH Demux"
116  * |_ group "Representation set 1"
117  * |   |_ chain "Qt Demux 0"
118  * |   |   |_ group "Stream 0"
119  * |   |       |_ chain "H264"
120  * |   |_ chain "Qt Demux 1"
121  * |       |_ group "Stream 1"
122  * |           |_ chain "AAC"
123  * |_ group "Representation set 2"
124  *     |_ chain "Qt Demux 3"
125  *     |   |_ group "Stream 2"
126  *     |       |_ chain "H264"
127  *     |_ chain "Qt Demux 4"
128  *         |_ group "Stream 3"
129  *             |_ chain "AAC"
130  *
131  * In both cases, when switching from Set 1 to Set 2 an EOS is sent on
132  * each end pad corresponding to Rep 0, triggering the "drain" state to
133  * propagate upstream.
134  * Once both EOS have been processed, the "Set 1" group is completely
135  * drained, and decodebin2 will switch to the "Set 2" group.
136  *
137  * Note: nothing can be pushed to the new decoding group before the
138  * old one has been drained, which means that in order to be able to
139  * adapt quickly to bandwidth changes, we will not be able to rely
140  * on downstream buffering, and will instead manage an internal queue.
141  *
142  *
143  * Keyframe trick-mode implementation:
144  *
145  * When requested (with GST_SEEK_FLAG_TRICKMODE_KEY_UNIT) and if the format
146  * is supported (ISOBMFF profiles), dashdemux can download only keyframes
147  * in order to provide fast forward/reverse playback without exceeding the
148  * available bandwidth/cpu/memory usage.
149  *
150  * This is done in two parts:
151  * 1) Parsing ISOBMFF atoms to detect the location of keyframes and only
152  *    download/push those.
153  * 2) Deciding what the ideal next keyframe to download is in order to
154  *    provide as many keyframes as possible without rebuffering.
155  *
156  * * Keyframe-only downloads:
157  *
158  * For each beginning of fragment, the fragment header will be parsed in
159  * gst_dash_demux_parse_isobmff() and then the information (offset, pts...)
160  * of each keyframe will be stored in moof_sync_samples.
161  *
162  * gst_dash_demux_stream_update_fragment_info() will specify the range
163  * start and end of the current keyframe, which will cause GstAdaptiveDemux
164  * to do a new upstream range request.
165  *
166  * When advancing, if there are still some keyframes in the current
167  * fragment, gst_dash_demux_stream_advance_fragment() will call
168  * gst_dash_demux_stream_advance_sync_sample() which decides what the next
169  * keyframe to get will be (it can be in reverse order for example, or
170  * might not be the *next* keyframe but one further as explained below).
171  *
172  * If no more keyframes are available in the current fragment, dash will
173  * advance to the next fragment (just like in the normal case) or to a
174  * fragment much further away (as explained below).
175  *
176  *
177  * * Deciding the optimal "next" keyframe/fragment to download:
178  *
179  * The main reason for doing keyframe-only downloads is for trick-modes
180  * (i.e. being able to do fast reverse/forward playback with limited
181  * bandwidth/cpu/memory).
182  *
183  * Downloading all keyframes might not be the optimal solution, especially
184  * at high playback rates, since the time taken to download the keyframe
185  * might exceed the available running time between two displayed frames
186  * (i.e. all frames would end up arriving late). This would cause severe
187  * rebuffering.
188  *
189  * Note: The values specified below can be in either the segment running
190  * time or in absolute values. Where position values need to be converted
191  * to segment running time the "running_time(val)" notation is used, and
192  * where running time need ot be converted to segment poisition the
193  * "position(val)" notation is used.
194  *
195  * The goal instead is to be able to download/display as many frames as
196  * possible for a given playback rate. For that the implementation will
197  * take into account:
198  *  * The requested playback rate and segment
199  *  * The average time to request and download a keyframe (in running time)
200  *  * The current position of dashdemux in the stream
201  *  * The current downstream (i.e. sink) position (in running time)
202  *
203  * To reach this goal we consider that there is some amount of buffering
204  * (in time) between dashdemux and the display sink. While we do not know
205  * the exact amount of buffering available, a safe and reasonable assertion
206  * is that there is at least a second (in running time).
207  *
208  * The average time to request and fully download a keyframe (with or
209  * without fragment header) is obtained by averaging the
210  * GstAdaptiveDemuxStream->last_download_time and is stored in
211  * GstDashDemuxStream->average_download_time. Those values include the
212  * network latency and full download time, which are more interesting and
213  * correct than just bitrates (with small download sizes, the impact of the
214  * network latency is much higher).
215  *
216  * The current position is calculated based on the fragment timestamp and
217  * the current keyframe index within that fragment. It is stored in
218  * GstDashDemuxStream->actual_position.
219  *
220  * The downstream position of the pipeline is obtained via QoS events and
221  * is stored in GstAdaptiveDemux (note: it's a running time value).
222  *
223  * The estimated buffering level between dashdemux and downstream is
224  * therefore:
225  *   buffering_level = running_time(actual_position) - qos_earliest_time
226  *
227  * In order to avoid rebuffering, we want to ensure that the next keyframe
228  * (including potential fragment header) we request will be download, demuxed
229  * and decoded in time so that it is not late. That next keyframe time is
230  * called the "target_time" and is calculated whenever we have finished
231  * pushing a keyframe downstream.
232  *
233  * One simple observation at this point is that we *need* to make sure that
234  * the target time is chosen such that:
235  *   running_time(target_time) > qos_earliest_time + average_download_time
236  *
237  * i.e. we chose a target time which will be greater than the time at which
238  * downstream will be once we request and download the keyframe (otherwise
239  * we're guaranteed to be late).
240  *
241  * This would provide the highest number of displayed frames per
242  * second, but it is just a *minimal* value and is not enough as-is,
243  * since it doesn't take into account the following items which could
244  * cause frames to arrive late (and therefore rebuffering):
245  * * Network jitter (i.e. by how much the download time can fluctuate)
246  * * Network stalling
247  * * Different keyframe sizes (and therefore download time)
248  * * Decoding speed
249  *
250  * Instead, we adjust the target time calculation based on the
251  * buffering_level.
252  *
253  * The smaller the buffering level is (i.e. the closer we are between
254  * current and downstream), the more aggressively we skip forward (and
255  * guarantee the keyframe will be downloaded, decoded and displayed in
256  * time). And the higher the buffering level, the least aggresivelly
257  * we need to skip forward (and therefore display more frames per
258  * second).
259  *
260  * Right now the threshold for aggressive switching is set to 3
261  * average_download_time. Below that buffering level we set the target time
262  * to at least 3 average_download_time distance beyond the
263  * qos_earliest_time.
264  *
265  * If we are above that buffering level we set the target time to:
266  *      position(running_time(position) + average_download_time)
267  *
268  * The logic is therefore:
269  * WHILE(!EOS)
270  *   Calculate target_time
271  *   Advance to keyframe/fragment for that target_time
272  *   Adaptivedemux downloads that keyframe/fragment
273  *
274  */
275
276 #ifdef HAVE_CONFIG_H
277 #  include "config.h"
278 #endif
279
280 #include <string.h>
281 #include <stdio.h>
282 #include <stdlib.h>
283 #include <inttypes.h>
284 #include <gio/gio.h>
285 #include <gst/base/gsttypefindhelper.h>
286 #include <gst/tag/tag.h>
287 #include <gst/net/gstnet.h>
288 #include "gst/gst-i18n-plugin.h"
289 #include "gstdashdemux.h"
290 #include "gstdash_debug.h"
291
292 static GstStaticPadTemplate gst_dash_demux_videosrc_template =
293 GST_STATIC_PAD_TEMPLATE ("video_%02u",
294     GST_PAD_SRC,
295     GST_PAD_SOMETIMES,
296     GST_STATIC_CAPS_ANY);
297
298 static GstStaticPadTemplate gst_dash_demux_audiosrc_template =
299 GST_STATIC_PAD_TEMPLATE ("audio_%02u",
300     GST_PAD_SRC,
301     GST_PAD_SOMETIMES,
302     GST_STATIC_CAPS_ANY);
303
304 static GstStaticPadTemplate gst_dash_demux_subtitlesrc_template =
305 GST_STATIC_PAD_TEMPLATE ("subtitle_%02u",
306     GST_PAD_SRC,
307     GST_PAD_SOMETIMES,
308     GST_STATIC_CAPS_ANY);
309
310 static GstStaticPadTemplate sinktemplate = GST_STATIC_PAD_TEMPLATE ("sink",
311     GST_PAD_SINK,
312     GST_PAD_ALWAYS,
313     GST_STATIC_CAPS ("application/dash+xml"));
314
315 GST_DEBUG_CATEGORY (gst_dash_demux_debug);
316 #define GST_CAT_DEFAULT gst_dash_demux_debug
317
318 enum
319 {
320   PROP_0,
321
322   PROP_MAX_BUFFERING_TIME,
323   PROP_BANDWIDTH_USAGE,
324   PROP_MAX_BITRATE,
325   PROP_MAX_VIDEO_WIDTH,
326   PROP_MAX_VIDEO_HEIGHT,
327   PROP_MAX_VIDEO_FRAMERATE,
328   PROP_PRESENTATION_DELAY,
329   PROP_LAST
330 };
331
332 /* Default values for properties */
333 #define DEFAULT_MAX_BUFFERING_TIME       30     /* in seconds */
334 #define DEFAULT_BANDWIDTH_USAGE         0.8f    /* 0 to 1     */
335 #define DEFAULT_MAX_BITRATE               0     /* in bit/s  */
336 #define DEFAULT_MAX_VIDEO_WIDTH           0
337 #define DEFAULT_MAX_VIDEO_HEIGHT          0
338 #define DEFAULT_MAX_VIDEO_FRAMERATE_N     0
339 #define DEFAULT_MAX_VIDEO_FRAMERATE_D     1
340 #define DEFAULT_PRESENTATION_DELAY     "10s"    /* 10s */
341
342 /* Clock drift compensation for live streams */
343 #define SLOW_CLOCK_UPDATE_INTERVAL  (1000000 * 30 * 60) /* 30 minutes */
344 #define FAST_CLOCK_UPDATE_INTERVAL  (1000000 * 30)      /* 30 seconds */
345 #define SUPPORTED_CLOCK_FORMATS (GST_MPD_UTCTIMING_TYPE_NTP | GST_MPD_UTCTIMING_TYPE_HTTP_HEAD | GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE | GST_MPD_UTCTIMING_TYPE_HTTP_ISO | GST_MPD_UTCTIMING_TYPE_HTTP_NTP)
346 #define NTP_TO_UNIX_EPOCH G_GUINT64_CONSTANT(2208988800)        /* difference (in seconds) between NTP epoch and Unix epoch */
347
348 struct _GstDashDemuxClockDrift
349 {
350   GMutex clock_lock;            /* used to protect access to struct */
351   guint selected_url;
352   gint64 next_update;
353   /* @clock_compensation: amount (in usecs) to add to client's idea of
354      now to map it to the server's idea of now */
355   GTimeSpan clock_compensation;
356   GstClock *ntp_clock;
357 };
358
359 typedef struct
360 {
361   guint64 start_offset, end_offset;
362   /* TODO: Timestamp and duration */
363 } GstDashStreamSyncSample;
364
365 /* GObject */
366 static void gst_dash_demux_set_property (GObject * object, guint prop_id,
367     const GValue * value, GParamSpec * pspec);
368 static void gst_dash_demux_get_property (GObject * object, guint prop_id,
369     GValue * value, GParamSpec * pspec);
370 static void gst_dash_demux_dispose (GObject * obj);
371
372 /* GstAdaptiveDemux */
373 static GstClockTime gst_dash_demux_get_duration (GstAdaptiveDemux * ademux);
374 static gboolean gst_dash_demux_is_live (GstAdaptiveDemux * ademux);
375 static void gst_dash_demux_reset (GstAdaptiveDemux * ademux);
376 static gboolean gst_dash_demux_process_manifest (GstAdaptiveDemux * ademux,
377     GstBuffer * buf);
378 static gboolean gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek);
379 static GstFlowReturn
380 gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream);
381 static GstFlowReturn gst_dash_demux_stream_seek (GstAdaptiveDemuxStream *
382     stream, gboolean forward, GstSeekFlags flags, GstClockTime ts,
383     GstClockTime * final_ts);
384 static gboolean gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemuxStream
385     * stream);
386 static GstFlowReturn
387 gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream);
388 static gboolean
389 gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream);
390 static gboolean gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream *
391     stream, guint64 bitrate);
392 static gint64 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux *
393     demux);
394 static GstFlowReturn gst_dash_demux_update_manifest_data (GstAdaptiveDemux *
395     demux, GstBuffer * buf);
396 static gint64
397 gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
398     stream);
399 static void gst_dash_demux_advance_period (GstAdaptiveDemux * demux);
400 static gboolean gst_dash_demux_has_next_period (GstAdaptiveDemux * demux);
401 static GstFlowReturn gst_dash_demux_data_received (GstAdaptiveDemux * demux,
402     GstAdaptiveDemuxStream * stream, GstBuffer * buffer);
403 static gboolean
404 gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
405     GstAdaptiveDemuxStream * stream);
406 static GstFlowReturn
407 gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
408     GstAdaptiveDemuxStream * stream);
409 static gboolean gst_dash_demux_need_another_chunk (GstAdaptiveDemuxStream *
410     stream);
411
412 /* GstDashDemux */
413 static gboolean gst_dash_demux_setup_all_streams (GstDashDemux * demux);
414 static void gst_dash_demux_stream_free (GstAdaptiveDemuxStream * stream);
415
416 static GstCaps *gst_dash_demux_get_input_caps (GstDashDemux * demux,
417     GstActiveStream * stream);
418 static GstPad *gst_dash_demux_create_pad (GstDashDemux * demux,
419     GstActiveStream * stream);
420 static GstDashDemuxClockDrift *gst_dash_demux_clock_drift_new (GstDashDemux *
421     demux);
422 static void gst_dash_demux_clock_drift_free (GstDashDemuxClockDrift *);
423 static gboolean gst_dash_demux_poll_clock_drift (GstDashDemux * demux);
424 static GTimeSpan gst_dash_demux_get_clock_compensation (GstDashDemux * demux);
425 static GDateTime *gst_dash_demux_get_server_now_utc (GstDashDemux * demux);
426
427 #define SIDX(s) (&(s)->sidx_parser.sidx)
428
429 static inline GstSidxBoxEntry *
430 SIDX_ENTRY (GstDashDemuxStream * s, gint i)
431 {
432   g_assert (i < SIDX (s)->entries_count);
433   return &(SIDX (s)->entries[(i)]);
434 }
435
436 #define SIDX_CURRENT_ENTRY(s) SIDX_ENTRY(s, SIDX(s)->entry_index)
437
438 static void gst_dash_demux_send_content_protection_event (gpointer cp_data,
439     gpointer stream);
440
441 #define gst_dash_demux_parent_class parent_class
442 G_DEFINE_TYPE_WITH_CODE (GstDashDemux, gst_dash_demux, GST_TYPE_ADAPTIVE_DEMUX,
443     GST_DEBUG_CATEGORY_INIT (gst_dash_demux_debug, "dashdemux", 0,
444         "dashdemux element")
445     );
446 GST_ELEMENT_REGISTER_DEFINE (dashdemux, "dashdemux", GST_RANK_PRIMARY,
447     GST_TYPE_DASH_DEMUX);
448
449 static void
450 gst_dash_demux_dispose (GObject * obj)
451 {
452   GstDashDemux *demux = GST_DASH_DEMUX (obj);
453
454   gst_dash_demux_reset (GST_ADAPTIVE_DEMUX_CAST (demux));
455
456   if (demux->client) {
457     gst_mpd_client_free (demux->client);
458     demux->client = NULL;
459   }
460
461   g_mutex_clear (&demux->client_lock);
462
463   gst_dash_demux_clock_drift_free (demux->clock_drift);
464   demux->clock_drift = NULL;
465   g_free (demux->default_presentation_delay);
466   G_OBJECT_CLASS (parent_class)->dispose (obj);
467 }
468
469 static gboolean
470 gst_dash_demux_get_live_seek_range (GstAdaptiveDemux * demux, gint64 * start,
471     gint64 * stop)
472 {
473   GstDashDemux *self = GST_DASH_DEMUX (demux);
474   GDateTime *now;
475   GDateTime *mstart;
476   GTimeSpan stream_now;
477   GstClockTime seg_duration;
478
479   if (self->client->mpd_root_node->availabilityStartTime == NULL)
480     return FALSE;
481
482   seg_duration = gst_mpd_client_get_maximum_segment_duration (self->client);
483   now = gst_dash_demux_get_server_now_utc (self);
484   mstart =
485       gst_date_time_to_g_date_time (self->client->mpd_root_node->
486       availabilityStartTime);
487   stream_now = g_date_time_difference (now, mstart);
488   g_date_time_unref (now);
489   g_date_time_unref (mstart);
490
491   if (stream_now <= 0)
492     return FALSE;
493
494   *stop = stream_now * GST_USECOND;
495   if (self->client->mpd_root_node->timeShiftBufferDepth ==
496       GST_MPD_DURATION_NONE) {
497     *start = 0;
498   } else {
499     *start =
500         *stop -
501         (self->client->mpd_root_node->timeShiftBufferDepth * GST_MSECOND);
502     if (*start < 0)
503       *start = 0;
504   }
505
506   /* As defined in 5.3.9.5.3 of the DASH specification, a segment does
507      not become available until the sum of:
508      * the value of the MPD@availabilityStartTime,
509      * the PeriodStart time of the containing Period
510      * the MPD start time of the Media Segment, and
511      * the MPD duration of the Media Segment.
512      Therefore we need to subtract the media segment duration from the stop
513      time.
514    */
515   *stop -= seg_duration;
516   return TRUE;
517 }
518
519 static GstClockTime
520 gst_dash_demux_get_presentation_offset (GstAdaptiveDemux * demux,
521     GstAdaptiveDemuxStream * stream)
522 {
523   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
524   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
525
526   return gst_mpd_client_get_stream_presentation_offset (dashdemux->client,
527       dashstream->index);
528 }
529
530 static GstClockTime
531 gst_dash_demux_get_period_start_time (GstAdaptiveDemux * demux)
532 {
533   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
534
535   return gst_mpd_client_get_period_start_time (dashdemux->client);
536 }
537
538 static void
539 gst_dash_demux_class_init (GstDashDemuxClass * klass)
540 {
541   GObjectClass *gobject_class;
542   GstElementClass *gstelement_class;
543   GstAdaptiveDemuxClass *gstadaptivedemux_class;
544
545   gobject_class = (GObjectClass *) klass;
546   gstelement_class = (GstElementClass *) klass;
547   gstadaptivedemux_class = (GstAdaptiveDemuxClass *) klass;
548
549   gobject_class->set_property = gst_dash_demux_set_property;
550   gobject_class->get_property = gst_dash_demux_get_property;
551   gobject_class->dispose = gst_dash_demux_dispose;
552
553 #ifndef GST_REMOVE_DEPRECATED
554   g_object_class_install_property (gobject_class, PROP_MAX_BUFFERING_TIME,
555       g_param_spec_uint ("max-buffering-time", "Maximum buffering time",
556           "Maximum number of seconds of buffer accumulated during playback"
557           "(deprecated)",
558           2, G_MAXUINT, DEFAULT_MAX_BUFFERING_TIME,
559           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
560
561   g_object_class_install_property (gobject_class, PROP_BANDWIDTH_USAGE,
562       g_param_spec_float ("bandwidth-usage",
563           "Bandwidth usage [0..1]",
564           "Percentage of the available bandwidth to use when "
565           "selecting representations (deprecated)",
566           0, 1, DEFAULT_BANDWIDTH_USAGE,
567           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_DEPRECATED));
568 #endif
569
570   g_object_class_install_property (gobject_class, PROP_MAX_BITRATE,
571       g_param_spec_uint ("max-bitrate", "Max bitrate",
572           "Max of bitrate supported by target video decoder (0 = no maximum)",
573           0, G_MAXUINT, DEFAULT_MAX_BITRATE,
574           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
575
576   g_object_class_install_property (gobject_class, PROP_MAX_VIDEO_WIDTH,
577       g_param_spec_uint ("max-video-width", "Max video width",
578           "Max video width to select (0 = no maximum)",
579           0, G_MAXUINT, DEFAULT_MAX_VIDEO_WIDTH,
580           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
581
582   g_object_class_install_property (gobject_class, PROP_MAX_VIDEO_HEIGHT,
583       g_param_spec_uint ("max-video-height", "Max video height",
584           "Max video height to select (0 = no maximum)",
585           0, G_MAXUINT, DEFAULT_MAX_VIDEO_HEIGHT,
586           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
587
588   g_object_class_install_property (gobject_class, PROP_MAX_VIDEO_FRAMERATE,
589       gst_param_spec_fraction ("max-video-framerate", "Max video framerate",
590           "Max video framerate to select (0/1 = no maximum)",
591           0, 1, G_MAXINT, 1, DEFAULT_MAX_VIDEO_FRAMERATE_N,
592           DEFAULT_MAX_VIDEO_FRAMERATE_D,
593           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
594
595   g_object_class_install_property (gobject_class, PROP_PRESENTATION_DELAY,
596       g_param_spec_string ("presentation-delay", "Presentation delay",
597           "Default presentation delay (in seconds, milliseconds or fragments) (e.g. 12s, 2500ms, 3f)",
598           DEFAULT_PRESENTATION_DELAY,
599           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
600
601   gst_element_class_add_static_pad_template (gstelement_class,
602       &gst_dash_demux_audiosrc_template);
603   gst_element_class_add_static_pad_template (gstelement_class,
604       &gst_dash_demux_videosrc_template);
605   gst_element_class_add_static_pad_template (gstelement_class,
606       &gst_dash_demux_subtitlesrc_template);
607
608   gst_element_class_add_static_pad_template (gstelement_class, &sinktemplate);
609
610   gst_element_class_set_static_metadata (gstelement_class,
611       "DASH Demuxer",
612       "Codec/Demuxer/Adaptive",
613       "Dynamic Adaptive Streaming over HTTP demuxer",
614       "David Corvoysier <david.corvoysier@orange.com>\n\
615                 Hamid Zakari <hamid.zakari@gmail.com>\n\
616                 Gianluca Gennari <gennarone@gmail.com>");
617
618
619   gstadaptivedemux_class->get_duration = gst_dash_demux_get_duration;
620   gstadaptivedemux_class->is_live = gst_dash_demux_is_live;
621   gstadaptivedemux_class->reset = gst_dash_demux_reset;
622   gstadaptivedemux_class->seek = gst_dash_demux_seek;
623
624   gstadaptivedemux_class->process_manifest = gst_dash_demux_process_manifest;
625   gstadaptivedemux_class->update_manifest_data =
626       gst_dash_demux_update_manifest_data;
627   gstadaptivedemux_class->get_manifest_update_interval =
628       gst_dash_demux_get_manifest_update_interval;
629
630   gstadaptivedemux_class->has_next_period = gst_dash_demux_has_next_period;
631   gstadaptivedemux_class->advance_period = gst_dash_demux_advance_period;
632   gstadaptivedemux_class->stream_has_next_fragment =
633       gst_dash_demux_stream_has_next_fragment;
634   gstadaptivedemux_class->stream_advance_fragment =
635       gst_dash_demux_stream_advance_fragment;
636   gstadaptivedemux_class->stream_get_fragment_waiting_time =
637       gst_dash_demux_stream_get_fragment_waiting_time;
638   gstadaptivedemux_class->stream_seek = gst_dash_demux_stream_seek;
639   gstadaptivedemux_class->stream_select_bitrate =
640       gst_dash_demux_stream_select_bitrate;
641   gstadaptivedemux_class->stream_update_fragment_info =
642       gst_dash_demux_stream_update_fragment_info;
643   gstadaptivedemux_class->stream_free = gst_dash_demux_stream_free;
644   gstadaptivedemux_class->get_live_seek_range =
645       gst_dash_demux_get_live_seek_range;
646   gstadaptivedemux_class->get_presentation_offset =
647       gst_dash_demux_get_presentation_offset;
648   gstadaptivedemux_class->get_period_start_time =
649       gst_dash_demux_get_period_start_time;
650
651   gstadaptivedemux_class->start_fragment = gst_dash_demux_stream_fragment_start;
652   gstadaptivedemux_class->finish_fragment =
653       gst_dash_demux_stream_fragment_finished;
654   gstadaptivedemux_class->data_received = gst_dash_demux_data_received;
655   gstadaptivedemux_class->need_another_chunk =
656       gst_dash_demux_need_another_chunk;
657 }
658
659 static void
660 gst_dash_demux_init (GstDashDemux * demux)
661 {
662   /* Properties */
663   demux->max_buffering_time = DEFAULT_MAX_BUFFERING_TIME * GST_SECOND;
664   demux->max_bitrate = DEFAULT_MAX_BITRATE;
665   demux->max_video_width = DEFAULT_MAX_VIDEO_WIDTH;
666   demux->max_video_height = DEFAULT_MAX_VIDEO_HEIGHT;
667   demux->max_video_framerate_n = DEFAULT_MAX_VIDEO_FRAMERATE_N;
668   demux->max_video_framerate_d = DEFAULT_MAX_VIDEO_FRAMERATE_D;
669   demux->default_presentation_delay = g_strdup (DEFAULT_PRESENTATION_DELAY);
670
671   g_mutex_init (&demux->client_lock);
672
673   gst_adaptive_demux_set_stream_struct_size (GST_ADAPTIVE_DEMUX_CAST (demux),
674       sizeof (GstDashDemuxStream));
675 }
676
677 static void
678 gst_dash_demux_set_property (GObject * object, guint prop_id,
679     const GValue * value, GParamSpec * pspec)
680 {
681   GstAdaptiveDemux *adaptivedemux = GST_ADAPTIVE_DEMUX_CAST (object);
682   GstDashDemux *demux = GST_DASH_DEMUX (object);
683
684   switch (prop_id) {
685     case PROP_MAX_BUFFERING_TIME:
686       demux->max_buffering_time = g_value_get_uint (value) * GST_SECOND;
687       break;
688     case PROP_BANDWIDTH_USAGE:
689       adaptivedemux->bitrate_limit = g_value_get_float (value);
690       break;
691     case PROP_MAX_BITRATE:
692       demux->max_bitrate = g_value_get_uint (value);
693       break;
694     case PROP_MAX_VIDEO_WIDTH:
695       demux->max_video_width = g_value_get_uint (value);
696       break;
697     case PROP_MAX_VIDEO_HEIGHT:
698       demux->max_video_height = g_value_get_uint (value);
699       break;
700     case PROP_MAX_VIDEO_FRAMERATE:
701       demux->max_video_framerate_n = gst_value_get_fraction_numerator (value);
702       demux->max_video_framerate_d = gst_value_get_fraction_denominator (value);
703       break;
704     case PROP_PRESENTATION_DELAY:
705       g_free (demux->default_presentation_delay);
706       demux->default_presentation_delay = g_value_dup_string (value);
707       break;
708     default:
709       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
710       break;
711   }
712 }
713
714 static void
715 gst_dash_demux_get_property (GObject * object, guint prop_id, GValue * value,
716     GParamSpec * pspec)
717 {
718   GstAdaptiveDemux *adaptivedemux = GST_ADAPTIVE_DEMUX_CAST (object);
719   GstDashDemux *demux = GST_DASH_DEMUX (object);
720
721   switch (prop_id) {
722     case PROP_MAX_BUFFERING_TIME:
723       g_value_set_uint (value, demux->max_buffering_time / GST_SECOND);
724       break;
725     case PROP_BANDWIDTH_USAGE:
726       g_value_set_float (value, adaptivedemux->bitrate_limit);
727       break;
728     case PROP_MAX_BITRATE:
729       g_value_set_uint (value, demux->max_bitrate);
730       break;
731     case PROP_MAX_VIDEO_WIDTH:
732       g_value_set_uint (value, demux->max_video_width);
733       break;
734     case PROP_MAX_VIDEO_HEIGHT:
735       g_value_set_uint (value, demux->max_video_height);
736       break;
737     case PROP_MAX_VIDEO_FRAMERATE:
738       gst_value_set_fraction (value, demux->max_video_framerate_n,
739           demux->max_video_framerate_d);
740       break;
741     case PROP_PRESENTATION_DELAY:
742       if (demux->default_presentation_delay == NULL)
743         g_value_set_static_string (value, "");
744       else
745         g_value_set_string (value, demux->default_presentation_delay);
746       break;
747     default:
748       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
749       break;
750   }
751 }
752
753 static gboolean
754 gst_dash_demux_setup_mpdparser_streams (GstDashDemux * demux,
755     GstMPDClient * client)
756 {
757   gboolean has_streams = FALSE;
758   GList *adapt_sets, *iter;
759
760   adapt_sets = gst_mpd_client_get_adaptation_sets (client);
761   for (iter = adapt_sets; iter; iter = g_list_next (iter)) {
762     GstMPDAdaptationSetNode *adapt_set_node = iter->data;
763
764     gst_mpd_client_setup_streaming (client, adapt_set_node);
765     has_streams = TRUE;
766   }
767
768   if (!has_streams) {
769     GST_ELEMENT_ERROR (demux, STREAM, DEMUX, ("Manifest has no playable "
770             "streams"), ("No streams could be activated from the manifest"));
771   }
772   return has_streams;
773 }
774
775 static gboolean
776 gst_dash_demux_setup_all_streams (GstDashDemux * demux)
777 {
778   guint i;
779
780   GST_DEBUG_OBJECT (demux, "Setting up streams for period %d",
781       gst_mpd_client_get_period_index (demux->client));
782
783   /* clean old active stream list, if any */
784   gst_mpd_client_active_streams_free (demux->client);
785
786   if (!gst_dash_demux_setup_mpdparser_streams (demux, demux->client)) {
787     return FALSE;
788   }
789
790   GST_DEBUG_OBJECT (demux, "Creating stream objects");
791   for (i = 0; i < gst_mpd_client_get_nb_active_stream (demux->client); i++) {
792     GstDashDemuxStream *stream;
793     GstActiveStream *active_stream;
794     GstCaps *caps;
795     GstStructure *s;
796     GstPad *srcpad;
797     gchar *lang = NULL;
798     GstTagList *tags = NULL;
799
800     active_stream =
801         gst_mpd_client_get_active_stream_by_index (demux->client, i);
802     if (active_stream == NULL)
803       continue;
804
805     if (demux->trickmode_no_audio
806         && active_stream->mimeType == GST_STREAM_AUDIO) {
807       GST_DEBUG_OBJECT (demux,
808           "Skipping audio stream %d because of TRICKMODE_NO_AUDIO flag", i);
809       continue;
810     }
811
812     srcpad = gst_dash_demux_create_pad (demux, active_stream);
813     if (srcpad == NULL)
814       continue;
815
816     caps = gst_dash_demux_get_input_caps (demux, active_stream);
817     GST_LOG_OBJECT (demux, "Creating stream %d %" GST_PTR_FORMAT, i, caps);
818
819     if (active_stream->cur_adapt_set) {
820       GstMPDAdaptationSetNode *adp_set = active_stream->cur_adapt_set;
821       lang = adp_set->lang;
822
823       /* Fallback to the language in ContentComponent node */
824       if (lang == NULL) {
825         GList *it;
826
827         for (it = adp_set->ContentComponents; it; it = it->next) {
828           GstMPDContentComponentNode *cc_node = it->data;
829           if (cc_node->lang) {
830             lang = cc_node->lang;
831             break;
832           }
833         }
834       }
835     }
836
837     if (lang) {
838       if (gst_tag_check_language_code (lang))
839         tags = gst_tag_list_new (GST_TAG_LANGUAGE_CODE, lang, NULL);
840       else
841         tags = gst_tag_list_new (GST_TAG_LANGUAGE_NAME, lang, NULL);
842     }
843
844     stream = (GstDashDemuxStream *)
845         gst_adaptive_demux_stream_new (GST_ADAPTIVE_DEMUX_CAST (demux), srcpad);
846     stream->active_stream = active_stream;
847     s = gst_caps_get_structure (caps, 0);
848     stream->allow_sidx =
849         gst_mpd_client_has_isoff_ondemand_profile (demux->client);
850     stream->is_isobmff = gst_structure_has_name (s, "video/quicktime")
851         || gst_structure_has_name (s, "audio/x-m4a");
852     stream->first_sync_sample_always_after_moof = TRUE;
853     stream->adapter = gst_adapter_new ();
854     gst_adaptive_demux_stream_set_caps (GST_ADAPTIVE_DEMUX_STREAM_CAST (stream),
855         caps);
856     if (tags)
857       gst_adaptive_demux_stream_set_tags (GST_ADAPTIVE_DEMUX_STREAM_CAST
858           (stream), tags);
859     stream->index = i;
860     stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
861     stream->sidx_position = GST_CLOCK_TIME_NONE;
862     stream->actual_position = GST_CLOCK_TIME_NONE;
863     stream->target_time = GST_CLOCK_TIME_NONE;
864     /* Set a default average keyframe download time of a quarter of a second */
865     stream->average_download_time = 250 * GST_MSECOND;
866
867     if (active_stream->cur_adapt_set &&
868         GST_MPD_REPRESENTATION_BASE_NODE (active_stream->
869             cur_adapt_set)->ContentProtection) {
870       GST_DEBUG_OBJECT (demux, "Adding ContentProtection events to source pad");
871       g_list_foreach (GST_MPD_REPRESENTATION_BASE_NODE
872           (active_stream->cur_adapt_set)->ContentProtection,
873           gst_dash_demux_send_content_protection_event, stream);
874     }
875
876     gst_isoff_sidx_parser_init (&stream->sidx_parser);
877   }
878
879   return TRUE;
880 }
881
882 static void
883 gst_dash_demux_send_content_protection_event (gpointer data, gpointer userdata)
884 {
885   GstMPDDescriptorTypeNode *cp = (GstMPDDescriptorTypeNode *) data;
886   GstDashDemuxStream *stream = (GstDashDemuxStream *) userdata;
887   GstEvent *event;
888   GstBuffer *pssi;
889   glong pssi_len;
890   gchar *schemeIdUri;
891   GstPad *pad = GST_ADAPTIVE_DEMUX_STREAM_PAD (stream);
892
893   if (cp->schemeIdUri == NULL)
894     return;
895
896   GST_TRACE_OBJECT (pad, "check schemeIdUri %s", cp->schemeIdUri);
897   /* RFC 2141 states: The leading "urn:" sequence is case-insensitive */
898   schemeIdUri = g_ascii_strdown (cp->schemeIdUri, -1);
899   if (g_str_has_prefix (schemeIdUri, "urn:uuid:")) {
900     pssi_len = strlen (cp->value);
901     pssi = gst_buffer_new_memdup (cp->value, pssi_len);
902     /* RFC 4122 states that the hex part of a UUID is in lower case,
903      * but some streams seem to ignore this and use upper case for the
904      * protection system ID */
905     event = gst_event_new_protection (cp->schemeIdUri + 9, pssi, "dash/mpd");
906     GST_LOG_OBJECT (pad,
907         "Queueing protection event %" GST_PTR_FORMAT " on source pad", event);
908     gst_adaptive_demux_stream_queue_event ((GstAdaptiveDemuxStream *) stream,
909         event);
910     gst_buffer_unref (pssi);
911   }
912   g_free (schemeIdUri);
913 }
914
915 static GstClockTime
916 gst_dash_demux_get_duration (GstAdaptiveDemux * ademux)
917 {
918   GstDashDemux *demux = GST_DASH_DEMUX_CAST (ademux);
919
920   g_return_val_if_fail (demux->client != NULL, GST_CLOCK_TIME_NONE);
921
922   return gst_mpd_client_get_media_presentation_duration (demux->client);
923 }
924
925 static gboolean
926 gst_dash_demux_is_live (GstAdaptiveDemux * ademux)
927 {
928   GstDashDemux *demux = GST_DASH_DEMUX_CAST (ademux);
929
930   g_return_val_if_fail (demux->client != NULL, FALSE);
931
932   return gst_mpd_client_is_live (demux->client);
933 }
934
935 static gboolean
936 gst_dash_demux_setup_streams (GstAdaptiveDemux * demux)
937 {
938   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
939   gboolean ret = TRUE;
940   GstDateTime *now = NULL;
941   guint period_idx;
942
943   /* setup video, audio and subtitle streams, starting from first Period if
944    * non-live */
945   period_idx = 0;
946   if (gst_mpd_client_is_live (dashdemux->client)) {
947     GDateTime *g_now;
948     if (dashdemux->client->mpd_root_node->availabilityStartTime == NULL) {
949       ret = FALSE;
950       GST_ERROR_OBJECT (demux, "MPD does not have availabilityStartTime");
951       goto done;
952     }
953     if (dashdemux->clock_drift == NULL) {
954       gchar **urls;
955       urls =
956           gst_mpd_client_get_utc_timing_sources (dashdemux->client,
957           SUPPORTED_CLOCK_FORMATS, NULL);
958       if (urls) {
959         GST_DEBUG_OBJECT (dashdemux, "Found a supported UTCTiming element");
960         dashdemux->clock_drift = gst_dash_demux_clock_drift_new (dashdemux);
961         gst_dash_demux_poll_clock_drift (dashdemux);
962       }
963     }
964     /* get period index for period encompassing the current time */
965     g_now = gst_dash_demux_get_server_now_utc (dashdemux);
966     now = gst_date_time_new_from_g_date_time (g_now);
967     if (dashdemux->client->mpd_root_node->suggestedPresentationDelay != -1) {
968       GstDateTime *target = gst_mpd_client_add_time_difference (now,
969           dashdemux->client->mpd_root_node->suggestedPresentationDelay * -1000);
970       gst_date_time_unref (now);
971       now = target;
972     } else if (dashdemux->default_presentation_delay) {
973       gint64 dfp =
974           gst_mpd_client_parse_default_presentation_delay (dashdemux->client,
975           dashdemux->default_presentation_delay);
976       GstDateTime *target = gst_mpd_client_add_time_difference (now,
977           dfp * -1000);
978       gst_date_time_unref (now);
979       now = target;
980     }
981     period_idx =
982         gst_mpd_client_get_period_index_at_time (dashdemux->client, now);
983     if (period_idx == G_MAXUINT) {
984 #ifndef GST_DISABLE_GST_DEBUG
985       gchar *date_str = gst_date_time_to_iso8601_string (now);
986       GST_DEBUG_OBJECT (demux, "Unable to find live period active at %s",
987           date_str);
988       g_free (date_str);
989 #endif
990       ret = FALSE;
991       goto done;
992     }
993   }
994
995   if (!gst_mpd_client_set_period_index (dashdemux->client, period_idx) ||
996       !gst_dash_demux_setup_all_streams (dashdemux)) {
997     ret = FALSE;
998     goto done;
999   }
1000
1001   /* If stream is live, try to find the segment that
1002    * is closest to current time */
1003   if (gst_mpd_client_is_live (dashdemux->client)) {
1004     GDateTime *gnow;
1005
1006     GST_DEBUG_OBJECT (demux, "Seeking to current time of day for live stream ");
1007
1008     gnow = gst_date_time_to_g_date_time (now);
1009     gst_mpd_client_seek_to_time (dashdemux->client, gnow);
1010     g_date_time_unref (gnow);
1011   } else {
1012     GST_DEBUG_OBJECT (demux, "Seeking to first segment for on-demand stream ");
1013
1014     /* start playing from the first segment */
1015     gst_mpd_client_seek_to_first_segment (dashdemux->client);
1016   }
1017
1018 done:
1019   if (now != NULL)
1020     gst_date_time_unref (now);
1021   return ret;
1022 }
1023
1024 static gboolean
1025 gst_dash_demux_process_manifest (GstAdaptiveDemux * demux, GstBuffer * buf)
1026 {
1027   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
1028   gboolean ret = FALSE;
1029   gchar *manifest;
1030   GstMapInfo mapinfo;
1031
1032   if (dashdemux->client)
1033     gst_mpd_client_free (dashdemux->client);
1034   dashdemux->client = gst_mpd_client_new ();
1035   gst_mpd_client_set_uri_downloader (dashdemux->client, demux->downloader);
1036
1037   dashdemux->client->mpd_uri = g_strdup (demux->manifest_uri);
1038   dashdemux->client->mpd_base_uri = g_strdup (demux->manifest_base_uri);
1039
1040   GST_DEBUG_OBJECT (demux, "Fetched MPD file at URI: %s (base: %s)",
1041       dashdemux->client->mpd_uri,
1042       GST_STR_NULL (dashdemux->client->mpd_base_uri));
1043
1044   if (gst_buffer_map (buf, &mapinfo, GST_MAP_READ)) {
1045     manifest = (gchar *) mapinfo.data;
1046     if (gst_mpd_client_parse (dashdemux->client, manifest, mapinfo.size)) {
1047       if (gst_mpd_client_setup_media_presentation (dashdemux->client, 0, 0,
1048               NULL)) {
1049         ret = TRUE;
1050       } else {
1051         GST_ELEMENT_ERROR (demux, STREAM, DECODE,
1052             ("Incompatible manifest file."), (NULL));
1053       }
1054     }
1055     gst_buffer_unmap (buf, &mapinfo);
1056   } else {
1057     GST_WARNING_OBJECT (demux, "Failed to map manifest buffer");
1058   }
1059
1060   if (ret)
1061     ret = gst_dash_demux_setup_streams (demux);
1062
1063   return ret;
1064 }
1065
1066 static GstPad *
1067 gst_dash_demux_create_pad (GstDashDemux * demux, GstActiveStream * stream)
1068 {
1069   GstPad *pad;
1070   GstPadTemplate *tmpl;
1071   gchar *name;
1072
1073   switch (stream->mimeType) {
1074     case GST_STREAM_AUDIO:
1075       name = g_strdup_printf ("audio_%02u", demux->n_audio_streams++);
1076       tmpl = gst_static_pad_template_get (&gst_dash_demux_audiosrc_template);
1077       break;
1078     case GST_STREAM_VIDEO:
1079       name = g_strdup_printf ("video_%02u", demux->n_video_streams++);
1080       tmpl = gst_static_pad_template_get (&gst_dash_demux_videosrc_template);
1081       break;
1082     case GST_STREAM_APPLICATION:
1083       if (gst_mpd_client_active_stream_contains_subtitles (stream)) {
1084         name = g_strdup_printf ("subtitle_%02u", demux->n_subtitle_streams++);
1085         tmpl =
1086             gst_static_pad_template_get (&gst_dash_demux_subtitlesrc_template);
1087       } else {
1088         return NULL;
1089       }
1090       break;
1091     default:
1092       g_assert_not_reached ();
1093       return NULL;
1094   }
1095
1096   /* Create and activate new pads */
1097   pad = gst_pad_new_from_template (tmpl, name);
1098   g_free (name);
1099   gst_object_unref (tmpl);
1100
1101   gst_pad_set_active (pad, TRUE);
1102   GST_INFO_OBJECT (demux, "Creating srcpad %s:%s", GST_DEBUG_PAD_NAME (pad));
1103   return pad;
1104 }
1105
1106 static void
1107 gst_dash_demux_reset (GstAdaptiveDemux * ademux)
1108 {
1109   GstDashDemux *demux = GST_DASH_DEMUX_CAST (ademux);
1110
1111   GST_DEBUG_OBJECT (demux, "Resetting demux");
1112
1113   demux->end_of_period = FALSE;
1114   demux->end_of_manifest = FALSE;
1115
1116   if (demux->client) {
1117     gst_mpd_client_free (demux->client);
1118     demux->client = NULL;
1119   }
1120   gst_dash_demux_clock_drift_free (demux->clock_drift);
1121   demux->clock_drift = NULL;
1122   demux->client = gst_mpd_client_new ();
1123   gst_mpd_client_set_uri_downloader (demux->client, ademux->downloader);
1124
1125   demux->n_audio_streams = 0;
1126   demux->n_video_streams = 0;
1127   demux->n_subtitle_streams = 0;
1128
1129   demux->trickmode_no_audio = FALSE;
1130   demux->allow_trickmode_key_units = TRUE;
1131 }
1132
1133 static GstCaps *
1134 gst_dash_demux_get_video_input_caps (GstDashDemux * demux,
1135     GstActiveStream * stream)
1136 {
1137   guint width = 0, height = 0;
1138   gint fps_num = 0, fps_den = 1;
1139   gboolean have_fps = FALSE;
1140   GstCaps *caps = NULL;
1141
1142   if (stream == NULL)
1143     return NULL;
1144
1145   /* if bitstreamSwitching is true we don't need to switch pads on resolution change */
1146   if (!gst_mpd_client_get_bitstream_switching_flag (stream)) {
1147     width = gst_mpd_client_get_video_stream_width (stream);
1148     height = gst_mpd_client_get_video_stream_height (stream);
1149     have_fps =
1150         gst_mpd_client_get_video_stream_framerate (stream, &fps_num, &fps_den);
1151   }
1152   caps = gst_mpd_client_get_stream_caps (stream);
1153   if (caps == NULL)
1154     return NULL;
1155
1156   if (width > 0 && height > 0) {
1157     gst_caps_set_simple (caps, "width", G_TYPE_INT, width, "height",
1158         G_TYPE_INT, height, NULL);
1159   }
1160
1161   if (have_fps) {
1162     gst_caps_set_simple (caps, "framerate", GST_TYPE_FRACTION, fps_num,
1163         fps_den, NULL);
1164   }
1165
1166   return caps;
1167 }
1168
1169 static GstCaps *
1170 gst_dash_demux_get_audio_input_caps (GstDashDemux * demux,
1171     GstActiveStream * stream)
1172 {
1173   guint rate = 0, channels = 0;
1174   GstCaps *caps = NULL;
1175
1176   if (stream == NULL)
1177     return NULL;
1178
1179   /* if bitstreamSwitching is true we don't need to switch pads on rate/channels change */
1180   if (!gst_mpd_client_get_bitstream_switching_flag (stream)) {
1181     channels = gst_mpd_client_get_audio_stream_num_channels (stream);
1182     rate = gst_mpd_client_get_audio_stream_rate (stream);
1183   }
1184   caps = gst_mpd_client_get_stream_caps (stream);
1185   if (caps == NULL)
1186     return NULL;
1187
1188   if (rate > 0) {
1189     gst_caps_set_simple (caps, "rate", G_TYPE_INT, rate, NULL);
1190   }
1191   if (channels > 0) {
1192     gst_caps_set_simple (caps, "channels", G_TYPE_INT, channels, NULL);
1193   }
1194
1195   return caps;
1196 }
1197
1198 static GstCaps *
1199 gst_dash_demux_get_application_input_caps (GstDashDemux * demux,
1200     GstActiveStream * stream)
1201 {
1202   GstCaps *caps = NULL;
1203
1204   if (stream == NULL)
1205     return NULL;
1206
1207   caps = gst_mpd_client_get_stream_caps (stream);
1208   if (caps == NULL)
1209     return NULL;
1210
1211   return caps;
1212 }
1213
1214 static GstCaps *
1215 gst_dash_demux_get_input_caps (GstDashDemux * demux, GstActiveStream * stream)
1216 {
1217   switch (stream->mimeType) {
1218     case GST_STREAM_VIDEO:
1219       return gst_dash_demux_get_video_input_caps (demux, stream);
1220     case GST_STREAM_AUDIO:
1221       return gst_dash_demux_get_audio_input_caps (demux, stream);
1222     case GST_STREAM_APPLICATION:
1223       return gst_dash_demux_get_application_input_caps (demux, stream);
1224     default:
1225       return GST_CAPS_NONE;
1226   }
1227 }
1228
1229 static void
1230 gst_dash_demux_stream_update_headers_info (GstAdaptiveDemuxStream * stream)
1231 {
1232   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1233   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
1234   gchar *path = NULL;
1235
1236   gst_mpd_client_get_next_header (dashdemux->client,
1237       &path, dashstream->index,
1238       &stream->fragment.header_range_start, &stream->fragment.header_range_end);
1239
1240   if (path != NULL) {
1241     stream->fragment.header_uri =
1242         gst_uri_join_strings (gst_mpd_client_get_baseURL (dashdemux->client,
1243             dashstream->index), path);
1244     g_free (path);
1245     path = NULL;
1246   }
1247
1248   gst_mpd_client_get_next_header_index (dashdemux->client,
1249       &path, dashstream->index,
1250       &stream->fragment.index_range_start, &stream->fragment.index_range_end);
1251
1252   if (path != NULL) {
1253     stream->fragment.index_uri =
1254         gst_uri_join_strings (gst_mpd_client_get_baseURL (dashdemux->client,
1255             dashstream->index), path);
1256     g_free (path);
1257   }
1258 }
1259
1260 static GstFlowReturn
1261 gst_dash_demux_stream_update_fragment_info (GstAdaptiveDemuxStream * stream)
1262 {
1263   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1264   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
1265   GstClockTime ts;
1266   GstMediaFragmentInfo fragment;
1267   gboolean isombff;
1268
1269   gst_adaptive_demux_stream_fragment_clear (&stream->fragment);
1270
1271   isombff = gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client);
1272
1273   /* Reset chunk size if any */
1274   stream->fragment.chunk_size = 0;
1275   dashstream->current_fragment_keyframe_distance = GST_CLOCK_TIME_NONE;
1276
1277   if (GST_ADAPTIVE_DEMUX_STREAM_NEED_HEADER (stream) && isombff) {
1278     gst_dash_demux_stream_update_headers_info (stream);
1279     /* sidx entries may not be available in here */
1280     if (stream->fragment.index_uri
1281         && dashstream->sidx_position != GST_CLOCK_TIME_NONE) {
1282       /* request only the index to be downloaded as we need to reposition the
1283        * stream to a subsegment */
1284       return GST_FLOW_OK;
1285     }
1286   }
1287
1288   if (dashstream->moof_sync_samples
1289       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux)) {
1290     GstDashStreamSyncSample *sync_sample =
1291         &g_array_index (dashstream->moof_sync_samples, GstDashStreamSyncSample,
1292         dashstream->current_sync_sample);
1293
1294     gst_mpd_client_get_next_fragment (dashdemux->client, dashstream->index,
1295         &fragment);
1296
1297     if (isombff && dashstream->sidx_position != GST_CLOCK_TIME_NONE
1298         && SIDX (dashstream)->entries) {
1299       GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dashstream);
1300       dashstream->current_fragment_timestamp = fragment.timestamp = entry->pts;
1301       dashstream->current_fragment_duration = fragment.duration =
1302           entry->duration;
1303     } else {
1304       dashstream->current_fragment_timestamp = fragment.timestamp;
1305       dashstream->current_fragment_duration = fragment.duration;
1306     }
1307
1308     dashstream->current_fragment_keyframe_distance =
1309         fragment.duration / dashstream->moof_sync_samples->len;
1310     dashstream->actual_position =
1311         fragment.timestamp +
1312         dashstream->current_sync_sample *
1313         dashstream->current_fragment_keyframe_distance;
1314     if (stream->segment.rate < 0.0)
1315       dashstream->actual_position +=
1316           dashstream->current_fragment_keyframe_distance;
1317     dashstream->actual_position =
1318         MIN (dashstream->actual_position,
1319         fragment.timestamp + fragment.duration);
1320
1321     stream->fragment.uri = fragment.uri;
1322     stream->fragment.timestamp = GST_CLOCK_TIME_NONE;
1323     stream->fragment.duration = GST_CLOCK_TIME_NONE;
1324     stream->fragment.range_start = sync_sample->start_offset;
1325     stream->fragment.range_end = sync_sample->end_offset;
1326
1327     GST_DEBUG_OBJECT (stream->pad, "Actual position %" GST_TIME_FORMAT,
1328         GST_TIME_ARGS (dashstream->actual_position));
1329
1330     return GST_FLOW_OK;
1331   }
1332
1333   if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
1334           dashstream->index, &ts)) {
1335     if (GST_ADAPTIVE_DEMUX_STREAM_NEED_HEADER (stream)) {
1336       gst_adaptive_demux_stream_fragment_clear (&stream->fragment);
1337       gst_dash_demux_stream_update_headers_info (stream);
1338     }
1339
1340     gst_mpd_client_get_next_fragment (dashdemux->client, dashstream->index,
1341         &fragment);
1342
1343     stream->fragment.uri = fragment.uri;
1344     /* If mpd does not specify indexRange (i.e., null index_uri),
1345      * sidx entries may not be available until download it */
1346     if (isombff && dashstream->sidx_position != GST_CLOCK_TIME_NONE
1347         && SIDX (dashstream)->entries) {
1348       GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dashstream);
1349       stream->fragment.range_start =
1350           dashstream->sidx_base_offset + entry->offset;
1351       dashstream->actual_position = stream->fragment.timestamp = entry->pts;
1352       dashstream->current_fragment_timestamp = stream->fragment.timestamp =
1353           entry->pts;
1354       dashstream->current_fragment_duration = stream->fragment.duration =
1355           entry->duration;
1356       if (stream->demux->segment.rate < 0.0) {
1357         stream->fragment.range_end =
1358             stream->fragment.range_start + entry->size - 1;
1359         dashstream->actual_position += entry->duration;
1360       } else {
1361         stream->fragment.range_end = fragment.range_end;
1362       }
1363     } else {
1364       dashstream->actual_position = stream->fragment.timestamp =
1365           fragment.timestamp;
1366       dashstream->current_fragment_timestamp = fragment.timestamp;
1367       dashstream->current_fragment_duration = stream->fragment.duration =
1368           fragment.duration;
1369       if (stream->demux->segment.rate < 0.0)
1370         dashstream->actual_position += fragment.duration;
1371       stream->fragment.range_start =
1372           MAX (fragment.range_start, dashstream->sidx_base_offset);
1373       stream->fragment.range_end = fragment.range_end;
1374     }
1375
1376     GST_DEBUG_OBJECT (stream->pad, "Actual position %" GST_TIME_FORMAT,
1377         GST_TIME_ARGS (dashstream->actual_position));
1378
1379     return GST_FLOW_OK;
1380   }
1381
1382   return GST_FLOW_EOS;
1383 }
1384
1385 static gint
1386 gst_dash_demux_index_entry_search (GstSidxBoxEntry * entry, GstClockTime * ts,
1387     gpointer user_data)
1388 {
1389   GstClockTime entry_ts = entry->pts + entry->duration;
1390   if (entry_ts <= *ts)
1391     return -1;
1392   else if (entry->pts > *ts)
1393     return 1;
1394   else
1395     return 0;
1396 }
1397
1398 static GstFlowReturn
1399 gst_dash_demux_stream_sidx_seek (GstDashDemuxStream * dashstream,
1400     gboolean forward, GstSeekFlags flags, GstClockTime ts,
1401     GstClockTime * final_ts)
1402 {
1403   GstSidxBox *sidx = SIDX (dashstream);
1404   GstSidxBoxEntry *entry;
1405   gint idx = sidx->entries_count;
1406   GstFlowReturn ret = GST_FLOW_OK;
1407
1408   if (sidx->entries_count == 0)
1409     return GST_FLOW_EOS;
1410
1411   entry =
1412       gst_util_array_binary_search (sidx->entries, sidx->entries_count,
1413       sizeof (GstSidxBoxEntry),
1414       (GCompareDataFunc) gst_dash_demux_index_entry_search,
1415       GST_SEARCH_MODE_EXACT, &ts, NULL);
1416
1417   /* No exact match found, nothing in our index
1418    * This is usually a bug or broken stream, as the seeking code already
1419    * makes sure that we're in the correct period and segment, and only need
1420    * to find the correct place inside the segment. Allow for some rounding
1421    * errors and inaccuracies here though */
1422   if (!entry) {
1423     GstSidxBoxEntry *last_entry = &sidx->entries[sidx->entries_count - 1];
1424
1425     GST_WARNING_OBJECT (dashstream->parent.pad, "Couldn't find SIDX entry");
1426
1427     if (ts < sidx->entries[0].pts
1428         && ts + 250 * GST_MSECOND >= sidx->entries[0].pts)
1429       entry = &sidx->entries[0];
1430     else if (ts >= last_entry->pts + last_entry->duration &&
1431         ts < last_entry->pts + last_entry->duration + 250 * GST_MSECOND)
1432       entry = last_entry;
1433   }
1434   if (!entry)
1435     return GST_FLOW_EOS;
1436
1437   idx = entry - sidx->entries;
1438
1439   /* FIXME in reverse mode, if we are exactly at a fragment start it makes more
1440    * sense to start from the end of the previous fragment */
1441   if (!forward && idx > 0 && entry->pts == ts) {
1442     idx--;
1443     entry = &sidx->entries[idx];
1444   }
1445
1446   /* Now entry->pts <= ts < entry->pts + entry->duration, need to adjust for
1447    * snapping */
1448   if ((flags & GST_SEEK_FLAG_SNAP_NEAREST) == GST_SEEK_FLAG_SNAP_NEAREST) {
1449     if (idx + 1 < sidx->entries_count
1450         && sidx->entries[idx + 1].pts - ts < ts - sidx->entries[idx].pts)
1451       idx += 1;
1452   } else if ((forward && (flags & GST_SEEK_FLAG_SNAP_AFTER)) || (!forward
1453           && (flags & GST_SEEK_FLAG_SNAP_BEFORE))) {
1454     if (idx + 1 < sidx->entries_count && entry->pts < ts)
1455       idx += 1;
1456   }
1457
1458   g_assert (sidx->entry_index < sidx->entries_count);
1459
1460   sidx->entry_index = idx;
1461   dashstream->sidx_position = sidx->entries[idx].pts;
1462
1463   if (final_ts)
1464     *final_ts = dashstream->sidx_position;
1465
1466   return ret;
1467 }
1468
1469 static GstFlowReturn
1470 gst_dash_demux_stream_seek (GstAdaptiveDemuxStream * stream, gboolean forward,
1471     GstSeekFlags flags, GstClockTime ts, GstClockTime * final_ts)
1472 {
1473   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1474   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
1475   gint last_index, last_repeat;
1476   gboolean is_isobmff;
1477
1478   last_index = dashstream->active_stream->segment_index;
1479   last_repeat = dashstream->active_stream->segment_repeat_index;
1480
1481   if (dashstream->adapter)
1482     gst_adapter_clear (dashstream->adapter);
1483   dashstream->current_offset = -1;
1484   dashstream->current_index_header_or_data = 0;
1485
1486   dashstream->isobmff_parser.current_fourcc = 0;
1487   dashstream->isobmff_parser.current_start_offset = 0;
1488   dashstream->isobmff_parser.current_size = 0;
1489
1490   if (dashstream->moof)
1491     gst_isoff_moof_box_free (dashstream->moof);
1492   dashstream->moof = NULL;
1493   if (dashstream->moof_sync_samples)
1494     g_array_free (dashstream->moof_sync_samples, TRUE);
1495   dashstream->moof_sync_samples = NULL;
1496   dashstream->current_sync_sample = -1;
1497   dashstream->target_time = GST_CLOCK_TIME_NONE;
1498
1499   is_isobmff = gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client);
1500
1501   if (!gst_mpd_client_stream_seek (dashdemux->client, dashstream->active_stream,
1502           forward,
1503           is_isobmff ? (flags & (~(GST_SEEK_FLAG_SNAP_BEFORE |
1504                       GST_SEEK_FLAG_SNAP_AFTER))) : flags, ts, final_ts)) {
1505     return GST_FLOW_EOS;
1506   }
1507
1508   if (is_isobmff) {
1509     GstClockTime period_start, offset;
1510
1511     period_start = gst_mpd_client_get_period_start_time (dashdemux->client);
1512     offset =
1513         gst_mpd_client_get_stream_presentation_offset (dashdemux->client,
1514         dashstream->index);
1515
1516     if (G_UNLIKELY (ts < period_start))
1517       ts = offset;
1518     else
1519       ts += offset - period_start;
1520
1521     if (last_index != dashstream->active_stream->segment_index ||
1522         last_repeat != dashstream->active_stream->segment_repeat_index) {
1523       GST_LOG_OBJECT (stream->pad,
1524           "Segment index was changed, reset sidx parser");
1525       gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
1526       dashstream->sidx_base_offset = 0;
1527       dashstream->allow_sidx = TRUE;
1528     }
1529
1530     if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
1531       if (gst_dash_demux_stream_sidx_seek (dashstream, forward, flags, ts,
1532               final_ts) != GST_FLOW_OK) {
1533         GST_ERROR_OBJECT (stream->pad, "Couldn't find position in sidx");
1534         dashstream->sidx_position = GST_CLOCK_TIME_NONE;
1535         gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
1536       }
1537       dashstream->pending_seek_ts = GST_CLOCK_TIME_NONE;
1538     } else {
1539       /* no index yet, seek when we have it */
1540       /* FIXME - the final_ts won't be correct here */
1541       dashstream->pending_seek_ts = ts;
1542     }
1543   }
1544
1545   stream->discont = TRUE;
1546
1547   return GST_FLOW_OK;
1548 }
1549
1550 static gboolean
1551 gst_dash_demux_stream_has_next_sync_sample (GstAdaptiveDemuxStream * stream)
1552 {
1553   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1554
1555   if (dashstream->moof_sync_samples &&
1556       GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)) {
1557     if (stream->demux->segment.rate > 0.0) {
1558       if (dashstream->current_sync_sample + 1 <
1559           dashstream->moof_sync_samples->len)
1560         return TRUE;
1561     } else {
1562       if (dashstream->current_sync_sample >= 1)
1563         return TRUE;
1564     }
1565   }
1566   return FALSE;
1567 }
1568
1569 static gboolean
1570 gst_dash_demux_stream_has_next_subfragment (GstAdaptiveDemuxStream * stream)
1571 {
1572   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1573   GstSidxBox *sidx = SIDX (dashstream);
1574
1575   if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
1576     if (stream->demux->segment.rate > 0.0) {
1577       if (sidx->entry_index + 1 < sidx->entries_count)
1578         return TRUE;
1579     } else {
1580       if (sidx->entry_index >= 1)
1581         return TRUE;
1582     }
1583   }
1584   return FALSE;
1585 }
1586
1587 static gboolean
1588 gst_dash_demux_stream_advance_sync_sample (GstAdaptiveDemuxStream * stream,
1589     GstClockTime target_time)
1590 {
1591   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1592   gboolean fragment_finished = FALSE;
1593   guint idx = -1;
1594
1595   if (GST_CLOCK_TIME_IS_VALID (target_time)) {
1596     GST_LOG_OBJECT (stream->pad,
1597         "target_time:%" GST_TIME_FORMAT " fragment ts %" GST_TIME_FORMAT
1598         " average keyframe dist: %" GST_TIME_FORMAT
1599         " current keyframe dist: %" GST_TIME_FORMAT
1600         " fragment duration:%" GST_TIME_FORMAT,
1601         GST_TIME_ARGS (target_time),
1602         GST_TIME_ARGS (dashstream->current_fragment_timestamp),
1603         GST_TIME_ARGS (dashstream->keyframe_average_distance),
1604         GST_TIME_ARGS (dashstream->current_fragment_keyframe_distance),
1605         GST_TIME_ARGS (stream->fragment.duration));
1606
1607     if (stream->demux->segment.rate > 0.0) {
1608       idx =
1609           (target_time -
1610           dashstream->current_fragment_timestamp) /
1611           dashstream->current_fragment_keyframe_distance;
1612
1613       /* Prevent getting stuck in a loop due to rounding errors */
1614       if (idx == dashstream->current_sync_sample)
1615         idx++;
1616     } else {
1617       GstClockTime end_time =
1618           dashstream->current_fragment_timestamp +
1619           dashstream->current_fragment_duration;
1620
1621       if (end_time < target_time) {
1622         idx = dashstream->moof_sync_samples->len;
1623       } else {
1624         idx =
1625             (end_time -
1626             target_time) / dashstream->current_fragment_keyframe_distance;
1627         if (idx == dashstream->moof_sync_samples->len) {
1628           dashstream->current_sync_sample = -1;
1629           fragment_finished = TRUE;
1630           goto beach;
1631         }
1632         idx = dashstream->moof_sync_samples->len - 1 - idx;
1633       }
1634
1635       /* Prevent getting stuck in a loop due to rounding errors */
1636       if (idx == dashstream->current_sync_sample) {
1637         if (idx == 0) {
1638           dashstream->current_sync_sample = -1;
1639           fragment_finished = TRUE;
1640           goto beach;
1641         }
1642
1643         idx--;
1644       }
1645     }
1646   }
1647
1648   GST_DEBUG_OBJECT (stream->pad,
1649       "Advancing sync sample #%d target #%d",
1650       dashstream->current_sync_sample, idx);
1651
1652   if (idx != -1 && idx >= dashstream->moof_sync_samples->len) {
1653     dashstream->current_sync_sample = -1;
1654     fragment_finished = TRUE;
1655     goto beach;
1656   }
1657
1658   if (stream->demux->segment.rate > 0.0) {
1659     /* Try to get the sync sample for the target time */
1660     if (idx != -1) {
1661       dashstream->current_sync_sample = idx;
1662     } else {
1663       dashstream->current_sync_sample++;
1664       if (dashstream->current_sync_sample >= dashstream->moof_sync_samples->len) {
1665         fragment_finished = TRUE;
1666       }
1667     }
1668   } else {
1669     if (idx != -1) {
1670       dashstream->current_sync_sample = idx;
1671     } else if (dashstream->current_sync_sample == -1) {
1672       dashstream->current_sync_sample = dashstream->moof_sync_samples->len - 1;
1673     } else if (dashstream->current_sync_sample == 0) {
1674       dashstream->current_sync_sample = -1;
1675       fragment_finished = TRUE;
1676     } else {
1677       dashstream->current_sync_sample--;
1678     }
1679   }
1680
1681 beach:
1682   GST_DEBUG_OBJECT (stream->pad,
1683       "Advancing sync sample #%d fragment_finished:%d",
1684       dashstream->current_sync_sample, fragment_finished);
1685
1686   if (!fragment_finished)
1687     stream->discont = TRUE;
1688
1689   return !fragment_finished;
1690 }
1691
1692 static gboolean
1693 gst_dash_demux_stream_advance_subfragment (GstAdaptiveDemuxStream * stream)
1694 {
1695   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1696
1697   GstSidxBox *sidx = SIDX (dashstream);
1698   gboolean fragment_finished = TRUE;
1699
1700   if (dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
1701     if (stream->demux->segment.rate > 0.0) {
1702       gint idx = ++sidx->entry_index;
1703       if (idx < sidx->entries_count) {
1704         fragment_finished = FALSE;
1705       }
1706
1707       if (idx == sidx->entries_count)
1708         dashstream->sidx_position =
1709             sidx->entries[idx - 1].pts + sidx->entries[idx - 1].duration;
1710       else
1711         dashstream->sidx_position = sidx->entries[idx].pts;
1712     } else {
1713       gint idx = --sidx->entry_index;
1714
1715       if (idx >= 0) {
1716         fragment_finished = FALSE;
1717         dashstream->sidx_position = sidx->entries[idx].pts;
1718       } else {
1719         dashstream->sidx_position = GST_CLOCK_TIME_NONE;
1720       }
1721     }
1722   }
1723
1724   GST_DEBUG_OBJECT (stream->pad, "New sidx index: %d / %d. "
1725       "Finished fragment: %d", sidx->entry_index, sidx->entries_count,
1726       fragment_finished);
1727
1728   return !fragment_finished;
1729 }
1730
1731 static gboolean
1732 gst_dash_demux_stream_has_next_fragment (GstAdaptiveDemuxStream * stream)
1733 {
1734   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
1735   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1736
1737   if (dashstream->moof_sync_samples &&
1738       GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux)) {
1739     if (gst_dash_demux_stream_has_next_sync_sample (stream))
1740       return TRUE;
1741   }
1742
1743   if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
1744     if (gst_dash_demux_stream_has_next_subfragment (stream))
1745       return TRUE;
1746   }
1747
1748   return gst_mpd_client_has_next_segment (dashdemux->client,
1749       dashstream->active_stream, stream->demux->segment.rate > 0.0);
1750 }
1751
1752 /* The goal here is to figure out, once we have pushed a keyframe downstream,
1753  * what the next ideal keyframe to download is.
1754  * 
1755  * This is done based on:
1756  * * the current internal position (i.e. actual_position)
1757  * * the reported downstream position (QoS feedback)
1758  * * the average keyframe download time (average_download_time)
1759  */
1760 static GstClockTime
1761 gst_dash_demux_stream_get_target_time (GstDashDemux * dashdemux,
1762     GstAdaptiveDemuxStream * stream, GstClockTime cur_position,
1763     GstClockTime min_skip)
1764 {
1765   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1766   GstClockTime cur_running, min_running, min_position;
1767   GstClockTimeDiff diff;
1768   GstClockTime ret = cur_position;
1769   GstClockTime deadline;
1770   GstClockTime upstream_earliest_time;
1771   GstClockTime earliest_time = GST_CLOCK_TIME_NONE;
1772
1773   g_assert (min_skip > 0);
1774
1775   /* minimum stream position we have to skip to */
1776   if (stream->segment.rate > 0)
1777     min_position = cur_position + min_skip;
1778   else if (cur_position < min_skip)
1779     min_position = 0;
1780   else
1781     min_position = cur_position - min_skip;
1782
1783   /* Use current clock time or the QoS earliest time, whichever is further in
1784    * the future. The QoS time is only updated on every QoS event and
1785    * especially not if e.g. a videodecoder or converter drops a frame further
1786    * downstream.
1787    *
1788    * We only use the times if we ever received a QoS event since the last
1789    * flush, as otherwise base_time and clock might not be correct because of a
1790    * still pre-rolling sink
1791    */
1792   upstream_earliest_time =
1793       gst_adaptive_demux_get_qos_earliest_time ((GstAdaptiveDemux *) dashdemux);
1794   if (upstream_earliest_time != GST_CLOCK_TIME_NONE) {
1795     GstClock *clock;
1796
1797     clock = gst_element_get_clock (GST_ELEMENT_CAST (dashdemux));
1798
1799     if (clock) {
1800       GstClockTime base_time;
1801       GstClockTime now_time;
1802
1803       base_time = gst_element_get_base_time (GST_ELEMENT_CAST (dashdemux));
1804       now_time = gst_clock_get_time (clock);
1805       if (now_time > base_time)
1806         now_time -= base_time;
1807       else
1808         now_time = 0;
1809
1810       gst_object_unref (clock);
1811
1812       earliest_time = MAX (now_time, upstream_earliest_time);
1813     } else {
1814       earliest_time = upstream_earliest_time;
1815     }
1816   }
1817
1818   /* our current position in running time */
1819   cur_running =
1820       gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
1821       cur_position);
1822
1823   /* the minimum position we have to skip to in running time */
1824   min_running =
1825       gst_segment_to_running_time (&stream->segment, GST_FORMAT_TIME,
1826       min_position);
1827
1828   GST_DEBUG_OBJECT (stream->pad,
1829       "position: current %" GST_TIME_FORMAT " min next %" GST_TIME_FORMAT,
1830       GST_TIME_ARGS (cur_position), GST_TIME_ARGS (min_position));
1831   GST_DEBUG_OBJECT (stream->pad,
1832       "running time: current %" GST_TIME_FORMAT " min next %" GST_TIME_FORMAT
1833       " earliest %" GST_TIME_FORMAT, GST_TIME_ARGS (cur_running),
1834       GST_TIME_ARGS (min_running), GST_TIME_ARGS (earliest_time));
1835
1836   /* Take configured maximum video bandwidth and framerate into account */
1837   {
1838     GstClockTime min_run_dist, min_frame_dist, diff = 0;
1839     guint max_fps_n, max_fps_d;
1840
1841     min_run_dist = min_skip / ABS (stream->segment.rate);
1842
1843     if (dashdemux->max_video_framerate_n != 0) {
1844       max_fps_n = dashdemux->max_video_framerate_n;
1845       max_fps_d = dashdemux->max_video_framerate_d;
1846     } else {
1847       /* more than 10 fps is not very useful if we're skipping anyway */
1848       max_fps_n = 10;
1849       max_fps_d = 1;
1850     }
1851
1852     min_frame_dist = gst_util_uint64_scale_ceil (GST_SECOND,
1853         max_fps_d, max_fps_n);
1854
1855     GST_DEBUG_OBJECT (stream->pad,
1856         "Have max framerate %d/%d - Min dist %" GST_TIME_FORMAT
1857         ", min requested dist %" GST_TIME_FORMAT,
1858         max_fps_n, max_fps_d,
1859         GST_TIME_ARGS (min_run_dist), GST_TIME_ARGS (min_frame_dist));
1860     if (min_frame_dist > min_run_dist)
1861       diff = MAX (diff, min_frame_dist - min_run_dist);
1862
1863     if (dashdemux->max_bitrate != 0) {
1864       guint64 max_bitrate = gst_util_uint64_scale_ceil (GST_SECOND,
1865           8 * dashstream->keyframe_average_size,
1866           dashstream->keyframe_average_distance) * ABS (stream->segment.rate);
1867
1868       if (max_bitrate > dashdemux->max_bitrate) {
1869         min_frame_dist = gst_util_uint64_scale_ceil (GST_SECOND,
1870             8 * dashstream->keyframe_average_size,
1871             dashdemux->max_bitrate) * ABS (stream->segment.rate);
1872
1873         GST_DEBUG_OBJECT (stream->pad,
1874             "Have max bitrate %u - Min dist %" GST_TIME_FORMAT
1875             ", min requested dist %" GST_TIME_FORMAT, dashdemux->max_bitrate,
1876             GST_TIME_ARGS (min_run_dist), GST_TIME_ARGS (min_frame_dist));
1877         if (min_frame_dist > min_run_dist)
1878           diff = MAX (diff, min_frame_dist - min_run_dist);
1879       }
1880     }
1881
1882     if (diff > 0) {
1883       GST_DEBUG_OBJECT (stream->pad,
1884           "Skipping further ahead by %" GST_TIME_FORMAT, GST_TIME_ARGS (diff));
1885       min_running += diff;
1886     }
1887   }
1888
1889   if (earliest_time == GST_CLOCK_TIME_NONE) {
1890     GstClockTime run_key_dist;
1891
1892     run_key_dist =
1893         dashstream->keyframe_average_distance / ABS (stream->segment.rate);
1894
1895     /* If we don't have downstream information (such as at startup or
1896      * without live sinks), just get the next time by taking the minimum
1897      * amount we have to skip ahead
1898      * Except if it takes us longer to download */
1899     if (run_key_dist > dashstream->average_download_time)
1900       ret =
1901           gst_segment_position_from_running_time (&stream->segment,
1902           GST_FORMAT_TIME, min_running);
1903     else
1904       ret = gst_segment_position_from_running_time (&stream->segment,
1905           GST_FORMAT_TIME,
1906           min_running - run_key_dist + dashstream->average_download_time);
1907
1908     GST_DEBUG_OBJECT (stream->pad,
1909         "Advancing to %" GST_TIME_FORMAT " (was %" GST_TIME_FORMAT ")",
1910         GST_TIME_ARGS (ret), GST_TIME_ARGS (min_position));
1911
1912     goto out;
1913   }
1914
1915   /* Figure out the difference, in running time, between where we are and
1916    * where downstream is */
1917   diff = min_running - earliest_time;
1918   GST_LOG_OBJECT (stream->pad,
1919       "min_running %" GST_TIME_FORMAT " diff %" GST_STIME_FORMAT
1920       " average_download %" GST_TIME_FORMAT, GST_TIME_ARGS (min_running),
1921       GST_STIME_ARGS (diff), GST_TIME_ARGS (dashstream->average_download_time));
1922
1923   /* Have at least 500ms or 3 keyframes safety between current position and downstream */
1924   deadline = MAX (500 * GST_MSECOND, 3 * dashstream->average_download_time);
1925
1926   /* The furthest away we are from the current position, the least we need to advance */
1927   if (diff < 0 || diff < deadline) {
1928     /* Force skipping (but not more than 1s ahead) */
1929     ret =
1930         gst_segment_position_from_running_time (&stream->segment,
1931         GST_FORMAT_TIME, earliest_time + MIN (deadline, GST_SECOND));
1932     GST_DEBUG_OBJECT (stream->pad,
1933         "MUST SKIP to at least %" GST_TIME_FORMAT " (was %" GST_TIME_FORMAT ")",
1934         GST_TIME_ARGS (ret), GST_TIME_ARGS (min_position));
1935   } else if (diff < 4 * dashstream->average_download_time) {
1936     /* Go forward a bit less aggressively (and at most 1s forward) */
1937     ret = gst_segment_position_from_running_time (&stream->segment,
1938         GST_FORMAT_TIME, min_running + MIN (GST_SECOND,
1939             2 * dashstream->average_download_time));
1940     GST_DEBUG_OBJECT (stream->pad,
1941         "MUST SKIP to at least %" GST_TIME_FORMAT " (was %" GST_TIME_FORMAT ")",
1942         GST_TIME_ARGS (ret), GST_TIME_ARGS (min_position));
1943   } else {
1944     /* Get the next position satisfying the download time */
1945     ret = gst_segment_position_from_running_time (&stream->segment,
1946         GST_FORMAT_TIME, min_running);
1947     GST_DEBUG_OBJECT (stream->pad,
1948         "Advance to %" GST_TIME_FORMAT " (was %" GST_TIME_FORMAT ")",
1949         GST_TIME_ARGS (ret), GST_TIME_ARGS (min_position));
1950   }
1951
1952 out:
1953
1954   {
1955     GstClockTime cur_skip =
1956         (cur_position < ret) ? ret - cur_position : cur_position - ret;
1957
1958     if (dashstream->average_skip_size == 0) {
1959       dashstream->average_skip_size = cur_skip;
1960     } else {
1961       dashstream->average_skip_size =
1962           (cur_skip + 3 * dashstream->average_skip_size) / 4;
1963     }
1964
1965     if (dashstream->average_skip_size >
1966         cur_skip + dashstream->keyframe_average_distance
1967         && dashstream->average_skip_size > min_skip) {
1968       if (stream->segment.rate > 0)
1969         ret = cur_position + dashstream->average_skip_size;
1970       else if (cur_position > dashstream->average_skip_size)
1971         ret = cur_position - dashstream->average_skip_size;
1972       else
1973         ret = 0;
1974     }
1975   }
1976
1977   return ret;
1978 }
1979
1980 static GstFlowReturn
1981 gst_dash_demux_stream_advance_fragment (GstAdaptiveDemuxStream * stream)
1982 {
1983   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
1984   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
1985   GstClockTime target_time = GST_CLOCK_TIME_NONE;
1986   GstClockTime previous_position;
1987   GstFlowReturn ret;
1988
1989   GST_DEBUG_OBJECT (stream->pad, "Advance fragment");
1990
1991   /* Update download statistics */
1992   if (dashstream->moof_sync_samples &&
1993       GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux) &&
1994       GST_CLOCK_TIME_IS_VALID (stream->last_download_time)) {
1995     if (GST_CLOCK_TIME_IS_VALID (dashstream->average_download_time)) {
1996       dashstream->average_download_time =
1997           (3 * dashstream->average_download_time +
1998           stream->last_download_time) / 4;
1999     } else {
2000       dashstream->average_download_time = stream->last_download_time;
2001     }
2002
2003     GST_DEBUG_OBJECT (stream->pad,
2004         "Download time last: %" GST_TIME_FORMAT " average: %" GST_TIME_FORMAT,
2005         GST_TIME_ARGS (stream->last_download_time),
2006         GST_TIME_ARGS (dashstream->average_download_time));
2007   }
2008
2009   previous_position = dashstream->actual_position;
2010
2011   /* Update internal position */
2012   if (GST_CLOCK_TIME_IS_VALID (dashstream->actual_position)) {
2013     GstClockTime dur;
2014     if (dashstream->moof_sync_samples
2015         && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux)) {
2016       GST_LOG_OBJECT (stream->pad, "current sync sample #%d",
2017           dashstream->current_sync_sample);
2018       if (dashstream->current_sync_sample == -1) {
2019         dur = 0;
2020       } else if (dashstream->current_sync_sample <
2021           dashstream->moof_sync_samples->len) {
2022         dur = dashstream->current_fragment_keyframe_distance;
2023       } else {
2024         if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client) &&
2025             dashstream->sidx_position != GST_CLOCK_TIME_NONE
2026             && SIDX (dashstream)->entries) {
2027           GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dashstream);
2028           dur = entry->duration;
2029         } else {
2030           dur =
2031               dashstream->current_fragment_timestamp +
2032               dashstream->current_fragment_duration -
2033               dashstream->actual_position;
2034         }
2035       }
2036     } else if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client) &&
2037         dashstream->sidx_position != GST_CLOCK_TIME_NONE
2038         && SIDX (dashstream)->entries) {
2039       GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dashstream);
2040       dur = entry->duration;
2041     } else {
2042       dur = stream->fragment.duration;
2043     }
2044
2045     if (dashstream->moof_sync_samples
2046         && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux)) {
2047       /* We just downloaded the header, we actually use the previous
2048        * target_time now as it was not used up yet */
2049       if (dashstream->current_sync_sample == -1)
2050         target_time = dashstream->target_time;
2051       else
2052         target_time =
2053             gst_dash_demux_stream_get_target_time (dashdemux, stream,
2054             dashstream->actual_position, dur);
2055       dashstream->actual_position = target_time;
2056     } else {
2057       /* Adjust based on direction */
2058       if (stream->demux->segment.rate > 0.0)
2059         dashstream->actual_position += dur;
2060       else if (dashstream->actual_position >= dur)
2061         dashstream->actual_position -= dur;
2062       else
2063         dashstream->actual_position = 0;
2064     }
2065
2066     GST_DEBUG_OBJECT (stream->pad, "Actual position %" GST_TIME_FORMAT,
2067         GST_TIME_ARGS (dashstream->actual_position));
2068   }
2069   dashstream->target_time = target_time;
2070
2071   GST_DEBUG_OBJECT (stream->pad, "target_time: %" GST_TIME_FORMAT,
2072       GST_TIME_ARGS (target_time));
2073
2074   /* If downloading only keyframes, switch to the next one or fall through */
2075   if (dashstream->moof_sync_samples &&
2076       GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux)) {
2077     if (gst_dash_demux_stream_advance_sync_sample (stream, target_time))
2078       return GST_FLOW_OK;
2079   }
2080
2081   dashstream->isobmff_parser.current_fourcc = 0;
2082   dashstream->isobmff_parser.current_start_offset = 0;
2083   dashstream->isobmff_parser.current_size = 0;
2084
2085   if (dashstream->moof)
2086     gst_isoff_moof_box_free (dashstream->moof);
2087   dashstream->moof = NULL;
2088   if (dashstream->moof_sync_samples)
2089     g_array_free (dashstream->moof_sync_samples, TRUE);
2090   dashstream->moof_sync_samples = NULL;
2091   dashstream->current_sync_sample = -1;
2092
2093   /* Check if we just need to 'advance' to the next fragment, or if we
2094    * need to skip by more. */
2095   if (GST_CLOCK_TIME_IS_VALID (target_time)
2096       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux) &&
2097       dashstream->active_stream->mimeType == GST_STREAM_VIDEO) {
2098     GstClockTime actual_ts;
2099     GstSeekFlags flags = 0;
2100
2101     /* Key-unit trick mode, seek to fragment containing target time
2102      *
2103      * We first try seeking without snapping. As above code to skip keyframes
2104      * in the current fragment was not successful, we should go at least one
2105      * fragment ahead. Due to rounding errors we could end up at the same
2106      * fragment again here, in which case we retry seeking with the SNAP_AFTER
2107      * flag.
2108      *
2109      * We don't always set that flag as we would then end up one further
2110      * fragment in the future in all good cases.
2111      */
2112     while (TRUE) {
2113       ret =
2114           gst_dash_demux_stream_seek (stream, (stream->segment.rate > 0), flags,
2115           target_time, &actual_ts);
2116
2117       if (ret != GST_FLOW_OK) {
2118         GST_WARNING_OBJECT (stream->pad, "Failed to seek to %" GST_TIME_FORMAT,
2119             GST_TIME_ARGS (target_time));
2120         /* Give up */
2121         if (flags != 0)
2122           break;
2123
2124         /* Retry with skipping ahead */
2125         flags |= GST_SEEK_FLAG_SNAP_AFTER;
2126         continue;
2127       }
2128
2129       GST_DEBUG_OBJECT (stream->pad,
2130           "Skipped to %" GST_TIME_FORMAT " (wanted %" GST_TIME_FORMAT ", was %"
2131           GST_TIME_FORMAT ")", GST_TIME_ARGS (actual_ts),
2132           GST_TIME_ARGS (target_time), GST_TIME_ARGS (previous_position));
2133
2134       if ((stream->segment.rate > 0 && actual_ts <= previous_position) ||
2135           (stream->segment.rate < 0 && actual_ts >= previous_position)) {
2136         /* Give up */
2137         if (flags != 0)
2138           break;
2139
2140         /* Retry with forcing skipping ahead */
2141         flags |= GST_SEEK_FLAG_SNAP_AFTER;
2142
2143         continue;
2144       }
2145
2146       /* All good */
2147       break;
2148     }
2149   } else {
2150     /* Normal mode, advance to the next fragment */
2151     if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)) {
2152       if (gst_dash_demux_stream_advance_subfragment (stream))
2153         return GST_FLOW_OK;
2154     }
2155
2156     if (dashstream->adapter)
2157       gst_adapter_clear (dashstream->adapter);
2158
2159     gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
2160     dashstream->sidx_base_offset = 0;
2161     dashstream->sidx_position = GST_CLOCK_TIME_NONE;
2162     dashstream->allow_sidx = TRUE;
2163
2164     ret = gst_mpd_client_advance_segment (dashdemux->client,
2165         dashstream->active_stream, stream->demux->segment.rate > 0.0);
2166   }
2167   return ret;
2168 }
2169
2170 static gboolean
2171 gst_dash_demux_stream_select_bitrate (GstAdaptiveDemuxStream * stream,
2172     guint64 bitrate)
2173 {
2174   GstActiveStream *active_stream = NULL;
2175   GList *rep_list = NULL;
2176   gint new_index;
2177   GstAdaptiveDemux *base_demux = stream->demux;
2178   GstDashDemux *demux = GST_DASH_DEMUX_CAST (stream->demux);
2179   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
2180   gboolean ret = FALSE;
2181
2182   active_stream = dashstream->active_stream;
2183   if (active_stream == NULL) {
2184     goto end;
2185   }
2186
2187   /* In key-frame trick mode don't change bitrates */
2188   if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (demux)) {
2189     GST_DEBUG_OBJECT (demux, "In key-frame trick mode, not changing bitrates");
2190     goto end;
2191   }
2192
2193   /* retrieve representation list */
2194   if (active_stream->cur_adapt_set)
2195     rep_list = active_stream->cur_adapt_set->Representations;
2196   if (!rep_list) {
2197     goto end;
2198   }
2199
2200   GST_DEBUG_OBJECT (stream->pad,
2201       "Trying to change to bitrate: %" G_GUINT64_FORMAT, bitrate);
2202
2203   if (active_stream->mimeType == GST_STREAM_VIDEO && demux->max_bitrate) {
2204     bitrate = MIN (demux->max_bitrate, bitrate);
2205   }
2206
2207   /* get representation index with current max_bandwidth */
2208   if (GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (base_demux) ||
2209       ABS (base_demux->segment.rate) <= 1.0) {
2210     new_index =
2211         gst_mpd_client_get_rep_idx_with_max_bandwidth (rep_list, bitrate,
2212         demux->max_video_width, demux->max_video_height,
2213         demux->max_video_framerate_n, demux->max_video_framerate_d);
2214   } else {
2215     new_index =
2216         gst_mpd_client_get_rep_idx_with_max_bandwidth (rep_list,
2217         bitrate / ABS (base_demux->segment.rate), demux->max_video_width,
2218         demux->max_video_height, demux->max_video_framerate_n,
2219         demux->max_video_framerate_d);
2220   }
2221
2222   /* if no representation has the required bandwidth, take the lowest one */
2223   if (new_index == -1)
2224     new_index = gst_mpd_client_get_rep_idx_with_min_bandwidth (rep_list);
2225
2226   if (new_index != active_stream->representation_idx) {
2227     GstMPDRepresentationNode *rep = g_list_nth_data (rep_list, new_index);
2228     GST_INFO_OBJECT (demux, "Changing representation idx: %d %d %u",
2229         dashstream->index, new_index, rep->bandwidth);
2230     if (gst_mpd_client_setup_representation (demux->client, active_stream, rep)) {
2231       GstCaps *caps;
2232
2233       GST_INFO_OBJECT (demux, "Switching bitrate to %d",
2234           active_stream->cur_representation->bandwidth);
2235       caps = gst_dash_demux_get_input_caps (demux, active_stream);
2236       gst_adaptive_demux_stream_set_caps (stream, caps);
2237       ret = TRUE;
2238
2239     } else {
2240       GST_WARNING_OBJECT (demux, "Can not switch representation, aborting...");
2241     }
2242   }
2243
2244   if (ret) {
2245     if (gst_mpd_client_has_isoff_ondemand_profile (demux->client)
2246         && SIDX (dashstream)->entries) {
2247       /* store our current position to change to the same one in a different
2248        * representation if needed */
2249       if (SIDX (dashstream)->entry_index < SIDX (dashstream)->entries_count)
2250         dashstream->sidx_position = SIDX_CURRENT_ENTRY (dashstream)->pts;
2251       else if (SIDX (dashstream)->entry_index >=
2252           SIDX (dashstream)->entries_count)
2253         dashstream->sidx_position =
2254             SIDX_ENTRY (dashstream,
2255             SIDX (dashstream)->entries_count - 1)->pts + SIDX_ENTRY (dashstream,
2256             SIDX (dashstream)->entries_count - 1)->duration;
2257       else
2258         dashstream->sidx_position = GST_CLOCK_TIME_NONE;
2259     } else {
2260       dashstream->sidx_position = GST_CLOCK_TIME_NONE;
2261     }
2262
2263     gst_isoff_sidx_parser_clear (&dashstream->sidx_parser);
2264     dashstream->sidx_base_offset = 0;
2265     dashstream->allow_sidx = TRUE;
2266
2267     /* Reset ISOBMFF box parsing state */
2268     dashstream->isobmff_parser.current_fourcc = 0;
2269     dashstream->isobmff_parser.current_start_offset = 0;
2270     dashstream->isobmff_parser.current_size = 0;
2271
2272     dashstream->current_offset = -1;
2273     dashstream->current_index_header_or_data = 0;
2274
2275     if (dashstream->adapter)
2276       gst_adapter_clear (dashstream->adapter);
2277
2278     if (dashstream->moof)
2279       gst_isoff_moof_box_free (dashstream->moof);
2280     dashstream->moof = NULL;
2281     if (dashstream->moof_sync_samples)
2282       g_array_free (dashstream->moof_sync_samples, TRUE);
2283     dashstream->moof_sync_samples = NULL;
2284     dashstream->current_sync_sample = -1;
2285     dashstream->target_time = GST_CLOCK_TIME_NONE;
2286   }
2287
2288 end:
2289   return ret;
2290 }
2291
2292 #define SEEK_UPDATES_PLAY_POSITION(r, start_type, stop_type) \
2293   ((r >= 0 && start_type != GST_SEEK_TYPE_NONE) || \
2294    (r < 0 && stop_type != GST_SEEK_TYPE_NONE))
2295
2296 static gboolean
2297 gst_dash_demux_seek (GstAdaptiveDemux * demux, GstEvent * seek)
2298 {
2299   gdouble rate;
2300   GstFormat format;
2301   GstSeekFlags flags;
2302   GstSeekType start_type, stop_type;
2303   gint64 start, stop;
2304   GList *list;
2305   GstClockTime current_pos, target_pos;
2306   guint current_period;
2307   GstStreamPeriod *period;
2308   GList *iter, *streams = NULL;
2309   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2310   gboolean trickmode_no_audio;
2311
2312   gst_event_parse_seek (seek, &rate, &format, &flags, &start_type, &start,
2313       &stop_type, &stop);
2314
2315   if (!SEEK_UPDATES_PLAY_POSITION (rate, start_type, stop_type)) {
2316     /* nothing to do if we don't have to update the current position */
2317     return TRUE;
2318   }
2319
2320   if (demux->segment.rate > 0.0) {
2321     target_pos = (GstClockTime) start;
2322   } else {
2323     target_pos = (GstClockTime) stop;
2324   }
2325
2326   /* select the requested Period in the Media Presentation */
2327   if (!gst_mpd_client_setup_media_presentation (dashdemux->client, target_pos,
2328           -1, NULL))
2329     return FALSE;
2330
2331   current_period = 0;
2332   for (list = g_list_first (dashdemux->client->periods); list;
2333       list = g_list_next (list)) {
2334     period = list->data;
2335     current_pos = period->start;
2336     current_period = period->number;
2337     GST_DEBUG_OBJECT (demux, "Looking at period %u) start:%"
2338         GST_TIME_FORMAT " - duration:%"
2339         GST_TIME_FORMAT ") for position %" GST_TIME_FORMAT,
2340         current_period, GST_TIME_ARGS (current_pos),
2341         GST_TIME_ARGS (period->duration), GST_TIME_ARGS (target_pos));
2342     if (current_pos <= target_pos
2343         && target_pos <= current_pos + period->duration) {
2344       break;
2345     }
2346   }
2347   if (list == NULL) {
2348     GST_WARNING_OBJECT (demux, "Could not find seeked Period");
2349     return FALSE;
2350   }
2351
2352   trickmode_no_audio = ! !(flags & GST_SEEK_FLAG_TRICKMODE_NO_AUDIO);
2353
2354   streams = demux->streams;
2355   if (current_period != gst_mpd_client_get_period_index (dashdemux->client)) {
2356     GST_DEBUG_OBJECT (demux, "Seeking to Period %d", current_period);
2357
2358     /* clean old active stream list, if any */
2359     gst_mpd_client_active_streams_free (dashdemux->client);
2360     dashdemux->trickmode_no_audio = trickmode_no_audio;
2361
2362     /* setup video, audio and subtitle streams, starting from the new Period */
2363     if (!gst_mpd_client_set_period_index (dashdemux->client, current_period)
2364         || !gst_dash_demux_setup_all_streams (dashdemux))
2365       return FALSE;
2366     streams = demux->next_streams;
2367   } else if (dashdemux->trickmode_no_audio != trickmode_no_audio) {
2368     /* clean old active stream list, if any */
2369     gst_mpd_client_active_streams_free (dashdemux->client);
2370     dashdemux->trickmode_no_audio = trickmode_no_audio;
2371
2372     /* setup video, audio and subtitle streams, starting from the new Period */
2373     if (!gst_dash_demux_setup_all_streams (dashdemux))
2374       return FALSE;
2375     streams = demux->next_streams;
2376   }
2377
2378   /* Update the current sequence on all streams */
2379   for (iter = streams; iter; iter = g_list_next (iter)) {
2380     GstAdaptiveDemuxStream *stream = iter->data;
2381     GstDashDemuxStream *dashstream = iter->data;
2382
2383     dashstream->average_skip_size = 0;
2384     if (gst_dash_demux_stream_seek (stream, rate >= 0, 0, target_pos,
2385             NULL) != GST_FLOW_OK)
2386       return FALSE;
2387   }
2388
2389   return TRUE;
2390 }
2391
2392 static gint64
2393 gst_dash_demux_get_manifest_update_interval (GstAdaptiveDemux * demux)
2394 {
2395   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2396   return MIN (dashdemux->client->mpd_root_node->minimumUpdatePeriod * 1000,
2397       SLOW_CLOCK_UPDATE_INTERVAL);
2398 }
2399
2400 static GstFlowReturn
2401 gst_dash_demux_update_manifest_data (GstAdaptiveDemux * demux,
2402     GstBuffer * buffer)
2403 {
2404   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2405   GstMPDClient *new_client = NULL;
2406   GstMapInfo mapinfo;
2407
2408   GST_DEBUG_OBJECT (demux, "Updating manifest file from URL");
2409
2410   /* parse the manifest file */
2411   new_client = gst_mpd_client_new ();
2412   gst_mpd_client_set_uri_downloader (new_client, demux->downloader);
2413   new_client->mpd_uri = g_strdup (demux->manifest_uri);
2414   new_client->mpd_base_uri = g_strdup (demux->manifest_base_uri);
2415   gst_buffer_map (buffer, &mapinfo, GST_MAP_READ);
2416
2417   if (gst_mpd_client_parse (new_client, (gchar *) mapinfo.data, mapinfo.size)) {
2418     const gchar *period_id;
2419     guint period_idx;
2420     GList *iter;
2421     GList *streams_iter;
2422     GList *streams;
2423
2424     /* prepare the new manifest and try to transfer the stream position
2425      * status from the old manifest client  */
2426
2427     GST_DEBUG_OBJECT (demux, "Updating manifest");
2428
2429     period_id = gst_mpd_client_get_period_id (dashdemux->client);
2430     period_idx = gst_mpd_client_get_period_index (dashdemux->client);
2431
2432     /* setup video, audio and subtitle streams, starting from current Period */
2433     if (!gst_mpd_client_setup_media_presentation (new_client, -1,
2434             (period_id ? -1 : period_idx), period_id)) {
2435       /* TODO */
2436     }
2437
2438     if (period_id) {
2439       if (!gst_mpd_client_set_period_id (new_client, period_id)) {
2440         GST_DEBUG_OBJECT (demux, "Error setting up the updated manifest file");
2441         gst_mpd_client_free (new_client);
2442         gst_buffer_unmap (buffer, &mapinfo);
2443         return GST_FLOW_EOS;
2444       }
2445     } else {
2446       if (!gst_mpd_client_set_period_index (new_client, period_idx)) {
2447         GST_DEBUG_OBJECT (demux, "Error setting up the updated manifest file");
2448         gst_mpd_client_free (new_client);
2449         gst_buffer_unmap (buffer, &mapinfo);
2450         return GST_FLOW_EOS;
2451       }
2452     }
2453
2454     if (!gst_dash_demux_setup_mpdparser_streams (dashdemux, new_client)) {
2455       GST_ERROR_OBJECT (demux, "Failed to setup streams on manifest " "update");
2456       gst_mpd_client_free (new_client);
2457       gst_buffer_unmap (buffer, &mapinfo);
2458       return GST_FLOW_ERROR;
2459     }
2460
2461     /* If no pads have been exposed yet, need to use those */
2462     streams = NULL;
2463     if (demux->streams == NULL) {
2464       if (demux->prepared_streams) {
2465         streams = demux->prepared_streams;
2466       }
2467     } else {
2468       streams = demux->streams;
2469     }
2470
2471     /* update the streams to play from the next segment */
2472     for (iter = streams, streams_iter = new_client->active_streams;
2473         iter && streams_iter;
2474         iter = g_list_next (iter), streams_iter = g_list_next (streams_iter)) {
2475       GstDashDemuxStream *demux_stream = iter->data;
2476       GstActiveStream *new_stream = streams_iter->data;
2477       GstClockTime ts;
2478
2479       if (!new_stream) {
2480         GST_DEBUG_OBJECT (demux,
2481             "Stream of index %d is missing from manifest update",
2482             demux_stream->index);
2483         gst_mpd_client_free (new_client);
2484         gst_buffer_unmap (buffer, &mapinfo);
2485         return GST_FLOW_EOS;
2486       }
2487
2488       if (gst_mpd_client_get_next_fragment_timestamp (dashdemux->client,
2489               demux_stream->index, &ts)
2490           || gst_mpd_client_get_last_fragment_timestamp_end (dashdemux->client,
2491               demux_stream->index, &ts)) {
2492
2493         /* Due to rounding when doing the timescale conversions it might happen
2494          * that the ts falls back to a previous segment, leading the same data
2495          * to be downloaded twice. We try to work around this by always adding
2496          * 10 microseconds to get back to the correct segment. The errors are
2497          * usually on the order of nanoseconds so it should be enough.
2498          */
2499
2500         /* _get_next_fragment_timestamp() returned relative timestamp to
2501          * corresponding period start, but _client_stream_seek expects absolute
2502          * MPD time. */
2503         ts += gst_mpd_client_get_period_start_time (dashdemux->client);
2504
2505         GST_DEBUG_OBJECT (GST_ADAPTIVE_DEMUX_STREAM_PAD (demux_stream),
2506             "Current position: %" GST_TIME_FORMAT ", updating to %"
2507             GST_TIME_FORMAT, GST_TIME_ARGS (ts),
2508             GST_TIME_ARGS (ts + (10 * GST_USECOND)));
2509         ts += 10 * GST_USECOND;
2510         gst_mpd_client_stream_seek (new_client, new_stream,
2511             demux->segment.rate >= 0, 0, ts, NULL);
2512       }
2513
2514       demux_stream->active_stream = new_stream;
2515     }
2516
2517     gst_mpd_client_free (dashdemux->client);
2518     dashdemux->client = new_client;
2519
2520     GST_DEBUG_OBJECT (demux, "Manifest file successfully updated");
2521     if (dashdemux->clock_drift) {
2522       gst_dash_demux_poll_clock_drift (dashdemux);
2523     }
2524   } else {
2525     /* In most cases, this will happen if we set a wrong url in the
2526      * source element and we have received the 404 HTML response instead of
2527      * the manifest */
2528     GST_WARNING_OBJECT (demux, "Error parsing the manifest.");
2529     gst_mpd_client_free (new_client);
2530     gst_buffer_unmap (buffer, &mapinfo);
2531     return GST_FLOW_ERROR;
2532   }
2533
2534   gst_buffer_unmap (buffer, &mapinfo);
2535
2536   return GST_FLOW_OK;
2537 }
2538
2539 static gint64
2540 gst_dash_demux_stream_get_fragment_waiting_time (GstAdaptiveDemuxStream *
2541     stream)
2542 {
2543   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (stream->demux);
2544   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
2545   GstDateTime *segmentAvailability;
2546   GstActiveStream *active_stream = dashstream->active_stream;
2547
2548   segmentAvailability =
2549       gst_mpd_client_get_next_segment_availability_start_time
2550       (dashdemux->client, active_stream);
2551
2552   if (segmentAvailability) {
2553     gint64 diff;
2554     GstDateTime *cur_time;
2555
2556     cur_time =
2557         gst_date_time_new_from_g_date_time
2558         (gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST
2559             (dashdemux)));
2560     diff =
2561         gst_mpd_client_calculate_time_difference (cur_time,
2562         segmentAvailability);
2563     gst_date_time_unref (segmentAvailability);
2564     gst_date_time_unref (cur_time);
2565     /* subtract the server's clock drift, so that if the server's
2566        time is behind our idea of UTC, we need to sleep for longer
2567        before requesting a fragment */
2568     return diff -
2569         gst_dash_demux_get_clock_compensation (dashdemux) * GST_USECOND;
2570   }
2571   return 0;
2572 }
2573
2574 static gboolean
2575 gst_dash_demux_has_next_period (GstAdaptiveDemux * demux)
2576 {
2577   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2578
2579   if (demux->segment.rate >= 0)
2580     return gst_mpd_client_has_next_period (dashdemux->client);
2581   else
2582     return gst_mpd_client_has_previous_period (dashdemux->client);
2583 }
2584
2585 static void
2586 gst_dash_demux_advance_period (GstAdaptiveDemux * demux)
2587 {
2588   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2589
2590   if (demux->segment.rate >= 0) {
2591     if (!gst_mpd_client_set_period_index (dashdemux->client,
2592             gst_mpd_client_get_period_index (dashdemux->client) + 1)) {
2593       /* TODO error */
2594       return;
2595     }
2596   } else {
2597     if (!gst_mpd_client_set_period_index (dashdemux->client,
2598             gst_mpd_client_get_period_index (dashdemux->client) - 1)) {
2599       /* TODO error */
2600       return;
2601     }
2602   }
2603
2604   gst_dash_demux_setup_all_streams (dashdemux);
2605   gst_mpd_client_seek_to_first_segment (dashdemux->client);
2606 }
2607
2608 static GstBuffer *
2609 _gst_buffer_split (GstBuffer * buffer, gint offset, gsize size)
2610 {
2611   GstBuffer *newbuf = gst_buffer_copy_region (buffer,
2612       GST_BUFFER_COPY_FLAGS | GST_BUFFER_COPY_TIMESTAMPS | GST_BUFFER_COPY_META
2613       | GST_BUFFER_COPY_MEMORY, offset, size == -1 ? size : size - offset);
2614
2615   gst_buffer_resize (buffer, 0, offset);
2616
2617   return newbuf;
2618 }
2619
2620 static gboolean
2621 gst_dash_demux_stream_fragment_start (GstAdaptiveDemux * demux,
2622     GstAdaptiveDemuxStream * stream)
2623 {
2624   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2625   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
2626
2627   GST_LOG_OBJECT (stream->pad, "Actual position %" GST_TIME_FORMAT,
2628       GST_TIME_ARGS (dashstream->actual_position));
2629
2630   dashstream->current_index_header_or_data = 0;
2631   dashstream->current_offset = -1;
2632
2633   /* We need to mark every first buffer of a key unit as discont,
2634    * and also every first buffer of a moov and moof. This ensures
2635    * that qtdemux takes note of our buffer offsets for each of those
2636    * buffers instead of keeping track of them itself from the first
2637    * buffer. We need offsets to be consistent between moof and mdat
2638    */
2639   if (dashstream->is_isobmff && dashdemux->allow_trickmode_key_units
2640       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (demux)
2641       && dashstream->active_stream->mimeType == GST_STREAM_VIDEO)
2642     stream->discont = TRUE;
2643
2644   return TRUE;
2645 }
2646
2647 static GstFlowReturn
2648 gst_dash_demux_stream_fragment_finished (GstAdaptiveDemux * demux,
2649     GstAdaptiveDemuxStream * stream)
2650 {
2651   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2652   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
2653
2654   /* We need to mark every first buffer of a key unit as discont,
2655    * and also every first buffer of a moov and moof. This ensures
2656    * that qtdemux takes note of our buffer offsets for each of those
2657    * buffers instead of keeping track of them itself from the first
2658    * buffer. We need offsets to be consistent between moof and mdat
2659    */
2660   if (dashstream->is_isobmff && dashdemux->allow_trickmode_key_units
2661       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (demux)
2662       && dashstream->active_stream->mimeType == GST_STREAM_VIDEO)
2663     stream->discont = TRUE;
2664
2665   /* Only handle fragment advancing specifically for SIDX if we're not
2666    * in key unit mode */
2667   if (!(dashstream->moof_sync_samples
2668           && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (dashdemux))
2669       && gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)
2670       && dashstream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
2671     /* fragment is advanced on data_received when byte limits are reached */
2672     if (dashstream->pending_seek_ts != GST_CLOCK_TIME_NONE) {
2673       if (SIDX (dashstream)->entry_index < SIDX (dashstream)->entries_count)
2674         return GST_FLOW_OK;
2675     } else if (gst_dash_demux_stream_has_next_subfragment (stream)) {
2676       return GST_FLOW_OK;
2677     }
2678   }
2679
2680   if (G_UNLIKELY (stream->downloading_header || stream->downloading_index))
2681     return GST_FLOW_OK;
2682
2683   return gst_adaptive_demux_stream_advance_fragment (demux, stream,
2684       stream->fragment.duration);
2685 }
2686
2687 static gboolean
2688 gst_dash_demux_need_another_chunk (GstAdaptiveDemuxStream * stream)
2689 {
2690   GstDashDemux *dashdemux = (GstDashDemux *) stream->demux;
2691   GstDashDemuxStream *dashstream = (GstDashDemuxStream *) stream;
2692
2693   /* We're chunked downloading for ISOBMFF in KEY_UNITS mode for the actual
2694    * fragment until we parsed the moof and arrived at the mdat. 8192 is a
2695    * random guess for the moof size
2696    */
2697   if (dashstream->is_isobmff
2698       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)
2699       && dashstream->active_stream->mimeType == GST_STREAM_VIDEO
2700       && !stream->downloading_header && !stream->downloading_index
2701       && dashdemux->allow_trickmode_key_units) {
2702     if (dashstream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
2703       /* Need to download the moof first to know anything */
2704
2705       stream->fragment.chunk_size = 8192;
2706       /* Do we have the first fourcc already or are we in the middle */
2707       if (dashstream->isobmff_parser.current_fourcc == 0) {
2708         stream->fragment.chunk_size += dashstream->moof_average_size;
2709         if (dashstream->first_sync_sample_always_after_moof) {
2710           gboolean first = FALSE;
2711           /* Check if we'll really need that first sample */
2712           if (GST_CLOCK_TIME_IS_VALID (dashstream->target_time)) {
2713             first =
2714                 ((dashstream->target_time -
2715                     dashstream->current_fragment_timestamp) /
2716                 dashstream->keyframe_average_distance) == 0 ? TRUE : FALSE;
2717           } else if (stream->segment.rate > 0) {
2718             first = TRUE;
2719           }
2720
2721           if (first)
2722             stream->fragment.chunk_size += dashstream->keyframe_average_size;
2723         }
2724       }
2725
2726       if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client) &&
2727           dashstream->sidx_parser.sidx.entries) {
2728         guint64 sidx_start_offset =
2729             dashstream->sidx_base_offset +
2730             SIDX_CURRENT_ENTRY (dashstream)->offset;
2731         guint64 sidx_end_offset =
2732             sidx_start_offset + SIDX_CURRENT_ENTRY (dashstream)->size;
2733         guint64 downloaded_end_offset;
2734
2735         if (dashstream->current_offset == GST_CLOCK_TIME_NONE) {
2736           downloaded_end_offset = sidx_start_offset;
2737         } else {
2738           downloaded_end_offset =
2739               dashstream->current_offset +
2740               gst_adapter_available (dashstream->adapter);
2741         }
2742
2743         downloaded_end_offset = MAX (downloaded_end_offset, sidx_start_offset);
2744
2745         if (stream->fragment.chunk_size +
2746             downloaded_end_offset > sidx_end_offset) {
2747           stream->fragment.chunk_size = sidx_end_offset - downloaded_end_offset;
2748         }
2749       }
2750     } else if (dashstream->moof && dashstream->moof_sync_samples) {
2751       /* Have the moof, either we're done now or we want to download the
2752        * directly following sync sample */
2753       if (dashstream->first_sync_sample_after_moof
2754           && dashstream->current_sync_sample == 0) {
2755         GstDashStreamSyncSample *sync_sample =
2756             &g_array_index (dashstream->moof_sync_samples,
2757             GstDashStreamSyncSample, 0);
2758         guint64 end_offset = sync_sample->end_offset + 1;
2759         guint64 downloaded_end_offset;
2760
2761         downloaded_end_offset =
2762             dashstream->current_offset +
2763             gst_adapter_available (dashstream->adapter);
2764
2765         if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client) &&
2766             dashstream->sidx_parser.sidx.entries) {
2767           guint64 sidx_end_offset =
2768               dashstream->sidx_base_offset +
2769               SIDX_CURRENT_ENTRY (dashstream)->offset +
2770               SIDX_CURRENT_ENTRY (dashstream)->size;
2771
2772           if (end_offset > sidx_end_offset) {
2773             end_offset = sidx_end_offset;
2774           }
2775         }
2776
2777         if (downloaded_end_offset < end_offset) {
2778           stream->fragment.chunk_size = end_offset - downloaded_end_offset;
2779         } else {
2780           stream->fragment.chunk_size = 0;
2781         }
2782       } else {
2783         stream->fragment.chunk_size = 0;
2784       }
2785     } else {
2786       /* Have moof but can't do key-units mode, just download until the end */
2787       stream->fragment.chunk_size = -1;
2788     }
2789   } else {
2790     /* We might've decided that we can't allow key-unit only
2791      * trickmodes while doing chunked downloading. In that case
2792      * just download from here to the end now */
2793     if (dashstream->moof
2794         && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)) {
2795       stream->fragment.chunk_size = -1;
2796     } else {
2797       stream->fragment.chunk_size = 0;
2798     }
2799   }
2800
2801   return stream->fragment.chunk_size != 0;
2802 }
2803
2804 static GstFlowReturn
2805 gst_dash_demux_parse_isobmff (GstAdaptiveDemux * demux,
2806     GstDashDemuxStream * dash_stream, gboolean * sidx_seek_needed)
2807 {
2808   GstAdaptiveDemuxStream *stream = (GstAdaptiveDemuxStream *) dash_stream;
2809   GstDashDemux *dashdemux = GST_DASH_DEMUX_CAST (demux);
2810   gsize available;
2811   GstBuffer *buffer;
2812   GstMapInfo map;
2813   GstByteReader reader;
2814   guint32 fourcc;
2815   guint header_size;
2816   guint64 size, buffer_offset;
2817
2818   *sidx_seek_needed = FALSE;
2819
2820   /* This must not be called when we're in the mdat. We only look at the mdat
2821    * header and then stop parsing the boxes as we're only interested in the
2822    * metadata! Handling mdat is the job of the surrounding code, as well as
2823    * stopping or starting the next fragment when mdat is over (=> sidx)
2824    */
2825   g_assert (dash_stream->isobmff_parser.current_fourcc !=
2826       GST_ISOFF_FOURCC_MDAT);
2827
2828   available = gst_adapter_available (dash_stream->adapter);
2829   buffer = gst_adapter_take_buffer (dash_stream->adapter, available);
2830   buffer_offset = dash_stream->current_offset;
2831
2832   /* Always at the start of a box here */
2833   g_assert (dash_stream->isobmff_parser.current_size == 0);
2834
2835   /* At the start of a box => Parse it */
2836   gst_buffer_map (buffer, &map, GST_MAP_READ);
2837   gst_byte_reader_init (&reader, map.data, map.size);
2838
2839   /* While there are more boxes left to parse ... */
2840   dash_stream->isobmff_parser.current_start_offset = buffer_offset;
2841   do {
2842     dash_stream->isobmff_parser.current_fourcc = 0;
2843     dash_stream->isobmff_parser.current_size = 0;
2844
2845     if (!gst_isoff_parse_box_header (&reader, &fourcc, NULL, &header_size,
2846             &size)) {
2847       break;
2848     }
2849
2850     dash_stream->isobmff_parser.current_fourcc = fourcc;
2851     if (size == 0) {
2852       /* We assume this is mdat, anything else with "size until end"
2853        * does not seem to make sense */
2854       g_assert (dash_stream->isobmff_parser.current_fourcc ==
2855           GST_ISOFF_FOURCC_MDAT);
2856       dash_stream->isobmff_parser.current_size = -1;
2857       break;
2858     }
2859
2860     dash_stream->isobmff_parser.current_size = size;
2861
2862     /* Do we have the complete box or are at MDAT */
2863     if (gst_byte_reader_get_remaining (&reader) < size - header_size ||
2864         dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
2865       /* Reset byte reader to the beginning of the box */
2866       gst_byte_reader_set_pos (&reader,
2867           gst_byte_reader_get_pos (&reader) - header_size);
2868       break;
2869     }
2870
2871     GST_LOG_OBJECT (stream->pad,
2872         "box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
2873         G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
2874         dash_stream->isobmff_parser.current_start_offset, size);
2875
2876     if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MOOF) {
2877       GstByteReader sub_reader;
2878
2879       /* Only allow SIDX before the very first moof */
2880       dash_stream->allow_sidx = FALSE;
2881
2882       g_assert (dash_stream->moof == NULL);
2883       g_assert (dash_stream->moof_sync_samples == NULL);
2884       gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size);
2885       dash_stream->moof = gst_isoff_moof_box_parse (&sub_reader);
2886       dash_stream->moof_offset =
2887           dash_stream->isobmff_parser.current_start_offset;
2888       dash_stream->moof_size = size;
2889       dash_stream->current_sync_sample = -1;
2890
2891       if (dash_stream->moof_average_size) {
2892         if (dash_stream->moof_average_size < size)
2893           dash_stream->moof_average_size =
2894               (size * 3 + dash_stream->moof_average_size) / 4;
2895         else
2896           dash_stream->moof_average_size =
2897               (size + dash_stream->moof_average_size + 3) / 4;
2898       } else {
2899         dash_stream->moof_average_size = size;
2900       }
2901     } else if (dash_stream->isobmff_parser.current_fourcc ==
2902         GST_ISOFF_FOURCC_SIDX &&
2903         gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client) &&
2904         dash_stream->allow_sidx) {
2905       GstByteReader sub_reader;
2906       GstIsoffParserResult res;
2907       guint dummy;
2908
2909       dash_stream->sidx_base_offset =
2910           dash_stream->isobmff_parser.current_start_offset + size;
2911       dash_stream->allow_sidx = FALSE;
2912
2913       gst_byte_reader_get_sub_reader (&reader, &sub_reader, size - header_size);
2914
2915       res =
2916           gst_isoff_sidx_parser_parse (&dash_stream->sidx_parser, &sub_reader,
2917           &dummy);
2918
2919       if (res == GST_ISOFF_PARSER_DONE) {
2920         guint64 first_offset = dash_stream->sidx_parser.sidx.first_offset;
2921         GstSidxBox *sidx = SIDX (dash_stream);
2922         guint i;
2923
2924         if (first_offset) {
2925           GST_LOG_OBJECT (stream->pad,
2926               "non-zero sidx first offset %" G_GUINT64_FORMAT, first_offset);
2927           dash_stream->sidx_base_offset += first_offset;
2928         }
2929
2930         for (i = 0; i < sidx->entries_count; i++) {
2931           GstSidxBoxEntry *entry = &sidx->entries[i];
2932
2933           if (entry->ref_type != 0) {
2934             GST_FIXME_OBJECT (stream->pad, "SIDX ref_type 1 not supported yet");
2935             dash_stream->sidx_position = GST_CLOCK_TIME_NONE;
2936             gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
2937             break;
2938           }
2939         }
2940
2941         /* We might've cleared the index above */
2942         if (sidx->entries_count > 0) {
2943           if (GST_CLOCK_TIME_IS_VALID (dash_stream->pending_seek_ts)) {
2944             /* FIXME, preserve seek flags */
2945             if (gst_dash_demux_stream_sidx_seek (dash_stream,
2946                     demux->segment.rate >= 0, 0, dash_stream->pending_seek_ts,
2947                     NULL) != GST_FLOW_OK) {
2948               GST_ERROR_OBJECT (stream->pad, "Couldn't find position in sidx");
2949               dash_stream->sidx_position = GST_CLOCK_TIME_NONE;
2950               gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
2951             }
2952             dash_stream->pending_seek_ts = GST_CLOCK_TIME_NONE;
2953           } else {
2954
2955             if (dash_stream->sidx_position == GST_CLOCK_TIME_NONE) {
2956               SIDX (dash_stream)->entry_index = 0;
2957             } else {
2958               if (gst_dash_demux_stream_sidx_seek (dash_stream,
2959                       demux->segment.rate >= 0, GST_SEEK_FLAG_SNAP_BEFORE,
2960                       dash_stream->sidx_position, NULL) != GST_FLOW_OK) {
2961                 GST_ERROR_OBJECT (stream->pad,
2962                     "Couldn't find position in sidx");
2963                 dash_stream->sidx_position = GST_CLOCK_TIME_NONE;
2964                 gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
2965               }
2966             }
2967             dash_stream->sidx_position =
2968                 SIDX (dash_stream)->entries[SIDX (dash_stream)->entry_index].
2969                 pts;
2970           }
2971         }
2972
2973         if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED &&
2974             SIDX (dash_stream)->entry_index != 0) {
2975           /* Need to jump to the requested SIDX entry. Push everything up to
2976            * the SIDX box below and let the caller handle everything else */
2977           *sidx_seek_needed = TRUE;
2978           break;
2979         }
2980       }
2981     } else {
2982       gst_byte_reader_skip (&reader, size - header_size);
2983     }
2984
2985     dash_stream->isobmff_parser.current_fourcc = 0;
2986     dash_stream->isobmff_parser.current_start_offset += size;
2987     dash_stream->isobmff_parser.current_size = 0;
2988   } while (gst_byte_reader_get_remaining (&reader) > 0);
2989
2990   gst_buffer_unmap (buffer, &map);
2991
2992   /* mdat? Push all we have and wait for it to be over */
2993   if (dash_stream->isobmff_parser.current_fourcc == GST_ISOFF_FOURCC_MDAT) {
2994     GstBuffer *pending;
2995
2996     GST_LOG_OBJECT (stream->pad,
2997         "box %" GST_FOURCC_FORMAT " at offset %" G_GUINT64_FORMAT " size %"
2998         G_GUINT64_FORMAT, GST_FOURCC_ARGS (fourcc),
2999         dash_stream->isobmff_parser.current_start_offset,
3000         dash_stream->isobmff_parser.current_size);
3001
3002     /* At mdat. Move the start of the mdat to the adapter and have everything
3003      * else be pushed. We parsed all header boxes at this point and are not
3004      * supposed to be called again until the next moof */
3005     pending = _gst_buffer_split (buffer, gst_byte_reader_get_pos (&reader), -1);
3006     gst_adapter_push (dash_stream->adapter, pending);
3007     dash_stream->current_offset += gst_byte_reader_get_pos (&reader);
3008     dash_stream->isobmff_parser.current_size = 0;
3009
3010     GST_BUFFER_OFFSET (buffer) = buffer_offset;
3011     GST_BUFFER_OFFSET_END (buffer) =
3012         buffer_offset + gst_buffer_get_size (buffer);
3013     return gst_adaptive_demux_stream_push_buffer (stream, buffer);
3014   } else if (gst_byte_reader_get_pos (&reader) != 0) {
3015     GstBuffer *pending;
3016
3017     /* Multiple complete boxes and no mdat? Push them and keep the remainder,
3018      * which is the start of the next box if any remainder */
3019
3020     pending = _gst_buffer_split (buffer, gst_byte_reader_get_pos (&reader), -1);
3021     gst_adapter_push (dash_stream->adapter, pending);
3022     dash_stream->current_offset += gst_byte_reader_get_pos (&reader);
3023     dash_stream->isobmff_parser.current_size = 0;
3024
3025     GST_BUFFER_OFFSET (buffer) = buffer_offset;
3026     GST_BUFFER_OFFSET_END (buffer) =
3027         buffer_offset + gst_buffer_get_size (buffer);
3028     return gst_adaptive_demux_stream_push_buffer (stream, buffer);
3029   }
3030
3031   /* Not even a single complete, non-mdat box, wait */
3032   dash_stream->isobmff_parser.current_size = 0;
3033   gst_adapter_push (dash_stream->adapter, buffer);
3034
3035   return GST_FLOW_OK;
3036 }
3037
3038 static gboolean
3039 gst_dash_demux_find_sync_samples (GstAdaptiveDemux * demux,
3040     GstAdaptiveDemuxStream * stream)
3041 {
3042   GstDashDemux *dashdemux = (GstDashDemux *) stream->demux;
3043   GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
3044   guint i;
3045   guint32 track_id = 0;
3046   guint64 prev_traf_end;
3047   gboolean trex_sample_flags = FALSE;
3048
3049   if (!dash_stream->moof) {
3050     dashdemux->allow_trickmode_key_units = FALSE;
3051     return FALSE;
3052   }
3053
3054   dash_stream->current_sync_sample = -1;
3055   dash_stream->moof_sync_samples =
3056       g_array_new (FALSE, FALSE, sizeof (GstDashStreamSyncSample));
3057
3058   prev_traf_end = dash_stream->moof_offset;
3059
3060   /* generate table of keyframes and offsets */
3061   for (i = 0; i < dash_stream->moof->traf->len; i++) {
3062     GstTrafBox *traf = &g_array_index (dash_stream->moof->traf, GstTrafBox, i);
3063     guint64 traf_offset = 0, prev_trun_end;
3064     guint j;
3065
3066     if (i == 0) {
3067       track_id = traf->tfhd.track_id;
3068     } else if (track_id != traf->tfhd.track_id) {
3069       GST_ERROR_OBJECT (stream->pad,
3070           "moof with trafs of different track ids (%u != %u)", track_id,
3071           traf->tfhd.track_id);
3072       g_array_free (dash_stream->moof_sync_samples, TRUE);
3073       dash_stream->moof_sync_samples = NULL;
3074       dashdemux->allow_trickmode_key_units = FALSE;
3075       return FALSE;
3076     }
3077
3078     if (traf->tfhd.flags & GST_TFHD_FLAGS_BASE_DATA_OFFSET_PRESENT) {
3079       traf_offset = traf->tfhd.base_data_offset;
3080     } else if (traf->tfhd.flags & GST_TFHD_FLAGS_DEFAULT_BASE_IS_MOOF) {
3081       traf_offset = dash_stream->moof_offset;
3082     } else {
3083       traf_offset = prev_traf_end;
3084     }
3085
3086     prev_trun_end = traf_offset;
3087
3088     for (j = 0; j < traf->trun->len; j++) {
3089       GstTrunBox *trun = &g_array_index (traf->trun, GstTrunBox, j);
3090       guint64 trun_offset, prev_sample_end;
3091       guint k;
3092
3093       if (trun->flags & GST_TRUN_FLAGS_DATA_OFFSET_PRESENT) {
3094         trun_offset = traf_offset + trun->data_offset;
3095       } else {
3096         trun_offset = prev_trun_end;
3097       }
3098
3099       prev_sample_end = trun_offset;
3100       for (k = 0; k < trun->samples->len; k++) {
3101         GstTrunSample *sample =
3102             &g_array_index (trun->samples, GstTrunSample, k);
3103         guint64 sample_offset;
3104         guint32 sample_flags;
3105 #if 0
3106         guint32 sample_duration;
3107 #endif
3108
3109         sample_offset = prev_sample_end;
3110
3111         if (trun->flags & GST_TRUN_FLAGS_SAMPLE_FLAGS_PRESENT) {
3112           sample_flags = sample->sample_flags;
3113         } else if ((trun->flags & GST_TRUN_FLAGS_FIRST_SAMPLE_FLAGS_PRESENT)
3114             && k == 0) {
3115           sample_flags = trun->first_sample_flags;
3116         } else if (traf->tfhd.
3117             flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_FLAGS_PRESENT) {
3118           sample_flags = traf->tfhd.default_sample_flags;
3119         } else {
3120           trex_sample_flags = TRUE;
3121           continue;
3122         }
3123
3124 #if 0
3125         if (trun->flags & GST_TRUN_FLAGS_SAMPLE_DURATION_PRESENT) {
3126           sample_duration = sample->sample_duration;
3127         } else if (traf->tfhd.
3128             flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_DURATION_PRESENT) {
3129           sample_duration = traf->tfhd.default_sample_duration;
3130         } else {
3131           GST_FIXME_OBJECT (stream->pad,
3132               "Sample duration given by trex - can't download only keyframes");
3133           g_array_free (dash_stream->moof_sync_samples, TRUE);
3134           dash_stream->moof_sync_samples = NULL;
3135           return FALSE;
3136         }
3137 #endif
3138
3139         if (trun->flags & GST_TRUN_FLAGS_SAMPLE_SIZE_PRESENT) {
3140           prev_sample_end += sample->sample_size;
3141         } else if (traf->tfhd.
3142             flags & GST_TFHD_FLAGS_DEFAULT_SAMPLE_SIZE_PRESENT) {
3143           prev_sample_end += traf->tfhd.default_sample_size;
3144         } else {
3145           GST_FIXME_OBJECT (stream->pad,
3146               "Sample size given by trex - can't download only keyframes");
3147           g_array_free (dash_stream->moof_sync_samples, TRUE);
3148           dash_stream->moof_sync_samples = NULL;
3149           dashdemux->allow_trickmode_key_units = FALSE;
3150           return FALSE;
3151         }
3152
3153         /* Non-non-sync sample aka sync sample */
3154         if (!GST_ISOFF_SAMPLE_FLAGS_SAMPLE_IS_NON_SYNC_SAMPLE (sample_flags) ||
3155             GST_ISOFF_SAMPLE_FLAGS_SAMPLE_DEPENDS_ON (sample_flags) == 2) {
3156           GstDashStreamSyncSample sync_sample =
3157               { sample_offset, prev_sample_end - 1 };
3158           /* TODO: need timestamps so we can decide to download or not */
3159           g_array_append_val (dash_stream->moof_sync_samples, sync_sample);
3160         }
3161       }
3162
3163       prev_trun_end = prev_sample_end;
3164     }
3165
3166     prev_traf_end = prev_trun_end;
3167   }
3168
3169   if (trex_sample_flags) {
3170     if (dash_stream->moof_sync_samples->len > 0) {
3171       GST_LOG_OBJECT (stream->pad,
3172           "Some sample flags given by trex but still found sync samples");
3173     } else {
3174       GST_FIXME_OBJECT (stream->pad,
3175           "Sample flags given by trex - can't download only keyframes");
3176       g_array_free (dash_stream->moof_sync_samples, TRUE);
3177       dash_stream->moof_sync_samples = NULL;
3178       dashdemux->allow_trickmode_key_units = FALSE;
3179       return FALSE;
3180     }
3181   }
3182
3183   if (dash_stream->moof_sync_samples->len == 0) {
3184     GST_LOG_OBJECT (stream->pad, "No sync samples found in fragment");
3185     g_array_free (dash_stream->moof_sync_samples, TRUE);
3186     dash_stream->moof_sync_samples = NULL;
3187     dashdemux->allow_trickmode_key_units = FALSE;
3188     return FALSE;
3189   }
3190
3191   {
3192     GstDashStreamSyncSample *sync_sample;
3193     guint i;
3194     guint size;
3195     GstClockTime current_keyframe_distance;
3196
3197     for (i = 0; i < dash_stream->moof_sync_samples->len; i++) {
3198       sync_sample =
3199           &g_array_index (dash_stream->moof_sync_samples,
3200           GstDashStreamSyncSample, i);
3201       size = sync_sample->end_offset + 1 - sync_sample->start_offset;
3202
3203       if (dash_stream->keyframe_average_size) {
3204         /* Over-estimate the keyframe size */
3205         if (dash_stream->keyframe_average_size < size)
3206           dash_stream->keyframe_average_size =
3207               (size * 3 + dash_stream->keyframe_average_size) / 4;
3208         else
3209           dash_stream->keyframe_average_size =
3210               (size + dash_stream->keyframe_average_size * 3) / 4;
3211       } else {
3212         dash_stream->keyframe_average_size = size;
3213       }
3214
3215       if (i == 0) {
3216         if (dash_stream->moof_offset + dash_stream->moof_size + 8 <
3217             sync_sample->start_offset) {
3218           dash_stream->first_sync_sample_after_moof = FALSE;
3219           dash_stream->first_sync_sample_always_after_moof = FALSE;
3220         } else {
3221           dash_stream->first_sync_sample_after_moof =
3222               (dash_stream->moof_sync_samples->len == 1
3223               || demux->segment.rate > 0.0);
3224         }
3225       }
3226     }
3227
3228     g_assert (stream->fragment.duration != 0);
3229     g_assert (stream->fragment.duration != GST_CLOCK_TIME_NONE);
3230
3231     if (gst_mpd_client_has_isoff_ondemand_profile (dashdemux->client)
3232         && dash_stream->sidx_position != GST_CLOCK_TIME_NONE
3233         && SIDX (dash_stream)->entries) {
3234       GstSidxBoxEntry *entry = SIDX_CURRENT_ENTRY (dash_stream);
3235       current_keyframe_distance =
3236           entry->duration / dash_stream->moof_sync_samples->len;
3237     } else {
3238       current_keyframe_distance =
3239           stream->fragment.duration / dash_stream->moof_sync_samples->len;
3240     }
3241     dash_stream->current_fragment_keyframe_distance = current_keyframe_distance;
3242
3243     if (dash_stream->keyframe_average_distance) {
3244       /* Under-estimate the keyframe distance */
3245       if (dash_stream->keyframe_average_distance > current_keyframe_distance)
3246         dash_stream->keyframe_average_distance =
3247             (dash_stream->keyframe_average_distance * 3 +
3248             current_keyframe_distance) / 4;
3249       else
3250         dash_stream->keyframe_average_distance =
3251             (dash_stream->keyframe_average_distance +
3252             current_keyframe_distance * 3) / 4;
3253     } else {
3254       dash_stream->keyframe_average_distance = current_keyframe_distance;
3255     }
3256
3257     GST_DEBUG_OBJECT (stream->pad,
3258         "average keyframe sample size: %" G_GUINT64_FORMAT,
3259         dash_stream->keyframe_average_size);
3260     GST_DEBUG_OBJECT (stream->pad,
3261         "average keyframe distance: %" GST_TIME_FORMAT " (%" GST_TIME_FORMAT
3262         ")", GST_TIME_ARGS (dash_stream->keyframe_average_distance),
3263         GST_TIME_ARGS (current_keyframe_distance));
3264     GST_DEBUG_OBJECT (stream->pad, "first sync sample after moof: %d",
3265         dash_stream->first_sync_sample_after_moof);
3266   }
3267
3268   return TRUE;
3269 }
3270
3271
3272 static GstFlowReturn
3273 gst_dash_demux_handle_isobmff (GstAdaptiveDemux * demux,
3274     GstAdaptiveDemuxStream * stream)
3275 {
3276   GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
3277   GstFlowReturn ret = GST_FLOW_OK;
3278   GstBuffer *buffer;
3279   gboolean sidx_advance = FALSE;
3280
3281   /* We parse all ISOBMFF boxes of a (sub)fragment until the mdat. This covers
3282    * at least moov, moof and sidx boxes. Once mdat is received we just output
3283    * everything until the next (sub)fragment */
3284   if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT) {
3285     gboolean sidx_seek_needed = FALSE;
3286
3287     ret = gst_dash_demux_parse_isobmff (demux, dash_stream, &sidx_seek_needed);
3288     if (ret != GST_FLOW_OK)
3289       return ret;
3290
3291     /* Go to selected segment if needed here */
3292     if (sidx_seek_needed && !stream->downloading_index)
3293       return GST_ADAPTIVE_DEMUX_FLOW_END_OF_FRAGMENT;
3294
3295     /* No mdat yet, let's get called again with the next boxes */
3296     if (dash_stream->isobmff_parser.current_fourcc != GST_ISOFF_FOURCC_MDAT)
3297       return ret;
3298
3299     /* Here we end up only if we're right at the mdat start */
3300
3301     /* Jump to the next sync sample. As we're doing chunked downloading
3302      * here, just drop data until our chunk is over so we can reuse the
3303      * HTTP connection instead of having to create a new one or
3304      * reuse the data if the sync sample follows the moof */
3305     if (dash_stream->active_stream->mimeType == GST_STREAM_VIDEO
3306         && gst_dash_demux_find_sync_samples (demux, stream) &&
3307         GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)) {
3308       guint idx = -1;
3309
3310       if (GST_CLOCK_TIME_IS_VALID (dash_stream->target_time)) {
3311         idx =
3312             (dash_stream->target_time -
3313             dash_stream->current_fragment_timestamp) /
3314             dash_stream->current_fragment_keyframe_distance;
3315       } else if (stream->segment.rate > 0) {
3316         idx = 0;
3317       }
3318
3319       GST_DEBUG_OBJECT (stream->pad, "target %" GST_TIME_FORMAT " idx %d",
3320           GST_TIME_ARGS (dash_stream->target_time), idx);
3321       /* Figure out target time */
3322
3323       if (dash_stream->first_sync_sample_after_moof && idx == 0) {
3324         /* If we're here, don't throw away data but collect sync
3325          * sample while we're at it below. We're doing chunked
3326          * downloading so might need to adjust the next chunk size for
3327          * the remainder */
3328         dash_stream->current_sync_sample = 0;
3329         GST_DEBUG_OBJECT (stream->pad, "Using first keyframe after header");
3330       }
3331     }
3332
3333     if (gst_adapter_available (dash_stream->adapter) == 0)
3334       return ret;
3335
3336     /* We have some data from the mdat available in the adapter, handle it
3337      * below in the push code */
3338   } else {
3339     /* Somewhere in the middle of the mdat */
3340   }
3341
3342   /* At mdat */
3343   if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
3344     guint64 sidx_end_offset =
3345         dash_stream->sidx_base_offset +
3346         SIDX_CURRENT_ENTRY (dash_stream)->offset +
3347         SIDX_CURRENT_ENTRY (dash_stream)->size;
3348     gboolean has_next = gst_dash_demux_stream_has_next_subfragment (stream);
3349     gsize available;
3350
3351     /* Need to handle everything in the adapter according to the parsed SIDX
3352      * and advance subsegments accordingly */
3353
3354     available = gst_adapter_available (dash_stream->adapter);
3355     if (dash_stream->current_offset + available < sidx_end_offset) {
3356       buffer = gst_adapter_take_buffer (dash_stream->adapter, available);
3357     } else {
3358       if (!has_next && sidx_end_offset <= dash_stream->current_offset) {
3359         /* Drain all bytes, since there might be trailing bytes at the end of subfragment */
3360         buffer = gst_adapter_take_buffer (dash_stream->adapter, available);
3361       } else {
3362         if (sidx_end_offset <= dash_stream->current_offset) {
3363           /* This means a corrupted stream or a bug: ignoring bugs, it
3364            * should only happen if the SIDX index is corrupt */
3365           GST_ERROR_OBJECT (stream->pad, "Invalid SIDX state");
3366           gst_adapter_clear (dash_stream->adapter);
3367           return GST_FLOW_ERROR;
3368         } else {
3369           buffer =
3370               gst_adapter_take_buffer (dash_stream->adapter,
3371               sidx_end_offset - dash_stream->current_offset);
3372           sidx_advance = TRUE;
3373         }
3374       }
3375     }
3376   } else {
3377     /* Take it all and handle it further below */
3378     buffer =
3379         gst_adapter_take_buffer (dash_stream->adapter,
3380         gst_adapter_available (dash_stream->adapter));
3381
3382     /* Attention: All code paths below need to update dash_stream->current_offset */
3383   }
3384
3385   /* We're actually running in key-units trick mode */
3386   if (dash_stream->active_stream->mimeType == GST_STREAM_VIDEO
3387       && dash_stream->moof_sync_samples
3388       && GST_ADAPTIVE_DEMUX_IN_TRICKMODE_KEY_UNITS (stream->demux)) {
3389     if (dash_stream->current_sync_sample == -1) {
3390       /* We're doing chunked downloading and wait for finishing the current
3391        * chunk so we can jump to the first keyframe */
3392       dash_stream->current_offset += gst_buffer_get_size (buffer);
3393       gst_buffer_unref (buffer);
3394       return GST_FLOW_OK;
3395     } else {
3396       GstDashStreamSyncSample *sync_sample =
3397           &g_array_index (dash_stream->moof_sync_samples,
3398           GstDashStreamSyncSample, dash_stream->current_sync_sample);
3399       guint64 end_offset =
3400           dash_stream->current_offset + gst_buffer_get_size (buffer);
3401
3402       /* Make sure to not download too much, this should only happen for
3403        * the very first keyframe if it follows the moof */
3404       if (dash_stream->current_offset >= sync_sample->end_offset + 1) {
3405         dash_stream->current_offset += gst_buffer_get_size (buffer);
3406         gst_buffer_unref (buffer);
3407         return GST_FLOW_OK;
3408       } else if (end_offset > sync_sample->end_offset + 1) {
3409         guint64 remaining =
3410             sync_sample->end_offset + 1 - dash_stream->current_offset;
3411         GstBuffer *sub = gst_buffer_copy_region (buffer, GST_BUFFER_COPY_ALL, 0,
3412             remaining);
3413         gst_buffer_unref (buffer);
3414         buffer = sub;
3415       }
3416     }
3417   }
3418
3419   GST_BUFFER_OFFSET (buffer) = dash_stream->current_offset;
3420   dash_stream->current_offset += gst_buffer_get_size (buffer);
3421   GST_BUFFER_OFFSET_END (buffer) = dash_stream->current_offset;
3422
3423   ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
3424   if (ret != GST_FLOW_OK)
3425     return ret;
3426
3427   if (sidx_advance) {
3428     ret =
3429         gst_adaptive_demux_stream_advance_fragment (demux, stream,
3430         SIDX_CURRENT_ENTRY (dash_stream)->duration);
3431     if (ret != GST_FLOW_OK)
3432       return ret;
3433
3434     /* If we still have data available, recurse and use it up if possible */
3435     if (gst_adapter_available (dash_stream->adapter) > 0)
3436       return gst_dash_demux_handle_isobmff (demux, stream);
3437   }
3438
3439   return ret;
3440 }
3441
3442 static GstFlowReturn
3443 gst_dash_demux_data_received (GstAdaptiveDemux * demux,
3444     GstAdaptiveDemuxStream * stream, GstBuffer * buffer)
3445 {
3446   GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
3447   GstFlowReturn ret = GST_FLOW_OK;
3448   guint index_header_or_data;
3449
3450   if (stream->downloading_index)
3451     index_header_or_data = 1;
3452   else if (stream->downloading_header)
3453     index_header_or_data = 2;
3454   else
3455     index_header_or_data = 3;
3456
3457   if (dash_stream->current_index_header_or_data != index_header_or_data) {
3458     /* Clear pending data */
3459     if (gst_adapter_available (dash_stream->adapter) != 0)
3460       GST_ERROR_OBJECT (stream->pad,
3461           "Had pending SIDX data after switch between index/header/data");
3462     gst_adapter_clear (dash_stream->adapter);
3463     dash_stream->current_index_header_or_data = index_header_or_data;
3464     dash_stream->current_offset = -1;
3465   }
3466
3467   if (dash_stream->current_offset == -1)
3468     dash_stream->current_offset =
3469         GST_BUFFER_OFFSET_IS_VALID (buffer) ? GST_BUFFER_OFFSET (buffer) : 0;
3470
3471   gst_adapter_push (dash_stream->adapter, buffer);
3472   buffer = NULL;
3473
3474   if (dash_stream->is_isobmff || stream->downloading_index) {
3475     /* SIDX index is also ISOBMMF */
3476     ret = gst_dash_demux_handle_isobmff (demux, stream);
3477   } else if (dash_stream->sidx_parser.status == GST_ISOFF_SIDX_PARSER_FINISHED) {
3478     gsize available;
3479
3480     /* Not ISOBMFF but had a SIDX index. Does this even exist or work? */
3481     while (ret == GST_FLOW_OK
3482         && ((available = gst_adapter_available (dash_stream->adapter)) > 0)) {
3483       gboolean advance = FALSE;
3484       guint64 sidx_end_offset =
3485           dash_stream->sidx_base_offset +
3486           SIDX_CURRENT_ENTRY (dash_stream)->offset +
3487           SIDX_CURRENT_ENTRY (dash_stream)->size;
3488       gboolean has_next = gst_dash_demux_stream_has_next_subfragment (stream);
3489
3490       if (dash_stream->current_offset + available < sidx_end_offset) {
3491         buffer = gst_adapter_take_buffer (dash_stream->adapter, available);
3492       } else {
3493         if (!has_next && sidx_end_offset <= dash_stream->current_offset) {
3494           /* Drain all bytes, since there might be trailing bytes at the end of subfragment */
3495           buffer = gst_adapter_take_buffer (dash_stream->adapter, available);
3496         } else {
3497           if (sidx_end_offset <= dash_stream->current_offset) {
3498             /* This means a corrupted stream or a bug: ignoring bugs, it
3499              * should only happen if the SIDX index is corrupt */
3500             GST_ERROR_OBJECT (stream->pad, "Invalid SIDX state");
3501             gst_adapter_clear (dash_stream->adapter);
3502             ret = GST_FLOW_ERROR;
3503             break;
3504           } else {
3505             buffer =
3506                 gst_adapter_take_buffer (dash_stream->adapter,
3507                 sidx_end_offset - dash_stream->current_offset);
3508             advance = TRUE;
3509           }
3510         }
3511       }
3512
3513       GST_BUFFER_OFFSET (buffer) = dash_stream->current_offset;
3514       GST_BUFFER_OFFSET_END (buffer) =
3515           GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer);
3516       dash_stream->current_offset = GST_BUFFER_OFFSET_END (buffer);
3517
3518       ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
3519
3520       if (advance) {
3521         if (has_next) {
3522           GstFlowReturn new_ret;
3523           new_ret =
3524               gst_adaptive_demux_stream_advance_fragment (demux, stream,
3525               SIDX_CURRENT_ENTRY (dash_stream)->duration);
3526
3527           /* only overwrite if it was OK before */
3528           if (ret == GST_FLOW_OK)
3529             ret = new_ret;
3530         } else {
3531           break;
3532         }
3533       }
3534     }
3535   } else {
3536     /* this should be the main header, just push it all */
3537     buffer = gst_adapter_take_buffer (dash_stream->adapter,
3538         gst_adapter_available (dash_stream->adapter));
3539
3540     GST_BUFFER_OFFSET (buffer) = dash_stream->current_offset;
3541     GST_BUFFER_OFFSET_END (buffer) =
3542         GST_BUFFER_OFFSET (buffer) + gst_buffer_get_size (buffer);
3543     dash_stream->current_offset = GST_BUFFER_OFFSET_END (buffer);
3544
3545     ret = gst_adaptive_demux_stream_push_buffer (stream, buffer);
3546   }
3547
3548   return ret;
3549 }
3550
3551 static void
3552 gst_dash_demux_stream_free (GstAdaptiveDemuxStream * stream)
3553 {
3554   GstDashDemuxStream *dash_stream = (GstDashDemuxStream *) stream;
3555
3556   gst_isoff_sidx_parser_clear (&dash_stream->sidx_parser);
3557   if (dash_stream->adapter)
3558     g_object_unref (dash_stream->adapter);
3559   if (dash_stream->moof)
3560     gst_isoff_moof_box_free (dash_stream->moof);
3561   if (dash_stream->moof_sync_samples)
3562     g_array_free (dash_stream->moof_sync_samples, TRUE);
3563 }
3564
3565 static GstDashDemuxClockDrift *
3566 gst_dash_demux_clock_drift_new (GstDashDemux * demux)
3567 {
3568   GstDashDemuxClockDrift *clock_drift;
3569
3570   clock_drift = g_slice_new0 (GstDashDemuxClockDrift);
3571   g_mutex_init (&clock_drift->clock_lock);
3572   clock_drift->next_update =
3573       GST_TIME_AS_USECONDS (gst_adaptive_demux_get_monotonic_time
3574       (GST_ADAPTIVE_DEMUX_CAST (demux)));
3575   return clock_drift;
3576 }
3577
3578 static void
3579 gst_dash_demux_clock_drift_free (GstDashDemuxClockDrift * clock_drift)
3580 {
3581   if (clock_drift) {
3582     g_mutex_lock (&clock_drift->clock_lock);
3583     if (clock_drift->ntp_clock)
3584       g_object_unref (clock_drift->ntp_clock);
3585     g_mutex_unlock (&clock_drift->clock_lock);
3586     g_mutex_clear (&clock_drift->clock_lock);
3587     g_slice_free (GstDashDemuxClockDrift, clock_drift);
3588   }
3589 }
3590
3591 /*
3592  * The value attribute of the UTCTiming element contains a white-space
3593  * separated list of servers that are recommended to be used in
3594  * combination with the NTP protocol as defined in IETF RFC 5905 for
3595  * getting the appropriate time.
3596  *
3597  * The DASH standard does not specify which version of NTP. This
3598  * function only works with NTPv4 servers.
3599 */
3600 static GstDateTime *
3601 gst_dash_demux_poll_ntp_server (GstDashDemuxClockDrift * clock_drift,
3602     gchar ** urls)
3603 {
3604   GstClockTime ntp_clock_time;
3605   GDateTime *dt, *dt2;
3606
3607   if (!clock_drift->ntp_clock) {
3608     GResolver *resolver;
3609     GList *inet_addrs;
3610     GError *err = NULL;
3611     gchar *ip_addr;
3612
3613     resolver = g_resolver_get_default ();
3614     /* We don't round-robin NTP servers. If the manifest specifies multiple
3615        NTP time servers, select one at random */
3616     clock_drift->selected_url = g_random_int_range (0, g_strv_length (urls));
3617     GST_DEBUG ("Connecting to NTP time server %s",
3618         urls[clock_drift->selected_url]);
3619     inet_addrs = g_resolver_lookup_by_name (resolver,
3620         urls[clock_drift->selected_url], NULL, &err);
3621     g_object_unref (resolver);
3622     if (!inet_addrs || g_list_length (inet_addrs) == 0) {
3623       GST_ERROR ("Failed to resolve hostname of NTP server: %s",
3624           err ? (err->message) : "unknown error");
3625       if (inet_addrs)
3626         g_resolver_free_addresses (inet_addrs);
3627       if (err)
3628         g_error_free (err);
3629       return NULL;
3630     }
3631     ip_addr =
3632         g_inet_address_to_string ((GInetAddress
3633             *) (g_list_first (inet_addrs)->data));
3634     clock_drift->ntp_clock = gst_ntp_clock_new ("dashntp", ip_addr, 123, 0);
3635     g_free (ip_addr);
3636     g_resolver_free_addresses (inet_addrs);
3637     if (!clock_drift->ntp_clock) {
3638       GST_ERROR ("Failed to create NTP clock");
3639       return NULL;
3640     }
3641     if (!gst_clock_wait_for_sync (clock_drift->ntp_clock, 5 * GST_SECOND)) {
3642       g_object_unref (clock_drift->ntp_clock);
3643       clock_drift->ntp_clock = NULL;
3644       GST_ERROR ("Failed to lock to NTP clock");
3645       return NULL;
3646     }
3647   }
3648   ntp_clock_time = gst_clock_get_time (clock_drift->ntp_clock);
3649   if (ntp_clock_time == GST_CLOCK_TIME_NONE) {
3650     GST_ERROR ("Failed to get time from NTP clock");
3651     return NULL;
3652   }
3653   ntp_clock_time -= NTP_TO_UNIX_EPOCH * GST_SECOND;
3654   dt = g_date_time_new_from_unix_utc (ntp_clock_time / GST_SECOND);
3655   if (!dt) {
3656     GST_ERROR ("Failed to create GstDateTime");
3657     return NULL;
3658   }
3659   ntp_clock_time =
3660       gst_util_uint64_scale (ntp_clock_time % GST_SECOND, 1000000, GST_SECOND);
3661   dt2 = g_date_time_add (dt, ntp_clock_time);
3662   g_date_time_unref (dt);
3663   return gst_date_time_new_from_g_date_time (dt2);
3664 }
3665
3666 struct Rfc5322TimeZone
3667 {
3668   const gchar *name;
3669   gfloat tzoffset;
3670 };
3671
3672 /*
3673  Parse an RFC5322 (section 3.3) date-time from the Date: field in the
3674  HTTP response. 
3675  See https://tools.ietf.org/html/rfc5322#section-3.3
3676 */
3677 static GstDateTime *
3678 gst_dash_demux_parse_http_head (GstDashDemuxClockDrift * clock_drift,
3679     GstFragment * download)
3680 {
3681   static const gchar *months[] = { NULL, "Jan", "Feb", "Mar", "Apr",
3682     "May", "Jun", "Jul", "Aug",
3683     "Sep", "Oct", "Nov", "Dec", NULL
3684   };
3685   static const struct Rfc5322TimeZone timezones[] = {
3686     {"Z", 0},
3687     {"UT", 0},
3688     {"GMT", 0},
3689     {"BST", 1},
3690     {"EST", -5},
3691     {"EDT", -4},
3692     {"CST", -6},
3693     {"CDT", -5},
3694     {"MST", -7},
3695     {"MDT", -6},
3696     {"PST", -8},
3697     {"PDT", -7},
3698     {NULL, 0}
3699   };
3700   GstDateTime *value = NULL;
3701   const GstStructure *response_headers;
3702   const gchar *http_date;
3703   const GValue *val;
3704   gint ret;
3705   const gchar *pos;
3706   gint year = -1, month = -1, day = -1, hour = -1, minute = -1, second = -1;
3707   gchar zone[6];
3708   gchar monthstr[4];
3709   gfloat tzoffset = 0;
3710   gboolean parsed_tz = FALSE;
3711
3712   g_return_val_if_fail (download != NULL, NULL);
3713   g_return_val_if_fail (download->headers != NULL, NULL);
3714
3715   val = gst_structure_get_value (download->headers, "response-headers");
3716   if (!val) {
3717     return NULL;
3718   }
3719   response_headers = gst_value_get_structure (val);
3720   http_date = gst_structure_get_string (response_headers, "Date");
3721   if (!http_date) {
3722     return NULL;
3723   }
3724
3725   /* skip optional text version of day of the week */
3726   pos = strchr (http_date, ',');
3727   if (pos)
3728     pos++;
3729   else
3730     pos = http_date;
3731   ret =
3732       sscanf (pos, "%02d %3s %04d %02d:%02d:%02d %5s", &day, monthstr, &year,
3733       &hour, &minute, &second, zone);
3734   if (ret == 7) {
3735     gchar *z = zone;
3736     gint i;
3737
3738     for (i = 1; months[i]; ++i) {
3739       if (g_ascii_strncasecmp (months[i], monthstr, strlen (months[i])) == 0) {
3740         month = i;
3741         break;
3742       }
3743     }
3744     for (i = 0; timezones[i].name && !parsed_tz; ++i) {
3745       if (g_ascii_strncasecmp (timezones[i].name, z,
3746               strlen (timezones[i].name)) == 0) {
3747         tzoffset = timezones[i].tzoffset;
3748         parsed_tz = TRUE;
3749       }
3750     }
3751     if (!parsed_tz) {
3752       gint hh, mm;
3753       gboolean neg = FALSE;
3754       /* check if it is in the form +-HHMM */
3755       if (*z == '+' || *z == '-') {
3756         if (*z == '+')
3757           ++z;
3758         else if (*z == '-') {
3759           ++z;
3760           neg = TRUE;
3761         }
3762         ret = sscanf (z, "%02d%02d", &hh, &mm);
3763         if (ret == 2) {
3764           tzoffset = hh;
3765           tzoffset += mm / 60.0;
3766           if (neg)
3767             tzoffset = -tzoffset;
3768           parsed_tz = TRUE;
3769         }
3770       }
3771     }
3772     /* Accept year in both 2 digit or 4 digit format */
3773     if (year < 100)
3774       year += 2000;
3775   }
3776   if (month > 0 && parsed_tz) {
3777     value = gst_date_time_new (tzoffset,
3778         year, month, day, hour, minute, second);
3779   }
3780   return value;
3781 }
3782
3783 /*
3784    The timing information is contained in the message body of the HTTP
3785    response and contains a time value formatted according to NTP timestamp
3786    format in IETF RFC 5905.
3787
3788        0                   1                   2                   3
3789        0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
3790       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3791       |                            Seconds                            |
3792       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3793       |                            Fraction                           |
3794       +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
3795
3796                              NTP Timestamp Format
3797 */
3798 static GstDateTime *
3799 gst_dash_demux_parse_http_ntp (GstDashDemuxClockDrift * clock_drift,
3800     GstBuffer * buffer)
3801 {
3802   gint64 seconds;
3803   guint64 fraction;
3804   GDateTime *dt, *dt2;
3805   GstMapInfo mapinfo;
3806
3807   /* See https://tools.ietf.org/html/rfc5905#page-12 for details of
3808      the NTP Timestamp Format */
3809   gst_buffer_map (buffer, &mapinfo, GST_MAP_READ);
3810   if (mapinfo.size != 8) {
3811     gst_buffer_unmap (buffer, &mapinfo);
3812     return NULL;
3813   }
3814   seconds = GST_READ_UINT32_BE (mapinfo.data);
3815   fraction = GST_READ_UINT32_BE (mapinfo.data + 4);
3816   gst_buffer_unmap (buffer, &mapinfo);
3817   fraction = gst_util_uint64_scale (fraction, 1000000,
3818       G_GUINT64_CONSTANT (1) << 32);
3819   /* subtract constant to convert from 1900 based time to 1970 based time */
3820   seconds -= NTP_TO_UNIX_EPOCH;
3821   dt = g_date_time_new_from_unix_utc (seconds);
3822   dt2 = g_date_time_add (dt, fraction);
3823   g_date_time_unref (dt);
3824   return gst_date_time_new_from_g_date_time (dt2);
3825 }
3826
3827 /*
3828   The timing information is contained in the message body of the
3829   HTTP response and contains a time value formatted according to
3830   xs:dateTime as defined in W3C XML Schema Part 2: Datatypes specification.
3831 */
3832 static GstDateTime *
3833 gst_dash_demux_parse_http_xsdate (GstDashDemuxClockDrift * clock_drift,
3834     GstBuffer * buffer)
3835 {
3836   GstDateTime *value = NULL;
3837   GstMapInfo mapinfo;
3838
3839   /* the string from the server might not be zero terminated */
3840   if (gst_buffer_map (buffer, &mapinfo, GST_MAP_READ)) {
3841     gchar *str;
3842     str = g_strndup ((const gchar *) mapinfo.data, mapinfo.size);
3843     gst_buffer_unmap (buffer, &mapinfo);
3844     value = gst_date_time_new_from_iso8601_string (str);
3845     g_free (str);
3846   }
3847   return value;
3848 }
3849
3850 static gboolean
3851 gst_dash_demux_poll_clock_drift (GstDashDemux * demux)
3852 {
3853   GstDashDemuxClockDrift *clock_drift;
3854   GDateTime *start = NULL, *end;
3855   GstBuffer *buffer = NULL;
3856   GstDateTime *value = NULL;
3857   gboolean ret = FALSE;
3858   gint64 now;
3859   GstMPDUTCTimingType method;
3860   gchar **urls;
3861
3862   g_return_val_if_fail (demux != NULL, FALSE);
3863   g_return_val_if_fail (demux->clock_drift != NULL, FALSE);
3864   clock_drift = demux->clock_drift;
3865   now =
3866       GST_TIME_AS_USECONDS (gst_adaptive_demux_get_monotonic_time
3867       (GST_ADAPTIVE_DEMUX_CAST (demux)));
3868   if (now < clock_drift->next_update) {
3869     /*TODO: If a fragment fails to download in adaptivedemux, it waits
3870        for a manifest reload before another attempt to fetch a fragment.
3871        Section 10.8.6 of the DVB-DASH standard states that the DASH client
3872        shall refresh the manifest and resynchronise to one of the time sources.
3873
3874        Currently the fact that the manifest refresh follows a download failure
3875        does not make it into dashdemux. */
3876     return TRUE;
3877   }
3878   urls = gst_mpd_client_get_utc_timing_sources (demux->client,
3879       SUPPORTED_CLOCK_FORMATS, &method);
3880   if (!urls) {
3881     return FALSE;
3882   }
3883   /* Update selected_url just in case the number of URLs in the UTCTiming
3884      element has shrunk since the last poll */
3885   clock_drift->selected_url = clock_drift->selected_url % g_strv_length (urls);
3886   g_mutex_lock (&clock_drift->clock_lock);
3887
3888   if (method == GST_MPD_UTCTIMING_TYPE_NTP) {
3889     value = gst_dash_demux_poll_ntp_server (clock_drift, urls);
3890     if (!value) {
3891       GST_ERROR_OBJECT (demux, "Failed to fetch time from NTP server %s",
3892           urls[clock_drift->selected_url]);
3893       g_mutex_unlock (&clock_drift->clock_lock);
3894       goto quit;
3895     }
3896   }
3897   start =
3898       gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST (demux));
3899   if (!value) {
3900     GstFragment *download;
3901     gint64 range_start = 0, range_end = -1;
3902     GST_DEBUG_OBJECT (demux, "Fetching current time from %s",
3903         urls[clock_drift->selected_url]);
3904     if (method == GST_MPD_UTCTIMING_TYPE_HTTP_HEAD) {
3905       range_start = -1;
3906     }
3907     download =
3908         gst_uri_downloader_fetch_uri_with_range (GST_ADAPTIVE_DEMUX_CAST
3909         (demux)->downloader, urls[clock_drift->selected_url], NULL, TRUE, TRUE,
3910         TRUE, range_start, range_end, NULL);
3911     if (download) {
3912       if (method == GST_MPD_UTCTIMING_TYPE_HTTP_HEAD && download->headers) {
3913         value = gst_dash_demux_parse_http_head (clock_drift, download);
3914       } else {
3915         buffer = gst_fragment_get_buffer (download);
3916       }
3917       g_object_unref (download);
3918     }
3919   }
3920   g_mutex_unlock (&clock_drift->clock_lock);
3921   if (!value && !buffer) {
3922     GST_ERROR_OBJECT (demux, "Failed to fetch time from %s",
3923         urls[clock_drift->selected_url]);
3924     goto quit;
3925   }
3926   end = gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST (demux));
3927   if (!value && method == GST_MPD_UTCTIMING_TYPE_HTTP_NTP) {
3928     value = gst_dash_demux_parse_http_ntp (clock_drift, buffer);
3929   } else if (!value) {
3930     /* GST_MPD_UTCTIMING_TYPE_HTTP_XSDATE or GST_MPD_UTCTIMING_TYPE_HTTP_ISO */
3931     value = gst_dash_demux_parse_http_xsdate (clock_drift, buffer);
3932   }
3933   if (buffer)
3934     gst_buffer_unref (buffer);
3935   if (value) {
3936     GTimeSpan download_duration = g_date_time_difference (end, start);
3937     GDateTime *client_now, *server_now;
3938     /* We don't know when the server sampled its clock, but we know
3939        it must have been before "end" and probably after "start".
3940        A reasonable estimate is to use (start+end)/2
3941      */
3942     client_now = g_date_time_add (start, download_duration / 2);
3943     server_now = gst_date_time_to_g_date_time (value);
3944     /* If gst_date_time_new_from_iso8601_string is given an unsupported
3945        ISO 8601 format, it can return a GstDateTime that is not valid,
3946        which causes gst_date_time_to_g_date_time to return NULL */
3947     if (server_now) {
3948       g_mutex_lock (&clock_drift->clock_lock);
3949       clock_drift->clock_compensation =
3950           g_date_time_difference (server_now, client_now);
3951       g_mutex_unlock (&clock_drift->clock_lock);
3952       GST_DEBUG_OBJECT (demux,
3953           "Difference between client and server clocks is %lfs",
3954           ((double) clock_drift->clock_compensation) / 1000000.0);
3955       g_date_time_unref (server_now);
3956       ret = TRUE;
3957     } else {
3958       GST_ERROR_OBJECT (demux, "Failed to parse DateTime from server");
3959     }
3960     g_date_time_unref (client_now);
3961     gst_date_time_unref (value);
3962   } else {
3963     GST_ERROR_OBJECT (demux, "Failed to parse DateTime from server");
3964   }
3965   g_date_time_unref (end);
3966 quit:
3967   if (start)
3968     g_date_time_unref (start);
3969   /* if multiple URLs were specified, use a simple round-robin to
3970      poll each server */
3971   g_mutex_lock (&clock_drift->clock_lock);
3972   if (method == GST_MPD_UTCTIMING_TYPE_NTP) {
3973     clock_drift->next_update = now + FAST_CLOCK_UPDATE_INTERVAL;
3974   } else {
3975     clock_drift->selected_url =
3976         (1 + clock_drift->selected_url) % g_strv_length (urls);
3977     if (ret) {
3978       clock_drift->next_update = now + SLOW_CLOCK_UPDATE_INTERVAL;
3979     } else {
3980       clock_drift->next_update = now + FAST_CLOCK_UPDATE_INTERVAL;
3981     }
3982   }
3983   g_mutex_unlock (&clock_drift->clock_lock);
3984   return ret;
3985 }
3986
3987 static GTimeSpan
3988 gst_dash_demux_get_clock_compensation (GstDashDemux * demux)
3989 {
3990   GTimeSpan rv = 0;
3991   if (demux->clock_drift) {
3992     g_mutex_lock (&demux->clock_drift->clock_lock);
3993     rv = demux->clock_drift->clock_compensation;
3994     g_mutex_unlock (&demux->clock_drift->clock_lock);
3995   }
3996   GST_LOG_OBJECT (demux, "Clock drift %" GST_STIME_FORMAT, GST_STIME_ARGS (rv));
3997   return rv;
3998 }
3999
4000 static GDateTime *
4001 gst_dash_demux_get_server_now_utc (GstDashDemux * demux)
4002 {
4003   GDateTime *client_now;
4004   GDateTime *server_now;
4005
4006   client_now =
4007       gst_adaptive_demux_get_client_now_utc (GST_ADAPTIVE_DEMUX_CAST (demux));
4008   server_now =
4009       g_date_time_add (client_now,
4010       gst_dash_demux_get_clock_compensation (demux));
4011   g_date_time_unref (client_now);
4012   return server_now;
4013 }