Commit 3843d77d authored by Francois Cartegnie's avatar Francois Cartegnie

stream_filter: smooth: rewrite buffering

Gets rid of useless indirect access to chunks.
Uses time as chunk based instead of indexes.
Does not keep chunks on live stream.
parent 31dab577
This diff is collapsed.
This diff is collapsed.
......@@ -24,6 +24,13 @@
#ifndef _VLC_SMOOTH_H
#define _VLC_SMOOTH_H 1
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include <vlc_arrays.h>
//#define DISABLE_BANDWIDTH_ADAPTATION
typedef struct item_s
......@@ -39,18 +46,22 @@ typedef struct sms_queue_s
item_t *first;
} sms_queue_t;
typedef struct chunk_s
#define CHUNK_OFFSET_UNSET 0
#define CHUNK_OFFSET_0 1
typedef struct chunk_s chunk_t;
struct chunk_s
{
uint64_t duration; /* chunk duration (seconds / TimeScale) */
uint64_t start_time; /* PTS (seconds / TimeScale) */
uint64_t size; /* chunk size in bytes */
unsigned sequence; /* unique sequence number */
uint64_t offset; /* offset in the media */
uint64_t read_pos; /* position in the chunk */
int type; /* video, audio, or subtitles */
uint8_t *data;
} chunk_t;
chunk_t *p_next;
};
typedef struct
{
......@@ -70,7 +81,6 @@ typedef struct quality_level_s
unsigned BitsPerSample;
unsigned AudioTag;
unsigned nBlockAlign;
unsigned id;
char *CodecPrivateData; /* hex encoded string */
DECL_ARRAY(custom_attrs_t *) custom_attrs;
......@@ -78,63 +88,64 @@ typedef struct quality_level_s
typedef struct sms_stream_s
{
vlc_array_t *qlevels; /* list of available Quality Levels */
vlc_array_t *chunks; /* list of chunks */
DECL_ARRAY( quality_level_t * ) qlevels; /* list of available Quality Levels */
chunk_t *p_chunks; /* Time Ordered list of chunks */
chunk_t *p_lastchunk; /* Time Ordered list of chunks's tail */
chunk_t *p_nextdownload; /* Pointer to next chunk to download */
chunk_t *p_playback; /* Pointer to current playback chunk */
vlc_mutex_t chunks_lock; /* chunks global lock */
uint32_t default_FourCC;
unsigned vod_chunks_nb; /* total num of chunks of the VOD stream */
unsigned timescale;
unsigned qlevel_nb; /* number of quality levels */
unsigned qlevel_nb; /* declared number of quality levels */
unsigned id; /* track id, will be set arbitrarily */
char *name;
char *url_template;
int type;
unsigned download_qlvl; /* current quality level ID for Download() */
const quality_level_t *current_qlvl; /* current quality level for Download() */
} sms_stream_t;
struct stream_sys_t
{
char *base_url; /* URL common part for chunks */
vlc_thread_t thread; /* SMS chunk download thread */
vlc_array_t *sms_streams; /* available streams */
vlc_array_t *selected_st; /* selected streams */
vlc_array_t *init_chunks;
unsigned i_tracks; /* Total number of tracks in the Manifest */
sms_queue_t *bws; /* Measured bandwidths of the N last chunks */
uint64_t vod_duration; /* total duration of the VOD media */
unsigned lookahead_count;/* max number of fragments ahead on server on live streaming */
DECL_ARRAY( sms_stream_t * ) sms; /* available streams */
DECL_ARRAY( sms_stream_t * ) sms_selected; /* selected streams */
uint64_t vod_duration; /* total duration of the VOD media (seconds / TimeScale) */
uint64_t time_pos;
unsigned timescale;
/* Download */
struct sms_download_s
struct
{
uint64_t lead[3]; /* how much audio/video/text data is available
(downloaded), in seconds / TimeScale */
unsigned ck_index[3]; /* current chunk for download */
uint64_t next_chunk_offset;
vlc_array_t *chunks; /* chunks that have been downloaded */
vlc_mutex_t lock_wait; /* protect chunk download counter. */
char *base_url; /* URL common part for chunks */
unsigned lookahead_count;/* max number of fragments ahead on server on live streaming */
vlc_thread_t thread; /* SMS chunk download thread */
sms_queue_t *bws; /* Measured bandwidths of the N last chunks */
vlc_cond_t wait; /* some condition to wait on */
} download;
/* Playback */
struct sms_playback_s
sms_stream_t *p_current_stream;
vlc_mutex_t lock;
struct
{
uint64_t boffset; /* current byte offset in media */
uint64_t toffset; /* current time offset in media */
unsigned index; /* current chunk for playback */
uint64_t next_chunk_offset;
struct
{
chunk_t *p_datachunk; /* the (re)init data chunk */
const chunk_t *p_startchunk; /* reinit must be sent before this one */
} init;
vlc_mutex_t lock;
vlc_cond_t wait; /* some condition to wait on */
} playback;
/* state */
bool b_cache; /* can cache files */
bool b_live; /* live stream? or vod? */
bool b_error; /* parsing error */
bool b_close; /* set by Close() */
bool b_tseek; /* time seeking */
};
#define SMS_GET4BYTES( dst ) do { \
......@@ -169,28 +180,23 @@ struct stream_sys_t
} while(0)
#define SMS_GET_SELECTED_ST( cat ) \
sms_get_stream_by_cat( p_sys->selected_st, cat )
#define NO_MORE_CHUNKS ( !p_sys->b_live && \
no_more_chunks( p_sys->download.ck_index, p_sys->selected_st ) )
sms_get_stream_by_cat( p_sys, cat )
void sms_queue_free( sms_queue_t* );
sms_queue_t *sms_queue_init( const unsigned int );
int sms_queue_put( sms_queue_t *, const uint64_t );
uint64_t sms_queue_avg( sms_queue_t *);
quality_level_t *get_qlevel( sms_stream_t *, const unsigned );
void* sms_Thread( void *);
quality_level_t * ql_New( void );
void ql_Free( quality_level_t *);
chunk_t *chunk_New( sms_stream_t* , uint64_t , uint64_t );
chunk_t *chunk_AppendNew( sms_stream_t* , uint64_t , uint64_t );
void chunk_Free( chunk_t *);
sms_stream_t * sms_New( void );
void sms_Free( sms_stream_t *);
uint8_t *decode_string_hex_to_binary( const char * );
sms_stream_t * sms_get_stream_by_cat( vlc_array_t *, int );
bool no_more_chunks( unsigned[], vlc_array_t *);
unsigned int ahead_chunks_count( stream_sys_t *, sms_stream_t * );
sms_stream_t * sms_get_stream_by_cat( stream_sys_t *, int );
bool no_more_chunks( stream_sys_t * );
int index_to_es_cat( int );
int es_cat_to_index( int );
void resetChunksState( stream_sys_t * );
#endif
......@@ -21,16 +21,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc_common.h>
#include "smooth.h"
#include <vlc_es.h>
#include <vlc_block.h>
#include <assert.h>
#include "smooth.h"
static int hex_digit( const char c )
{
if (c >= 'A' && c <= 'F')
......@@ -86,8 +82,8 @@ void ql_Free( quality_level_t *qlevel )
qlevel = NULL;
}
chunk_t *chunk_New( sms_stream_t* sms, uint64_t duration,\
uint64_t start_time )
chunk_t *chunk_AppendNew( sms_stream_t* sms, uint64_t duration,
uint64_t start_time )
{
chunk_t *chunk = calloc( 1, sizeof( chunk_t ) );
if( unlikely( chunk == NULL ) )
......@@ -96,8 +92,21 @@ chunk_t *chunk_New( sms_stream_t* sms, uint64_t duration,\
chunk->duration = duration;
chunk->start_time = start_time;
chunk->type = UNKNOWN_ES;
chunk->sequence = vlc_array_count( sms->chunks );
vlc_array_append( sms->chunks, chunk );
if ( sms->p_lastchunk )
{
assert(sms->p_chunks);
sms->p_lastchunk->p_next = chunk;
}
else
{
assert(!sms->p_chunks);
sms->p_chunks = chunk;
/* Everything starts from first chunk */
sms->p_nextdownload = chunk;
sms->p_playback = chunk;
}
sms->p_lastchunk = chunk;
return chunk;
}
......@@ -112,14 +121,9 @@ sms_stream_t * sms_New( void )
sms_stream_t *sms = calloc( 1, sizeof( sms_stream_t ) );
if( unlikely( !sms ) ) return NULL;
sms->qlevels = vlc_array_new();
sms->chunks = vlc_array_new();
if ( unlikely(!sms->qlevels || !sms->chunks) )
{
sms_Free( sms );
return NULL;
}
ARRAY_INIT( sms->qlevels );
sms->type = UNKNOWN_ES;
vlc_mutex_init( &sms->chunks_lock );
return sms;
}
......@@ -127,43 +131,27 @@ void sms_Free( sms_stream_t *sms )
{
if ( !sms )
return;
if( sms->qlevels )
{
for( int n = 0; n < vlc_array_count( sms->qlevels ); n++ )
{
quality_level_t *qlevel = vlc_array_item_at_index( sms->qlevels, n );
if( qlevel ) ql_Free( qlevel );
}
vlc_array_destroy( sms->qlevels );
}
if( sms->chunks )
FOREACH_ARRAY( quality_level_t *qlevel, sms->qlevels );
if( qlevel )
ql_Free( qlevel );
FOREACH_END();
ARRAY_RESET( sms->qlevels );
vlc_mutex_lock( &sms->chunks_lock );
while( sms->p_chunks )
{
for( int n = 0; n < vlc_array_count( sms->chunks ); n++ )
{
chunk_t *chunk = vlc_array_item_at_index( sms->chunks, n );
if( chunk) chunk_Free( chunk );
}
vlc_array_destroy( sms->chunks );
chunk_t *p_chunk = sms->p_chunks;
sms->p_chunks = sms->p_chunks->p_next;
chunk_Free( p_chunk );
}
vlc_mutex_unlock( &sms->chunks_lock );
vlc_mutex_destroy( &sms->chunks_lock );
free( sms->name );
free( sms->url_template );
free( sms );
}
quality_level_t *get_qlevel( sms_stream_t *sms, const unsigned qid )
{
quality_level_t *qlevel = NULL;
for( unsigned i = 0; i < sms->qlevel_nb; i++ )
{
qlevel = vlc_array_item_at_index( sms->qlevels, i );
if( qlevel->id == qid )
return qlevel;
}
return NULL;
}
sms_queue_t *sms_queue_init( const unsigned length )
{
sms_queue_t *ret = malloc( sizeof( sms_queue_t ) );
......@@ -234,18 +222,13 @@ uint64_t sms_queue_avg( sms_queue_t *queue )
return sum / queue->length;
}
sms_stream_t * sms_get_stream_by_cat( vlc_array_t *streams, int i_cat )
sms_stream_t * sms_get_stream_by_cat( stream_sys_t *p_sys, int i_cat )
{
sms_stream_t *ret = NULL;
int count = vlc_array_count( streams );
assert( count >= 0 && count <= 3 );
for( int i = 0; i < count; i++ )
{
ret = vlc_array_item_at_index( streams, i );
if( ret->type == i_cat )
return ret;
}
assert( p_sys->sms_selected.i_size >= 0 && p_sys->sms_selected.i_size <= 3 );
FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
if( sms->type == i_cat )
return sms;
FOREACH_END();
return NULL;
}
......@@ -279,26 +262,34 @@ int index_to_es_cat( int index )
}
}
bool no_more_chunks( unsigned *indexes, vlc_array_t *streams )
bool no_more_chunks( stream_sys_t *p_sys )
{
sms_stream_t *sms = NULL;
int count = vlc_array_count( streams );
unsigned ck_index;
for( int i = 0; i < count; i++ )
FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
if ( sms->p_playback )
{
sms = vlc_array_item_at_index( streams, i );
ck_index = indexes[es_cat_to_index( sms->type )];
if( ck_index < sms->vod_chunks_nb - 1 )
return false;
return false;
}
FOREACH_END();
return true;
}
unsigned int ahead_chunks_count( stream_sys_t *p_sys, sms_stream_t *sms )
void resetChunksState( stream_sys_t *p_sys )
{
int ind = es_cat_to_index( sms->type );
if ( p_sys->download.ck_index[ind] > vlc_array_count( p_sys->download.chunks ) )
return p_sys->download.ck_index[ind] - vlc_array_count( p_sys->download.chunks );
else
return 0;
FOREACH_ARRAY( sms_stream_t *sms, p_sys->sms_selected );
vlc_mutex_lock( &sms->chunks_lock );
chunk_t *p_chunk = sms->p_playback;
while( p_chunk )
{
FREENULL( p_chunk->data );
p_chunk->offset = CHUNK_OFFSET_UNSET;
p_chunk->size = 0;
p_chunk->read_pos = 0;
if ( p_chunk == sms->p_nextdownload )
break;
p_chunk = p_chunk->p_next;
}
sms->p_playback = NULL;
sms->p_nextdownload = NULL;
vlc_mutex_unlock( &sms->chunks_lock );
FOREACH_END();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment