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