[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, ¤t) != 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, ¤t) != 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, ¤t_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