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