]> git.sesse.net Git - vlc/blobdiff - modules/stream_filter/httplive.c
modules: avoid using genmf where unnecessary
[vlc] / modules / stream_filter / httplive.c
index 6297b1ffe110d9f28f1e45a1d91fb66cb26fada0..51a27286a24879fe65231e86110b9c5d8a979707 100644 (file)
@@ -530,7 +530,7 @@ static int string_to_IV(char *string_hexa, uint8_t iv[AES_BLOCK_SIZE])
             return VLC_EGENERIC;
     }
 
-    for (int i = 8; i ; --i) {
+    for (int i = 7; i >= 0 ; --i) {
         iv[  i] = iv_hi & 0xff;
         iv[8+i] = iv_lo & 0xff;
         iv_hi >>= 8;
@@ -542,20 +542,49 @@ static int string_to_IV(char *string_hexa, uint8_t iv[AES_BLOCK_SIZE])
 
 static char *relative_URI(const char *psz_url, const char *psz_path)
 {
+    char *ret = NULL;
     assert(psz_url != NULL && psz_path != NULL);
+
+
     //If the path is actually an absolute URL, don't do anything.
     if (strncmp(psz_path, "http", 4) == 0)
         return NULL;
 
-    char    *path_end = strrchr(psz_url, '/');
-    if (path_end == NULL)
+    size_t len = strlen(psz_path);
+
+    char *new_url = strdup(psz_url);
+    if (unlikely(!new_url))
         return NULL;
-    unsigned int    url_length = path_end - psz_url + 1;
-    char    *psz_res = malloc(url_length + strlen(psz_path) + 1);
-    strncpy(psz_res, psz_url, url_length);
-    psz_res[url_length] = 0;
-    strcat(psz_res, psz_path);
-    return psz_res;
+
+    if( psz_path[0] == '/' ) //Relative URL with absolute path
+    {
+        //Try to find separator for name and path, try to skip
+        //access and first ://
+        char *slash = strchr(&new_url[8], '/');
+        if (unlikely(slash == NULL))
+            goto end;
+        *slash = '\0';
+    } else {
+        int levels = 0;
+        while(len >= 3 && !strncmp(psz_path, "../", 3)) {
+            psz_path += 3;
+            len -= 3;
+            levels++;
+        }
+        do {
+            char *slash = strrchr(new_url, '/');
+            if (unlikely(slash == NULL))
+                goto end;
+            *slash = '\0';
+        } while (levels--);
+    }
+
+    if (asprintf(&ret, "%s/%s", new_url, psz_path) < 0)
+        ret = NULL;
+
+end:
+    free(new_url);
+    return ret;
 }
 
 static int parse_SegmentInformation(hls_stream_t *hls, char *p_read, int *duration)
@@ -653,13 +682,13 @@ static int parse_StreamInformation(stream_t *s, vlc_array_t **hls_stream,
     assert(*hls == NULL);
 
     attr = parse_Attributes(p_read, "PROGRAM-ID");
-    if (attr == NULL)
+    if (attr)
     {
-        msg_Err(s, "#EXT-X-STREAM-INF: expected PROGRAM-ID=<value>");
-        return VLC_EGENERIC;
+        id = atol(attr);
+        free(attr);
     }
-    id = atol(attr);
-    free(attr);
+    else
+        id = 0;
 
     attr = parse_Attributes(p_read, "BANDWIDTH");
     if (attr == NULL)
@@ -775,7 +804,13 @@ static int parse_Key(stream_t *s, hls_stream_t *hls, char *p_read)
             if (end != NULL)
                 *end = 0;
         }
-        hls->psz_current_key_path = strdup(uri);
+        /* For absolute URI, just duplicate it
+         * don't limit to HTTP, maybe some sanity checking
+         * should be done more in here? */
+        if( strstr( uri , "://" ) )
+            hls->psz_current_key_path = strdup( uri );
+        else
+            hls->psz_current_key_path = relative_URI(hls->url, uri);
         free(value);
 
         value = iv = parse_Attributes(p_read, "IV");
@@ -954,6 +989,8 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
 
         /* M3U8 Meta Index file */
         do {
+            bool failed_to_download_stream_m3u8 = false;
+
             /* Next line */
             line = ReadLine(p_begin, &p_read, p_end - p_begin);
             if (line == NULL)
@@ -976,24 +1013,38 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
                     }
                     else
                     {
+                        bool new_stream_added = false;
                         hls_stream_t *hls = NULL;
                         err = parse_StreamInformation(s, &streams, &hls, line, uri);
-                        free(uri);
+                        if (err == VLC_SUCCESS)
+                            new_stream_added = true;
 
-                        /* Download playlist file from server */
-                        uint8_t *buf = NULL;
-                        ssize_t len = read_M3U8_from_url(s, hls->url, &buf);
-                        if (len < 0)
-                            err = VLC_EGENERIC;
-                        else
-                        {
-                            /* Parse HLS m3u8 content. */
-                            err = parse_M3U8(s, streams, buf, len);
-                            free(buf);
-                        }
+                        free(uri);
 
                         if (hls)
                         {
+                            /* Download playlist file from server */
+                            uint8_t *buf = NULL;
+                            ssize_t len = read_M3U8_from_url(s, hls->url, &buf);
+                            if (len < 0)
+                            {
+                                msg_Warn(s, "failed to read %s, continue for other streams", hls->url);
+                                failed_to_download_stream_m3u8 = true;
+
+                                /* remove stream just added */
+                                if (new_stream_added)
+                                    vlc_array_remove(streams, vlc_array_count(streams) - 1);
+
+                                /* ignore download error, so we have chance to try other streams */
+                                err = VLC_SUCCESS;
+                            }
+                            else
+                            {
+                                /* Parse HLS m3u8 content. */
+                                err = parse_M3U8(s, streams, buf, len);
+                                free(buf);
+                            }
+
                             hls->version = version;
                             if (!p_sys->b_live)
                                 hls->size = hls_GetStreamSize(hls); /* Stream size (approximate) */
@@ -1011,6 +1062,13 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
 
         } while (err == VLC_SUCCESS);
 
+        size_t stream_count = vlc_array_count(streams);
+        msg_Dbg(s, "%d streams loaded in Meta playlist", (int)stream_count);
+        if (stream_count == 0)
+        {
+            msg_Err(s, "No playable streams found in Meta playlist");
+            err = VLC_EGENERIC;
+        }
     }
     else
     {
@@ -1046,6 +1104,7 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
         assert(hls);
 
         /* */
+        bool media_sequence_loaded = false;
         int segment_duration = -1;
         do
         {
@@ -1060,7 +1119,15 @@ static int parse_M3U8(stream_t *s, vlc_array_t *streams, uint8_t *buffer, const
             else if (strncmp(line, "#EXT-X-TARGETDURATION", 21) == 0)
                 err = parse_TargetDuration(s, hls, line);
             else if (strncmp(line, "#EXT-X-MEDIA-SEQUENCE", 21) == 0)
-                err = parse_MediaSequence(s, hls, line);
+            {
+                /* A Playlist file MUST NOT contain more than one EXT-X-MEDIA-SEQUENCE tag. */
+                /* We only care about first one */
+                if (!media_sequence_loaded)
+                {
+                    err = parse_MediaSequence(s, hls, line);
+                    media_sequence_loaded = true;
+                }
+            }
             else if (strncmp(line, "#EXT-X-KEY", 10) == 0)
                 err = parse_Key(s, hls, line);
             else if (strncmp(line, "#EXT-X-PROGRAM-DATE-TIME", 24) == 0)
@@ -1271,7 +1338,7 @@ static int get_HTTPLiveMetaPlaylist(stream_t *s, vlc_array_t **streams)
     return err;
 }
 
-/* Update hls_old (an existing member of p_sys->hls_stream) to match hls_new 
+/* Update hls_old (an existing member of p_sys->hls_stream) to match hls_new
    (which represents a downloaded, perhaps newer version of the same playlist) */
 static int hls_UpdatePlaylist(stream_t *s, hls_stream_t *hls_new, hls_stream_t *hls_old)
 {
@@ -1836,7 +1903,7 @@ static char *ReadLine(uint8_t *buffer, uint8_t **pos, const size_t len)
             /* next pass start after \r and \n */
             p++;
             *pos = p;
-        }   
+        }
     }
 
     return line;
@@ -2423,7 +2490,7 @@ static int segment_Seek(stream_t *s, const uint64_t pos)
         /* Wait for download to be finished */
         msg_Info(s, "seek to segment %d", p_sys->playback.segment);
         while ((p_sys->download.seek != -1) ||
-              ((p_sys->download.segment - p_sys->playback.segment < 3) &&
+           ((p_sys->download.segment - p_sys->playback.segment < 3) &&
                 (p_sys->download.segment < count)))
         {
             vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
@@ -2447,6 +2514,13 @@ static int Control(stream_t *s, int i_query, va_list args)
         case STREAM_CAN_SEEK:
             *(va_arg (args, bool *)) = hls_MaySeek(s);
             break;
+        case STREAM_CAN_CONTROL_PACE:
+            *(va_arg (args, bool *)) = true;
+            break;
+        case STREAM_CAN_FASTSEEK:
+        case STREAM_CAN_PAUSE: /* TODO */
+            *(va_arg (args, bool *)) = false;
+            break;
         case STREAM_GET_POSITION:
             *(va_arg (args, uint64_t *)) = p_sys->playback.offset;
             break;