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