[vlc-devel] [PATCH] stream_filter: httplive: factorize segment read and remove vlc_object_alive
Francois Cartegnie
fcvlcdev at free.fr
Mon Apr 20 21:12:02 CEST 2015
---
modules/stream_filter/httplive.c | 168 ++++++++++++++++++++-------------------
1 file changed, 88 insertions(+), 80 deletions(-)
diff --git a/modules/stream_filter/httplive.c b/modules/stream_filter/httplive.c
index 24b44c4..ec785e2 100644
--- a/modules/stream_filter/httplive.c
+++ b/modules/stream_filter/httplive.c
@@ -1594,13 +1594,20 @@ static int hls_DownloadSegmentData(stream_t *s, hls_stream_t *hls, segment_t *se
}
mtime_t start = mdate();
- if (hls_Download(s, segment) != VLC_SUCCESS)
+ int i_ret;
+
+ mutex_cleanup_push( &segment->lock ); // C0
+ i_ret = hls_Download(s, segment);
+ vlc_cleanup_pop( ); // C0
+
+ if (i_ret != VLC_SUCCESS)
{
msg_Err(s, "downloading segment %d from stream %d failed",
segment->sequence, *cur_stream);
vlc_mutex_unlock(&segment->lock);
- return VLC_EGENERIC;
+ return i_ret;
}
+
mtime_t duration = mdate() - start;
if (hls->bandwidth == 0 && segment->duration > 0)
{
@@ -1609,14 +1616,13 @@ static int hls_DownloadSegmentData(stream_t *s, hls_stream_t *hls, segment_t *se
}
/* If the segment is encrypted, decode it */
- if (hls_DecodeSegmentData(s, hls, segment) != VLC_SUCCESS)
- {
- vlc_mutex_unlock(&segment->lock);
- return VLC_EGENERIC;
- }
+ i_ret = hls_DecodeSegmentData(s, hls, segment);
vlc_mutex_unlock(&segment->lock);
+ if(i_ret != VLC_SUCCESS)
+ return i_ret;
+
msg_Dbg(s, "downloaded segment %d from stream %d",
segment->sequence, *cur_stream);
@@ -1642,9 +1648,7 @@ static void* hls_Thread(void *p_this)
stream_t *s = (stream_t *)p_this;
stream_sys_t *p_sys = s->p_sys;
- int canc = vlc_savecancel();
-
- while (vlc_object_alive(s))
+ for( ;; )
{
hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
assert(hls);
@@ -1660,6 +1664,7 @@ static void* hls_Thread(void *p_this)
{
/* wait */
vlc_mutex_lock(&p_sys->download.lock_wait);
+ mutex_cleanup_push(&p_sys->download.lock_wait); //CO
while (((p_sys->download.segment - p_sys->playback.segment > 6) ||
(p_sys->download.segment >= count)) &&
(p_sys->download.seek == -1))
@@ -1667,19 +1672,21 @@ static void* hls_Thread(void *p_this)
vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
if (p_sys->b_live /*&& (mdate() >= p_sys->playlist.wakeup)*/)
break;
- if (!vlc_object_alive(s))
- break;
+ vlc_testcancel();
}
+ vlc_cleanup_pop( ); //CO
+
/* */
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);
}
- if (!vlc_object_alive(s)) break;
+ vlc_testcancel();
vlc_mutex_lock(&hls->lock);
segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
@@ -1688,8 +1695,6 @@ static void* hls_Thread(void *p_this)
if ((segment != NULL) &&
(hls_DownloadSegmentData(s, hls, segment, &p_sys->download.stream) != VLC_SUCCESS))
{
- if (!vlc_object_alive(s)) break;
-
if (!p_sys->b_live)
{
p_sys->b_error = true;
@@ -1714,9 +1719,10 @@ static void* hls_Thread(void *p_this)
vlc_mutex_lock(&p_sys->read.lock_wait);
vlc_cond_signal(&p_sys->read.wait);
vlc_mutex_unlock(&p_sys->read.lock_wait);
+
+ vlc_testcancel();
}
- vlc_restorecancel(canc);
return NULL;
}
@@ -1727,14 +1733,14 @@ static void* hls_Reload(void *p_this)
assert(p_sys->b_live);
- int canc = vlc_savecancel();
-
double wait = 1.0;
- while (vlc_object_alive(s))
+ for ( ;; )
{
mtime_t now = mdate();
if (now >= p_sys->playlist.wakeup)
{
+ int canc = vlc_savecancel();
+
/* reload the m3u8 if there are less than 3 segments what aren't downloaded */
if ( ( p_sys->download.segment - p_sys->playback.segment < 3 ) &&
( hls_ReloadPlaylist(s) != VLC_SUCCESS) )
@@ -1758,6 +1764,8 @@ static void* hls_Reload(void *p_this)
wait = 1.0;
}
+ vlc_restorecancel(canc);
+
hls_stream_t *hls = hls_Get(p_sys->hls_stream, p_sys->download.stream);
assert(hls);
@@ -1774,7 +1782,6 @@ static void* hls_Reload(void *p_this)
mwait(p_sys->playlist.wakeup);
}
- vlc_restorecancel(canc);
return NULL;
}
@@ -1794,7 +1801,7 @@ static int Prefetch(stream_t *s, int *current)
/* Download ~10s worth of segments of this HLS stream if they exist */
unsigned segment_amount = (0.5f + 10/hls->duration);
- for (int i = 0; i < __MIN(vlc_array_count(hls->segments), segment_amount); i++)
+ for (unsigned i = 0; i < __MIN((unsigned)vlc_array_count(hls->segments), segment_amount); i++)
{
segment_t *segment = segment_GetSegment(hls, p_sys->download.segment);
if (segment == NULL )
@@ -1830,92 +1837,86 @@ static int Prefetch(stream_t *s, int *current)
/****************************************************************************
*
****************************************************************************/
+#define HLS_READ_SIZE 65536
static int hls_Download(stream_t *s, segment_t *segment)
{
stream_sys_t *p_sys = s->p_sys;
assert(segment);
+ volatile int i_return = VLC_SUCCESS;
vlc_mutex_lock(&p_sys->lock);
+ mutex_cleanup_push(&p_sys->lock); // C0
while (p_sys->paused)
vlc_cond_wait(&p_sys->wait, &p_sys->lock);
- vlc_mutex_unlock(&p_sys->lock);
+ vlc_cleanup_run( ); // C0 vlc_mutex_unlock(&p_sys->lock);
+ int i_canc = vlc_savecancel();
stream_t *p_ts = stream_UrlNew(s, segment->url);
+ vlc_restorecancel(i_canc);
if (p_ts == NULL)
return VLC_EGENERIC;
- segment->size = stream_Size(p_ts);
+ int64_t size = stream_Size(p_ts);
+ if (size < 0)
+ size = 0;
- if (segment->size == 0) {
- int chunk_size = 65536;
- segment->data = block_Alloc(chunk_size);
- if (!segment->data)
- goto nomem;
- do {
- if (segment->data->i_buffer - segment->size < chunk_size) {
- chunk_size *= 2;
- block_t *p_block = block_Realloc(segment->data, 0, segment->data->i_buffer + chunk_size);
- if (!p_block) {
- block_Release(segment->data);
- segment->data = NULL;
- goto nomem;
- }
- segment->data = p_block;
- }
+ vlc_cleanup_push( stream_Delete, p_ts ); /* C1 */
- ssize_t length = stream_Read(p_ts, segment->data->p_buffer + segment->size, chunk_size);
- if (length <= 0) {
- segment->data->i_buffer = segment->size;
- break;
- }
- segment->size += length;
- } while (vlc_object_alive(s));
+ volatile unsigned i_total_read = 0;
- stream_Delete(p_ts);
- return VLC_SUCCESS;
+ block_t *p_segment_data = block_Alloc(size ? size : HLS_READ_SIZE);
+ if (!p_segment_data)
+ {
+ i_return = VLC_ENOMEM;
+ goto end;
}
-
- segment->data = block_Alloc(segment->size);
- if (segment->data == NULL)
- goto nomem;
-
- assert(segment->data->i_buffer == segment->size);
-
- ssize_t curlen = 0;
- do
+ for( ;; )
{
/* NOTE: Beware the size reported for a segment by the HLS server may not
* be correct, when downloading the segment data. Therefore check the size
* and enlarge the segment data block if necessary.
*/
- uint64_t size = stream_Size(p_ts);
- if (size > segment->size)
+ uint64_t i_toread = (size > 0) ? (uint64_t) size - i_total_read: HLS_READ_SIZE;
+
+ if (i_total_read + i_toread > p_segment_data->i_buffer)
{
- msg_Dbg(s, "size changed %"PRIu64, segment->size);
- block_t *p_block = block_Realloc(segment->data, 0, size);
- if (p_block == NULL)
+ msg_Dbg(s, "size changed to %"PRIu64, i_total_read + i_toread);
+ block_t *p_realloc_block = block_Realloc(p_segment_data, 0, i_total_read + i_toread);
+ if (p_realloc_block == NULL)
{
- block_Release(segment->data);
- segment->data = NULL;
- goto nomem;
+ if(p_segment_data)
+ block_Release(p_segment_data);
+ i_return = VLC_ENOMEM;
+ goto end;
}
- segment->data = p_block;
- segment->size = size;
- assert(segment->data->i_buffer == segment->size);
- p_block = NULL;
+ p_segment_data = p_realloc_block;
}
- ssize_t length = stream_Read(p_ts, segment->data->p_buffer + curlen, segment->size - curlen);
- if (length <= 0)
+
+ int i_canc = vlc_savecancel();
+ int i_length = stream_Read(p_ts, &p_segment_data->p_buffer[i_total_read], HLS_READ_SIZE);
+ vlc_restorecancel(i_canc);
+
+ if (i_length <= 0)
+ {
+ if(size > 0 && i_total_read < size)
+ msg_Warn(s, "segment read %"PRIu64"/%"PRIu64, size - i_total_read, size );
+ p_segment_data->i_buffer = i_total_read;
break;
- curlen += length;
- } while (vlc_object_alive(s));
+ }
- stream_Delete(p_ts);
- return VLC_SUCCESS;
+ i_total_read += i_length;
+
+ vlc_cleanup_push( block_Release, p_segment_data ); /* C2 */
+ vlc_testcancel();
+ vlc_cleanup_pop( ); /* C2 */
+ };
-nomem:
- stream_Delete(p_ts);
- return VLC_ENOMEM;
+ segment->data = p_segment_data;
+ segment->size = p_segment_data->i_buffer;
+
+end:
+ vlc_cleanup_run( ); /* C1 stream_Delete p_ts */
+ return i_return;
}
/* Read M3U8 file */
@@ -2134,7 +2135,10 @@ static int Open(vlc_object_t *p_this)
if (vlc_clone(&p_sys->thread, hls_Thread, s, VLC_THREAD_PRIORITY_INPUT))
{
if (p_sys->b_live)
+ {
+ vlc_cancel(p_sys->reload);
vlc_join(p_sys->reload, NULL);
+ }
goto fail_thread;
}
@@ -2177,6 +2181,7 @@ static void Close(vlc_object_t *p_this)
vlc_mutex_lock(&p_sys->lock);
p_sys->paused = false;
+ p_sys->b_error = true;
vlc_cond_signal(&p_sys->wait);
vlc_mutex_unlock(&p_sys->lock);
@@ -2191,7 +2196,10 @@ static void Close(vlc_object_t *p_this)
/* */
if (p_sys->b_live)
vlc_join(p_sys->reload, NULL);
+
+ vlc_cancel(p_sys->thread);
vlc_join(p_sys->thread, NULL);
+
vlc_mutex_destroy(&p_sys->download.lock_wait);
vlc_cond_destroy(&p_sys->download.wait);
@@ -2393,7 +2401,7 @@ static int Read(stream_t *s, void *buffer, unsigned int i_read)
while (length == 0)
{
// In case an error occurred or the stream was closed return 0
- if (p_sys->b_error || !vlc_object_alive(s))
+ if (p_sys->b_error || s->b_error)
return 0;
// Lock the mutex before trying to read to avoid a race condition with the download thread
@@ -2672,7 +2680,7 @@ static int segment_Seek(stream_t *s, const uint64_t pos)
(p_sys->download.segment < count)))
{
vlc_cond_wait(&p_sys->download.wait, &p_sys->download.lock_wait);
- if (!vlc_object_alive(s) || s->b_error) break;
+ if (p_sys->b_error || s->b_error) break;
}
vlc_mutex_unlock(&p_sys->download.lock_wait);
--
2.1.0
More information about the vlc-devel
mailing list