[vlc-devel] [PATCH 28/48] hls: Reworking threading.

Hugo Beauzée-Luyssen beauze.h at gmail.com
Mon Jan 9 16:16:37 CET 2012


---
 modules/stream_filter/httplive.c |  218 +++++++++++---------------------------
 1 files changed, 61 insertions(+), 157 deletions(-)

diff --git a/modules/stream_filter/httplive.c b/modules/stream_filter/httplive.c
index 89e2d27..ac4b5dc 100644
--- a/modules/stream_filter/httplive.c
+++ b/modules/stream_filter/httplive.c
@@ -1594,75 +1594,47 @@ static void* hls_Thread(void *p_this)
         hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
         assert(hls);
 
-        /* Sliding window (~60 seconds worth of movie) */
-        vlc_mutex_lock(&hls->lock);
-        int count = vlc_array_count(hls->segments);
-        vlc_mutex_unlock(&hls->lock);
-
-        /* Is there a new segment to process? */
-        if ((!p_sys->b_live && (p_sys->playback.segment < (count - 6))) ||
-            (p_sys->download.segment >= count))
-        {
-            /* wait */
-            vlc_mutex_lock(&p_sys->download.lock_wait);
-            while (((p_sys->download.segment - p_sys->playback.segment > 6) ||
-                    (p_sys->download.segment >= count)) &&
-                   (p_sys->download.seek == -1))
-            {
-                mtime_t timeout = mdate() + 5000000;
-                vlc_cond_timedwait(&p_sys->download.wait, &p_sys->download.lock_wait, timeout);
-                if (!vlc_object_alive(s)) break;
-                if (p_sys->b_live) break;
-                if (p_sys->b_quit) break;
-            }
-            /* */
-            if (p_sys->download.seek >= 0)
-            {
-                p_sys->download.segment = p_sys->download.seek;
-                p_sys->download.seek = -1;
-            }
-            vlc_mutex_unlock(&p_sys->download.lock_wait);
-        }
+        /* Wait to be wake up when a new segment is needed */
+        msg_Dbg(s, "Sleeping until we have a new segment to download");
+        vlc_mutex_lock(&p_sys->download.lock_wait);
+        vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
+        vlc_mutex_unlock(&p_sys->download.lock_wait);
 
         if (!vlc_object_alive(s)) break;
         if (p_sys->b_quit) break;
 
         vlc_mutex_lock(&hls->lock);
         segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
+        msg_Dbg(s, "Downloading segment %d from stream %d (aka %s)", p_sys->download.segment, p_sys->download.stream, segment->uri);
         vlc_mutex_unlock(&hls->lock);
 
         if (segment == NULL)
         {
-            msg_Dbg(s, "segment %d from stream %d is null !!!", p_sys->download.segment, p_sys->download.stream);
+            if (p_sys->b_live == false)
+                break;
+            msg_Info(s, "no segment available for download, waiting for a playlist update");
             continue;
         }
 
-        msg_Dbg(s, "Downloading segment %d from stream %d (aka %s)", p_sys->download.segment, p_sys->download.stream, segment->uri);
-
-        if ((segment != NULL) &&
-            (hls_DownloadSegmentData(s, hls, segment, &p_sys->download.stream) != VLC_SUCCESS))
+        int current = p_sys->download.stream;
+        if (hls_DownloadSegmentData(s, hls, segment, &current) != VLC_SUCCESS)
         {
-            if (!vlc_object_alive(s)) break;
-            if (p_sys->b_quit) break;
-
             if (!p_sys->b_live)
             {
                 p_sys->b_error = true;
                 break;
             }
         }
-
-        /* download succeeded */
-        /* determine next segment to download */
-        vlc_mutex_lock(&p_sys->download.lock_wait);
-        if (p_sys->download.seek >= 0)
+        else
         {
-            p_sys->download.segment = p_sys->download.seek;
-            p_sys->download.seek = -1;
-        }
-        else if (p_sys->download.segment < count)
+            /* Perhaps we should take a lock for this */
             p_sys->download.segment++;
-        vlc_mutex_unlock(&p_sys->download.lock_wait);
+
+            /* Perhaps we need to wake up the Peek() or Read() */
+            vlc_mutex_lock(&p_sys->playback.lock_wait);
+            vlc_cond_signal(&p_sys->playback.wait);
+            vlc_mutex_unlock(&p_sys->playback.lock_wait);
+        }
     }
 
     msg_Err(s, "Leaving thread hls_Thread() (is_alive=%d, b_quit=%d)", vlc_object_alive(s), p_sys->b_quit);
@@ -1710,6 +1682,11 @@ static void* hls_Reload(void *p_this)
             hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
             assert(hls);
 
