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