]> git.sesse.net Git - vlc/blob - modules/stream_filter/hds/hds.c
enable the macosx GUI to handle negative stop-time
[vlc] / modules / stream_filter / hds / hds.c
1 /*****************************************************************************
2  * hds.c: Http Dynamic Streaming (HDS) stream filter
3  *****************************************************************************
4  *
5  * Author: Jonathan Thambidurai <jonathan _AT_ fastly _DOT_ com>
6  * Heavily inspired by SMooth module of Frédéric Yhuel <fyhuel _AT_ viotech _DOT_ net>
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, write to the Free Software
20  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301 USA
21  *****************************************************************************/
22
23 #ifdef HAVE_CONFIG_H
24 # include "config.h"
25 #endif
26
27 #include <limits.h> /* INT_MAX */
28
29 #include <vlc_common.h>
30 #include <vlc_plugin.h>
31 #include <vlc_stream.h>
32 #include <vlc_strings.h>            /* b64_decode */
33 #include <vlc_xml.h>
34 #include <vlc_charset.h>            /* FromCharset */
35 #include <vlc_es.h>                 /* UNKNOWN_ES */
36
37 typedef struct chunk_s
38 {
39     int64_t     duration;   /* chunk duration in afrt timescale units */
40     uint64_t    timestamp;
41     uint32_t    frag_num;
42     uint32_t    seg_num;
43     uint32_t    frun_entry; /* Used to speed things up in vod situations */
44
45     uint32_t    data_len;
46
47     uint32_t    mdat_pos;   /* position in the mdat */
48     uint32_t    mdat_len;
49
50     void        *next;
51
52     uint8_t     *mdat_data;
53     uint8_t     *data;
54     bool        failed;
55     bool        eof;
56 } chunk_t;
57
58 typedef struct segment_run_s
59 {
60     uint32_t first_segment;
61     uint32_t fragments_per_segment;
62 } segment_run_t;
63
64 typedef struct fragment_run_s
65 {
66     uint32_t fragment_number_start;
67     uint32_t fragment_duration;
68     uint64_t fragment_timestamp;
69     uint8_t  discont;
70 } fragment_run_t;
71
72 typedef struct hds_stream_s
73 {
74     /* linked-list of chunks */
75     chunk_t        *chunks_head;
76     chunk_t        *chunks_livereadpos;
77     chunk_t        *chunks_downloadpos;
78
79     char*          quality_segment_modifier;
80
81     /* we can make this configurable */
82     uint64_t       download_leadtime;
83
84     /* in timescale units */
85     uint32_t       afrt_timescale;
86
87     /* these two values come from the abst */
88     uint32_t       timescale;
89     uint64_t       live_current_time;
90
91     /* kilobits per second */
92     uint32_t       bitrate;
93
94     vlc_mutex_t    abst_lock;
95
96     vlc_mutex_t    dl_lock;
97     vlc_cond_t     dl_cond;
98
99     /* can be left as null */
100     char*          abst_url;
101
102     /* these come from the manifest media section  */
103     char*          url;
104     uint8_t*       metadata;
105     size_t         metadata_len;
106
107     /* this comes from the bootstrap info */
108     char*          movie_id;
109
110 #define MAX_HDS_SERVERS 10
111     char*          server_entries[MAX_HDS_SERVERS];
112     uint8_t        server_entry_count;
113
114 #define MAX_HDS_SEGMENT_RUNS 256
115     segment_run_t  segment_runs[MAX_HDS_SEGMENT_RUNS];
116     uint8_t        segment_run_count;
117
118 #define MAX_HDS_FRAGMENT_RUNS 10000
119     fragment_run_t fragment_runs[MAX_HDS_FRAGMENT_RUNS];
120     uint32_t       fragment_run_count;
121 } hds_stream_t;
122
123 /* this is effectively just a sanity check  mechanism */
124 #define MAX_REQUEST_SIZE (50*1024*1024)
125
126 #define BITRATE_AS_BYTES_PER_SECOND 1024/8
127
128 struct stream_sys_t
129 {
130     char         *base_url;    /* URL common part for chunks */
131     vlc_thread_t live_thread;
132     vlc_thread_t dl_thread;
133
134     /* we pend on peek until some number of segments arrives; otherwise
135      * the downstream system dies in case of playback */
136     uint64_t     chunk_count;
137
138     vlc_array_t  *hds_streams; /* available streams */
139
140     /* Buffer that holds the very first bytes of the stream: the FLV
141      * file header and a possible metadata packet.
142      */
143     uint8_t      *flv_header;
144     size_t       flv_header_len;
145     size_t       flv_header_bytes_sent;
146     uint64_t     duration_seconds;
147     uint64_t     playback_offset;
148
149     bool         live;
150     bool         closed;
151 };
152
153 typedef struct _bootstrap_info {
154     uint8_t* data;
155     char*    id;
156     char*    url;
157     char*    profile;
158     int      data_len;
159 } bootstrap_info;
160
161 typedef struct _media_info {
162     char*    stream_id;
163     char*    media_url;
164     char*    bootstrap_id;
165     uint8_t* metadata;
166     size_t   metadata_len;
167     uint32_t bitrate;
168 } media_info;
169
170 #define MAX_BOOTSTRAP_INFO 10
171 #define MAX_MEDIA_ELEMENTS 10
172 #define MAX_XML_DEPTH 256
173
174 typedef struct _manifest {
175     char* element_stack[MAX_XML_DEPTH];
176     bootstrap_info bootstraps[MAX_BOOTSTRAP_INFO];
177     media_info medias[MAX_MEDIA_ELEMENTS];
178     xml_reader_t *vlc_reader;
179     xml_t *vlc_xml;
180 } manifest_t;
181
182 static unsigned char flv_header_bytes[] = {
183         'F',
184         'L',
185         'V',
186         0x1, //version
187         0x5, //indicates audio and video
188         0x0, // length
189         0x0, // length
190         0x0, // length
191         0x9, // length of header
192         0x0,
193         0x0,
194         0x0,
195         0x0, // initial "trailer"
196 };
197
198 static unsigned char amf_object_end[] = { 0x0, 0x0, 0x9 };
199
200 #define FLV_FILE_HEADER_LEN sizeof(flv_header_bytes)
201 #define FLV_TAG_HEADER_LEN 15
202 #define SCRIPT_TAG 0x12
203
204 /*****************************************************************************
205  * Module descriptor
206  *****************************************************************************/
207 static int  Open( vlc_object_t * );
208 static void Close( vlc_object_t * );
209
210 vlc_module_begin()
211     set_category( CAT_INPUT )
212     set_subcategory( SUBCAT_INPUT_STREAM_FILTER )
213     set_description( N_("HTTP Dynamic Streaming") )
214     set_shortname( "Dynamic Streaming")
215     add_shortcut( "hds" )
216     set_capability( "stream_filter", 30 )
217     set_callbacks( Open, Close )
218 vlc_module_end()
219
220 static int   Read( stream_t *, void *, unsigned );
221 static int   Peek( stream_t *, const uint8_t **, unsigned );
222 static int   Control( stream_t *, int , va_list );
223
224 static inline bool isFQUrl( char* url )
225 {
226     return ( NULL != vlc_strcasestr( url, "https://") ||
227              NULL != vlc_strcasestr( url, "http://" ) );
228 }
229
230 static bool isHDS( stream_t *s )
231 {
232     const char *peek;
233     int i_size = stream_Peek( s->p_source, (const uint8_t**) &peek, 200 );
234     if( i_size < 200 )
235         return false;
236
237     char *str;
238
239     if( !memcmp( peek, "\xFF\xFE", 2 ) )
240     {
241         str = FromCharset( "UTF-16LE", peek, i_size );
242     }
243     else if( !memcmp( peek, "\xFE\xFF", 2 ) )
244     {
245         str = FromCharset( "UTF-16BE", peek, i_size );
246     }
247     else
248         str = strndup( peek, i_size );
249
250     if( str == NULL )
251         return false;
252
253     bool ret = strstr( str, "<manifest" ) != NULL;
254     free( str );
255     return ret;
256 }
257
258 static uint64_t get_stream_size( stream_t* s )
259 {
260     stream_sys_t *p_sys = s->p_sys;
261
262     if ( p_sys->live )
263         return 0;
264
265     if ( vlc_array_count( p_sys->hds_streams ) == 0 )
266         return 0;
267
268     hds_stream_t* hds_stream = p_sys->hds_streams->pp_elems[0];
269
270     if ( hds_stream->bitrate == 0 )
271         return 0;
272
273     return p_sys->flv_header_len + p_sys->duration_seconds *
274         hds_stream->bitrate * BITRATE_AS_BYTES_PER_SECOND;
275 }
276
277 static uint8_t* parse_asrt( vlc_object_t* p_this,
278                         hds_stream_t* s,
279                         uint8_t* data,
280                         uint8_t* data_end )
281 {
282     uint8_t* data_p = data;
283
284     uint32_t asrt_len = 0;
285     asrt_len = U32_AT( data_p );
286     if( asrt_len > data_end - data ||
287         data_end - data <  14 )
288     {
289         msg_Err( p_this, "Not enough asrt data (%"PRIu32", %tu)", asrt_len,
290                  data_end - data );
291         return NULL;
292     }
293
294     data_p += sizeof(asrt_len);
295
296     if( 0 != memcmp( "asrt", data_p, 4 ) )
297     {
298         msg_Err( p_this, "Cant find asrt in bootstrap" );
299         return NULL;
300     }
301     data_p += 4;
302
303     /* ignore flags and versions (we don't handle multiple updates) */
304     data_p += 4;
305
306     uint8_t quality_entry_count = *data_p;
307     bool quality_found = false;
308     data_p++;
309
310     if( ! s->quality_segment_modifier )
311     {
312         quality_found = true;
313     }
314
315     while( quality_entry_count-- > 0 )
316     {
317         char* str_start = (char*) data_p;
318         data_p = memchr( data_p, '\0', data_end - data_p );
319         if( ! data_p )
320         {
321             msg_Err( p_this, "Couldn't find quality entry string in asrt" );
322             return NULL;
323         }
324         data_p++;
325
326         if( ! quality_found )
327         {
328             if( ! strncmp( str_start, s->quality_segment_modifier,
329                            strlen(s->quality_segment_modifier) ) )
330             {
331                 quality_found = true;
332             }
333         }
334
335         if( data_p >= data_end )
336         {
337             msg_Err( p_this, "Premature end of asrt in quality entries" );
338             return NULL;
339         }
340     }
341
342     if( data_end - data_p < 4 )
343     {
344         msg_Err( p_this, "Premature end of asrt after quality entries" );
345         return NULL;
346     }
347
348     uint32_t segment_run_entry_count = U32_AT( data_p );
349     data_p += sizeof(segment_run_entry_count);
350
351     if( data_end - data_p < 8 * segment_run_entry_count )
352     {
353         msg_Err( p_this, "Not enough data in asrt for segment run entries" );
354         return NULL;
355     }
356
357     if( segment_run_entry_count >= MAX_HDS_SEGMENT_RUNS )
358     {
359         msg_Err( p_this, "Too many segment runs" );
360         return NULL;
361     }
362
363     while( segment_run_entry_count-- > 0 )
364     {
365         if( quality_found )
366         {
367             s->segment_runs[s->segment_run_count].first_segment = U32_AT(data_p);
368         }
369         data_p+=4;
370
371         if( quality_found )
372         {
373             s->segment_runs[s->segment_run_count].fragments_per_segment = U32_AT(data_p);
374         }
375         data_p+=4;
376
377         s->segment_run_count++;
378     }
379
380     return data_p;
381 }
382
383 static uint8_t* parse_afrt( vlc_object_t* p_this,
384                         hds_stream_t* s,
385                         uint8_t* data,
386                         uint8_t* data_end )
387 {
388     uint8_t* data_p = data;
389
390     uint32_t afrt_len = U32_AT( data_p );
391     if( afrt_len > data_end - data ||
392         data_end - data <  9 )
393     {
394         msg_Err( p_this, "Not enough afrt data %u, %td", afrt_len,
395                  data_end - data );
396         return NULL;
397     }
398     data_p += sizeof(afrt_len);
399
400     if( 0 != memcmp( data_p, "afrt", 4 ) )
401     {
402         msg_Err( p_this, "Cant find afrt in bootstrap" );
403         return NULL;
404     }
405     data_p += 4;
406
407     /* ignore flags and versions (we don't handle multiple updates) */
408     data_p += 4;
409
410     if( data_end - data_p < 9 )
411     {
412         msg_Err( p_this, "afrt is too short" );
413         return NULL;
414     }
415
416     s->afrt_timescale = U32_AT( data_p );
417     data_p += 4;
418
419     bool quality_found = false;
420     if( ! s->quality_segment_modifier )
421     {
422         quality_found = true;
423     }
424
425     uint32_t quality_entry_count = *data_p;
426     data_p++;
427     while( quality_entry_count-- > 0 )
428     {
429         char* str_start = (char*)data_p;
430         data_p = memchr( data_p, '\0', data_end - data_p );
431         if( ! data_p )
432         {
433             msg_Err( p_this, "Couldn't find quality entry string in afrt" );
434             return NULL;
435         }
436         data_p++;
437
438         if( ! quality_found )
439         {
440             if( ! strncmp( str_start, s->quality_segment_modifier,
441                            strlen(s->quality_segment_modifier) ) )
442             {
443                 quality_found = true;
444             }
445         }
446     }
447
448     if( data_end - data_p < 5 )
449     {
450         msg_Err( p_this, "No more space in afrt after quality entries" );
451         return NULL;
452     }
453
454     uint32_t fragment_run_entry_count = U32_AT( data_p );
455     data_p += sizeof(uint32_t);
456
457     while(fragment_run_entry_count-- > 0)
458     {
459         if( data_end - data_p < 16 )
460         {
461             msg_Err( p_this, "Not enough data in afrt" );
462             return NULL;
463         }
464
465         if( s->fragment_run_count >= MAX_HDS_FRAGMENT_RUNS )
466         {
467             msg_Err( p_this, "Too many fragment runs, exiting" );
468             return NULL;
469         }
470
471         s->fragment_runs[s->fragment_run_count].fragment_number_start = U32_AT(data_p);
472         data_p += 4;
473
474         s->fragment_runs[s->fragment_run_count].fragment_timestamp = U64_AT( data_p );
475         data_p += 8;
476
477         s->fragment_runs[s->fragment_run_count].fragment_duration = U32_AT( data_p );
478         data_p += 4;
479
480         s->fragment_runs[s->fragment_run_count].discont = 0;
481         if( s->fragment_runs[s->fragment_run_count].fragment_duration == 0 )
482         {
483             /* discontinuity flag */
484             s->fragment_runs[s->fragment_run_count].discont = *(data_p++);
485         }
486
487         s->fragment_run_count++;
488     }
489
490     if ( s->fragment_runs[s->fragment_run_count-1].fragment_number_start == 0 &&
491          s->fragment_runs[s->fragment_run_count-1].fragment_timestamp == 0 &&
492          s->fragment_runs[s->fragment_run_count-1].fragment_duration == 0 &&
493          s->fragment_runs[s->fragment_run_count-1].discont == 0 )
494     {
495         /* ignore sentinel value */
496         s->fragment_run_count--;
497     }
498
499     return data_p;
500 }
501
502 static inline chunk_t* chunk_new()
503 {
504     chunk_t* chunk = calloc(1, sizeof(chunk_t));
505     return chunk;
506 }
507
508 static void chunk_free( chunk_t * chunk )
509 {
510     FREENULL( chunk->data );
511     free( chunk );
512 }
513
514 static void parse_BootstrapData( vlc_object_t* p_this,
515                                  hds_stream_t * s,
516                                  uint8_t* data,
517                                  uint8_t* data_end )
518 {
519     uint8_t* data_p = data;
520
521     uint32_t abst_len = U32_AT( data_p );
522     if( abst_len > data_end - data
523         || data_end - data < 29 /* min size of data */ )
524     {
525         msg_Warn( p_this, "Not enough bootstrap data" );
526         return;
527     }
528     data_p += sizeof(abst_len);
529
530     if( 0 != memcmp( data_p, "abst", 4 ) )
531     {
532         msg_Warn( p_this, "Cant find abst in bootstrap" );
533         return;
534     }
535     data_p += 4;
536
537     /* version, flags*/
538     data_p += 4;
539
540     /* we ignore the version */
541     data_p += 4;
542
543     /* some flags we don't care about here because they are
544      * in the manifest
545      */
546     data_p += 1;
547
548     /* timescale */
549     s->timescale = U32_AT( data_p );
550     data_p += sizeof(s->timescale);
551
552     s->live_current_time = U64_AT( data_p );
553     data_p += sizeof(s->live_current_time);
554
555     /* smtpe time code offset */
556     data_p += 8;
557
558     s->movie_id = strndup( (char*)data_p, data_end - data_p );
559     data_p += ( strlen( s->movie_id ) + 1 );
560
561     if( data_end - data_p < 4 ) {
562         msg_Warn( p_this, "Not enough bootstrap after Movie Identifier" );
563         return;
564     }
565
566     uint8_t server_entry_count = 0;
567     server_entry_count = (uint8_t) *data_p;
568     data_p++;
569
570     s->server_entry_count = 0;
571     while( server_entry_count-- > 0 )
572     {
573         if( s->server_entry_count < MAX_HDS_SERVERS )
574         {
575             s->server_entries[s->server_entry_count++] = strndup( (char*)data_p,
576                                                                   data_end - data_p );
577             data_p += strlen( s->server_entries[s->server_entry_count-1] ) + 1;
578         }
579         else
580         {
581             msg_Warn( p_this, "Too many servers" );
582             data_p = memchr( data_p, '\0', data_end - data_p );
583             if( ! data_p )
584             {
585                 msg_Err( p_this, "Couldn't find server entry" );
586                 return;
587             }
588             data_p++;
589         }
590
591         if( data_p >= data_end )
592         {
593             msg_Warn( p_this, "Premature end of bootstrap info while reading servers" );
594             return;
595         }
596     }
597
598     if( data_end - data_p < 3 ) {
599         msg_Warn( p_this, "Not enough bootstrap after Servers" );
600         return;
601     }
602
603     s->quality_segment_modifier = NULL;
604
605     uint8_t quality_entry_count = *data_p;
606     data_p++;
607
608     if( quality_entry_count > 1 )
609     {
610         msg_Err( p_this, "I don't know what to do with multiple quality levels in the bootstrap - shouldn't this be handled at the manifest level?" );
611         return;
612     }
613
614     s->quality_segment_modifier = NULL;
615     while( quality_entry_count-- > 0 )
616     {
617         if( s->quality_segment_modifier )
618         {
619             s->quality_segment_modifier = strndup( (char*)data_p, data_end - data_p );
620         }
621         data_p += strnlen( (char*)data_p, data_end - data_p ) + 1;
622     }
623
624     if( data_end - data_p < 2 ) {
625         msg_Warn( p_this, "Not enough bootstrap after quality entries" );
626         return;
627     }
628
629     /* ignoring "DrmData" */
630     data_p = memchr( data_p, '\0', data_end - data_p );
631     if( ! data_p )
632     {
633         msg_Err( p_this, "Couldn't find DRM Data" );
634         return;
635     }
636     data_p++;
637
638     if( data_end - data_p < 2 ) {
639         msg_Warn( p_this, "Not enough bootstrap after drm data" );
640         return;
641     }
642
643     /* ignoring "metadata" */
644     data_p = memchr( data_p, '\0', data_end - data_p );
645     if( ! data_p )
646     {
647         msg_Err( p_this, "Couldn't find metadata");
648         return;
649     }
650     data_p++;
651
652     if( data_end - data_p < 2 ) {
653         msg_Warn( p_this, "Not enough bootstrap after drm data" );
654         return;
655     }
656
657     uint8_t asrt_count = *data_p;
658     data_p++;
659
660     s->segment_run_count = 0;
661     while( asrt_count-- > 0 &&
662            data_end > data_p &&
663            (data_p = parse_asrt( p_this, s, data_p, data_end )) );
664
665     if( ! data_p )
666     {
667         msg_Warn( p_this, "Couldn't find afrt data" );
668         return;
669     }
670
671     uint8_t afrt_count = *data_p;
672     data_p++;
673
674     s->fragment_run_count = 0;
675     while( afrt_count-- > 0 &&
676            data_end > data_p &&
677            (data_p = parse_afrt( p_this, s, data_p, data_end )) );
678 }
679
680 /* this only works with ANSI characters - this is ok
681    for the bootstrapinfo field which this function is
682    exclusively used for since it is merely a base64 encoding
683 */
684 static bool is_whitespace( char c )
685 {
686     return ( ' '  == c ||
687              '\t' == c ||
688              '\n' == c ||
689              '\v' == c ||
690              '\f' == c ||
691              '\r' == c );
692 }
693
694 /* see above note for is_whitespace */
695 static void whitespace_substr( char** start,
696                                char** end )
697 {
698     while( is_whitespace( **start ) && *start != *end ) {
699         (*start)++;
700     }
701
702     if( *start == *end )
703         return;
704
705     while( is_whitespace(*(*end - 1) ) ) {
706         (*end)--;
707     }
708 }
709
710 /* returns length (could be zero, indicating all of remaining data) */
711 /* ptr is to start of data, right after 'mdat' string */
712 static uint32_t find_chunk_mdat( vlc_object_t* p_this,
713                                  uint8_t* chunkdata, uint8_t* chunkdata_end,
714                                  uint8_t** mdatptr )
715 {
716     uint8_t* boxname = NULL;
717     uint8_t* boxdata = NULL;
718     uint64_t boxsize = 0;
719
720     do {
721         if( chunkdata_end < chunkdata ||
722             chunkdata_end - chunkdata < 8 )
723         {
724             msg_Err( p_this, "Couldn't find mdat in box 1!" );
725             *mdatptr = 0;
726             return 0;
727         }
728
729         boxsize = (uint64_t)U32_AT( chunkdata );
730         chunkdata += 4;
731
732         boxname = chunkdata;
733         chunkdata += 4;
734
735         if( boxsize == 1 )
736         {
737             if( chunkdata_end - chunkdata >= 12 )
738             {
739                 boxsize =  U64_AT(chunkdata);
740                 chunkdata += 8;
741             }
742             else
743             {
744                 msg_Err( p_this, "Couldn't find mdat in box 2!");
745                 *mdatptr = 0;
746                 return 0;
747             }
748             boxdata = chunkdata;
749             chunkdata += (boxsize - 16);
750         }
751         else
752         {
753             boxdata = chunkdata;
754             chunkdata += (boxsize - 8);
755         }
756     } while ( 0 != memcmp( boxname, "mdat", 4 ) );
757
758     *mdatptr = boxdata;
759
760     return chunkdata_end - ((uint8_t*)boxdata);
761 }
762
763 /* returns data ptr if valid (updating the chunk itself
764    tells the reader that the chunk is safe to read, which is not yet correct)*/
765 static uint8_t* download_chunk( stream_t *s,
766                                 stream_sys_t* sys,
767                                 hds_stream_t* stream, chunk_t* chunk )
768 {
769     const char* quality = "";
770     char* server_base = sys->base_url;
771     if( stream->server_entry_count > 0 &&
772         strlen(stream->server_entries[0]) > 0 )
773     {
774         server_base = stream->server_entries[0];
775     }
776
777     if( stream->quality_segment_modifier )
778     {
779         quality = stream->quality_segment_modifier;
780     }
781
782     const char* movie_id = "";
783     if( stream->url && strlen(stream->url) > 0 )
784     {
785         if( isFQUrl( stream->url ) )
786         {
787             server_base = stream->url;
788         }
789         else
790         {
791             movie_id = stream->url;
792         }
793     }
794
795     char* fragment_url;
796     if( 0 > asprintf( &fragment_url, "%s/%s%sSeg%u-Frag%u",
797               server_base,
798               movie_id,
799               quality,
800               chunk->seg_num,
801                       chunk->frag_num ) ) {
802         msg_Err(s, "Failed to allocate memory for fragment url" );
803         return NULL;
804     }
805
806     msg_Info(s, "Downloading fragment %s",  fragment_url );
807
808     stream_t* download_stream = stream_UrlNew( s, fragment_url );
809     if( ! download_stream )
810     {
811         msg_Err(s, "Failed to download fragment %s", fragment_url );
812         free( fragment_url );
813         chunk->failed = true;
814         return NULL;
815     }
816     free( fragment_url );
817
818     int64_t size = stream_Size( download_stream );
819     chunk->data_len = (uint32_t) size;
820
821     if( size > MAX_REQUEST_SIZE )
822     {
823         msg_Err(s, "Strangely-large chunk of %"PRIi64" Bytes", size );
824         return NULL;
825     }
826
827     uint8_t* data = malloc( size );
828     if( ! data )
829     {
830         msg_Err(s, "Couldn't allocate chunk" );
831         return NULL;
832     }
833
834     int read = stream_Read( download_stream, data,
835                             size );
836     chunk->data_len = read;
837
838     if( read < size )
839     {
840         msg_Err( s, "Requested %"PRIi64" bytes, "\
841                  "but only got %d", size, read );
842         data = realloc( chunk->data, read );
843         if( data != NULL )
844             chunk->data = data;
845         chunk->failed = true;
846         return NULL;
847     }
848     else
849     {
850         chunk->failed = false;
851     }
852
853     stream_Delete( download_stream );
854     return data;
855 }
856
857 static void* download_thread( void* p )
858 {
859     vlc_object_t* p_this = (vlc_object_t*)p;
860     stream_t* s = (stream_t*) p_this;
861     stream_sys_t* sys = s->p_sys;
862
863     if ( vlc_array_count( sys->hds_streams ) == 0 )
864         return NULL;
865
866     // TODO: Change here for selectable stream
867     hds_stream_t* hds_stream = sys->hds_streams->pp_elems[0];
868
869     int canc = vlc_savecancel();
870
871     vlc_mutex_lock( & hds_stream->dl_lock );
872
873     while( ! sys->closed )
874     {
875         if( ! hds_stream->chunks_downloadpos )
876         {
877             chunk_t* chunk = hds_stream->chunks_head;
878             while(chunk && chunk->data )
879             {
880                 chunk = chunk->next;
881             }
882
883             if( chunk && ! chunk->data )
884                 hds_stream->chunks_downloadpos = chunk;
885         }
886
887         while( hds_stream->chunks_downloadpos )
888         {
889             chunk_t *chunk = hds_stream->chunks_downloadpos;
890
891             uint8_t *data = download_chunk( (stream_t*)p_this,
892                                             sys,
893                                             hds_stream,
894                                             chunk );
895
896             if( ! chunk->failed )
897             {
898                 chunk->mdat_len =
899                     find_chunk_mdat( p_this,
900                                      data,
901                                      data + chunk->data_len,
902                                      & chunk->mdat_data );
903                 if( chunk->mdat_len == 0 ) {
904                     chunk->mdat_len = chunk->data_len - (chunk->mdat_data - data);
905                 }
906                 hds_stream->chunks_downloadpos = chunk->next;
907                 chunk->data = data;
908
909                 sys->chunk_count++;
910             }
911         }
912
913         vlc_cond_wait( & hds_stream->dl_cond,
914                        & hds_stream->dl_lock );
915     }
916
917     vlc_mutex_unlock( & hds_stream->dl_lock );
918
919     vlc_restorecancel( canc );
920     return NULL;
921 }
922
923 static chunk_t* generate_new_chunk(
924     vlc_object_t* p_this,
925     chunk_t* last_chunk,
926     hds_stream_t* hds_stream )
927 {
928     stream_t* s = (stream_t*) p_this;
929     stream_sys_t *sys = s->p_sys;
930     chunk_t *chunk = chunk_new();
931     unsigned int frun_entry = 0;
932
933     if( ! chunk ) {
934         msg_Err( p_this, "Couldn't allocate new chunk!" );
935         return NULL;
936     }
937
938     if( last_chunk )
939     {
940         chunk->timestamp = last_chunk->timestamp + last_chunk->duration;
941         chunk->frag_num = last_chunk->frag_num + 1;
942
943         if( ! sys->live )
944         {
945             frun_entry = last_chunk->frun_entry;
946         }
947     }
948     else
949     {
950         fragment_run_t* first_frun  = hds_stream->fragment_runs;
951         if( sys->live )
952         {
953             chunk->timestamp = (hds_stream->live_current_time * ((uint64_t)hds_stream->afrt_timescale)) / ((uint64_t)hds_stream->timescale);
954         }
955         else
956         {
957             chunk->timestamp = first_frun->fragment_timestamp;
958             chunk->frag_num =  first_frun->fragment_number_start;
959         }
960     }
961
962     for( ; frun_entry < hds_stream->fragment_run_count;
963          frun_entry++ )
964     {
965         /* check for discontinuity first */
966         if( hds_stream->fragment_runs[frun_entry].fragment_duration == 0 )
967         {
968             if( frun_entry == hds_stream->fragment_run_count - 1 )
969             {
970                 msg_Err( p_this, "Discontinuity but can't find next timestamp!");
971                 return NULL;
972             }
973
974             chunk->frag_num = hds_stream->fragment_runs[frun_entry+1].fragment_number_start;
975             chunk->duration = hds_stream->fragment_runs[frun_entry+1].fragment_duration;
976             chunk->timestamp = hds_stream->fragment_runs[frun_entry+1].fragment_timestamp;
977
978             frun_entry++;
979             break;
980         }
981
982         if( chunk->frag_num == 0 )
983         {
984             if( frun_entry == hds_stream->fragment_run_count - 1 ||
985                 ( chunk->timestamp >= hds_stream->fragment_runs[frun_entry].fragment_timestamp &&
986                   chunk->timestamp < hds_stream->fragment_runs[frun_entry+1].fragment_timestamp )
987                 )
988             {
989                 fragment_run_t* frun = hds_stream->fragment_runs + frun_entry;
990                 chunk->frag_num = frun->fragment_number_start + ( (chunk->timestamp - frun->fragment_timestamp) /
991                                                                   frun->fragment_duration );
992                 chunk->duration = frun->fragment_duration;
993             }
994
995         }
996
997         if( hds_stream->fragment_runs[frun_entry].fragment_number_start <=
998             chunk->frag_num &&
999             (frun_entry == hds_stream->fragment_run_count - 1 ||
1000              hds_stream->fragment_runs[frun_entry+1].fragment_number_start > chunk->frag_num ) )
1001         {
1002             chunk->duration = hds_stream->fragment_runs[frun_entry].fragment_duration;
1003             chunk->timestamp = hds_stream->fragment_runs[frun_entry].fragment_timestamp +
1004                 chunk->duration * (chunk->frag_num - hds_stream->fragment_runs[frun_entry].fragment_number_start);
1005             break;
1006         }
1007     }
1008
1009     if( frun_entry == hds_stream->fragment_run_count )
1010     {
1011         msg_Err( p_this, "Couldn'd find the fragment run!" );
1012         chunk_free( chunk );
1013         return NULL;
1014     }
1015
1016     int srun_entry = 0;
1017     unsigned int segment = 0;
1018     uint64_t fragments_accum = chunk->frag_num;
1019     for( srun_entry = 0; srun_entry < hds_stream->segment_run_count;
1020          srun_entry++ )
1021     {
1022         segment = hds_stream->segment_runs[srun_entry].first_segment +
1023             (chunk->frag_num - fragments_accum ) / hds_stream->segment_runs[srun_entry].fragments_per_segment;
1024
1025         if( srun_entry + 1 == hds_stream->segment_run_count ||
1026             hds_stream->segment_runs[srun_entry+1].first_segment > segment )
1027         {
1028             break;
1029         }
1030
1031         fragments_accum += (
1032             (hds_stream->segment_runs[srun_entry+1].first_segment -
1033              hds_stream->segment_runs[srun_entry].first_segment) *
1034             hds_stream->segment_runs[srun_entry].fragments_per_segment );
1035     }
1036
1037     chunk->seg_num = segment;
1038     chunk->frun_entry = frun_entry;
1039
1040     if( ! sys->live )
1041     {
1042         if( (chunk->timestamp + chunk->duration) / hds_stream->afrt_timescale  >= sys->duration_seconds )
1043         {
1044             chunk->eof = true;
1045         }
1046     }
1047
1048     return chunk;
1049 }
1050
1051 static void maintain_live_chunks(
1052     vlc_object_t* p_this,
1053     hds_stream_t* hds_stream
1054     )
1055 {
1056     if( ! hds_stream->chunks_head )
1057     {
1058         /* just start with the earliest in the abst
1059          * maybe it would be better to use the currentMediaTime?
1060          * but then we are right on the edge of buffering, esp for
1061          * small fragments */
1062         hds_stream->chunks_head = generate_new_chunk(
1063             p_this, 0, hds_stream );
1064         hds_stream->chunks_livereadpos = hds_stream->chunks_head;
1065     }
1066
1067     chunk_t* chunk = hds_stream->chunks_head;
1068     bool dl = false;
1069     while( chunk && ( chunk->timestamp * ((uint64_t)hds_stream->timescale) )
1070            / ((uint64_t)hds_stream->afrt_timescale)
1071            <= hds_stream->live_current_time )
1072     {
1073         if( chunk->next )
1074         {
1075             chunk = chunk->next;
1076         }
1077         else
1078         {
1079             chunk->next = generate_new_chunk( p_this, chunk, hds_stream );
1080             chunk = chunk->next;
1081             dl = true;
1082         }
1083     }
1084
1085     if( dl )
1086         vlc_cond_signal( & hds_stream->dl_cond );
1087
1088     chunk = hds_stream->chunks_head;
1089     while( chunk && chunk->data && chunk->mdat_pos >= chunk->mdat_len && chunk->next )
1090     {
1091         chunk_t* next_chunk = chunk->next;
1092         chunk_free( chunk );
1093         chunk = next_chunk;
1094     }
1095
1096     if( ! hds_stream->chunks_livereadpos )
1097         hds_stream->chunks_livereadpos = hds_stream->chunks_head;
1098
1099     hds_stream->chunks_head = chunk;
1100 }
1101
1102
1103 static void* live_thread( void* p )
1104 {
1105     vlc_object_t* p_this = (vlc_object_t*)p;
1106     stream_t* s = (stream_t*) p_this;
1107     stream_sys_t* sys = s->p_sys;
1108
1109     if ( vlc_array_count( sys->hds_streams ) == 0 )
1110         return NULL;
1111
1112     // TODO: Change here for selectable stream
1113     hds_stream_t* hds_stream = sys->hds_streams->pp_elems[0];
1114
1115     int canc = vlc_savecancel();
1116
1117     char* abst_url;
1118
1119     if( hds_stream->abst_url &&
1120         ( isFQUrl( hds_stream->abst_url ) ) )
1121     {
1122         if( !( abst_url = strdup( hds_stream->abst_url ) ) )
1123             return NULL;
1124     }
1125     else
1126     {
1127         char* server_base = sys->base_url;
1128
1129
1130         if( 0 > asprintf( &abst_url, "%s/%s",
1131                           server_base,
1132                           hds_stream->abst_url ) )
1133         {
1134             return NULL;
1135         }
1136     }
1137
1138     mtime_t last_dl_start_time;
1139
1140     while( ! sys->closed )
1141     {
1142         last_dl_start_time = mdate();
1143         stream_t* download_stream = stream_UrlNew( p_this, abst_url );
1144         if( ! download_stream )
1145         {
1146             msg_Err( p_this, "Failed to download abst %s", abst_url );
1147         }
1148         else
1149         {
1150             int64_t size = stream_Size( download_stream );
1151             uint8_t* data = malloc( size );
1152             int read = stream_Read( download_stream, data,
1153                                     size );
1154             if( read < size )
1155             {
1156                 msg_Err( p_this, "Requested %"PRIi64" bytes, "  \
1157                          "but only got %d", size, read );
1158
1159             }
1160             else
1161             {
1162                 vlc_mutex_lock( & hds_stream->abst_lock );
1163                 parse_BootstrapData( p_this, hds_stream,
1164                                      data, data + read );
1165                 vlc_mutex_unlock( & hds_stream->abst_lock );
1166                 maintain_live_chunks( p_this, hds_stream );
1167             }
1168
1169             free( data );
1170
1171             stream_Delete( download_stream );
1172         }
1173
1174         mwait( last_dl_start_time + ( ((int64_t)hds_stream->fragment_runs[hds_stream->fragment_run_count-1].fragment_duration) * 1000000LL) / ((int64_t)hds_stream->afrt_timescale) );
1175
1176
1177     }
1178
1179     free( abst_url );
1180
1181     vlc_restorecancel( canc );
1182     return NULL;
1183 }
1184
1185 static int init_Manifest( stream_t *s, manifest_t *m )
1186 {
1187     memset(m, 0, sizeof(*m));
1188     stream_t *st = s->p_source;
1189     m->vlc_xml = xml_Create( st );
1190     if( !m->vlc_xml )
1191     {
1192         msg_Err( s, "Failed to open XML parser" );
1193         return VLC_EGENERIC;
1194     }
1195
1196     m->vlc_reader = xml_ReaderCreate( m->vlc_xml, st );
1197     if( !m->vlc_reader )
1198     {
1199         msg_Err( s, "Failed to open source for parsing" );
1200         return VLC_EGENERIC;
1201     }
1202
1203     return VLC_SUCCESS;
1204 }
1205
1206 static void cleanup_Manifest( manifest_t *m )
1207 {
1208     for (unsigned i = 0; i < MAX_XML_DEPTH; i++)
1209         free( m->element_stack[i] );
1210
1211     for( unsigned i = 0; i < MAX_MEDIA_ELEMENTS; i++ )
1212     {
1213         free( m->medias[i].stream_id );
1214         free( m->medias[i].media_url );
1215         free( m->medias[i].bootstrap_id );
1216         free( m->medias[i].metadata );
1217     }
1218
1219     for( unsigned i = 0; i < MAX_BOOTSTRAP_INFO; i++ )
1220     {
1221         free( m->bootstraps[i].data );
1222         free( m->bootstraps[i].id );
1223         free( m->bootstraps[i].url );
1224         free( m->bootstraps[i].profile );
1225     }
1226
1227     if( m->vlc_reader )
1228         xml_ReaderDelete( m->vlc_reader );
1229     if( m->vlc_xml )
1230         xml_Delete( m->vlc_xml );
1231 }
1232
1233 static void cleanup_threading( hds_stream_t *stream )
1234 {
1235     vlc_mutex_destroy( &stream->dl_lock );
1236     vlc_cond_destroy( &stream->dl_cond );
1237     vlc_mutex_destroy( &stream->abst_lock );
1238 }
1239
1240 static void write_int_24( uint8_t *p, uint32_t val )
1241 {
1242     *p         = ( val & 0xFF0000 ) >> 16;
1243     *( p + 1 ) = ( val & 0xFF00 ) >> 8;
1244     *( p + 2 ) = val & 0xFF;
1245 }
1246
1247 static void write_int_32( uint8_t *p, uint32_t val )
1248 {
1249     *p         = ( val & 0xFF000000 ) >> 24;
1250     *( p + 1 ) = ( val & 0xFF0000 ) >> 16;
1251     *( p + 2 ) = ( val & 0xFF00 ) >> 8;
1252     *( p + 3 ) = val & 0xFF;
1253 }
1254
1255 static size_t write_flv_header_and_metadata(
1256     uint8_t **pp_buffer,
1257     const uint8_t *p_metadata_payload,
1258     size_t metadata_payload_len )
1259 {
1260     size_t metadata_packet_len;
1261     if ( metadata_payload_len > 0 && p_metadata_payload )
1262         metadata_packet_len = FLV_TAG_HEADER_LEN + metadata_payload_len;
1263     else
1264         metadata_packet_len = 0;
1265     size_t data_len = FLV_FILE_HEADER_LEN + metadata_packet_len;
1266
1267     *pp_buffer = malloc( data_len );
1268     if ( ! *pp_buffer )
1269     {
1270         return 0;
1271     }
1272
1273     // FLV file header
1274     memcpy( *pp_buffer, flv_header_bytes, FLV_FILE_HEADER_LEN );
1275
1276     if ( metadata_packet_len > 0 )
1277     {
1278         uint8_t *p = *pp_buffer + FLV_FILE_HEADER_LEN;
1279
1280         // tag type
1281         *p = SCRIPT_TAG;
1282         p++;
1283
1284         // payload size
1285         write_int_24( p, metadata_payload_len );
1286         p += 3;
1287
1288         // timestamp and stream id
1289         memset( p, 0, 7 );
1290         p += 7;
1291
1292         // metadata payload
1293         memcpy( p, p_metadata_payload, metadata_payload_len );
1294         p += metadata_payload_len;
1295
1296         // packet payload size
1297         write_int_32( p, metadata_packet_len );
1298     }
1299
1300     return data_len;
1301 }
1302
1303 static void initialize_header_and_metadata( stream_sys_t* p_sys, hds_stream_t *stream )
1304 {
1305     p_sys->flv_header_len =
1306         write_flv_header_and_metadata( &p_sys->flv_header, stream->metadata,
1307                                        stream->metadata_len );
1308 }
1309
1310 static int parse_Manifest( stream_t *s, manifest_t *m )
1311 {
1312     int type = UNKNOWN_ES;
1313
1314     msg_Dbg( s, "Manifest parsing\n" );
1315
1316     char *node;
1317
1318     stream_sys_t *sys = s->p_sys;
1319
1320     sys->duration_seconds = 0;
1321
1322     uint8_t bootstrap_idx = 0;
1323     uint8_t media_idx = 0;
1324     uint8_t current_element_idx = 0;
1325     char* current_element = NULL;
1326
1327     const char* attr_name;
1328     const char* attr_value;
1329
1330     char** element_stack = m->element_stack;
1331     bootstrap_info *bootstraps = m->bootstraps;
1332     media_info *medias = m->medias;
1333     xml_reader_t *vlc_reader = m->vlc_reader;
1334     char* media_id = NULL;
1335
1336 #define TIMESCALE 10000000
1337     while( (type = xml_ReaderNextNode( vlc_reader, (const char**) &node )) > 0 )
1338     {
1339         switch( type )
1340         {
1341         case XML_READER_STARTELEM:
1342             if( current_element_idx == 0 && element_stack[current_element_idx] == 0 ) {
1343                 if( !( element_stack[current_element_idx] = strdup( node ) ) )
1344                     return VLC_ENOMEM;
1345             } else {
1346                 if ( !( element_stack[++current_element_idx] = strdup( node ) ) )
1347                     return VLC_ENOMEM;
1348             }
1349
1350             break;
1351         case XML_READER_ENDELEM:
1352             if( current_element && ! strcmp( current_element, "bootstrapInfo") ) {
1353                 if( bootstrap_idx + 1 == MAX_BOOTSTRAP_INFO ) {
1354                     msg_Warn( (vlc_object_t*) s, "Too many bootstraps, ignoring" );
1355                 } else {
1356                     bootstrap_idx++;
1357                 }
1358             }
1359
1360             free( current_element );
1361             current_element = NULL;
1362             element_stack[current_element_idx--] = 0;
1363             break;
1364         }
1365
1366         if( ! element_stack[current_element_idx] ) {
1367             continue;
1368         }
1369
1370         current_element = element_stack[current_element_idx];
1371
1372         if( type == XML_READER_STARTELEM && ! strcmp( current_element, "media") )
1373         {
1374             if( media_idx == MAX_MEDIA_ELEMENTS )
1375             {
1376                 msg_Err( (vlc_object_t*) s, "Too many media elements, quitting" );
1377                 return VLC_EGENERIC;
1378             }
1379
1380             while( ( attr_name = xml_ReaderNextAttr( vlc_reader, &attr_value )) )
1381             {
1382                 if( !strcmp(attr_name, "streamId" ) )
1383                 {
1384                     if( !( medias[media_idx].stream_id = strdup( attr_value ) ) )
1385                         return VLC_ENOMEM;
1386                 }
1387                 else if( !strcmp(attr_name, "url" ) )
1388                 {
1389                     if( !( medias[media_idx].media_url = strdup( attr_value ) ) )
1390                         return VLC_ENOMEM;
1391                 }
1392                 else if( !strcmp(attr_name, "bootstrapInfoId" ) )
1393                 {
1394                     if( !( medias[media_idx].bootstrap_id = strdup( attr_value ) ) )
1395                         return VLC_ENOMEM;
1396                 }
1397                 else if( !strcmp(attr_name, "bitrate" ) )
1398                 {
1399                     medias[media_idx].bitrate = (uint32_t) atoi( attr_value );
1400                 }
1401             }
1402             media_idx++;
1403         }
1404
1405         else if( type == XML_READER_STARTELEM && ! strcmp( current_element, "bootstrapInfo") )
1406         {
1407             while( ( attr_name = xml_ReaderNextAttr( vlc_reader, &attr_value )) )
1408             {
1409                 if( !strcmp(attr_name, "url" ) )
1410                 {
1411                     if( !( bootstraps[bootstrap_idx].url = strdup( attr_value ) ) )
1412                         return VLC_ENOMEM;
1413                 }
1414                 else if( !strcmp(attr_name, "id" ) )
1415                 {
1416                     if( !( bootstraps[bootstrap_idx].id = strdup( attr_value ) ) )
1417                        return VLC_ENOMEM;
1418                 }
1419                 else if( !strcmp(attr_name, "profile" ) )
1420                 {
1421                     if( !( bootstraps[bootstrap_idx].profile = strdup( attr_value ) ) )
1422                         return VLC_ENOMEM;
1423                 }
1424             }
1425         }
1426
1427         else if( type == XML_READER_TEXT )
1428         {
1429             if( ! strcmp( current_element, "bootstrapInfo" ) )
1430             {
1431                 char* start = node;
1432                 char* end = start + strlen(start);
1433                 whitespace_substr( &start, &end );
1434                 *end = '\0';
1435
1436                 bootstraps[bootstrap_idx].data_len =
1437                     vlc_b64_decode_binary( (uint8_t**)&bootstraps[bootstrap_idx].data, start );
1438                 if( ! bootstraps[bootstrap_idx].data )
1439                 {
1440                     msg_Err( (vlc_object_t*) s, "Couldn't decode bootstrap info" );
1441                 }
1442             }
1443             else if( ! strcmp( current_element, "duration" ) )
1444             {
1445                 double shutup_gcc = atof( node );
1446                 sys->duration_seconds = (uint64_t) shutup_gcc;
1447             }
1448             else if( ! strcmp( current_element, "id" ) )
1449             {
1450                 if( ! strcmp( element_stack[current_element_idx-1], "manifest" ) )
1451                 {
1452                     if( !( media_id = strdup( node ) ) )
1453                         return VLC_ENOMEM;
1454                 }
1455             }
1456             else if( ! strcmp( current_element, "metadata" ) &&
1457                      ! strcmp( element_stack[current_element_idx-1], "media" ) &&
1458                      ( media_idx >= 1 ) )
1459             {
1460                 uint8_t mi = media_idx - 1;
1461                 if ( ! medias[mi].metadata )
1462                 {
1463                     char* start = node;
1464                     char* end = start + strlen(start);
1465                     whitespace_substr( &start, &end );
1466                     *end = '\0';
1467
1468                     medias[mi].metadata_len =
1469                         vlc_b64_decode_binary( (uint8_t**)&medias[mi].metadata, start );
1470
1471                     if ( ! medias[mi].metadata )
1472                         return VLC_ENOMEM;
1473
1474                     uint8_t *end_marker =
1475                         medias[mi].metadata + medias[mi].metadata_len - sizeof(amf_object_end);
1476                     if ( ( end_marker < medias[mi].metadata ) ||
1477                          memcmp(end_marker, amf_object_end, sizeof(amf_object_end)) != 0 )
1478                     {
1479                         msg_Dbg( (vlc_object_t*)s, "Ignoring invalid metadata packet on stream %d", mi );
1480                         FREENULL( medias[mi].metadata );
1481                         medias[mi].metadata_len = 0;
1482                     }
1483                 }
1484             }
1485         }
1486     }
1487
1488     for( int i = 0; i <= media_idx; i++ )
1489     {
1490         for( int j = 0; j < bootstrap_idx; j++ )
1491         {
1492             if( ( ! medias[i].bootstrap_id && ! bootstraps[j].id ) ||
1493                 (medias[i].bootstrap_id && bootstraps[j].id &&
1494                  ! strcmp( medias[i].bootstrap_id, bootstraps[j].id ) ) )
1495             {
1496                 hds_stream_t* new_stream = malloc(sizeof(hds_stream_t));
1497                 if( !new_stream )
1498                 {
1499                     free(media_id);
1500                     return VLC_ENOMEM;
1501                 }
1502                 memset( new_stream, 0, sizeof(hds_stream_t));
1503
1504                 vlc_mutex_init( & new_stream->abst_lock );
1505                 vlc_mutex_init( & new_stream->dl_lock );
1506                 vlc_cond_init( & new_stream->dl_cond );
1507
1508                 if( sys->duration_seconds )
1509                 {
1510                     sys->live = false;
1511                 }
1512                 else
1513                 {
1514                     sys->live = true;
1515                 }
1516
1517                 if( medias[i].media_url )
1518                 {
1519                     if( !(new_stream->url = strdup( medias[i].media_url ) ) )
1520                     {
1521                         free( media_id );
1522                         cleanup_threading( new_stream );
1523                         free( new_stream );
1524                         return VLC_ENOMEM;
1525                     }
1526                 }
1527
1528                 if( medias[i].metadata )
1529                 {
1530                     new_stream->metadata = malloc( medias[i].metadata_len );
1531                     if ( ! new_stream->metadata )
1532                     {
1533                         free( new_stream->url );
1534                         free( media_id );
1535                         cleanup_threading( new_stream );
1536                         free( new_stream );
1537                         return VLC_ENOMEM;
1538                     }
1539
1540                     memcpy( new_stream->metadata, medias[i].metadata, medias[i].metadata_len );
1541                     new_stream->metadata_len = medias[i].metadata_len;
1542                 }
1543
1544                 if( ! sys->live )
1545                 {
1546                     parse_BootstrapData( (vlc_object_t*)s,
1547                                          new_stream,
1548                                          bootstraps[j].data,
1549                                          bootstraps[j].data + bootstraps[j].data_len );
1550
1551                     new_stream->download_leadtime = 15;
1552
1553                     new_stream->chunks_head = generate_new_chunk(
1554                         (vlc_object_t*) s, 0, new_stream );
1555                     chunk_t* chunk = new_stream->chunks_head;
1556                     uint64_t total_duration = chunk->duration;
1557                     while( chunk && total_duration/new_stream->afrt_timescale < new_stream->download_leadtime )
1558                     {
1559                         chunk->next = generate_new_chunk(
1560                             (vlc_object_t*) s, chunk, new_stream );
1561                         chunk = chunk->next;
1562                         if( chunk )
1563                             total_duration += chunk->duration;
1564                     }
1565                 }
1566                 else
1567                 {
1568                     if( !(new_stream->abst_url = strdup( bootstraps[j].url ) ) )
1569                     {
1570                         free( new_stream->metadata );
1571                         free( new_stream->url );
1572                         free( media_id );
1573                         cleanup_threading( new_stream );
1574                         free( new_stream );
1575                         return VLC_ENOMEM;
1576                     }
1577                 }
1578
1579                 new_stream->bitrate = medias[i].bitrate;
1580
1581                 vlc_array_append( sys->hds_streams, new_stream );
1582
1583                 msg_Info( (vlc_object_t*)s, "New track with quality_segment(%s), bitrate(%u), timescale(%u), movie_id(%s), segment_run_count(%d), fragment_run_count(%u)",
1584                           new_stream->quality_segment_modifier?new_stream->quality_segment_modifier:"", new_stream->bitrate, new_stream->timescale,
1585                           new_stream->movie_id, new_stream->segment_run_count, new_stream->fragment_run_count );
1586
1587             }
1588         }
1589     }
1590
1591     free( media_id );
1592     cleanup_Manifest( m );
1593
1594     return VLC_SUCCESS;
1595 }
1596
1597
1598 static void hds_free( hds_stream_t *p_stream )
1599 {
1600     FREENULL( p_stream->quality_segment_modifier );
1601
1602     FREENULL( p_stream->abst_url );
1603
1604     cleanup_threading( p_stream );
1605
1606     FREENULL( p_stream->metadata );
1607     FREENULL( p_stream->url );
1608     FREENULL( p_stream->movie_id );
1609     for( int i = 0; i < p_stream->server_entry_count; i++ )
1610     {
1611         FREENULL( p_stream->server_entries[i] );
1612     }
1613
1614     chunk_t* chunk = p_stream->chunks_head;
1615     while( chunk )
1616     {
1617         chunk_t* next = chunk->next;
1618         chunk_free( chunk );
1619         chunk = next;
1620     }
1621
1622     free( p_stream );
1623 }
1624
1625 static void SysCleanup( stream_sys_t *p_sys )
1626 {
1627     if ( p_sys->hds_streams )
1628     {
1629         for ( int i=0; i< p_sys->hds_streams->i_count ; i++ )
1630             hds_free( p_sys->hds_streams->pp_elems[i] );
1631         vlc_array_destroy( p_sys->hds_streams );
1632     }
1633     free( p_sys->base_url );
1634 }
1635
1636 static int Open( vlc_object_t *p_this )
1637 {
1638     stream_t *s = (stream_t*)p_this;
1639     stream_sys_t *p_sys;
1640
1641     if( !isHDS( s ) )
1642         return VLC_EGENERIC;
1643
1644     msg_Info( p_this, "HTTP Dynamic Streaming (%s)", s->psz_path );
1645
1646     s->p_sys = p_sys = calloc( 1, sizeof(*p_sys ) );
1647     if( unlikely( p_sys == NULL ) )
1648         return VLC_ENOMEM;
1649
1650     char *uri_without_query = NULL;
1651     size_t pathlen = strcspn( s->psz_path, "?" );
1652     if( unlikely( ( pathlen > INT_MAX ) ||
1653         ( asprintf( &uri_without_query, "%s://%.*s", s->psz_access,
1654                     (int)pathlen, s->psz_path ) < 0 ) ) )
1655     {
1656         free( p_sys );
1657         return VLC_ENOMEM;
1658     }
1659
1660     /* remove the last part of the url */
1661     char *pos = strrchr( uri_without_query, '/');
1662     *pos = '\0';
1663     p_sys->base_url = uri_without_query;
1664
1665     p_sys->flv_header_bytes_sent = 0;
1666
1667     p_sys->hds_streams = vlc_array_new();
1668
1669     manifest_t m;
1670     if( init_Manifest( s, &m ) || parse_Manifest( s, &m ) )
1671     {
1672         cleanup_Manifest( &m );
1673         goto error;
1674     }
1675
1676     s->pf_read = Read;
1677     s->pf_peek = Peek;
1678     s->pf_control = Control;
1679
1680     if( vlc_clone( &p_sys->dl_thread, download_thread, s, VLC_THREAD_PRIORITY_INPUT ) )
1681     {
1682         goto error;
1683     }
1684
1685     if( p_sys->live ) {
1686         msg_Info( p_this, "Live stream detected" );
1687
1688         if( vlc_clone( &p_sys->live_thread, live_thread, s, VLC_THREAD_PRIORITY_INPUT ) )
1689         {
1690             goto error;
1691         }
1692     }
1693
1694     return VLC_SUCCESS;
1695
1696 error:
1697     SysCleanup( p_sys );
1698     free( p_sys );
1699     return VLC_EGENERIC;
1700 }
1701
1702 static void Close( vlc_object_t *p_this )
1703 {
1704     stream_t *s = (stream_t*)p_this;
1705     stream_sys_t *p_sys = s->p_sys;
1706
1707     // TODO: Change here for selectable stream
1708     hds_stream_t *stream = vlc_array_count(p_sys->hds_streams) ?
1709         s->p_sys->hds_streams->pp_elems[0] : NULL;
1710
1711     p_sys->closed = true;
1712     if (stream)
1713         vlc_cond_signal( & stream->dl_cond );
1714
1715     vlc_join( p_sys->dl_thread, NULL );
1716
1717     if( p_sys->live )
1718     {
1719         vlc_join( p_sys->live_thread, NULL );
1720     }
1721
1722     SysCleanup( p_sys );
1723     free( p_sys );
1724 }
1725
1726 static int send_flv_header( hds_stream_t *stream, stream_sys_t* p_sys,
1727                             void* buffer, unsigned i_read, bool peek )
1728 {
1729     if ( !p_sys->flv_header )
1730     {
1731         initialize_header_and_metadata( p_sys, stream );
1732     }
1733
1734     uint32_t to_be_read = i_read;
1735     uint32_t header_remaining =
1736         p_sys->flv_header_len - p_sys->flv_header_bytes_sent;
1737     if( to_be_read > header_remaining ) {
1738         to_be_read = header_remaining;
1739     }
1740
1741     memcpy( buffer, p_sys->flv_header + p_sys->flv_header_bytes_sent, to_be_read );
1742
1743     if( ! peek )
1744     {
1745         p_sys->flv_header_bytes_sent += to_be_read;
1746     }
1747     return to_be_read;
1748 }
1749
1750 static unsigned read_chunk_data(
1751     vlc_object_t* p_this,
1752     uint8_t* buffer, unsigned read_len,
1753     hds_stream_t* stream,
1754     bool* eof
1755     )
1756 {
1757     stream_t* s = (stream_t*) p_this;
1758     stream_sys_t* sys = s->p_sys;
1759     chunk_t* chunk = stream->chunks_head;
1760     uint8_t* buffer_start = buffer;
1761     bool dl = false;
1762
1763     if( chunk && chunk->eof && chunk->mdat_pos >= chunk->mdat_len ) {
1764         *eof = true;
1765         return 0;
1766     }
1767
1768     while( chunk && chunk->data && read_len > 0 && ! (chunk->eof && chunk->mdat_pos >= chunk->mdat_len ) )
1769     {
1770         /* in the live case, it is necessary to store the next
1771          * pointer here, since as soon as we increment the mdat_pos, that
1772          * chunk may be deleted */
1773         chunk_t* next = chunk->next;
1774
1775         if( chunk->mdat_pos < chunk->mdat_len )
1776         {
1777             unsigned cp_len = chunk->mdat_len - chunk->mdat_pos;
1778             if( cp_len > read_len )
1779                 cp_len = read_len;
1780             memcpy( buffer, chunk->mdat_data + chunk->mdat_pos,
1781                     cp_len );
1782
1783             read_len -= cp_len;
1784             buffer += cp_len;
1785             chunk->mdat_pos += cp_len;
1786         }
1787
1788         if( ! sys->live && (chunk->mdat_pos >= chunk->mdat_len || chunk->failed) )
1789         {
1790             if( chunk->eof )
1791             {
1792                 *eof = true;
1793             }
1794
1795             /* make sure there is at least one chunk in the queue */
1796             if( ! chunk->next && ! chunk->eof )
1797             {
1798                 chunk->next = generate_new_chunk( p_this, chunk,  stream );
1799                 dl = true;
1800             }
1801
1802             if( ! chunk->eof )
1803             {
1804                 chunk_free( chunk );
1805                 chunk = next;
1806                 stream->chunks_head = chunk;
1807             }
1808         }
1809         else if( sys->live && (chunk->mdat_pos >= chunk->mdat_len || chunk->failed) )
1810         {
1811             chunk = next;
1812         }
1813     }
1814
1815     if( sys->live )
1816     {
1817         stream->chunks_livereadpos = chunk;
1818     }
1819
1820     /* new chunk generation is handled by a different thread in live case */
1821     if( ! sys->live )
1822     {
1823         chunk = stream->chunks_head;
1824         if( chunk )
1825         {
1826             uint64_t total_duration = chunk->duration;
1827             while( chunk && total_duration/stream->afrt_timescale < stream->download_leadtime && ! chunk->eof )
1828             {
1829                 if( ! chunk->next && ! chunk->eof )
1830                 {
1831                     chunk->next = generate_new_chunk( p_this, chunk, stream );
1832                     dl = true;
1833                 }
1834
1835                 if( ! chunk->eof )
1836                 {
1837                     chunk = chunk->next;
1838                     if( chunk )
1839                     {
1840                         total_duration += chunk->duration;
1841                     }
1842                 }
1843             }
1844         }
1845
1846         if( dl )
1847             vlc_cond_signal( & stream->dl_cond );
1848     }
1849
1850     return ( ((uint8_t*)buffer) - ((uint8_t*)buffer_start));
1851 }
1852
1853 static inline bool header_unfinished( stream_sys_t *p_sys )
1854 {
1855     return p_sys->flv_header_bytes_sent < p_sys->flv_header_len;
1856 }
1857
1858 static int Read( stream_t *s, void *buffer, unsigned i_read )
1859 {
1860     stream_sys_t *p_sys = s->p_sys;
1861
1862     if ( vlc_array_count( p_sys->hds_streams ) == 0 )
1863         return 0;
1864
1865     // TODO: change here for selectable stream
1866     hds_stream_t *stream = s->p_sys->hds_streams->pp_elems[0];
1867     int length = 0;
1868
1869     uint8_t *buffer_uint8 = (uint8_t*) buffer;
1870
1871     if ( header_unfinished( p_sys ) )
1872     {
1873         unsigned hdr_bytes = send_flv_header( stream, p_sys, buffer, i_read, false );
1874         length += hdr_bytes;
1875         i_read -= hdr_bytes;
1876         buffer_uint8 += hdr_bytes;
1877     }
1878
1879     bool eof = false;
1880     while( i_read > 0 && ! eof )
1881     {
1882         int tmp_length = read_chunk_data( (vlc_object_t*)s, buffer_uint8, i_read, stream, &eof );
1883         buffer_uint8 += tmp_length;
1884         i_read -= tmp_length;
1885         length += tmp_length;
1886         p_sys->playback_offset += tmp_length;
1887     }
1888
1889     return length;
1890 }
1891
1892 static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned i_peek )
1893 {
1894     stream_sys_t *p_sys = s->p_sys;
1895
1896     if ( vlc_array_count( p_sys->hds_streams ) == 0 )
1897         return 0;
1898
1899     // TODO: change here for selectable stream
1900     hds_stream_t *stream = p_sys->hds_streams->pp_elems[0];
1901
1902     if ( !p_sys->flv_header )
1903     {
1904         initialize_header_and_metadata( p_sys, stream );
1905     }
1906
1907     if( header_unfinished( p_sys ) )
1908     {
1909         *pp_peek = p_sys->flv_header + p_sys->flv_header_bytes_sent;
1910         return p_sys->flv_header_len - p_sys->flv_header_bytes_sent;
1911     }
1912
1913     if( stream->chunks_head && ! stream->chunks_head->failed && stream->chunks_head->data )
1914     {
1915         // TODO: change here for selectable stream
1916         chunk_t* chunk = stream->chunks_head;
1917         *pp_peek = chunk->mdat_data + chunk->mdat_pos;
1918         if( chunk->mdat_len - chunk->mdat_pos < i_peek )
1919         {
1920             return chunk->mdat_len - chunk->mdat_pos;
1921         }
1922         else
1923         {
1924             return i_peek;
1925         }
1926     } else
1927     {
1928         return 0;
1929     }
1930 }
1931
1932 static int Control( stream_t *s, int i_query, va_list args )
1933 {
1934     switch( i_query )
1935     {
1936         case STREAM_CAN_SEEK:
1937             *(va_arg( args, bool * )) = false;
1938             break;
1939         case STREAM_CAN_FASTSEEK:
1940         case STREAM_CAN_PAUSE: /* TODO */
1941             *(va_arg( args, bool * )) = false;
1942             break;
1943         case STREAM_CAN_CONTROL_PACE:
1944             *(va_arg( args, bool * )) = true;
1945             break;
1946         case STREAM_GET_PTS_DELAY:
1947             *va_arg (args, int64_t *) = INT64_C(1000) *
1948                 var_InheritInteger(s, "network-caching");
1949              break;
1950         case STREAM_GET_POSITION:
1951             *(va_arg (args, uint64_t *)) = s->p_sys->playback_offset;
1952             break;
1953         case STREAM_GET_SIZE:
1954             *(va_arg (args, uint64_t *)) = get_stream_size(s);
1955             break;
1956         default:
1957             return VLC_EGENERIC;
1958     }
1959     return VLC_SUCCESS;
1960 }