]> git.sesse.net Git - vlc/blob - modules/stream_filter/httplive.c
stream_filter/httplive.c: Remove stream_t* argument from parse_SegmentInformation()
[vlc] / modules / stream_filter / httplive.c
1 /*****************************************************************************
2  * httplive.c: HTTP Live Streaming stream filter
3  *****************************************************************************
4  * Copyright (C) 2010-2011 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 <limits.h>
32
33 #include <vlc_common.h>
34 #include <vlc_plugin.h>
35
36 #include <assert.h>
37
38 #include <vlc_threads.h>
39 #include <vlc_arrays.h>
40 #include <vlc_stream.h>
41 #include <vlc_url.h>
42
43 /*****************************************************************************
44  * Module descriptor
45  *****************************************************************************/
46 static int  Open (vlc_object_t *);
47 static void Close(vlc_object_t *);
48
49 vlc_module_begin()
50     set_category(CAT_INPUT)
51     set_subcategory(SUBCAT_INPUT_STREAM_FILTER)
52     set_description(N_("Http Live Streaming stream filter"))
53     set_capability("stream_filter", 20)
54     set_callbacks(Open, Close)
55 vlc_module_end()
56
57 /*****************************************************************************
58  *
59  *****************************************************************************/
60 typedef struct segment_s
61 {
62     int         sequence;   /* unique sequence number */
63     int         duration;   /* segment duration (seconds) */
64     uint64_t    size;       /* segment size in bytes */
65     uint64_t    bandwidth;  /* bandwidth usage of segments (bits per second)*/
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 (bits per second)*/
79     uint64_t    size;       /* stream length (segment->duration * hls->bandwidth/8) */
80
81     vlc_array_t *segments;  /* list of segments */
82     vlc_url_t   url;        /* uri to m3u8 */
83     vlc_mutex_t lock;
84     bool        b_cache;    /* allow caching */
85 } hls_stream_t;
86
87 struct stream_sys_t
88 {
89     vlc_url_t     m3u8;         /* M3U8 url */
90     vlc_thread_t  reload;       /* HLS m3u8 reload thread */
91     vlc_thread_t  thread;       /* HLS segment download thread */
92
93     /* */
94     vlc_array_t  *hls_stream;   /* bandwidth adaptation */
95     uint64_t      bandwidth;    /* measured bandwidth (bits per second) */
96
97     /* Download */
98     struct hls_download_s
99     {
100         int         stream;     /* current hls_stream  */
101         int         segment;    /* current segment for downloading */
102         int         seek;       /* segment requested by seek (default -1) */
103         vlc_mutex_t lock_wait;  /* protect segment download counter */
104         vlc_cond_t  wait;       /* some condition to wait on */
105     } download;
106
107     /* Playback */
108     struct hls_playback_s
109     {
110         uint64_t    offset;     /* current offset in media */
111         int         stream;     /* current hls_stream  */
112         int         segment;    /* current segment for playback */
113     } playback;
114
115     /* Playlist */
116     struct hls_playlist_s
117     {
118         mtime_t     last;       /* playlist last loaded */
119         mtime_t     wakeup;     /* next reload time */
120         int         tries;      /* times it was not changed */
121     } playlist;
122
123     /* state */
124     bool        b_cache;    /* can cache files */
125     bool        b_meta;     /* meta playlist */
126     bool        b_live;     /* live stream? or vod? */
127     bool        b_error;    /* parsing error */
128 };
129
130 /****************************************************************************
131  * Local prototypes
132  ****************************************************************************/
133 static int  Read   (stream_t *, void *p_read, unsigned int i_read);
134 static int  Peek   (stream_t *, const uint8_t **pp_peek, unsigned int i_peek);
135 static int  Control(stream_t *, int i_query, va_list);
136
137 static ssize_t read_M3U8(stream_t *s, vlc_url_t *url, uint8_t **buffer);
138 static ssize_t ReadM3U8(stream_t *s, uint8_t **buffer);
139 static char *ReadLine(uint8_t *buffer, uint8_t **pos, size_t len);
140
141 static int hls_Download(stream_t *s, segment_t *segment);
142
143 static void* hls_Thread(void *);
144 static void* hls_Reload(void *);
145
146 static segment_t *segment_GetSegment(hls_stream_t *hls, int wanted);
147 static void segment_Free(segment_t *segment);
148
149 /****************************************************************************
150  *
151  ****************************************************************************/
152 static const char *const ext[] = {
153     "#EXT-X-TARGETDURATION",
154     "#EXT-X-MEDIA-SEQUENCE",
155     "#EXT-X-KEY",
156     "#EXT-X-ALLOW-CACHE",
157     "#EXT-X-ENDLIST",
158     "#EXT-X-STREAM-INF",
159     "#EXT-X-DISCONTINUITY",
160     "#EXT-X-VERSION"
161 };
162
163 static bool isHTTPLiveStreaming(stream_t *s)
164 {
165     const uint8_t *peek, *peek_end;
166
167     int64_t i_size = stream_Peek(s->p_source, &peek, 46);
168     if (i_size < 1)
169         return false;
170
171     if (strncasecmp((const char*)peek, "#EXTM3U", 7) != 0)
172         return false;
173
174     /* Parse stream and search for
175      * EXT-X-TARGETDURATION or EXT-X-STREAM-INF tag, see
176      * http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#page-8 */
177     peek_end = peek + i_size;
178     while(peek <= peek_end)
179     {
180         if (*peek == '#')
181         {
182             for (unsigned int i = 0; i < ARRAY_SIZE(ext); i++)
183             {
184                 char *p = strstr((const char*)peek, ext[i]);
185                 if (p != NULL)
186                     return true;
187             }
188         }
189         peek++;
190     };
191
192     return false;
193 }
194
195 /* HTTP Live Streaming */
196 static hls_stream_t *hls_New(vlc_array_t *hls_stream, const int id, const uint64_t bw, const char *uri)
197 {
198     hls_stream_t *hls = (hls_stream_t *)malloc(sizeof(hls_stream_t));
199     if (hls == NULL) return NULL;
200
201     hls->id = id;
202     hls->bandwidth = bw;
203     hls->duration = -1;/* unknown */
204     hls->size = 0;
205     hls->sequence = 0; /* default is 0 */
206     hls->version = 1;  /* default protocol version */
207     hls->b_cache = true;
208     vlc_UrlParse(&hls->url, uri, 0);
209     hls->segments = vlc_array_new();
210     vlc_array_append(hls_stream, hls);
211     vlc_mutex_init(&hls->lock);
212     return hls;
213 }
214
215 static void hls_Free(hls_stream_t *hls)
216 {
217     vlc_mutex_destroy(&hls->lock);
218
219     if (hls->segments)
220     {
221         for (int n = 0; n < vlc_array_count(hls->segments); n++)
222         {
223             segment_t *segment = (segment_t *)vlc_array_item_at_index(hls->segments, n);
224             if (segment) segment_Free(segment);
225         }
226         vlc_array_destroy(hls->segments);
227     }
228
229     vlc_UrlClean(&hls->url);
230     free(hls);
231     hls = NULL;
232 }
233
234 static hls_stream_t *hls_Get(vlc_array_t *hls_stream, const int wanted)
235 {
236     int count = vlc_array_count(hls_stream);
237     if (count <= 0)
238         return NULL;
239     if ((wanted < 0) || (wanted >= count))
240         return NULL;
241     return (hls_stream_t *) vlc_array_item_at_index(hls_stream, wanted);
242 }
243
244 static inline hls_stream_t *hls_GetFirst(vlc_array_t *hls_stream)
245 {
246     return (hls_stream_t*) hls_Get(hls_stream, 0);
247 }
248
249 static hls_stream_t *hls_GetLast(vlc_array_t *hls_stream)
250 {
251     int count = vlc_array_count(hls_stream);
252     if (count <= 0)
253         return NULL;
254     count--;
255     return (hls_stream_t *) hls_Get(hls_stream, count);
256 }
257
258 static hls_stream_t *hls_Find(vlc_array_t *hls_stream, hls_stream_t *hls_new)
259 {
260     int count = vlc_array_count(hls_stream);
261     for (int n = 0; n < count; n++)
262     {
263         hls_stream_t *hls = vlc_array_item_at_index(hls_stream, n);
264         if (hls)
265         {
266             /* compare */
267             if ((hls->id == hls_new->id) &&
268                 (hls->bandwidth == hls_new->bandwidth))
269                 return hls;
270         }
271     }
272     return NULL;
273 }
274
275 static uint64_t hls_GetStreamSize(hls_stream_t *hls)
276 {
277     /* NOTE: Stream size is calculated based on segment duration and
278      * HLS stream bandwidth from the .m3u8 file. If these are not correct
279      * then the deviation from exact byte size will be big and the seek/
280      * progressbar will not behave entirely as one expects. */
281     uint64_t size = 0UL;
282     int count = vlc_array_count(hls->segments);
283     for (int n = 0; n < count; n++)
284     {
285         segment_t *segment = segment_GetSegment(hls, n);
286         if (segment)
287         {
288             size += (segment->duration * (hls->bandwidth / 8));
289         }
290     }
291     return size;
292 }
293
294 /* Segment */
295 static segment_t *segment_New(hls_stream_t* hls, const int duration, const char *uri)
296 {
297     segment_t *segment = (segment_t *)malloc(sizeof(segment_t));
298     if (segment == NULL)
299         return NULL;
300
301     segment->duration = duration; /* seconds */
302     segment->size = 0; /* bytes */
303     segment->sequence = 0;
304     segment->bandwidth = 0;
305     vlc_UrlParse(&segment->url, uri, 0);
306     segment->data = NULL;
307     vlc_array_append(hls->segments, segment);
308     vlc_mutex_init(&segment->lock);
309     return segment;
310 }
311
312 static void segment_Free(segment_t *segment)
313 {
314     vlc_mutex_destroy(&segment->lock);
315
316     vlc_UrlClean(&segment->url);
317     if (segment->data)
318         block_Release(segment->data);
319     free(segment);
320     segment = NULL;
321 }
322
323 static segment_t *segment_GetSegment(hls_stream_t *hls, const int wanted)
324 {
325     assert(hls);
326
327     int count = vlc_array_count(hls->segments);
328     if (count <= 0)
329         return NULL;
330     if ((wanted < 0) || (wanted >= count))
331         return NULL;
332     return (segment_t *) vlc_array_item_at_index(hls->segments, wanted);
333 }
334
335 static segment_t *segment_Find(hls_stream_t *hls, const int sequence)
336 {
337     assert(hls);
338
339     int count = vlc_array_count(hls->segments);
340     if (count <= 0) return NULL;
341     for (int n = 0; n < count; n++)
342     {
343         segment_t *segment = vlc_array_item_at_index(hls->segments, n);
344         if (segment == NULL) break;
345         if (segment->sequence == sequence)
346             return segment;
347     }
348     return NULL;
349 }
350
351 static int ChooseSegment(stream_t *s, const int current)
352 {
353     stream_sys_t *p_sys = (stream_sys_t *)s->p_sys;
354     hls_stream_t *hls = hls_Get(p_sys->hls_stream, current);
355     if (hls == NULL) return 0;
356
357     /* Choose a segment to start which is no closer then
358      * 3 times the target duration from the end of the playlist.
359      */
360     int wanted = 0;
361     int duration = 0;
362     int sequence = 0;
363     int count = vlc_array_count(hls->segments);
364     int i = p_sys->b_live ? count - 1 : 0;
365
366     while((i >= 0) && (i < count) && vlc_object_alive(s))
367     {
368         segment_t *segment = segment_GetSegment(hls, i);
369         assert(segment);
370
371         if (segment->duration > hls->duration)
372         {
373             msg_Err(s, "EXTINF:%d duration is larger then EXT-X-TARGETDURATION:%d",
374                     segment->duration, hls->duration);
375         }
376
377         duration += segment->duration;
378         if (duration >= 3 * hls->duration)
379         {
380             /* Start point found */
381             wanted = p_sys->b_live ? i : 0;
382             sequence = segment->sequence;
383             break;
384         }
385
386         if (p_sys->b_live)
387             i-- ;
388         else
389           i++;
390     }
391
392     msg_Info(s, "Choose segment %d/%d (sequence=%d)", wanted, count, sequence);
393     return wanted;
394 }
395
396 /* Parsing */
397 static char *parse_Attributes(const char *line, const char *attr)
398 {
399     char *p;
400     char *begin = (char *) line;
401     char *end = begin + strlen(line);
402
403     /* Find start of attributes */
404     if ((p = strchr(begin, ':' )) == NULL)
405         return NULL;
406
407     begin = p;
408     do
409     {
410         if (strncasecmp(begin, attr, strlen(attr)) == 0)
411         {
412             /* <attr>=<value>[,]* */
413             p = strchr(begin, ',');
414             begin += strlen(attr) + 1;
415             if (begin >= end)
416                 return NULL;
417             if (p == NULL) /* last attribute */
418                 return strndup(begin, end - begin);
419             /* copy till ',' */
420             return strndup(begin, p - begin);
421         }
422         begin++;
423     } while(begin < end);
424
425     return NULL;
426 }
427
428 static char *relative_URI(stream_t *s, const char *uri, const char *path)
429 {
430     stream_sys_t *p_sys = s->p_sys;
431
432     char *p = strchr(uri, ':');
433     if (p != NULL)
434         return NULL;
435
436     if (p_sys->m3u8.psz_path == NULL)
437         return NULL;
438
439     char *psz_path = strdup(p_sys->m3u8.psz_path);
440     if (psz_path == NULL) return NULL;
441     p = strrchr(psz_path, '/');
442     if (p) *p = '\0';
443
444     char *psz_uri = NULL;
445     if (p_sys->m3u8.psz_password || p_sys->m3u8.psz_username)
446     {
447         if (asprintf(&psz_uri, "%s://%s:%s@%s:%d%s/%s", p_sys->m3u8.psz_protocol,
448                      p_sys->m3u8.psz_username, p_sys->m3u8.psz_password,
449                      p_sys->m3u8.psz_host, p_sys->m3u8.i_port,
450                      path ? path : psz_path, uri) < 0)
451             goto fail;
452     }
453     else
454     {
455         if (asprintf(&psz_uri, "%s://%s:%d%s/%s", p_sys->m3u8.psz_protocol,
456                      p_sys->m3u8.psz_host, p_sys->m3u8.i_port,
457                      path ? path : psz_path, uri) < 0)
458            goto fail;
459     }
460     free(psz_path);
461     return psz_uri;
462
463 fail:
464     free(psz_path);
465     return NULL;
466 }
467
468 static char *ConstructUrl(vlc_url_t *url)
469 {
470     if ((url->psz_protocol == NULL) ||
471         (url->psz_path == NULL))
472         return NULL;
473
474     if (url->i_port <= 0)
475     {
476         if (strncmp(url->psz_protocol, "https", 5) == 0)
477             url->i_port = 443;
478         else
479             url->i_port = 80;
480     }
481
482     char *psz_url = NULL;
483     if (url->psz_password || url->psz_username)
484     {
485         if (asprintf(&psz_url, "%s://%s:%s@%s:%d%s",
486                      url->psz_protocol,
487                      url->psz_username, url->psz_password,
488                      url->psz_host, url->i_port, url->psz_path) < 0)
489             return NULL;
490     }
491     else
492     {
493         if (asprintf(&psz_url, "%s://%s:%d%s",
494                      url->psz_protocol,
495                      url->psz_host, url->i_port, url->psz_path) < 0)
496             return NULL;
497     }
498
499     return psz_url;
500 }
501
502 static int parse_SegmentInformation(hls_stream_t *hls, char *p_read, int *duration)
503 {
504     assert(hls);
505     assert(p_read);
506
507     /* strip of #EXTINF: */
508     char *p_next = NULL;
509     char *token = strtok_r(p_read, ":", &p_next);
510     if (token == NULL)
511         return VLC_EGENERIC;
512
513     /* read duration */
514     token = strtok_r(NULL, ",", &p_next);
515     if (token == NULL)
516         return VLC_EGENERIC;
517
518     *duration = atoi(token);
519
520     /* Ignore the rest of the line */
521
522     return VLC_SUCCESS;
523 }
524
525 static int parse_AddSegment(stream_t *s, hls_stream_t *hls, const int duration, const char *uri)
526 {
527     assert(hls);
528     assert(uri);
529
530     /* Store segment information */
531     char *psz_path = NULL;
532     if (hls->url.psz_path != NULL)
533     {
534         psz_path = strdup(hls->url.psz_path);
535         if (psz_path == NULL)
536             return VLC_ENOMEM;
537         char *p = strrchr(psz_path, '/');
538         if (p) *p = '\0';
539     }
540     char *psz_uri = relative_URI(s, uri, psz_path);
541     free(psz_path);
542
543     vlc_mutex_lock(&hls->lock);
544     segment_t *segment = segment_New(hls, duration, psz_uri ? psz_uri : uri);
545     if (segment)
546         segment->sequence = hls->sequence + vlc_array_count(hls->segments) - 1;
547     vlc_mutex_unlock(&hls->lock);
548
549     free(psz_uri);
550     return segment ? VLC_SUCCESS : VLC_ENOMEM;
551 }
552
553 static int parse_TargetDuration(stream_t *s, hls_stream_t *hls, char *p_read)
554 {
555     assert(hls);
556
557     int duration = -1;
558     int ret = sscanf(p_read, "#EXT-X-TARGETDURATION:%d", &duration);
559     if (ret != 1)
560     {
561         msg_Err(s, "expected #EXT-X-TARGETDURATION:<s>");
562         return VLC_EGENERIC;
563     }
564
565     hls->duration = duration; /* seconds */
566     return VLC_SUCCESS;
567 }
568
569 static int parse_StreamInformation(stream_t *s, vlc_array_t **hls_stream,
570                                    hls_stream_t **hls, char *p_read, const char *uri)
571 {
572     int id;
573     uint64_t bw;
574     char *attr;
575
576     assert(*hls == NULL);
577
578     attr = parse_Attributes(p_read, "PROGRAM-ID");
579     if (attr == NULL)
580     {
581         msg_Err(s, "#EXT-X-STREAM-INF: expected PROGRAM-ID=<value>");
582         return VLC_EGENERIC;
583     }
584     id = atol(attr);
585     free(attr);
586
587     attr = parse_Attributes(p_read, "BANDWIDTH");
588     if (attr == NULL)
589     {
590         msg_Err(s, "#EXT-X-STREAM-INF: expected BANDWIDTH=<value>");
591         return VLC_EGENERIC;
592     }
593     bw = atoll(attr);
594     free(attr);
595
596     if (bw == 0)
597     {
598         msg_Err(s, "#EXT-X-STREAM-INF: bandwidth cannot be 0");
599         return VLC_EGENERIC;
600     }
601
602     msg_Info(s, "bandwidth adaption detected (program-id=%d, bandwidth=%"PRIu64").", id, bw);
603
604     char *psz_uri = relative_URI(s, uri, NULL);
605
606     *hls = hls_New(*hls_stream, id, bw, psz_uri ? psz_uri : uri);
607
608     free(psz_uri);
609
610     return (*hls == NULL) ? VLC_ENOMEM : VLC_SUCCESS;
611 }
612
613 static int parse_MediaSequence(stream_t *s, hls_stream_t *hls, char *p_read)
614 {
615     assert(hls);
616
617     int sequence;
618     int ret = sscanf(p_read, "#EXT-X-MEDIA-SEQUENCE:%d", &sequence);
619     if (ret != 1)
620     {
621         msg_Err(s, "expected #EXT-X-MEDIA-SEQUENCE:<s>");
622         return VLC_EGENERIC;
623     }
624
625     if (hls->sequence > 0)
626         msg_Err(s, "EXT-X-MEDIA-SEQUENCE already present in playlist (new=%d, old=%d)",
627                     sequence, hls->sequence);
628
629     hls->sequence = sequence;
630     return VLC_SUCCESS;
631 }
632
633 static int parse_Key(stream_t *s, hls_stream_t *hls, char *p_read)
634 {
635     assert(hls);
636
637     /* #EXT-X-KEY:METHOD=<method>[,URI="<URI>"][,IV=<IV>] */
638     int err = VLC_SUCCESS;
639     char *attr = parse_Attributes(p_read, "METHOD");
640     if (attr == NULL)
641     {
642         msg_Err(s, "#EXT-X-KEY: expected METHOD=<value>");
643         return err;
644     }
645
646     if (strncasecmp(attr, "NONE", 4) == 0)
647     {
648
649         char *uri = parse_Attributes(p_read, "URI");
650         if (uri != NULL)
651         {
652             msg_Err(s, "#EXT-X-KEY: URI not expected");
653             err = VLC_EGENERIC;
654         }
655         free(uri);
656         /* IV is only supported in version 2 and above */
657         if (hls->version >= 2)
658         {
659             char *iv = parse_Attributes(p_read, "IV");
660             if (iv != NULL)
661             {
662                 msg_Err(s, "#EXT-X-KEY: IV not expected");
663                 err = VLC_EGENERIC;
664             }
665             free(iv);
666         }
667     }
668     else
669     {
670         msg_Warn(s, "playback of encrypted HTTP Live media is not supported.");
671         err = VLC_EGENERIC;
672     }
673     free(attr);
674     return err;
675 }
676
677 static int parse_ProgramDateTime(stream_t *s, hls_stream_t *hls, char *p_read)
678 {
679     VLC_UNUSED(hls);
680     msg_Dbg(s, "tag not supported: #EXT-X-PROGRAM-DATE-TIME %s", p_read);
681     return VLC_SUCCESS;
682 }
683
684 static int parse_AllowCache(stream_t *s, hls_stream_t *hls, char *p_read)
685 {
686     assert(hls);
687
688     char answer[4] = "\0";
689     int ret = sscanf(p_read, "#EXT-X-ALLOW-CACHE:%3s", answer);
690     if (ret != 1)
691     {
692         msg_Err(s, "#EXT-X-ALLOW-CACHE, ignoring ...");
693         return VLC_EGENERIC;
694     }
695
696     hls->b_cache = (strncmp(answer, "NO", 2) != 0);
697     return VLC_SUCCESS;
698 }
699
700 static int parse_Version(stream_t *s, hls_stream_t *hls, char *p_read)
701 {
702     assert(hls);
703
704     int version;
705     int ret = sscanf(p_read, "#EXT-X-VERSION:%d", &version);
706     if (ret != 1)
707     {
708         msg_Err(s, "#EXT-X-VERSION: no protocol version found, should be version 1.");
709         return VLC_EGENERIC;
710     }
711
712     /* Check version */
713     hls->version = version;
714     if (hls->version != 1)
715     {
716         msg_Err(s, "#EXT-X-VERSION should be version 1 iso %d", version);
717         return VLC_EGENERIC;
718     }
719     return VLC_SUCCESS;
720 }
721
722 static int parse_EndList(stream_t *s, hls_stream_t *hls)
723 {
724     assert(hls);
725
726     s->p_sys->b_live = false;
727     msg_Info(s, "video on demand (vod) mode");
728     return VLC_SUCCESS;
729 }
730
731 static int parse_Discontinuity(stream_t *s, hls_stream_t *hls, char *p_read)
732 {
733     assert(hls);
734
735     /* FIXME: Do we need to act on discontinuity ?? */
736     msg_Dbg(s, "#EXT-X-DISCONTINUITY %s", p_read);
737     return VLC_SUCCESS;
738 }
739
740 /* The http://tools.ietf.org/html/draft-pantos-http-live-streaming-04#page-8
741  * document defines the following new tags: EXT-X-TARGETDURATION,
742  * EXT-X-MEDIA-SEQUENCE, EXT-X-KEY, EXT-X-PROGRAM-DATE-TIME, EXT-X-
743  * ALLOW-CACHE, EXT-X-STREAM-INF, EXT-X-ENDLIST, EXT-X-DISCONTINUITY,
744  * and EXT-X-VERSION.
745  */
746 static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const ssize_t len)
747 {
748     stream_sys_t *p_sys = s->p_sys;
749     uint8_t *p_read, *p_begin, *p_end;
750
751     assert(streams);
752     assert(buffer);
753
754     msg_Dbg(s, "parse_M3U8\n%s", buffer);
755     p_begin = buffer;
756     p_end = p_begin + len;
757
758     char *line = ReadLine(p_begin, &p_read, p_end - p_begin);
759     if (line == NULL)
760         return VLC_ENOMEM;
761     p_begin = p_read;
762
763     if (strncmp(line, "#EXTM3U", 7) != 0)
764     {
765         msg_Err(s, "missing #EXTM3U tag .. aborting");
766         free(line);
767         return VLC_EGENERIC;
768     }
769
770     free(line);
771     line = NULL;
772
773     /* What is the version ? */
774     int version = 1;
775     uint8_t *p = (uint8_t *)strstr((const char *)buffer, "#EXT-X-VERSION:");
776     if (p != NULL)
777     {
778         uint8_t *tmp = NULL;
779         char *psz_version = ReadLine(p, &tmp, p_end - p);
780         if (psz_version == NULL)
781             return VLC_ENOMEM;
782         int ret = sscanf((const char*)psz_version, "#EXT-X-VERSION:%d", &version);
783         if (ret != 1)
784         {
785             msg_Warn(s, "#EXT-X-VERSION: no protocol version found, assuming version 1.");
786             version = 1;
787         }
788         free(psz_version);
789         p = NULL;
790     }
791
792     /* Is it a live stream ? */
793     p_sys->b_live = (strstr((const char *)buffer, "#EXT-X-ENDLIST") == NULL) ? true : false;
794
795     /* Is it a meta index file ? */
796     bool b_meta = (strstr((const char *)buffer, "#EXT-X-STREAM-INF") == NULL) ? false : true;
797
798     int err = VLC_SUCCESS;
799
800     if (b_meta)
801     {
802         msg_Info(s, "Meta playlist");
803
804         /* M3U8 Meta Index file */
805         do {
806             /* Next line */
807             line = ReadLine(p_begin, &p_read, p_end - p_begin);
808             if (line == NULL)
809                 break;
810             p_begin = p_read;
811
812             /* */
813             if (strncmp(line, "#EXT-X-STREAM-INF", 17) == 0)
814             {
815                 p_sys->b_meta = true;
816                 char *uri = ReadLine(p_begin, &p_read, p_end - p_begin);
817                 if (uri == NULL)
818                     err = VLC_ENOMEM;
819                 else
820                 {
821                     hls_stream_t *hls = NULL;
822                     err = parse_StreamInformation(s, &streams, &hls, line, uri);
823                     free(uri);
824
825                     /* Download playlist file from server */
826                     uint8_t *buf = NULL;
827                     ssize_t len = read_M3U8(s, &hls->url, &buf);
828                     if (len < 0)
829                         err = VLC_EGENERIC;
830                     else
831                     {
832                         /* Parse HLS m3u8 content. */
833                         err = parse_M3U8(s, streams, buf, len);
834                         free(buf);
835                     }
836
837                     if (hls)
838                     {
839                         hls->version = version;
840                         if (!p_sys->b_live)
841                             hls->size = hls_GetStreamSize(hls); /* Stream size (approximate) */
842                     }
843                 }
844                 p_begin = p_read;
845             }
846
847             free(line);
848             line = NULL;
849
850             if (p_begin >= p_end)
851                 break;
852
853         } while ((err == VLC_SUCCESS) && vlc_object_alive(s));
854
855     }
856     else
857     {
858         msg_Info(s, "%s Playlist HLS protocol version: %d", p_sys->b_live ? "Live": "VOD", version);
859
860         hls_stream_t *hls = NULL;
861         if (p_sys->b_meta)
862             hls = hls_GetLast(streams);
863         else
864         {
865             /* No Meta playlist used */
866             hls = hls_New(streams, 0, -1, NULL);
867             if (hls)
868             {
869                 /* Get TARGET-DURATION first */
870                 p = (uint8_t *)strstr((const char *)buffer, "#EXT-X-TARGETDURATION:");
871                 if (p)
872                 {
873                     uint8_t *p_rest = NULL;
874                     char *psz_duration = ReadLine(p, &p_rest,  p_end - p);
875                     if (psz_duration == NULL)
876                         return VLC_EGENERIC;
877                     err = parse_TargetDuration(s, hls, psz_duration);
878                     free(psz_duration);
879                     p = NULL;
880                 }
881
882                 /* Store version */
883                 hls->version = version;
884             }
885             else return VLC_ENOMEM;
886         }
887         assert(hls);
888
889         /* */
890         int segment_duration = -1;
891         do
892         {
893             /* Next line */
894             line = ReadLine(p_begin, &p_read, p_end - p_begin);
895             if (line == NULL)
896                 break;
897             p_begin = p_read;
898
899             if (strncmp(line, "#EXTINF", 7) == 0)
900                 err = parse_SegmentInformation(hls, line, &segment_duration);
901             else if (strncmp(line, "#EXT-X-TARGETDURATION", 21) == 0)
902                 err = parse_TargetDuration(s, hls, line);
903             else if (strncmp(line, "#EXT-X-MEDIA-SEQUENCE", 21) == 0)
904                 err = parse_MediaSequence(s, hls, line);
905             else if (strncmp(line, "#EXT-X-KEY", 10) == 0)
906                 err = parse_Key(s, hls, line);
907             else if (strncmp(line, "#EXT-X-PROGRAM-DATE-TIME", 24) == 0)
908                 err = parse_ProgramDateTime(s, hls, line);
909             else if (strncmp(line, "#EXT-X-ALLOW-CACHE", 18) == 0)
910                 err = parse_AllowCache(s, hls, line);
911             else if (strncmp(line, "#EXT-X-DISCONTINUITY", 20) == 0)
912                 err = parse_Discontinuity(s, hls, line);
913             else if (strncmp(line, "#EXT-X-VERSION", 14) == 0)
914                 err = parse_Version(s, hls, line);
915             else if (strncmp(line, "#EXT-X-ENDLIST", 14) == 0)
916                 err = parse_EndList(s, hls);
917             else if (strncmp(line, "#", 1) != 0)
918             {
919                 err = parse_AddSegment(s, hls, segment_duration, line);
920                 segment_duration = -1; /* reset duration */
921             }
922
923             free(line);
924             line = NULL;
925
926             if (p_begin >= p_end)
927                 break;
928
929         } while ((err == VLC_SUCCESS) && vlc_object_alive(s));
930
931         free(line);
932     }
933
934     return err;
935 }
936
937 static int get_HTTPLiveMetaPlaylist(stream_t *s, vlc_array_t **streams)
938 {
939     stream_sys_t *p_sys = s->p_sys;
940     assert(*streams);
941
942     /* Download new playlist file from server */
943     uint8_t *buffer = NULL;
944     ssize_t len = read_M3U8(s, &p_sys->m3u8, &buffer);
945     if (len < 0)
946         return VLC_EGENERIC;
947
948     /* Parse HLS m3u8 content. */
949     int err = parse_M3U8(s, *streams, buffer, len);
950     free(buffer);
951
952     return err;
953 }
954
955 /* Reload playlist */
956 static int hls_UpdatePlaylist(stream_t *s, hls_stream_t *hls_new, hls_stream_t **hls)
957 {
958     int count = vlc_array_count(hls_new->segments);
959
960     msg_Info(s, "updating hls stream (program-id=%d, bandwidth=%"PRIu64") has %d segments",
961              hls_new->id, hls_new->bandwidth, count);
962     for (int n = 0; n < count; n++)
963     {
964         segment_t *p = segment_GetSegment(hls_new, n);
965         if (p == NULL) return VLC_EGENERIC;
966
967         vlc_mutex_lock(&(*hls)->lock);
968         segment_t *segment = segment_Find(*hls, p->sequence);
969         if (segment)
970         {
971             /* they should be the same */
972             if ((p->sequence != segment->sequence) ||
973                 (p->duration != segment->duration) ||
974                 (strcmp(p->url.psz_path, segment->url.psz_path) != 0))
975             {
976                 msg_Err(s, "existing segment found with different content - resetting");
977                 msg_Err(s, "- sequence: new=%d, old=%d", p->sequence, segment->sequence);
978                 msg_Err(s, "- duration: new=%d, old=%d", p->duration, segment->duration);
979                 msg_Err(s, "- file: new=%s", p->url.psz_path);
980                 msg_Err(s, "        old=%s", segment->url.psz_path);
981
982                 /* Resetting content */
983                 segment->sequence = p->sequence;
984                 segment->duration = p->duration;
985                 vlc_UrlClean(&segment->url);
986                 vlc_UrlParse(&segment->url, p->url.psz_buffer, 0);
987                 segment_Free(p);
988             }
989         }
990         else
991         {
992             int last = vlc_array_count((*hls)->segments) - 1;
993             segment_t *l = segment_GetSegment(*hls, last);
994             if (l == NULL) goto fail_and_unlock;
995
996             if ((l->sequence + 1) != p->sequence)
997             {
998                 msg_Err(s, "gap in sequence numbers found: new=%d expected %d",
999                         p->sequence, l->sequence+1);
1000             }
1001             vlc_array_append((*hls)->segments, p);
1002             msg_Info(s, "- segment %d appended", p->sequence);
1003         }
1004         vlc_mutex_unlock(&(*hls)->lock);
1005     }
1006     return VLC_SUCCESS;
1007
1008 fail_and_unlock:
1009     vlc_mutex_unlock(&(*hls)->lock);
1010     return VLC_EGENERIC;
1011 }
1012
1013 static int hls_ReloadPlaylist(stream_t *s)
1014 {
1015     stream_sys_t *p_sys = s->p_sys;
1016
1017     vlc_array_t *hls_streams = vlc_array_new();
1018     if (hls_streams == NULL)
1019         return VLC_ENOMEM;
1020
1021     msg_Info(s, "Reloading HLS live meta playlist");
1022
1023     if (get_HTTPLiveMetaPlaylist(s, &hls_streams) != VLC_SUCCESS)
1024     {
1025         /* Free hls streams */
1026         for (int i = 0; i < vlc_array_count(hls_streams); i++)
1027         {
1028             hls_stream_t *hls;
1029             hls = (hls_stream_t *)vlc_array_item_at_index(hls_streams, i);
1030             if (hls) hls_Free(hls);
1031         }
1032         vlc_array_destroy(hls_streams);
1033
1034         msg_Err(s, "reloading playlist failed");
1035         return VLC_EGENERIC;
1036     }
1037
1038     /* merge playlists */
1039     int count = vlc_array_count(hls_streams);
1040     for (int n = 0; n < count; n++)
1041     {
1042         hls_stream_t *hls_new = hls_Get(hls_streams, n);
1043         if (hls_new == NULL)
1044             continue;
1045
1046         hls_stream_t *hls_old = hls_Find(p_sys->hls_stream, hls_new);
1047         if (hls_old == NULL)
1048         {   /* new hls stream - append */
1049             vlc_array_append(p_sys->hls_stream, hls_new);
1050             msg_Info(s, "new HLS stream appended (id=%d, bandwidth=%"PRIu64")",
1051                      hls_new->id, hls_new->bandwidth);
1052         }
1053         else if (hls_UpdatePlaylist(s, hls_new, &hls_old) != VLC_SUCCESS)
1054             msg_Info(s, "failed updating HLS stream (id=%d, bandwidth=%"PRIu64")",
1055                      hls_new->id, hls_new->bandwidth);
1056     }
1057
1058     vlc_array_destroy(hls_streams);
1059     return VLC_SUCCESS;
1060 }
1061
1062 /****************************************************************************
1063  * hls_Thread
1064  ****************************************************************************/
1065 static int BandwidthAdaptation(stream_t *s, int progid, uint64_t *bandwidth)
1066 {
1067     stream_sys_t *p_sys = s->p_sys;
1068     int candidate = -1;
1069     uint64_t bw = *bandwidth;
1070     uint64_t bw_candidate = 0;
1071
1072     int count = vlc_array_count(p_sys->hls_stream);
1073     for (int n = 0; n < count; n++)
1074     {
1075         /* Select best bandwidth match */
1076         hls_stream_t *hls = hls_Get(p_sys->hls_stream, n);
1077         if (hls == NULL) break;
1078
1079         /* only consider streams with the same PROGRAM-ID */
1080         if (hls->id == progid)
1081         {
1082             if ((bw >= hls->bandwidth) && (bw_candidate < hls->bandwidth))
1083             {
1084                 msg_Dbg(s, "candidate %d bandwidth (bits/s) %"PRIu64" >= %"PRIu64,
1085                          n, bw, hls->bandwidth); /* bits / s */
1086                 bw_candidate = hls->bandwidth;
1087                 candidate = n; /* possible candidate */
1088             }
1089         }
1090     }
1091     *bandwidth = bw_candidate;
1092     return candidate;
1093 }
1094
1095 static int Download(stream_t *s, hls_stream_t *hls, segment_t *segment, int *cur_stream)
1096 {
1097     stream_sys_t *p_sys = s->p_sys;
1098
1099     assert(hls);
1100     assert(segment);
1101
1102     vlc_mutex_lock(&segment->lock);
1103     if (segment->data != NULL)
1104     {
1105         /* Segment already downloaded */
1106         vlc_mutex_unlock(&segment->lock);
1107         return VLC_SUCCESS;
1108     }
1109
1110     /* sanity check - can we download this segment on time? */
1111     if ((p_sys->bandwidth > 0) && (hls->bandwidth > 0))
1112     {
1113         uint64_t size = (segment->duration * hls->bandwidth); /* bits */
1114         int estimated = (int)(size / p_sys->bandwidth);
1115         if (estimated > segment->duration)
1116         {
1117             msg_Warn(s,"downloading of segment %d takes %ds, which is longer then its playback (%ds)",
1118                         segment->sequence, estimated, segment->duration);
1119         }
1120     }
1121
1122     mtime_t start = mdate();
1123     if (hls_Download(s, segment) != VLC_SUCCESS)
1124     {
1125         vlc_mutex_unlock(&segment->lock);
1126         return VLC_EGENERIC;
1127     }
1128     mtime_t duration = mdate() - start;
1129
1130     vlc_mutex_unlock(&segment->lock);
1131
1132     msg_Info(s, "downloaded segment %d from stream %d",
1133                 segment->sequence, *cur_stream);
1134
1135     /* check for division by zero */
1136     double ms = (double)duration / 1000.0; /* ms */
1137     if (ms <= 0.0)
1138         return VLC_SUCCESS;
1139
1140     uint64_t bw = ((double)(segment->size * 8) / ms) * 1000; /* bits / s */
1141     p_sys->bandwidth = bw;
1142     if (p_sys->b_meta && (hls->bandwidth != bw))
1143     {
1144         int newstream = BandwidthAdaptation(s, hls->id, &bw);
1145
1146         /* FIXME: we need an average here */
1147         if ((newstream >= 0) && (newstream != *cur_stream))
1148         {
1149             msg_Info(s, "detected %s bandwidth (%"PRIu64") stream",
1150                      (bw >= hls->bandwidth) ? "faster" : "lower", bw);
1151             *cur_stream = newstream;
1152         }
1153     }
1154     return VLC_SUCCESS;
1155 }
1156
1157 static void* hls_Thread(void *p_this)
1158 {
1159     stream_t *s = (stream_t *)p_this;
1160     stream_sys_t *p_sys = s->p_sys;
1161
1162     int canc = vlc_savecancel();
1163
1164     while (vlc_object_alive(s))
1165     {
1166         hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
1167         assert(hls);
1168
1169         /* Sliding window (~60 seconds worth of movie) */
1170         vlc_mutex_lock(&hls->lock);
1171         int count = vlc_array_count(hls->segments);
1172         vlc_mutex_unlock(&hls->lock);
1173
1174         /* Is there a new segment to process? */
1175         if ((!p_sys->b_live && (p_sys->playback.segment < (count - 6))) ||
1176             (p_sys->download.segment >= count))
1177         {
1178             /* wait */
1179             vlc_mutex_lock(&p_sys->download.lock_wait);
1180             while (((p_sys->download.segment - p_sys->playback.segment > 6) ||
1181                     (p_sys->download.segment >= count)) &&
1182                    (p_sys->download.seek == -1))
1183             {
1184                 if (p_sys->b_live /*&& (mdate() >= p_sys->playlist.wakeup)*/)
1185                     break;
1186                 vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
1187                 if (!vlc_object_alive(s)) break;
1188             }
1189             /* */
1190             if (p_sys->download.seek >= 0)
1191             {
1192                 p_sys->download.segment = p_sys->download.seek;
1193                 p_sys->download.seek = -1;
1194             }
1195             vlc_mutex_unlock(&p_sys->download.lock_wait);
1196         }
1197
1198         if (!vlc_object_alive(s)) break;
1199
1200         vlc_mutex_lock(&hls->lock);
1201         segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
1202         vlc_mutex_unlock(&hls->lock);
1203
1204         if ((segment != NULL) &&
1205             (Download(s, hls, segment, &p_sys->download.stream) != VLC_SUCCESS))
1206         {
1207             if (!vlc_object_alive(s)) break;
1208
1209             if (!p_sys->b_live)
1210             {
1211                 p_sys->b_error = true;
1212                 break;
1213             }
1214         }
1215
1216         /* download succeeded */
1217         /* determine next segment to download */
1218         vlc_mutex_lock(&p_sys->download.lock_wait);
1219         if (p_sys->download.seek >= 0)
1220         {
1221             p_sys->download.segment = p_sys->download.seek;
1222             p_sys->download.seek = -1;
1223         }
1224         else if (p_sys->download.segment < count)
1225             p_sys->download.segment++;
1226         vlc_cond_signal(&p_sys->download.wait);
1227         vlc_mutex_unlock(&p_sys->download.lock_wait);
1228     }
1229
1230     vlc_restorecancel(canc);
1231     return NULL;
1232 }
1233
1234 static void* hls_Reload(void *p_this)
1235 {
1236     stream_t *s = (stream_t *)p_this;
1237     stream_sys_t *p_sys = s->p_sys;
1238
1239     assert(p_sys->b_live);
1240
1241     int canc = vlc_savecancel();
1242
1243     while (vlc_object_alive(s))
1244     {
1245         double wait = 1;
1246         mtime_t now = mdate();
1247         if (now >= p_sys->playlist.wakeup)
1248         {
1249             /* reload the m3u8 */
1250             if (hls_ReloadPlaylist(s) != VLC_SUCCESS)
1251             {
1252                 /* No change in playlist, then backoff */
1253                 p_sys->playlist.tries++;
1254                 if (p_sys->playlist.tries == 1) wait = 0.5;
1255                 else if (p_sys->playlist.tries == 2) wait = 1;
1256                 else if (p_sys->playlist.tries >= 3) wait = 3;
1257             }
1258             else p_sys->playlist.tries = 0;
1259
1260             hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
1261             assert(hls);
1262
1263             /* determine next time to update playlist */
1264             p_sys->playlist.last = now;
1265             p_sys->playlist.wakeup = now + ((mtime_t)(hls->duration * wait)
1266                                                    * (mtime_t)1000000);
1267         }
1268
1269         mwait(p_sys->playlist.wakeup);
1270     }
1271
1272     vlc_restorecancel(canc);
1273     return NULL;
1274 }
1275
1276 static int Prefetch(stream_t *s, int *current)
1277 {
1278     stream_sys_t *p_sys = s->p_sys;
1279     int stream;
1280
1281     /* Try to pick best matching stream */;
1282 again:
1283     stream = *current;
1284
1285     hls_stream_t *hls = hls_Get(p_sys->hls_stream, *current);
1286     if (hls == NULL)
1287         return VLC_EGENERIC;
1288
1289     segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
1290     if (segment == NULL )
1291         return VLC_EGENERIC;
1292
1293     if (Download(s, hls, segment, current) != VLC_SUCCESS)
1294         return VLC_EGENERIC;
1295
1296     /* Found better bandwidth match, try again */
1297     if (*current != stream)
1298         goto again;
1299
1300     /* Download first 2 segments of this HLS stream */
1301     stream = *current;
1302     for (int i = 0; i < 2; i++)
1303     {
1304         segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
1305         if (segment == NULL )
1306             return VLC_EGENERIC;
1307
1308         if (segment->data)
1309         {
1310             p_sys->download.segment++;
1311             continue;
1312         }
1313
1314         if (Download(s, hls, segment, current) != VLC_SUCCESS)
1315             return VLC_EGENERIC;
1316
1317         p_sys->download.segment++;
1318
1319         /* adapt bandwidth? */
1320         if (*current != stream)
1321         {
1322             hls_stream_t *hls = hls_Get(p_sys->hls_stream, *current);
1323             if (hls == NULL)
1324                 return VLC_EGENERIC;
1325
1326              stream = *current;
1327         }
1328     }
1329
1330     return VLC_SUCCESS;
1331 }
1332
1333 /****************************************************************************
1334  *
1335  ****************************************************************************/
1336 static int hls_Download(stream_t *s, segment_t *segment)
1337 {
1338     assert(segment);
1339
1340     /* Construct URL */
1341     char *psz_url = ConstructUrl(&segment->url);
1342     if (psz_url == NULL)
1343            return VLC_ENOMEM;
1344
1345     stream_t *p_ts = stream_UrlNew(s, psz_url);
1346     free(psz_url);
1347     if (p_ts == NULL)
1348         return VLC_EGENERIC;
1349
1350     segment->size = stream_Size(p_ts);
1351     assert(segment->size > 0);
1352
1353     segment->data = block_Alloc(segment->size);
1354     if (segment->data == NULL)
1355     {
1356         stream_Delete(p_ts);
1357         return VLC_ENOMEM;
1358     }
1359
1360     assert(segment->data->i_buffer == segment->size);
1361
1362     ssize_t length = 0, curlen = 0;
1363     uint64_t size;
1364     do
1365     {
1366         size = stream_Size(p_ts);
1367         if (size > segment->size)
1368         {
1369             msg_Dbg(s, "size changed %"PRIu64, segment->size);
1370             segment->data = block_Realloc(segment->data, 0, size);
1371             if (segment->data == NULL)
1372             {
1373                 stream_Delete(p_ts);
1374                 return VLC_ENOMEM;
1375             }
1376             segment->size = size;
1377             assert(segment->data->i_buffer == segment->size);
1378         }
1379         length = stream_Read(p_ts, segment->data->p_buffer + curlen, segment->size - curlen);
1380         if (length <= 0)
1381             break;
1382         curlen += length;
1383     } while (vlc_object_alive(s));
1384
1385     stream_Delete(p_ts);
1386     return VLC_SUCCESS;
1387 }
1388
1389 /* Read M3U8 file */
1390 static ssize_t read_M3U8(stream_t *s, vlc_url_t *url, uint8_t **buffer)
1391 {
1392     assert(*buffer == NULL);
1393
1394     /* Construct URL */
1395     char *psz_url = ConstructUrl(url);
1396     if (psz_url == NULL)
1397            return VLC_ENOMEM;
1398
1399     stream_t *p_m3u8 = stream_UrlNew(s, psz_url);
1400     free(psz_url);
1401     if (p_m3u8 == NULL)
1402         return VLC_EGENERIC;
1403
1404     int64_t size = stream_Size(p_m3u8);
1405     if (size == 0) size = 8192; /* no Content-Length */
1406
1407     *buffer = calloc(1, size);
1408     if (*buffer == NULL)
1409     {
1410         stream_Delete(p_m3u8);
1411         return VLC_ENOMEM;
1412     }
1413
1414     int64_t len = 0, curlen = 0;
1415     do {
1416         int read = ((size - curlen) >= INT_MAX) ? INT_MAX : (size - curlen);
1417         len = stream_Read(p_m3u8, *buffer + curlen, read);
1418         if (len <= 0)
1419             break;
1420         curlen += len;
1421         if (curlen >= size)
1422         {
1423             uint8_t *tmp = realloc(*buffer, size + 8192);
1424             if (tmp == NULL)
1425                 break;
1426             size += 8192;
1427             *buffer = tmp;
1428         }
1429     } while (vlc_object_alive(s));
1430     stream_Delete(p_m3u8);
1431
1432     (*buffer)[curlen-1] = '\0';
1433     return size;
1434 }
1435
1436 static ssize_t ReadM3U8(stream_t *s, uint8_t **buffer)
1437 {
1438     assert(*buffer == NULL);
1439
1440     int64_t size = stream_Size(s->p_source);
1441     if (size == 0) size = 1024; /* no Content-Length */
1442
1443     *buffer = calloc(1, size);
1444     if (*buffer == NULL)
1445         return VLC_ENOMEM;
1446
1447     int64_t len = 0, curlen = 0;
1448     do {
1449         int read = ((size - curlen) >= INT_MAX) ? INT_MAX : (size - curlen);
1450         len = stream_Read(s->p_source, *buffer + curlen, read);
1451         if (len <= 0)
1452             break;
1453         curlen += len;
1454         if (curlen >= size)
1455         {
1456             uint8_t *tmp = realloc(*buffer, size + 1024);
1457             if (tmp == NULL)
1458                 break;
1459             size += 1024;
1460             *buffer = tmp;
1461         }
1462     } while (vlc_object_alive(s));
1463
1464     return size;
1465 }
1466
1467 static char *ReadLine(uint8_t *buffer, uint8_t **pos, const size_t len)
1468 {
1469     assert(buffer);
1470
1471     char *line = NULL;
1472     uint8_t *begin = buffer;
1473     uint8_t *p = begin;
1474     uint8_t *end = p + len;
1475
1476     while (p < end)
1477     {
1478         if ((*p == '\n') || (*p == '\0'))
1479             break;
1480         p++;
1481     }
1482
1483     /* copy line excluding \n or \0 */
1484     line = strndup((char *)begin, p - begin);
1485
1486     if (*p == '\0')
1487         *pos = end;
1488     else
1489     {
1490         /* next pass start after \n */
1491         p++;
1492         *pos = p;
1493     }
1494
1495     return line;
1496 }
1497
1498 /****************************************************************************
1499  * Open
1500  ****************************************************************************/
1501 static int Open(vlc_object_t *p_this)
1502 {
1503     stream_t *s = (stream_t*)p_this;
1504     stream_sys_t *p_sys;
1505
1506     if (!isHTTPLiveStreaming(s))
1507         return VLC_EGENERIC;
1508
1509     msg_Info(p_this, "HTTP Live Streaming (%s)", s->psz_path);
1510
1511     /* */
1512     s->p_sys = p_sys = calloc(1, sizeof(*p_sys));
1513     if (p_sys == NULL)
1514         return VLC_ENOMEM;
1515
1516     char *psz_uri = NULL;
1517     if (asprintf(&psz_uri,"%s://%s", s->psz_access, s->psz_path) < 0)
1518     {
1519         free(p_sys);
1520         return VLC_ENOMEM;
1521     }
1522     vlc_UrlParse(&p_sys->m3u8, psz_uri, 0);
1523     free(psz_uri);
1524
1525     p_sys->bandwidth = -1;
1526     p_sys->b_live = true;
1527     p_sys->b_meta = false;
1528     p_sys->b_error = false;
1529
1530     p_sys->hls_stream = vlc_array_new();
1531     if (p_sys->hls_stream == NULL)
1532     {
1533         vlc_UrlClean(&p_sys->m3u8);
1534         free(p_sys);
1535         return VLC_ENOMEM;
1536     }
1537
1538     /* */
1539     s->pf_read = Read;
1540     s->pf_peek = Peek;
1541     s->pf_control = Control;
1542
1543     /* Parse HLS m3u8 content. */
1544     uint8_t *buffer = NULL;
1545     ssize_t len = ReadM3U8(s, &buffer);
1546     if (len < 0)
1547         goto fail;
1548     if (parse_M3U8(s, p_sys->hls_stream, buffer, len) != VLC_SUCCESS)
1549     {
1550         free(buffer);
1551         goto fail;
1552     }
1553     free(buffer);
1554
1555     /* Choose first HLS stream to start with */
1556     int current = p_sys->playback.stream = 0;
1557     p_sys->playback.segment = p_sys->download.segment = ChooseSegment(s, current);
1558
1559     if (p_sys->b_live && (p_sys->playback.segment < 0))
1560     {
1561         msg_Warn(s, "less data then 3 times 'target duration' available for live playback, playback may stall");
1562     }
1563
1564     if (Prefetch(s, &current) != VLC_SUCCESS)
1565     {
1566         msg_Err(s, "fetching first segment failed.");
1567         goto fail;
1568     }
1569
1570
1571     p_sys->download.stream = current;
1572     p_sys->playback.stream = current;
1573     p_sys->download.seek = -1;
1574
1575     vlc_mutex_init(&p_sys->download.lock_wait);
1576     vlc_cond_init(&p_sys->download.wait);
1577
1578     /* Initialize HLS live stream */
1579     if (p_sys->b_live)
1580     {
1581         hls_stream_t *hls = hls_Get(p_sys->hls_stream, current);
1582         p_sys->playlist.last = mdate();
1583         p_sys->playlist.wakeup = p_sys->playlist.last +
1584                 ((mtime_t)hls->duration * UINT64_C(1000000));
1585
1586         if (vlc_clone(&p_sys->reload, hls_Reload, s, VLC_THREAD_PRIORITY_LOW))
1587         {
1588             goto fail_thread;
1589         }
1590     }
1591
1592     if (vlc_clone(&p_sys->thread, hls_Thread, s, VLC_THREAD_PRIORITY_INPUT))
1593     {
1594         if (p_sys->b_live)
1595             vlc_join(p_sys->reload, NULL);
1596         goto fail_thread;
1597     }
1598
1599     return VLC_SUCCESS;
1600
1601 fail_thread:
1602     vlc_mutex_destroy(&p_sys->download.lock_wait);
1603     vlc_cond_destroy(&p_sys->download.wait);
1604
1605 fail:
1606     /* Free hls streams */
1607     for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++)
1608     {
1609         hls_stream_t *hls;
1610         hls = (hls_stream_t *)vlc_array_item_at_index(p_sys->hls_stream, i);
1611         if (hls) hls_Free(hls);
1612     }
1613     vlc_array_destroy(p_sys->hls_stream);
1614
1615     /* */
1616     vlc_UrlClean(&p_sys->m3u8);
1617     free(p_sys);
1618     return VLC_EGENERIC;
1619 }
1620
1621 /****************************************************************************
1622  * Close
1623  ****************************************************************************/
1624 static void Close(vlc_object_t *p_this)
1625 {
1626     stream_t *s = (stream_t*)p_this;
1627     stream_sys_t *p_sys = s->p_sys;
1628
1629     assert(p_sys->hls_stream);
1630
1631     /* */
1632     vlc_mutex_lock(&p_sys->download.lock_wait);
1633     vlc_cond_signal(&p_sys->download.wait);
1634     vlc_mutex_unlock(&p_sys->download.lock_wait);
1635
1636     /* */
1637     if (p_sys->b_live)
1638         vlc_join(p_sys->reload, NULL);
1639     vlc_join(p_sys->thread, NULL);
1640     vlc_mutex_destroy(&p_sys->download.lock_wait);
1641     vlc_cond_destroy(&p_sys->download.wait);
1642
1643     /* Free hls streams */
1644     for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++)
1645     {
1646         hls_stream_t *hls;
1647         hls = (hls_stream_t *)vlc_array_item_at_index(p_sys->hls_stream, i);
1648         if (hls) hls_Free(hls);
1649     }
1650     vlc_array_destroy(p_sys->hls_stream);
1651
1652     /* */
1653     vlc_UrlClean(&p_sys->m3u8);
1654     free(p_sys);
1655 }
1656
1657 /****************************************************************************
1658  * Stream filters functions
1659  ****************************************************************************/
1660 static segment_t *GetSegment(stream_t *s)
1661 {
1662     stream_sys_t *p_sys = s->p_sys;
1663     segment_t *segment = NULL;
1664
1665     /* Is this segment of the current HLS stream ready? */
1666     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
1667     if (hls != NULL)
1668     {
1669         vlc_mutex_lock(&hls->lock);
1670         segment = segment_GetSegment(hls, p_sys->playback.segment);
1671         if (segment != NULL)
1672         {
1673             /* This segment is ready? */
1674             if (segment->data != NULL)
1675             {
1676                 p_sys->b_cache = hls->b_cache;
1677                 vlc_mutex_unlock(&hls->lock);
1678                 goto check;
1679             }
1680         }
1681         vlc_mutex_unlock(&hls->lock);
1682     }
1683
1684     /* Was the HLS stream changed to another bitrate? */
1685     int i_stream = 0;
1686     segment = NULL;
1687     while(vlc_object_alive(s))
1688     {
1689         /* Is the next segment ready */
1690         hls_stream_t *hls = hls_Get(p_sys->hls_stream, i_stream);
1691         if (hls == NULL)
1692             return NULL;
1693
1694         vlc_mutex_lock(&hls->lock);
1695         segment = segment_GetSegment(hls, p_sys->playback.segment);
1696         if (segment == NULL)
1697         {
1698             vlc_mutex_unlock(&hls->lock);
1699             break;
1700         }
1701
1702         vlc_mutex_lock(&p_sys->download.lock_wait);
1703         int i_segment = p_sys->download.segment;
1704         vlc_mutex_unlock(&p_sys->download.lock_wait);
1705
1706         /* This segment is ready? */
1707         if ((segment->data != NULL) &&
1708             (p_sys->playback.segment < i_segment))
1709         {
1710             p_sys->playback.stream = i_stream;
1711             p_sys->b_cache = hls->b_cache;
1712             vlc_mutex_unlock(&hls->lock);
1713             goto check;
1714         }
1715         vlc_mutex_unlock(&hls->lock);
1716
1717         if (!p_sys->b_meta)
1718             break;
1719
1720         /* Was the stream changed to another bitrate? */
1721         i_stream++;
1722         if (i_stream >= vlc_array_count(p_sys->hls_stream))
1723             break;
1724     }
1725     /* */
1726     return NULL;
1727
1728 check:
1729     /* sanity check */
1730     if (segment->data->i_buffer == 0)
1731     {
1732         vlc_mutex_lock(&hls->lock);
1733         int count = vlc_array_count(hls->segments);
1734         vlc_mutex_unlock(&hls->lock);
1735
1736         if ((p_sys->download.segment - p_sys->playback.segment == 0) &&
1737             ((count != p_sys->download.segment) || p_sys->b_live))
1738             msg_Err(s, "playback will stall");
1739         else if ((p_sys->download.segment - p_sys->playback.segment < 3) &&
1740                  ((count != p_sys->download.segment) || p_sys->b_live))
1741             msg_Warn(s, "playback in danger of stalling");
1742     }
1743     return segment;
1744 }
1745
1746 static ssize_t hls_Read(stream_t *s, uint8_t *p_read, unsigned int i_read)
1747 {
1748     stream_sys_t *p_sys = s->p_sys;
1749     ssize_t copied = 0;
1750
1751     do
1752     {
1753         /* Determine next segment to read. If this is a meta playlist and
1754          * bandwidth conditions changed, then the stream might have switched
1755          * to another bandwidth. */
1756         segment_t *segment = GetSegment(s);
1757         if (segment == NULL)
1758             break;
1759
1760         vlc_mutex_lock(&segment->lock);
1761         if (segment->data->i_buffer == 0)
1762         {
1763             if (!p_sys->b_cache || p_sys->b_live)
1764             {
1765                 block_Release(segment->data);
1766                 segment->data = NULL;
1767             }
1768             else
1769             {   /* reset playback pointer to start of buffer */
1770                 uint64_t size = segment->size - segment->data->i_buffer;
1771                 if (size > 0)
1772                 {
1773                     segment->data->i_buffer += size;
1774                     segment->data->p_buffer -= size;
1775                 }
1776             }
1777             p_sys->playback.segment++;
1778             vlc_mutex_unlock(&segment->lock);
1779
1780             /* signal download thread */
1781             vlc_mutex_lock(&p_sys->download.lock_wait);
1782             vlc_cond_signal(&p_sys->download.wait);
1783             vlc_mutex_unlock(&p_sys->download.lock_wait);
1784             continue;
1785         }
1786
1787         if (segment->size == segment->data->i_buffer)
1788             msg_Info(s, "playing segment %d from stream %d",
1789                      segment->sequence, p_sys->playback.stream);
1790
1791         ssize_t len = -1;
1792         if (i_read <= segment->data->i_buffer)
1793             len = i_read;
1794         else if (i_read > segment->data->i_buffer)
1795             len = segment->data->i_buffer;
1796
1797         if (len > 0)
1798         {
1799             memcpy(p_read + copied, segment->data->p_buffer, len);
1800             segment->data->i_buffer -= len;
1801             segment->data->p_buffer += len;
1802             copied += len;
1803             i_read -= len;
1804         }
1805         vlc_mutex_unlock(&segment->lock);
1806
1807     } while ((i_read > 0) && vlc_object_alive(s));
1808
1809     return copied;
1810 }
1811
1812 static int Read(stream_t *s, void *buffer, unsigned int i_read)
1813 {
1814     stream_sys_t *p_sys = s->p_sys;
1815     ssize_t length = 0;
1816
1817     assert(p_sys->hls_stream);
1818
1819     if (p_sys->b_error)
1820         return 0;
1821
1822     if (buffer == NULL)
1823     {
1824         /* caller skips data, get big enough buffer */
1825         msg_Warn(s, "buffer is NULL (allocate %d)", i_read);
1826         buffer = calloc(1, i_read);
1827         if (buffer == NULL)
1828             return 0; /* NO MEMORY left*/
1829     }
1830
1831     length = hls_Read(s, (uint8_t*) buffer, i_read);
1832     if (length < 0)
1833         return 0;
1834
1835     p_sys->playback.offset += length;
1836     return length;
1837 }
1838
1839 static int Peek(stream_t *s, const uint8_t **pp_peek, unsigned int i_peek)
1840 {
1841     stream_sys_t *p_sys = s->p_sys;
1842     size_t curlen = 0;
1843     segment_t *segment;
1844
1845 again:
1846     segment = GetSegment(s);
1847     if (segment == NULL)
1848     {
1849         msg_Err(s, "segment %d should have been available (stream %d)",
1850                 p_sys->playback.segment, p_sys->playback.stream);
1851         return 0; /* eof? */
1852     }
1853
1854     vlc_mutex_lock(&segment->lock);
1855
1856     /* remember segment to peek */
1857     int peek_segment = p_sys->playback.segment;
1858     do
1859     {
1860         if (i_peek < segment->data->i_buffer)
1861         {
1862             *pp_peek = segment->data->p_buffer;
1863             curlen += i_peek;
1864         }
1865         else
1866         {
1867             p_sys->playback.segment++;
1868             vlc_mutex_unlock(&segment->lock);
1869             goto again;
1870         }
1871     } while ((curlen < i_peek) && vlc_object_alive(s));
1872
1873     /* restore segment to read */
1874     p_sys->playback.segment = peek_segment;
1875
1876     vlc_mutex_unlock(&segment->lock);
1877
1878     return curlen;
1879 }
1880
1881 static bool hls_MaySeek(stream_t *s)
1882 {
1883     stream_sys_t *p_sys = s->p_sys;
1884
1885     if (p_sys->hls_stream == NULL)
1886         return false;
1887
1888     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
1889     if (hls == NULL) return false;
1890
1891     if (p_sys->b_live)
1892     {
1893         vlc_mutex_lock(&hls->lock);
1894         int count = vlc_array_count(hls->segments);
1895         vlc_mutex_unlock(&hls->lock);
1896
1897         vlc_mutex_lock(&p_sys->download.lock_wait);
1898         bool may_seek = (p_sys->download.segment < (count - 2));
1899         vlc_mutex_unlock(&p_sys->download.lock_wait);
1900         return may_seek;
1901     }
1902     return true;
1903 }
1904
1905 static uint64_t GetStreamSize(stream_t *s)
1906 {
1907     stream_sys_t *p_sys = s->p_sys;
1908
1909     if (p_sys->b_live)
1910         return 0;
1911
1912     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
1913     if (hls == NULL) return 0;
1914
1915     vlc_mutex_lock(&hls->lock);
1916     uint64_t size = hls->size;
1917     vlc_mutex_unlock(&hls->lock);
1918
1919     return size;
1920 }
1921
1922 static int segment_Seek(stream_t *s, const uint64_t pos)
1923 {
1924     stream_sys_t *p_sys = s->p_sys;
1925
1926     hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
1927     if (hls == NULL)
1928         return VLC_EGENERIC;
1929
1930     vlc_mutex_lock(&hls->lock);
1931
1932     bool b_found = false;
1933     uint64_t length = 0;
1934     uint64_t size = hls->size;
1935     int count = vlc_array_count(hls->segments);
1936
1937     for (int n = 0; n < count; n++)
1938     {
1939         segment_t *segment = vlc_array_item_at_index(hls->segments, n);
1940         if (segment == NULL)
1941         {
1942             vlc_mutex_unlock(&hls->lock);
1943             return VLC_EGENERIC;
1944         }
1945
1946         vlc_mutex_lock(&segment->lock);
1947         length += segment->duration * (hls->bandwidth/8);
1948         vlc_mutex_unlock(&segment->lock);
1949
1950         if (!b_found && (pos <= length))
1951         {
1952             if (count - n >= 3)
1953             {
1954                 p_sys->playback.segment = n;
1955                 b_found = true;
1956                 break;
1957             }
1958             /* Do not search in last 3 segments */
1959             vlc_mutex_unlock(&hls->lock);
1960             return VLC_EGENERIC;
1961         }
1962     }
1963
1964     /* */
1965     if (!b_found && (pos >= size))
1966     {
1967         p_sys->playback.segment = count - 1;
1968         b_found = true;
1969     }
1970
1971     /* */
1972     if (b_found)
1973     {
1974         /* restore segment to start position */
1975         segment_t *segment = segment_GetSegment(hls, p_sys->playback.segment);
1976         if (segment == NULL)
1977         {
1978             vlc_mutex_unlock(&hls->lock);
1979             return VLC_EGENERIC;
1980         }
1981
1982         vlc_mutex_lock(&segment->lock);
1983         if (segment->data)
1984         {
1985             uint64_t size = segment->size -segment->data->i_buffer;
1986             if (size > 0)
1987             {
1988                 segment->data->i_buffer += size;
1989                 segment->data->p_buffer -= size;
1990             }
1991         }
1992         vlc_mutex_unlock(&segment->lock);
1993
1994         /* start download at current playback segment */
1995         vlc_mutex_unlock(&hls->lock);
1996
1997         /* Wake up download thread */
1998         vlc_mutex_lock(&p_sys->download.lock_wait);
1999         p_sys->download.seek = p_sys->playback.segment;
2000         vlc_cond_signal(&p_sys->download.wait);
2001         vlc_mutex_unlock(&p_sys->download.lock_wait);
2002
2003         /* Wait for download to be finished */
2004         vlc_mutex_lock(&p_sys->download.lock_wait);
2005         msg_Info(s, "seek to segment %d", p_sys->playback.segment);
2006         while (((p_sys->download.seek != -1) ||
2007                 (p_sys->download.segment - p_sys->playback.segment < 3)) &&
2008                 (p_sys->download.segment < (count - 6)))
2009         {
2010             vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
2011             if (!vlc_object_alive(s) || s->b_error) break;
2012         }
2013         vlc_mutex_unlock(&p_sys->download.lock_wait);
2014
2015         return VLC_SUCCESS;
2016     }
2017     vlc_mutex_unlock(&hls->lock);
2018
2019     return b_found ? VLC_SUCCESS : VLC_EGENERIC;
2020 }
2021
2022 static int Control(stream_t *s, int i_query, va_list args)
2023 {
2024     stream_sys_t *p_sys = s->p_sys;
2025
2026     switch (i_query)
2027     {
2028         case STREAM_CAN_SEEK:
2029         case STREAM_CAN_FASTSEEK:
2030             *(va_arg (args, bool *)) = hls_MaySeek(s);
2031             break;
2032         case STREAM_GET_POSITION:
2033             *(va_arg (args, uint64_t *)) = p_sys->playback.offset;
2034             break;
2035         case STREAM_SET_POSITION:
2036             if (hls_MaySeek(s))
2037             {
2038                 uint64_t pos = (uint64_t)va_arg(args, uint64_t);
2039                 if (segment_Seek(s, pos) == VLC_SUCCESS)
2040                 {
2041                     p_sys->playback.offset = pos;
2042                     break;
2043                 }
2044             }
2045             return VLC_EGENERIC;
2046         case STREAM_GET_SIZE:
2047             *(va_arg (args, uint64_t *)) = GetStreamSize(s);
2048             break;
2049         default:
2050             return VLC_EGENERIC;
2051     }
2052     return VLC_SUCCESS;
2053 }