+            /* We have new segment, wake up the download thread */
+            vlc_mutex_lock(&p_sys->download.lock_wait);
+            vlc_cond_signal(&p_sys->download.wait);
+            vlc_mutex_unlock(&p_sys->download.lock_wait);
+
             /* determine next time to update playlist */
             p_sys->playlist.last = now;
             p_sys->playlist.wakeup = now + ((mtime_t)(hls->duration * wait)
@@ -2002,20 +1979,20 @@ static int OpenWithPlaylist(stream_t *s, const char *m3u8_playlist)
 
     /* manage encryption key if needed */
     if (hls_ManageSegmentKeys(s, hls_Get(p_sys->hls_stream, current)) != VLC_SUCCESS)
-    {
         goto fail;
-    }
 
     if (p_sys->b_live && (p_sys->playback.segment < 0))
     {
         msg_Warn(s, "less data than 3 times 'target duration' available for live playback, playback may stall");
     }
 
+#if 0
     if (Prefetch(s, &current) != VLC_SUCCESS)
     {
         msg_Err(s, "fetching first segment failed.");
         goto fail;
     }
+#endif
 
     p_sys->b_dont_change_bitrate = true;
 
@@ -2027,6 +2004,9 @@ static int OpenWithPlaylist(stream_t *s, const char *m3u8_playlist)
     vlc_mutex_init(&p_sys->download.lock_wait);
     vlc_cond_init(&p_sys->download.wait);
 
+    vlc_mutex_init(&p_sys->playback.lock_wait);
+    vlc_cond_init(&p_sys->playback.wait);
+
     /* Initialize HLS live stream */
     if (p_sys->b_live)
     {
@@ -2060,6 +2040,9 @@ fail_thread:
     vlc_mutex_destroy(&p_sys->download.lock_wait);
     vlc_cond_destroy(&p_sys->download.wait);
 
+    vlc_mutex_destroy(&p_sys->playback.lock_wait);
+    vlc_cond_destroy(&p_sys->playback.wait);
+
 fail:
     /* Free hls streams */
     for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++)
@@ -2111,6 +2094,11 @@ static void Close(vlc_object_t *p_this)
     vlc_cond_signal(&p_sys->download.wait);
     vlc_mutex_unlock(&p_sys->download.lock_wait);
 
+    vlc_mutex_lock(&p_sys->playback.lock_wait);
+    vlc_cond_signal(&p_sys->playback.wait);
+    vlc_mutex_unlock(&p_sys->playback.lock_wait);
+
+
     /* */
     msg_Err(s, "Waiting for thread reload playlist to finished (is_alive=%d)", vlc_object_alive(s));
     if (p_sys->b_live)
@@ -2118,6 +2106,8 @@ static void Close(vlc_object_t *p_this)
     vlc_join(p_sys->thread, NULL);
     vlc_mutex_destroy(&p_sys->download.lock_wait);
     vlc_cond_destroy(&p_sys->download.wait);
+    vlc_mutex_destroy(&p_sys->playback.lock_wait);
+    vlc_cond_destroy(&p_sys->playback.wait);
 
     /* Free hls streams */
     for (int i = 0; i < vlc_array_count(p_sys->hls_stream); i++)
@@ -2140,134 +2130,48 @@ static segment_t *GetSegment(stream_t *s)
 {
     stream_sys_t *p_sys = s->p_sys;
     segment_t *segment = NULL;
-    hls_stream_t *hls;
-    int retry_count = 0;
 
     /* Is this segment of the current HLS stream ready? */
-again:
-    if (p_sys->playback.stream != p_sys->download.stream)
+    hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
+    if (hls == NULL)
     {
-        msg_Dbg(s, "Change stream playback from %d to %d", p_sys->playback.stream, p_sys->download.stream);
-        p_sys->playback.stream = p_sys->download.stream;
+        msg_Warn(s, "No stream (%d) available ???. We need to move to another bitrate", p_sys->playback.stream);
+        return NULL;
     }
-    hls = hls_Get(p_sys->hls_stream, p_sys->playback.stream);
-    if (hls != NULL)
+
+    /* Is this segment exist ? */
+    do
     {
         vlc_mutex_lock(&hls->lock);
-        if ( p_sys->b_live == false && vlc_array_count(hls->segments) <= p_sys->playback.segment)
-        {
-            msg_Dbg(s, "End of the stream detected");
-            vlc_mutex_unlock(&hls->lock);
-            return NULL;
-        }
         segment = segment_GetSegment(hls, p_sys->playback.segment);
         vlc_mutex_unlock(&hls->lock);
-        if (segment != NULL)
-        {
-            /* This segment is ready? */
-            vlc_mutex_lock(&segment->lock);
-            if (segment->data != NULL)
-            {
-                p_sys->b_cache = hls->b_cache;
-                vlc_mutex_unlock(&segment->lock);
-                goto check;
-            }
-            vlc_mutex_unlock(&segment->lock);
 
-            /*  Perhaps nobody try to download it, so force a download after one retry */
-            if (retry_count < 3)
-            {
-                /* Force download, perhaps we are stuck into something */
-                msg_Dbg(s, "Force download segment %d of stream %d because we have already wait some time (retry_count=%d)", p_sys->playback.segment, p_sys->playback.stream, retry_count);
-                int current_stream = p_sys->playback.stream;
-                if (hls_DownloadSegmentData(s, hls, segment, &current_stream) == VLC_SUCCESS)
-                {
-                    msg_Dbg(s, "Success to download segment %d of stream %d.", p_sys->playback.segment, p_sys->playback.stream);
-                    goto again;
-                }
-                msg_Dbg(s, "Failed to force download segment %d of stream %d.", p_sys->playback.segment, p_sys->playback.stream);
-            }
-       }
-
-       mtime_t timeout = mdate() + 5000000;
-       vlc_mutex_lock(&p_sys->download.lock_wait);
-       msg_Dbg(s, "Wait until the segment %d of stream %d is downloaded (but download try to download segment %d from stream %d",
-                  p_sys->playback.segment, p_sys->playback.stream,
-                  p_sys->download.segment, p_sys->download.stream);
-       vlc_cond_timedwait(&p_sys->download.wait, &p_sys->download.lock_wait, timeout);
-       retry_count++;
-       if (vlc_object_alive(s) && !s->b_error && !p_sys->b_quit && retry_count <= 5)
-               goto again;
-    }
-
-    /* Was the HLS stream changed to another bitrate? */
-    int i_stream = 0;
-    segment = NULL;
-    while(vlc_object_alive(s) && p_sys->b_quit == false)
-    {
-        /* Is the next segment ready */
-        hls_stream_t *hls = hls_Get(p_sys->hls_stream, i_stream);
-        if (hls == NULL)
+        if (!vlc_object_alive(s) || p_sys->b_quit)
             return NULL;
 
-        vlc_mutex_lock(&hls->lock);
-        segment = segment_GetSegment(hls, p_sys->playback.segment);
         if (segment == NULL)
         {
-            vlc_mutex_unlock(&hls->lock);
-            break;
+             /* We must sleep, waiting the hls_ReloadPlaylist() thread to wake up and insert a new segment */
+             msg_Warn(s, "No segment (%d) available for stream %d. Waiting a little bit, that we have a new segment", p_sys->playback.segment, p_sys->playback.stream);
+             msleep(1000000);
         }
 
-        vlc_mutex_lock(&p_sys->download.lock_wait);
-        int i_segment = p_sys->download.segment;
-        vlc_mutex_unlock(&p_sys->download.lock_wait);
+    } while (segment == NULL);
 
-        /* This segment is ready? */
-        if ((segment->data != NULL) &&
-            (p_sys->playback.segment < i_segment))
+    /* Is this segment ready ? */
+    while (vlc_object_alive(s) && p_sys->b_quit == false)
+    {
+        vlc_mutex_lock(&segment->lock);
+        if (segment->data)
         {
-            p_sys->playback.stream = i_stream;
-            p_sys->b_cache = hls->b_cache;
-            vlc_mutex_unlock(&hls->lock);
-            goto check;
-        }
-        vlc_mutex_unlock(&hls->lock);
-
-        if (!p_sys->b_meta)
-            break;
-
-        /* Was the stream changed to another bitrate? */
-        i_stream++;
-        if (i_stream >= vlc_array_count(p_sys->hls_stream))
+            vlc_mutex_unlock(&segment->lock);
             break;
+        }
+        vlc_mutex_unlock(&segment->lock);
+        msg_Warn(s, "The segment (%d) is not downloaded for stream %d. Waiting a little bit....", p_sys->playback.segment, p_sys->playback.stream);
+        msleep(1000000);
     }
-    /* */
-    return NULL;
 
-check:
-    /* sanity check */
-    if (segment->data->i_buffer == 0)
-    {
-        vlc_mutex_lock(&hls->lock);
-        int count = vlc_array_count(hls->segments);
-        vlc_mutex_unlock(&hls->lock);
-
-        if ((p_sys->download.segment - p_sys->playback.segment == 0) &&
-            ((count != p_sys->download.segment) || p_sys->b_live))
-	 {
-	   msg_Err(s, "playback will stall");
-	   return NULL;
-	 }
-        else if ((p_sys->download.segment - p_sys->playback.segment < 3) &&
-                 ((count != p_sys->download.segment) || p_sys->b_live))
-	 {
-            msg_Warn(s, "playback in danger of stalling download.segment=%d playback.segment=%d count=%d p_sys->download.segment=%d", 
-                         p_sys->download.segment, p_sys->playback.segment,
-                         count, p_sys->download.segment);
-	    return NULL;
-	 }
-
-    }
     return segment;
 }
 
-- 
1.7.8.3




More information about the vlc-devel mailing list