]> git.sesse.net Git - vlc/blob - modules/stream_filter/httplive.c
stream_filter: httplive.c: remove unused include files
[vlc] / modules / stream_filter / httplive.c
1 /*****************************************************************************
2  * httplive.c: HTTP Live Streaming stream filter
3  *****************************************************************************
4  * Copyright (C) 2010 M2X BV
5  * $Id$
6  *
7  * Author: Jean-Paul Saman <jpsaman _AT_ videolan _DOT_ org>
8  *
9  * This program is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program; if not, write to the Free Software
21  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
22  *****************************************************************************/
23
24 /*****************************************************************************
25  * Preamble
26  *****************************************************************************/
27 #ifdef HAVE_CONFIG_H
28 # include "config.h"
29 #endif
30
31 #include <vlc_common.h>
32 #include <vlc_plugin.h>
33
34 #include <assert.h>
35
36 #include <vlc_threads.h>
37 #include <vlc_arrays.h>
38 #include <vlc_stream.h>
39 #include <vlc_url.h>
40
41 #include <vlc_modules.h>
42 #include <vlc_access.h>
43
44 /*****************************************************************************
45  * Module descriptor
46  *****************************************************************************/
47 static int  Open (vlc_object_t *);
48 static void Close(vlc_object_t *);
49
50 vlc_module_begin()
51     set_category(CAT_INPUT)
52     set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
53     set_description(N_("Http Live Streaming stream filter"))
54     set_capability("stream_filter", 20)
55     set_callbacks(Open, Close)
56 vlc_module_end()
57
58 /*****************************************************************************
59  *
60  *****************************************************************************/
61 typedef struct segment_s
62 {
63     int         sequence;   /* unique sequence number */
64     int         length;     /* segment duration (ms) */
65     uint64_t    size;       /* segment size in bytes */
66
67     vlc_url_t   url;
68     vlc_mutex_t lock;
69     block_t     *data;      /* data */
70 } segment_t;
71
72 typedef struct hls_stream_s
73 {
74     int         id;         /* program id */
75     uint64_t    bandwidth;  /* bandwidth usage of segments (kbps)*/
76     int         version;    /* protocol version should be 1 */
77     int         sequence;   /* media sequence number */
78     int         duration;   /* maximum duration per segment (ms) */
79     int         segment;    /* current segment downloading */
80     vlc_array_t *segments;  /* list of segments */
81
82     vlc_mutex_t lock;
83     vlc_url_t   url;        /* uri to m3u8 */
84     bool        b_cache;    /* allow caching */
85 } hls_stream_t;
86
87 typedef struct
88 {
89     VLC_COMMON_MEMBERS
90
91     /* */
92     vlc_array_t *hls_stream;/* bandwidth adaptation */
93     int         current;    /* current hls_stream  */
94
95     stream_t    *s;
96 } hls_thread_t;
97
98 struct stream_sys_t
99 {
100     access_t    *p_access;  /* HTTP access input */
101
102     /* */
103     hls_thread_t *thread;
104     vlc_array_t *hls_stream;/* bandwidth adaptation */
105
106     /* Playback */
107     uint64_t    offset;     /* current offset in media */
108     int         current;    /* current hls_stream  */
109     int         segment;    /* current segment for playback */
110
111     /* Playlist */
112     mtime_t     last;       /* playlist last loaded */
113     mtime_t     wakeup;     /* next reload time */
114     int         tries;      /* times it was not changed */
115
116     /* state */
117     bool        b_cache;    /* can cache files */
118     bool        b_meta;     /* meta playlist */
119     bool        b_live;     /* live stream? or vod? */
120     bool        b_error;    /* parsing error */
121 };
122
123 /****************************************************************************
124  * Local prototypes
125  ****************************************************************************/
126 static int  Read   (stream_t *, void *p_read, unsigned int i_read);
127 static int  Peek   (stream_t *, const uint8_t **pp_peek, unsigned int i_peek);
128 static int  Control(stream_t *, int i_query, va_list);
129
130 static int  AccessOpen(stream_t *s, vlc_url_t *url);
131 static void AccessClose(stream_t *s);
132 static char *AccessReadLine(access_t *p_access, uint8_t *psz_tmp, size_t i_len);
133 static int AccessDownload(stream_t *s, segment_t *segment);
134
135 static void* hls_Thread(vlc_object_t *);
136 static int get_HTTPLivePlaylist(stream_t *s, hls_stream_t *hls);
137
138 static void segment_Free(segment_t *segment);
139
140 /****************************************************************************
141  *
142  ****************************************************************************/
143 static bool isHTTPLiveStreaming(stream_t *s)
144 {
145     const uint8_t *peek, *peek_end;
146
147     int64_t i_size = stream_Peek(s->p_source, &peek, 46);
148     if (i_size < 1)
149         return false;
150
151     if (strncasecmp((const char*)peek, "#EXTM3U", 7) != 0)
152         return false;
153
154     /* Parse stream and search for
155      * EXT-X-TARGETDURATION or EXT-X-STREAM-INF tag, see
156      * http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#page-8 */
157     peek_end = peek + i_size;
158     while(peek <= peek_end)
159     {
160         if (*peek == '#')
161         {
162             if (strncasecmp((const char*)peek, "#EXT-X-TARGETDURATION", 21) == 0)
163                 return true;
164             else if (strncasecmp((const char*)peek, "#EXT-X-STREAM-INF", 17) == 0)
165                 return true;
166         }
167         peek++;
168     };
169
170     return false;
171 }
172
173 /* HTTP Live Streaming */
174 static hls_stream_t *hls_New(vlc_array_t *hls_stream, int id, uint64_t bw, char *uri)
175 {
176     hls_stream_t *hls = (hls_stream_t *)malloc(sizeof(hls_stream_t));
177     if (hls == NULL) return NULL;
178
179     hls->id = id;
180     hls->bandwidth = bw;
181     hls->sequence = 0; /* default is 0 */
182     hls->version = 1;  /* default protocol version */
183     hls->segment = 0;
184     hls->b_cache = true;
185     vlc_UrlParse(&hls->url, uri, 0);
186     hls->segments = vlc_array_new();
187     vlc_array_append(hls_stream, hls);
188     vlc_mutex_init(&hls->lock);
189     return hls;
190 }
191
192 static void hls_Free(hls_stream_t *hls)
193 {
194     vlc_mutex_destroy(&hls->lock);
195
196     if (hls->segments)
197     {
198         for (int n = 0; n < vlc_array_count(hls->segments); n++)
199         {
200             segment_t *segment = (segment_t *)vlc_array_item_at_index(hls->segments, n);
201             if (segment) segment_Free(segment);
202         }
203         vlc_array_destroy(hls->segments);
204     }
205
206     vlc_UrlClean(&hls->url);
207     free(hls);
208     hls = NULL;
209 }
210
211 static hls_stream_t *hls_Get(vlc_array_t *hls_stream, int wanted)
212 {
213     int count = vlc_array_count(hls_stream);
214     if (count <= 0)
215         return NULL;
216     if ((wanted < 0) || (wanted >= count))
217         return NULL;
218     return (hls_stream_t *) vlc_array_item_at_index(hls_stream, wanted);
219 }
220
221 static inline hls_stream_t *hls_GetFirst(vlc_array_t *hls_stream)
222 {
223     return (hls_stream_t*) hls_Get(hls_stream, 0);
224 }
225
226 static hls_stream_t *hls_GetLast(vlc_array_t *hls_stream)
227 {
228     int count = vlc_array_count(hls_stream);
229     if (count <= 0)
230         return NULL;
231     count--;
232     return (hls_stream_t *) hls_Get(hls_stream, count);
233 }
234
235 /* Segment */
236 static segment_t *segment_New(hls_stream_t* hls, int duration, char *uri)
237 {
238     segment_t *segment = (segment_t *)malloc(sizeof(segment_t));
239     if (segment == NULL)
240         return NULL;
241
242     segment->length = duration; /* seconds */
243     segment->size = 0; /* bytes */
244     segment->sequence = 0;
245     vlc_UrlParse(&segment->url, uri, 0);
246     segment->data = NULL;
247     vlc_array_append(hls->segments, segment);
248     vlc_mutex_init(&segment->lock);
249     return segment;
250 }
251
252 static void segment_Free(segment_t *segment)
253 {
254     vlc_mutex_destroy(&segment->lock);
255
256     vlc_UrlClean(&segment->url);
257     if (segment->data)
258         block_Release(segment->data);
259     free(segment);
260     segment = NULL;
261 }
262
263 static segment_t *segment_GetSegment(hls_stream_t *hls, int wanted)
264 {
265     assert(hls);
266
267     int count = vlc_array_count(hls->segments);
268     if (count <= 0)
269         return NULL;
270     if ((wanted < 0) || (wanted >= count))
271         return NULL;
272     return (segment_t *) vlc_array_item_at_index(hls->segments, wanted);
273 }
274
275 /* Parsing */
276 static char *parse_Attributes(const char *line, const char *attr)
277 {
278     char *p;
279     char *begin = (char *) line;
280     char *end = begin + strlen(line);
281
282     /* Find start of attributes */
283     if ((p = strchr(begin, ':' )) == NULL)
284         return NULL;
285
286     begin = p;
287     do
288     {
289         if (strncasecmp(begin, attr, strlen(attr)) == 0)
290         {
291             /* <attr>=<value>[,]* */
292             p = strchr(begin, ',');
293             begin += strlen(attr) + 1;
294             if (begin >= end)
295                 return NULL;
296             if (p == NULL) /* last attribute */
297                 return strndup(begin, end - begin);
298             /* copy till ',' */
299             return strndup(begin, p - begin);
300         }
301         begin++;
302     } while(begin < end);
303
304     return NULL;
305 }
306
307 static void parse_SegmentInformation(stream_t *s, hls_stream_t *hls, char *p_read, char *uri)
308 {
309     stream_sys_t *p_sys = s->p_sys;
310
311     assert(hls);
312
313     int duration;
314     int ret = sscanf(p_read, "#EXTINF:%d,", &duration);
315     if (ret != 1)
316     {
317         msg_Err(s, "expected #EXTINF:<s>,");
318         p_sys->b_error = true;
319         return;
320     }
321
322     vlc_mutex_lock(&hls->lock);
323     segment_t *segment = segment_New(hls, duration, uri);
324     if (segment)
325         segment->sequence = hls->sequence + vlc_array_count(hls->segments);
326     if (duration > hls->duration)
327     {
328         msg_Err(s, "EXTINF:%d duration is larger then EXT-X-TARGETDURATION:%d",
329                 duration, hls->duration);
330     }
331     vlc_mutex_unlock(&hls->lock);
332 }
333
334 static void parse_TargetDuration(stream_t *s, char *p_read)
335 {
336     stream_sys_t *p_sys = s->p_sys;
337
338     int duration;
339     int ret = sscanf(p_read, "#EXT-X-TARGETDURATION:%d", &duration);
340     if (ret != 1)
341     {
342         msg_Err(s, "expected #EXT-X-TARGETDURATION:<s>");
343         p_sys->b_error = true;
344         return;
345     }
346
347     hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
348     assert(hls);
349     hls->duration = duration; /* seconds */
350 }
351
352 static void parse_StreamInformation(stream_t *s, char *p_read, char *uri)
353 {
354     stream_sys_t *p_sys = s->p_sys;
355
356     int id, bw;
357     char *attr;
358
359     attr = parse_Attributes(p_read, "PROGRAM-ID");
360     if (attr == NULL)
361     {
362         msg_Err(s, "#EXT-X-STREAM-INF: expected PROGRAM-ID=<value>");
363         p_sys->b_error = true;
364         return;
365     }
366     id = atol(attr);
367     free(attr);
368
369     attr = parse_Attributes(p_read, "BANDWIDTH");
370     if (attr == NULL)
371     {
372         msg_Err(s, "#EXT-X-STREAM-INF: expected BANDWIDTH=<value>");
373         p_sys->b_error = true;
374         return;
375     }
376     bw = atoll(attr);
377     free(attr);
378
379     if (bw == 0)
380     {
381         msg_Err(s, "#EXT-X-STREAM-INF: bandwidth cannot be 0");
382         p_sys->b_error = true;
383         return;
384     }
385
386     msg_Info(s, "bandwidth adaption detected (program-id=%d, bandwidth=%d).", id, bw);
387
388     hls_stream_t *hls = hls_New(p_sys->hls_stream, id, bw, uri);
389     if (hls == NULL)
390         p_sys->b_error = true;
391 }
392
393 static void parse_MediaSequence(stream_t *s, char *p_read)
394 {
395     stream_sys_t *p_sys = s->p_sys;
396
397     int sequence;
398     int ret = sscanf(p_read, "#EXT-X-MEDIA-SEQUENCE:%d", &sequence);
399     if (ret != 1)
400     {
401         msg_Err(s, "expected #EXT-X-MEDIA-SEQUENCE:<s>");
402         p_sys->b_error = true;
403         return;
404     }
405
406     hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
407     assert(hls);
408     if (hls->sequence > 0)
409         msg_Err(s, "EXT-X-MEDIA-SEQUENCE already present in playlist");
410
411     hls->sequence = sequence;
412 }
413
414 static void parse_Key(stream_t *s, char *p_read)
415 {
416     stream_sys_t *p_sys = s->p_sys;
417
418     /* #EXT-X-KEY:METHOD=<method>[,URI="<URI>"][,IV=<IV>] */
419     char *attr;
420     attr = parse_Attributes(p_read, "METHOD");
421     if (attr == NULL)
422     {
423         msg_Err(s, "#EXT-X-KEY: expected METHOD=<value>");
424         p_sys->b_error = true;
425     }
426     else if (strncasecmp(attr, "NONE", 4) == 0)
427     {
428         char *uri = parse_Attributes(p_read, "URI");
429         char *iv = parse_Attributes(p_read, "IV");
430         if ((iv != NULL) || (uri != NULL))
431         {
432             msg_Err(s, "#EXT-X-KEY: URI and IV not expected");
433             p_sys->b_error = true;
434
435             free(iv);
436             free(uri);
437         }
438     }
439     else
440     {
441         msg_Warn(s, "playback of encrypted HTTP Live media is not supported.");
442         p_sys->b_error = true;
443     }
444     free(attr);
445 }
446
447 static void parse_ProgramDateTime(stream_t *s, char *p_read)
448 {
449     msg_Dbg(s, "tag not supported: #EXT-X-PROGRAM-DATE-TIME %s", p_read);
450 }
451
452 static void parse_AllowCache(stream_t *s, char *p_read)
453 {
454     stream_sys_t *p_sys = s->p_sys;
455
456     char answer[4] = "\0";
457     int ret = sscanf(p_read, "#EXT-X-ALLOW-CACHE:%3s", answer);
458     if (ret != 1)
459     {
460         msg_Err(s, "#EXT-X-ALLOW-CACHE, ignoring ...");
461         p_sys->b_error = true;
462         return;
463     }
464
465     hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
466
467     assert(hls);
468     hls->b_cache = (strncmp(answer, "NO", 2) != 0);
469 }
470
471 static void parse_Version(stream_t *s, char *p_read)
472 {
473     stream_sys_t *p_sys = s->p_sys;
474
475     int version;
476     int ret = sscanf(p_read, "#EXT-X-VERSION:%d", &version);
477     if (ret != 1)
478     {
479         msg_Err(s, "#EXT-X-VERSION: no protocol version found, should be version 1.");
480         p_sys->b_error = true;
481         return;
482     }
483
484     hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
485     assert(hls);
486
487     /* Check version */
488     hls->version = version;
489     if (hls->version != 1)
490     {
491         msg_Err(s, "#EXT-X-VERSION should be version 1 iso %d", version);
492         p_sys->b_error = true;
493     }
494 }
495
496 static void parse_EndList(stream_t *s)
497 {
498     stream_sys_t *p_sys = s->p_sys;
499     p_sys->b_live = false;
500
501     msg_Info(s, "video on demand (vod) mode");
502 }
503
504 static void parse_Discontinuity(stream_t *s, char *p_read)
505 {
506     /* FIXME: Do we need to act on discontinuity ?? */
507     msg_Dbg(s, "#EXT-X-DISCONTINUITY %s", p_read);
508 }
509
510 static void parse_M3U8ExtLine(stream_t *s, char *line)
511 {
512     if (*line == '#')
513     {
514         if (strncmp(line, "#EXT-X-TARGETDURATION", 21) == 0)
515             parse_TargetDuration(s, line);
516         else if (strncmp(line, "#EXT-X-MEDIA-SEQUENCE", 22) == 0)
517             parse_MediaSequence(s, line);
518         else if (strncmp(line, "#EXT-X-KEY", 11) == 0)
519             parse_Key(s, line);
520         else if (strncmp(line, "#EXT-X-PROGRAM-DATE-TIME", 25) == 0)
521             parse_ProgramDateTime(s, line);
522         else if (strncmp(line, "#EXT-X-ALLOW-CACHE", 17) == 0)
523             parse_AllowCache(s, line);
524         else if (strncmp(line, "#EXT-X-DISCONTINUITY", 20) == 0)
525             parse_Discontinuity(s, line);
526         else if (strncmp(line, "#EXT-X-VERSION", 14) == 0)
527             parse_Version(s, line);
528         else if (strncmp(line, "#EXT-X-ENDLIST", 14) == 0)
529             parse_EndList(s);
530     }
531 }
532
533 #define HTTPLIVE_MAX_LINE 4096
534 static int get_HTTPLivePlaylist(stream_t *s, hls_stream_t *hls)
535 {
536     stream_sys_t *p_sys = s->p_sys;
537
538     /* Download new playlist file from server */
539     if (AccessOpen(s, &hls->url) != VLC_SUCCESS)
540         return VLC_EGENERIC;
541
542     /* Parse the rest of the reply */
543     uint8_t *tmp = calloc(1, HTTPLIVE_MAX_LINE);
544     if (tmp == NULL)
545     {
546         AccessClose(s);
547         return VLC_ENOMEM;
548     }
549
550     char *line = AccessReadLine(p_sys->p_access, tmp, HTTPLIVE_MAX_LINE);
551     if (strncmp(line, "#EXTM3U", 7) != 0)
552     {
553         msg_Err(s, "missing #EXTM3U tag");
554         goto error;
555     }
556     free(line);
557     line = NULL;
558
559     for( ; ; )
560     {
561         line = AccessReadLine(p_sys->p_access, tmp, HTTPLIVE_MAX_LINE);
562         if (line == NULL)
563         {
564             msg_Dbg(s, "end of data");
565             break;
566         }
567
568         if (!vlc_object_alive(s))
569             goto error;
570
571         /* some more checks for actual data */
572         if (strncmp(line, "#EXTINF", 7) == 0)
573         {
574             char *uri = AccessReadLine(p_sys->p_access, tmp, HTTPLIVE_MAX_LINE);
575             if (uri == NULL)
576                 p_sys->b_error = true;
577             else
578             {
579                 parse_SegmentInformation(s, hls, line, uri);
580                 free(uri);
581             }
582         }
583         else
584         {
585             parse_M3U8ExtLine(s, line);
586         }
587
588         /* Error during m3u8 parsing abort */
589         if (p_sys->b_error)
590             goto error;
591
592         free(line);
593     }
594
595     free(line);
596     free(tmp);
597     AccessClose(s);
598     return VLC_SUCCESS;
599
600 error:
601     free(line);
602     free(tmp);
603     AccessClose(s);
604     return VLC_EGENERIC;
605 }
606 #undef HTTPLIVE_MAX_LINE
607
608 /* The http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#page-8
609  * document defines the following new tags: EXT-X-TARGETDURATION,
610  * EXT-X-MEDIA-SEQUENCE, EXT-X-KEY, EXT-X-PROGRAM-DATE-TIME, EXT-X-
611  * ALLOW-CACHE, EXT-X-STREAM-INF, EXT-X-ENDLIST, EXT-X-DISCONTINUITY,
612  * and EXT-X-VERSION.
613  */
614 static int parse_HTTPLiveStreaming(stream_t *s)
615 {
616     stream_sys_t *p_sys = s->p_sys;
617     char *p_read, *p_begin, *p_end;
618
619     assert(p_sys->hls_stream);
620
621     p_begin = p_read = stream_ReadLine(s->p_source);
622     if (!p_begin)
623         return VLC_ENOMEM;
624
625     /* */
626     int i_len = strlen(p_begin);
627     p_end = p_read + i_len;
628
629     if (strncmp(p_read, "#EXTM3U", 7) != 0)
630     {
631         msg_Err(s, "missing #EXTM3U tag .. aborting");
632         free(p_begin);
633         return VLC_EGENERIC;
634     }
635
636     do {
637         free(p_begin);
638
639         if (p_sys->b_error)
640             return VLC_EGENERIC;
641
642         /* Next line */
643         p_begin = stream_ReadLine(s->p_source);
644         if (p_begin == NULL)
645             break;
646
647         i_len = strlen(p_begin);
648         p_read = p_begin;
649         p_end = p_read + i_len;
650
651         if (strncmp(p_read, "#EXT-X-STREAM-INF", 17) == 0)
652         {
653             p_sys->b_meta = true;
654             char *uri = stream_ReadLine(s->p_source);
655             if (uri == NULL)
656                 p_sys->b_error = true;
657             else
658             {
659                 parse_StreamInformation(s, p_read, uri);
660                 free(uri);
661             }
662         }
663         else if (strncmp(p_read, "#EXTINF", 7) == 0)
664         {
665             char *uri = stream_ReadLine(s->p_source);
666             if (uri == NULL)
667                 p_sys->b_error = true;
668             else
669             {
670                 hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
671                 if (hls)
672                     parse_SegmentInformation(s, hls, p_read, uri);
673                 else
674                     p_sys->b_error = true;
675                 free(uri);
676             }
677         }
678         else
679         {
680             if (!p_sys->b_meta)
681             {
682                 hls_stream_t *hls = hls_GetLast(p_sys->hls_stream);
683                 if (hls == NULL)
684                 {
685                     hls = hls_New(p_sys->hls_stream, -1, -1, NULL);
686                     if (hls == NULL)
687                     {
688                         p_sys->b_error = true;
689                         return VLC_ENOMEM;
690                     }
691                 }
692             }
693             /* Parse M3U8 Ext Line */
694             parse_M3U8ExtLine(s, p_read);
695         }
696     } while(p_read < p_end);
697
698     free(p_begin);
699
700     /* */
701     int count = vlc_array_count(p_sys->hls_stream);
702     for (int n = 0; n < count; n++)
703     {
704         hls_stream_t *hls = hls_Get(p_sys->hls_stream, n);
705         if (hls == NULL) break;
706
707         /* Is it a meta playlist? */
708         if (p_sys->b_meta)
709         {
710             if (get_HTTPLivePlaylist(s, hls) != VLC_SUCCESS)
711             {
712                 msg_Err(s, "could not parse playlist file from meta index." );
713                 return VLC_EGENERIC;
714             }
715         }
716
717         if (p_sys->b_live)
718         {
719             /* There should at least be 3 segments of hls->duration */
720             int ok = 0;
721             int num = vlc_array_count(hls->segments);
722             for (int i = 0; i < num; i++)
723             {
724                 segment_t *segment = segment_GetSegment(hls, i);
725                 if (segment && segment->length >= hls->duration)
726                     ok++;
727             }
728             if (ok < 3)
729             {
730                 msg_Err(s, "cannot start live playback at this time, try again later.");
731                 return VLC_EGENERIC;
732             }
733             /* Determine next time to reload playlist */
734             p_sys->wakeup = p_sys->last + (hls->duration * 2 * (mtime_t)1000000);
735         }
736         /* Can we cache files after playback */
737         p_sys->b_cache = hls->b_cache;
738     }
739
740     return VLC_SUCCESS;
741 }
742
743 /****************************************************************************
744  * hls_Thread
745  ****************************************************************************/
746 static int BandwidthAdaptation(stream_t *s, int progid, uint64_t *bandwidth)
747 {
748     stream_sys_t *p_sys = s->p_sys;
749     int candidate = -1;
750     uint64_t bw = *bandwidth;
751
752     msg_Dbg(s, "bandwidth (bits/s) %"PRIu64, bw * 1000); /* bits / s */
753
754     int count = vlc_array_count(p_sys->hls_stream);
755     for (int n = 0; n < count; n++)
756     {
757         /* Select best bandwidth match */
758         hls_stream_t *hls = hls_Get(p_sys->hls_stream, n);
759         if (hls == NULL) break;
760
761         /* only consider streams with the same PROGRAM-ID */
762         if (hls->id == progid)
763         {
764             if (bw <= hls->bandwidth)
765             {
766                 *bandwidth = hls->bandwidth;
767                 candidate = n; /* possible candidate */
768             }
769         }
770     }
771     return candidate;
772 }
773
774 static int Download(stream_t *s, hls_stream_t *hls, segment_t *segment, int *cur_stream)
775 {
776     assert(hls);
777     assert(segment);
778
779     vlc_mutex_lock(&segment->lock);
780     if (segment->data != NULL)
781     {
782         /* Segment already downloaded */
783         vlc_mutex_unlock(&segment->lock);
784         return VLC_SUCCESS;
785     }
786
787     mtime_t start = mdate();
788     if (AccessDownload(s, segment) != VLC_SUCCESS)
789     {
790         vlc_mutex_unlock(&segment->lock);
791         return VLC_EGENERIC;
792     }
793     mtime_t duration = mdate() - start;
794
795     vlc_mutex_unlock(&segment->lock);
796
797     uint64_t bw = (segment->size * 8) / (duration/1000);      /* bits / ms */
798     if (hls->bandwidth != bw)
799     {
800         int newstream = BandwidthAdaptation(s, hls->id, &bw);
801         if ((newstream > 0) && (newstream != *cur_stream))
802         {
803             msg_Info(s, "switching to %s bandwidth (%"PRIu64") stream",
804                      (hls->bandwidth <= bw) ? "faster" : "lower", bw);
805             *cur_stream = newstream;
806         }
807     }
808     return VLC_SUCCESS;
809 }
810
811 static void* hls_Thread(vlc_object_t *p_this)
812 {
813     hls_thread_t *client = (hls_thread_t *) p_this;
814     stream_t *s = client->s;
815     stream_sys_t *p_sys = s->p_sys;
816
817     int canc = vlc_savecancel();
818
819     while (vlc_object_alive(p_this))
820     {
821         hls_stream_t *hls = hls_Get(client->hls_stream, client->current);
822         assert(hls);
823
824         vlc_mutex_lock(&hls->lock);
825         segment_t *segment = segment_GetSegment(hls, hls->segment);
826         if (segment) hls->segment++;
827         vlc_mutex_unlock(&hls->lock);
828
829         /* Is there a new segment to process? */
830         if (segment == NULL)
831         {
832             if (!p_sys->b_live) break;
833             mwait(p_sys->wakeup);
834         }
835         else if (Download(client->s, hls, segment, &client->current) != VLC_SUCCESS)
836         {
837             if (!p_sys->b_live) break;
838         }
839
840         /* FIXME: Reread the m3u8 index file */
841         if (p_sys->b_live)
842         {
843             double wait = 1;
844             mtime_t now = mdate();
845             if (now >= p_sys->wakeup)
846             {
847 #if 0
848                 /** FIXME: Implement m3u8 playlist reloading */
849                 if (!hls_ReloadPlaylist(client->s))
850                 {
851                     /* No change in playlist, then backoff */
852                     p_sys->tries++;
853                     if (p_sys->tries == 1) wait = 0.5;
854                     else if (p_sys->tries == 2) wait = 1;
855                     else if (p_sys->tries >= 3) wait = 3;
856                 }
857 #endif
858                 /* determine next time to update playlist */
859                 p_sys->last = now;
860                 p_sys->wakeup = now + ((mtime_t)(hls->duration * wait) * (mtime_t)1000000);
861             }
862         }
863     }
864
865     vlc_restorecancel(canc);
866     return NULL;
867 }
868
869 static int Prefetch(stream_t *s)
870 {
871     stream_sys_t *p_sys = s->p_sys;
872     int current;
873
874 again:
875     current = p_sys->current;
876
877     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
878     if (hls == NULL)
879         return VLC_EGENERIC;
880
881     segment_t *segment = segment_GetSegment(hls, hls->segment);
882     if (segment == NULL )
883         return VLC_EGENERIC;
884
885     if (Download(s, hls, segment, &p_sys->current) != VLC_SUCCESS)
886         return VLC_EGENERIC;
887
888     /* Bandwidth changed? */
889     if (current != p_sys->current)
890         goto again;
891
892     return VLC_SUCCESS;
893 }
894
895 /****************************************************************************
896  * Access
897  ****************************************************************************/
898 static int AccessOpen(stream_t *s, vlc_url_t *url)
899 {
900     stream_sys_t *p_sys = (stream_sys_t *) s->p_sys;
901
902     if ((url->psz_protocol == NULL) ||
903         (url->psz_path == NULL))
904         return VLC_EGENERIC;
905
906     p_sys->p_access = vlc_object_create(s, sizeof(access_t));
907     if (p_sys->p_access)
908     {
909         p_sys->p_access->psz_access = strdup(url->psz_protocol);
910         p_sys->p_access->psz_filepath = strdup(url->psz_path);
911         if (url->psz_password || url->psz_username)
912         {
913             if (asprintf(&p_sys->p_access->psz_location, "%s:%s@%s%s",
914                          url->psz_username, url->psz_password,
915                          url->psz_host, url->psz_path) < 0)
916             {
917                 msg_Err(s, "creating http access module");
918                 goto fail;
919             }
920         }
921         else
922         {
923             if (asprintf(&p_sys->p_access->psz_location, "%s%s",
924                          url->psz_host, url->psz_path) < 0)
925             {
926                 msg_Err(s, "creating http access module");
927                 goto fail;
928             }
929         }
930         vlc_object_attach(p_sys->p_access, s);
931         p_sys->p_access->p_module =
932             module_need(p_sys->p_access, "access", "http", true);
933         if (p_sys->p_access->p_module == NULL)
934         {
935             msg_Err(s, "could not load http access module");
936             goto fail;
937         }
938         return VLC_SUCCESS;
939     }
940     return VLC_ENOMEM;
941
942 fail:
943     vlc_object_release(p_sys->p_access);
944     p_sys->p_access = NULL;
945     return VLC_EGENERIC;
946 }
947
948 static void AccessClose(stream_t *s)
949 {
950     stream_sys_t *p_sys = (stream_sys_t *) s->p_sys;
951
952     if (p_sys->p_access)
953     {
954         vlc_object_kill(p_sys->p_access);
955         free(p_sys->p_access->psz_access);
956         if (p_sys->p_access->p_module)
957             module_unneed(p_sys->p_access,
958                           p_sys->p_access->p_module);
959
960         vlc_object_release(p_sys->p_access);
961         p_sys->p_access = NULL;
962     }
963 }
964
965 static char *AccessReadLine(access_t *p_access, uint8_t *psz_tmp, size_t i_len)
966 {
967     char *line = NULL;
968     char *begin = (char *)psz_tmp;
969
970     assert(psz_tmp);
971
972     int skip = strlen(begin);
973     ssize_t len = p_access->pf_read(p_access, psz_tmp + skip, i_len - skip);
974     if (len < 0) return NULL;
975     if ((len == 0) && (skip == 0))
976         return NULL;
977
978     char *p = begin;
979     char *end = p + len + skip;
980
981     while (p < end)
982     {
983         if (*p == '\n')
984             break;
985
986         p++;
987     }
988
989     /* EOL */
990     line = calloc(1, p - begin + 1);
991     if (line == NULL)
992         return NULL;
993     /* copy line excluding \n */
994     line = strndup(begin, p - begin);
995
996     p++;
997     if (p < end)
998     {
999         psz_tmp = memmove(begin, p, end - p);
1000         psz_tmp[end - p] = '\0';
1001     }
1002     else memset(psz_tmp, 0, i_len);
1003
1004     return line;
1005 }
1006
1007 static int AccessDownload(stream_t *s, segment_t *segment)
1008 {
1009     stream_sys_t *p_sys = (stream_sys_t *) s->p_sys;
1010
1011     assert(segment);
1012
1013     /* Download new playlist file from server */
1014     if (AccessOpen(s, &segment->url) != VLC_SUCCESS)
1015         return VLC_EGENERIC;
1016
1017     segment->size = p_sys->p_access->info.i_size;
1018     assert(segment->size > 0);
1019
1020     segment->data = block_Alloc(segment->size);
1021     if (segment->data == NULL)
1022     {
1023         AccessClose(s);
1024         return VLC_ENOMEM;
1025     }
1026
1027     assert(segment->data->i_buffer == segment->size);
1028
1029     ssize_t length = 0, curlen = 0;
1030     do
1031     {
1032         if (p_sys->p_access->info.i_size > segment->size)
1033         {
1034             msg_Dbg(s, "size changed %"PRIu64, segment->size);
1035             segment->data = block_Realloc(segment->data, 0, p_sys->p_access->info.i_size);
1036             if (segment->data)
1037                 segment->size = p_sys->p_access->info.i_size;
1038             assert(segment->data->i_buffer == segment->size);
1039         }
1040         length = p_sys->p_access->pf_read(p_sys->p_access,
1041                     segment->data->p_buffer + curlen, segment->size - curlen);
1042         if ((length <= 0) || ((uint64_t)length >= segment->size))
1043             break;
1044         curlen += length;
1045     } while (vlc_object_alive(s));
1046
1047     assert(curlen == (ssize_t)segment->size);
1048
1049     AccessClose(s);
1050     return VLC_SUCCESS;
1051 }
1052
1053 /****************************************************************************
1054  * Open
1055  ****************************************************************************/
1056 static int Open(vlc_object_t *p_this)
1057 {
1058     stream_t *s = (stream_t*)p_this;
1059     stream_sys_t *p_sys;
1060
1061     if (!isHTTPLiveStreaming(s))
1062         return VLC_EGENERIC;
1063
1064     msg_Info(p_this, "HTTP Live Streaming (%s)", s->psz_path);
1065
1066     /* */
1067     s->p_sys = p_sys = calloc(1, sizeof(*p_sys));
1068     if (p_sys == NULL)
1069         return VLC_ENOMEM;
1070
1071     p_sys->b_live = true;
1072     p_sys->b_meta = false;
1073
1074     p_sys->hls_stream = vlc_array_new();
1075     if (p_sys->hls_stream == NULL)
1076     {
1077         free(p_sys);
1078         return VLC_ENOMEM;
1079     }
1080
1081     /* */
1082     s->pf_read = Read;
1083     s->pf_peek = Peek;
1084     s->pf_control = Control;
1085
1086     /* Select first segment to play */
1087     p_sys->last = mdate();
1088     if (parse_HTTPLiveStreaming(s) != VLC_SUCCESS)
1089     {
1090         goto fail;
1091     }
1092
1093     /* */
1094     p_sys->segment = 0;
1095     p_sys->current = 0;
1096
1097     if (Prefetch(s) != VLC_SUCCESS)
1098     {
1099         msg_Err(s, "fetching first segment.");
1100         goto fail;
1101     }
1102
1103     p_sys->thread = vlc_object_create(s, sizeof(hls_thread_t));
1104     if( p_sys->thread == NULL )
1105     {
1106         msg_Err(s, "creating HTTP Live Streaming client thread");
1107         goto fail;
1108     }
1109
1110     p_sys->thread->hls_stream = p_sys->hls_stream;
1111     p_sys->thread->current = p_sys->current;
1112     p_sys->thread->s = s;
1113
1114     if (vlc_thread_create(p_sys->thread, "HTTP Live Streaming client",
1115                           hls_Thread, VLC_THREAD_PRIORITY_INPUT))
1116     {
1117         goto fail;
1118     }
1119
1120     vlc_object_attach(p_sys->thread, s);
1121
1122     return VLC_SUCCESS;
1123
1124 fail:
1125     Close(p_this);
1126     return VLC_EGENERIC;
1127 }
1128
1129 /****************************************************************************
1130  * Close
1131  ****************************************************************************/
1132 static void Close(vlc_object_t *p_this)
1133 {
1134     stream_t *s = (stream_t*)p_this;
1135     stream_sys_t *p_sys = s->p_sys;
1136
1137     assert(p_sys->hls_stream);
1138
1139     /* */
1140     if (p_sys->thread)
1141     {
1142         vlc_object_kill(p_sys->thread);
1143         vlc_thread_join(p_sys->thread);
1144         vlc_object_release(p_sys->thread);
1145     }
1146
1147     /* Free hls streams */
1148     for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++)
1149     {
1150         hls_stream_t *hls;
1151         hls = (hls_stream_t *)vlc_array_item_at_index(p_sys->hls_stream, i);
1152         if (hls) hls_Free(hls);
1153     }
1154     vlc_array_destroy(p_sys->hls_stream);
1155
1156     /* */
1157     free(p_sys);
1158 }
1159
1160 /****************************************************************************
1161  * Stream filters functions
1162  ****************************************************************************/
1163 static segment_t *NextSegment(stream_t *s)
1164 {
1165     stream_sys_t *p_sys = s->p_sys;
1166     segment_t *segment;
1167
1168     do
1169     {
1170         /* Is the next segment ready */
1171         hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
1172         if (hls == NULL) return NULL;
1173
1174         segment = segment_GetSegment(hls, p_sys->segment);
1175         if (segment == NULL) return NULL;
1176
1177         /* This segment is ready? */
1178         if (segment->data != NULL)
1179             return segment;
1180
1181         /* Was the stream changed to another bitrate? */
1182         if (!p_sys->b_meta) return NULL;
1183
1184         if (p_sys->current != p_sys->thread->current)
1185         {
1186             /* YES it was */
1187             p_sys->current = p_sys->thread->current;
1188         }
1189         else
1190         {
1191 #if 0
1192             /* Not downloaded yet, do it here */
1193             if (Download(s, hls, segment, &p_sys->current) != VLC_SUCCESS)
1194                 return segment;
1195             else
1196 #endif
1197                 return NULL;
1198         }
1199     }
1200     while(vlc_object_alive(s));
1201
1202     return segment;
1203 }
1204
1205 static ssize_t hls_Read(stream_t *s, uint8_t *p_read, unsigned int i_read)
1206 {
1207     stream_sys_t *p_sys = s->p_sys;
1208     ssize_t copied = 0;
1209
1210     do
1211     {
1212         /* Determine next segment to read. If this is a meta playlist and
1213          * bandwidth conditions changed, then the stream might have switched
1214          * to another bandwidth. */
1215         segment_t *segment = NextSegment(s);
1216         if (segment == NULL)
1217             break;
1218
1219         vlc_mutex_lock(&segment->lock);
1220         if (segment->data->i_buffer == 0)
1221         {
1222             if (!p_sys->b_cache)
1223             {
1224                 block_Release(segment->data);
1225                 segment->data = NULL;
1226             }
1227             msg_Dbg(s, "switching to segment %d", p_sys->segment);
1228             p_sys->segment++;
1229             vlc_mutex_unlock(&segment->lock);
1230             continue;
1231         }
1232
1233         ssize_t len = -1;
1234         if (i_read <= segment->data->i_buffer)
1235             len = i_read;
1236         else if (i_read > segment->data->i_buffer)
1237             len = segment->data->i_buffer;
1238
1239         if (len > 0)
1240         {
1241             memcpy(p_read + copied, segment->data->p_buffer, len);
1242             segment->data->i_buffer -= len;
1243             segment->data->p_buffer += len;
1244             copied += len;
1245             i_read -= len;
1246         }
1247         vlc_mutex_unlock(&segment->lock);
1248
1249     } while ((i_read > 0) && vlc_object_alive(s));
1250
1251     return copied;
1252 }
1253
1254 static int Read(stream_t *s, void *buffer, unsigned int i_read)
1255 {
1256     stream_sys_t *p_sys = s->p_sys;
1257     ssize_t length = 0;
1258
1259     assert(p_sys->hls_stream);
1260
1261     if (buffer == NULL)
1262     {
1263         /* caller skips data, get big enough buffer */
1264         msg_Warn(s, "buffer is NULL (allocate %d)", i_read);
1265         buffer = calloc(1, i_read);
1266         if (buffer == NULL)
1267             return 0; /* NO MEMORY left*/
1268     }
1269
1270     length = hls_Read(s, (uint8_t*) buffer, i_read);
1271     if (length < 0)
1272         return 0;
1273
1274     p_sys->offset += length;
1275     return length;
1276 }
1277
1278 static int Peek(stream_t *s, const uint8_t **pp_peek, unsigned int i_peek)
1279 {
1280     stream_sys_t *p_sys = s->p_sys;
1281     size_t curlen = 0;
1282
1283     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
1284     if (hls == NULL)
1285         return 0;
1286
1287     int peek_segment = p_sys->segment;
1288     do
1289     {
1290         segment_t *segment = segment_GetSegment(hls, peek_segment);
1291         if (segment == NULL) return 0;
1292
1293         vlc_mutex_lock(&segment->lock);
1294         if (i_peek < segment->data->i_buffer)
1295         {
1296             *pp_peek = segment->data->p_buffer;
1297             curlen += i_peek;
1298         }
1299         else
1300         {
1301              peek_segment++;
1302         }
1303         vlc_mutex_unlock(&segment->lock);
1304     } while ((curlen < i_peek) && vlc_object_alive(s));
1305
1306     return curlen;
1307 }
1308
1309 static bool hls_MaySeek(stream_t *s)
1310 {
1311     stream_sys_t *p_sys = s->p_sys;
1312
1313     if (p_sys->hls_stream == NULL)
1314         return false;
1315
1316     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
1317     if (hls == NULL) return false;
1318
1319     if (p_sys->b_live)
1320     {
1321        int count = vlc_array_count(hls->segments);
1322        vlc_mutex_lock(&hls->lock);
1323        bool may_seek = (hls->segment < count - 2);
1324        vlc_mutex_unlock(&hls->lock);
1325        return may_seek;
1326     }
1327     return true;
1328 }
1329
1330 static uint64_t GetStreamSize(stream_t *s)
1331 {
1332     stream_sys_t *p_sys = s->p_sys;
1333
1334     if (p_sys->b_live)
1335         return 0;
1336
1337     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
1338     if (hls == NULL) return 0;
1339
1340     /* FIXME: Stream size is not entirely exacts at this point */
1341     uint64_t length = 0UL;
1342     int count = vlc_array_count(hls->segments);
1343     for (int n = 0; n < count; n++)
1344     {
1345         segment_t *segment = segment_GetSegment(hls, n);
1346         if (segment)
1347         {
1348             length += (segment->size > 0) ? segment->size :
1349                         (segment->length * hls->bandwidth);
1350         }
1351     }
1352     return length;
1353 }
1354
1355 static int segment_Seek(stream_t *s, uint64_t pos)
1356 {
1357     stream_sys_t *p_sys = s->p_sys;
1358
1359     /* Find the right offset */
1360     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->current);
1361     if (hls == NULL)
1362         return VLC_EGENERIC;
1363
1364     uint64_t length = 0;
1365     bool b_found = false;
1366
1367     int count = vlc_array_count(hls->segments);
1368     for (int n = 0; n < count; n++)
1369     {
1370         /* FIXME: Seeking in segments not dowloaded is not supported. */
1371         if (n >= hls->segment)
1372         {
1373             msg_Err(s, "seeking in segment not downloaded yet.");
1374             return VLC_EGENERIC;
1375         }
1376
1377         segment_t *segment = vlc_array_item_at_index(hls->segments, n);
1378         if (segment == NULL)
1379             return VLC_EGENERIC;
1380
1381         vlc_mutex_lock(&segment->lock);
1382         length += segment->size;
1383         uint64_t size = segment->size -segment->data->i_buffer;
1384         if (size > 0)
1385         {
1386             segment->data->i_buffer += size;
1387             segment->data->p_buffer -= size;
1388         }
1389
1390         if (!b_found && (pos <= length))
1391         {
1392             uint64_t used = length - pos;
1393             segment->data->i_buffer -= used;
1394             segment->data->p_buffer += used;
1395
1396             count = p_sys->segment;
1397             p_sys->segment = n;
1398             b_found = true;
1399         }
1400         vlc_mutex_unlock(&segment->lock);
1401     }
1402     return VLC_SUCCESS;
1403 }
1404
1405 static int Control(stream_t *s, int i_query, va_list args)
1406 {
1407     stream_sys_t *p_sys = s->p_sys;
1408
1409     switch (i_query)
1410     {
1411         case STREAM_CAN_SEEK:
1412         case STREAM_CAN_FASTSEEK:
1413             *(va_arg (args, bool *)) = hls_MaySeek(s);
1414             break;
1415         case STREAM_GET_POSITION:
1416             *(va_arg (args, uint64_t *)) = p_sys->offset;
1417             break;
1418         case STREAM_SET_POSITION:
1419             if (hls_MaySeek(s))
1420             {
1421                 uint64_t pos = (uint64_t)va_arg(args, uint64_t);
1422                 if (segment_Seek(s, pos) == VLC_SUCCESS)
1423                 {
1424                     p_sys->offset = pos;
1425                     break;
1426                 }
1427             }
1428             return VLC_EGENERIC;
1429         case STREAM_GET_SIZE:
1430             *(va_arg (args, uint64_t *)) = GetStreamSize(s);
1431             break;
1432         default:
1433             return VLC_EGENERIC;
1434     }
1435     return VLC_SUCCESS;
1436 }