[vlc-devel] [PATCH] Smooth Streaming: clean / factorize code
Frédéric Yhuel
yhuelf at gmail.com
Thu Oct 4 13:12:55 CEST 2012
and prepare subtitle support
---
modules/stream_filter/smooth/downloader.c | 193 +++++++++++------------------
modules/stream_filter/smooth/smooth.c | 49 +++-----
modules/stream_filter/smooth/smooth.h | 26 ++--
modules/stream_filter/smooth/utils.c | 60 +++++++++
4 files changed, 163 insertions(+), 165 deletions(-)
diff --git a/modules/stream_filter/smooth/downloader.c b/modules/stream_filter/smooth/downloader.c
index 8f6582e..79a4a83 100644
--- a/modules/stream_filter/smooth/downloader.c
+++ b/modules/stream_filter/smooth/downloader.c
@@ -140,14 +140,8 @@ static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
stream_Delete( p_ts );
vlc_mutex_lock( &p_sys->download.lock_wait );
-
- if( chunk->type == AUDIO_ES )
- p_sys->download.alead += chunk->duration;
- else if( chunk->type == VIDEO_ES )
- p_sys->download.vlead += chunk->duration;
- else if( chunk->type == SPU_ES )
- p_sys->download.tlead += chunk->duration;
-
+ int index = es_cat_to_index( chunk->type );
+ p_sys->download.lead[index] += chunk->duration;
vlc_mutex_unlock( &p_sys->download.lock_wait );
return VLC_SUCCESS;
@@ -205,12 +199,7 @@ static int get_new_chunks( stream_t *s, chunk_t *ck )
UUID_t uuid;
TfrfBoxDataFields_t *tfrf_df;
- if( ck->type == AUDIO_ES )
- sms = p_sys->astream;
- else if ( ck->type == VIDEO_ES )
- sms = p_sys->vstream;
- else
- return 0;
+ sms = SMS_GET_SELECTED_ST( ck->type );
SMS_GET4BYTES( size );
SMS_GETFOURCC( type );
@@ -307,6 +296,7 @@ static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
for( int i = 0; i < 3; i++ )
{
sms = NULL;
+ int cat = UNKNOWN_ES;
stra_box = smoo_box + i * STRA_SIZE;
stra_box[26] = (STRA_SIZE & 0xff00)>>8;
@@ -322,21 +312,9 @@ static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
((uint32_t *)stra_box)[10] = bswap32( 0x96c7bf25 );
((uint32_t *)stra_box)[11] = bswap32( 0xf97e2447 );
- if( i == 0)
- {
- stra_box[48] = VIDEO_ES;
- sms = p_sys->vstream;
- }
- else if( i == 1 )
- {
- stra_box[48] = AUDIO_ES;
- sms = p_sys->astream;
- }
- else if( i == 2 )
- {
- stra_box[48] = SPU_ES;
- sms = p_sys->tstream;
- }
+ cat = index_to_es_cat( i );
+ stra_box[48] = cat;
+ sms = SMS_GET_SELECTED_ST( cat );
stra_box[49] = 0; /* reserved */
if( sms == NULL )
@@ -359,6 +337,8 @@ static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
((uint32_t *)stra_box)[23] = bswap32( qlvl->AudioTag );
((uint16_t *)stra_box)[48] = bswap16( qlvl->nBlockAlign );
+ if( !qlvl->CodecPrivateData )
+ continue;
stra_box[98] = stra_box[99] = stra_box[100] = 0; /* reserved */
assert( strlen( qlvl->CodecPrivateData ) < 512 );
stra_box[101] = strlen( qlvl->CodecPrivateData ) / 2;
@@ -396,16 +376,8 @@ static int Download( stream_t *s, sms_stream_t *sms )
{
stream_sys_t *p_sys = s->p_sys;
- int64_t start_time;
-
- if( sms->type == AUDIO_ES )
- start_time = p_sys->download.alead;
- else if ( sms->type == VIDEO_ES )
- start_time = p_sys->download.vlead;
- else
- {
- return VLC_EGENERIC;
- }
+ int index = es_cat_to_index( sms->type );
+ int64_t start_time = p_sys->download.lead[index];
quality_level_t *qlevel = get_qlevel( sms, sms->download_qlvl );
if( unlikely( !qlevel ) )
@@ -485,21 +457,15 @@ static int Download( stream_t *s, sms_stream_t *sms )
chunk->sequence, sms->name, qlevel->Bitrate );
uint64_t actual_lead = chunk->start_time + chunk->duration;
- if( sms->type == AUDIO_ES )
- {
- p_sys->download.aindex = chunk->sequence;
- p_sys->download.alead = __MIN( p_sys->download.alead, actual_lead );
- }
- else if( sms->type == VIDEO_ES )
- {
- p_sys->download.vindex = chunk->sequence;
- p_sys->download.vlead = __MIN( p_sys->download.vlead, actual_lead );
- p_sys->playback.toffset = __MIN( p_sys->playback.toffset, (uint64_t)chunk->start_time );
- }
- else if( sms->type == SPU_ES )
+ int ind = es_cat_to_index( sms->type );
+ p_sys->download.ck_index[ind] = chunk->sequence;
+ p_sys->download.lead[ind] = __MIN( p_sys->download.lead[ind], actual_lead );
+
+ if( sms->type == VIDEO_ES ||
+ ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && sms->type == AUDIO_ES ) )
{
- p_sys->download.sindex = chunk->sequence;
- p_sys->download.tlead = __MIN( p_sys->download.tlead, actual_lead );
+ p_sys->playback.toffset = __MIN( p_sys->playback.toffset,
+ (uint64_t)chunk->start_time );
}
unsigned dur_ms = __MAX( 1, duration / 1000 );
@@ -555,30 +521,49 @@ static inline int64_t get_lead( stream_t *s )
{
stream_sys_t *p_sys = s->p_sys;
int64_t lead = 0;
-
- if( p_sys->vstream && p_sys->astream )
- lead = __MIN( p_sys->download.vlead, p_sys->download.alead );
- else if( p_sys->vstream )
- lead = p_sys->download.vlead;
+ int64_t alead = p_sys->download.lead[es_cat_to_index( AUDIO_ES )];
+ int64_t vlead = p_sys->download.lead[es_cat_to_index( VIDEO_ES )];
+ bool video = SMS_GET_SELECTED_ST( VIDEO_ES ) ? true : false;
+ bool audio = SMS_GET_SELECTED_ST( AUDIO_ES ) ? true : false;
+
+ if( video && audio )
+ lead = __MIN( vlead, alead );
+ else if( video )
+ lead = vlead;
else
- lead = p_sys->download.alead;
+ lead = alead;
lead -= p_sys->playback.toffset;
return lead;
}
+static int who_s_turn( stream_t *s )
+{
+ stream_sys_t *p_sys = s->p_sys;
+ uint64_t tmp, min = 0;
+ int cat, ret = UNKNOWN_ES;
+ for( int i = 0; i < 3; i++ )
+ {
+ tmp = p_sys->download.lead[i];
+ cat = index_to_es_cat( i );
+ if( (!min || tmp < min) && SMS_GET_SELECTED_ST( cat ) )
+ {
+ min = tmp;
+ ret = cat;
+ }
+ }
+ return ret;
+}
+
void* sms_Thread( void *p_this )
{
stream_t *s = (stream_t *)p_this;
stream_sys_t *p_sys = s->p_sys;
+ sms_stream_t *sms = NULL;
+ chunk_t *chunk;
int canc = vlc_savecancel();
- sms_stream_t *vsms = p_sys->vstream;
- sms_stream_t *asms = p_sys->astream;
- if( !vsms && !asms )
- goto cancel;
-
/* We compute the average bandwidth of the 4 last downloaded
* chunks, but feel free to replace '4' by whatever you wish */
p_sys->bws = sms_queue_init( 4 );
@@ -595,57 +580,31 @@ void* sms_Thread( void *p_this )
p_sys->download.next_chunk_offset = init_ck->size;
- chunk_t *audio_chunk, *video_chunk;
- if( vsms )
- video_chunk = vlc_array_item_at_index( vsms->chunks, 0 );
- if( asms )
- audio_chunk = vlc_array_item_at_index( asms->chunks, 0 );
- if( (vsms && !video_chunk) || (asms && !audio_chunk) )
- goto cancel;
-
- /* Sometimes, the video stream is cut into pieces of one exact length,
+ /* XXX Sometimes, the video stream is cut into pieces of one exact length,
* while the audio stream fragments can't be made to match exactly,
* and for some reason the n^th advertised video fragment is related to
* the n+1^th advertised audio chunk or vice versa */
- if( asms && vsms )
- {
- int64_t amid, vmid;
- amid = audio_chunk->duration / 2;
- vmid = video_chunk->duration / 2;
- if( audio_chunk->start_time > video_chunk->start_time + vmid )
- {
- video_chunk = vlc_array_item_at_index( vsms->chunks, 1 );
- }
- else if( video_chunk->start_time > audio_chunk->start_time + amid )
- {
- audio_chunk = vlc_array_item_at_index( asms->chunks, 1 );
- }
- }
+ int64_t start_time = 0, lead = 0;
- if( p_sys->b_live )
+ for( int i = 0; i < 3; i++ )
{
- p_sys->download.vlead = vsms ?
- video_chunk->start_time + p_sys->timescale / 1000 : 0;
- p_sys->download.alead = asms ?
- audio_chunk->start_time + p_sys->timescale / 1000 : 0;
- }
+ sms = SMS_GET_SELECTED_ST( index_to_es_cat( i ) );
+ if( sms )
+ {
+ chunk = vlc_array_item_at_index( sms->chunks, 0 );
+ p_sys->download.lead[i] = chunk->start_time + p_sys->timescale / 1000;
+ if( !start_time )
+ start_time = chunk->start_time;
- if( vsms && Download( s, vsms ) != VLC_SUCCESS )
- {
- goto cancel;
- }
- if( asms && Download( s, asms ) != VLC_SUCCESS )
- {
- goto cancel;
+ if( Download( s, sms ) != VLC_SUCCESS )
+ goto cancel;
+ }
}
- int64_t lead = 0;
- int64_t start_time = vsms ? video_chunk->start_time : audio_chunk->start_time;
-
while( 1 )
{
- /* XXX replace magic number 20 by a value depending on
+ /* XXX replace magic number 10 by a value depending on
* LookAheadFragmentCount and DVRWindowLength */
vlc_mutex_lock( &p_sys->download.lock_wait );
@@ -655,13 +614,9 @@ void* sms_Thread( void *p_this )
break;
}
- bool no_more_chunks = !p_sys->b_live &&
- (!vsms || p_sys->download.vindex >= vsms->vod_chunks_nb - 1) &&
- (!asms || p_sys->download.aindex >= asms->vod_chunks_nb - 1);
-
lead = get_lead( s );
- while( lead > 10 * p_sys->timescale + start_time || no_more_chunks )
+ while( lead > 10 * p_sys->timescale + start_time || NO_MORE_CHUNKS )
{
vlc_cond_wait( &p_sys->download.wait, &p_sys->download.lock_wait );
lead = get_lead( s );
@@ -690,8 +645,11 @@ void* sms_Thread( void *p_this )
p_sys->download.chunks = vlc_array_new();
p_sys->playback.toffset = p_sys->time_pos;
- p_sys->download.vlead = p_sys->download.alead = p_sys->time_pos;
- p_sys->download.aindex = p_sys->download.vindex = 0;
+ for( int i = 0; i < 3; i++ )
+ {
+ p_sys->download.lead[i] = p_sys->time_pos;
+ p_sys->download.ck_index[i] = 0;
+ }
p_sys->download.next_chunk_offset = 0;
p_sys->playback.boffset = 0;
@@ -709,16 +667,9 @@ void* sms_Thread( void *p_this )
}
vlc_mutex_unlock( &p_sys->download.lock_wait );
- if( !vsms || (asms && p_sys->download.alead < p_sys->download.vlead) )
- {
- if( Download( s, asms ) != VLC_SUCCESS )
- break;
- }
- else if( !asms || (vsms && p_sys->download.vlead <= p_sys->download.alead ) )
- {
- if( Download( s, vsms ) != VLC_SUCCESS )
- break;
- }
+ sms = SMS_GET_SELECTED_ST( who_s_turn( s ) );
+ if( Download( s, sms ) != VLC_SUCCESS )
+ goto cancel;
}
cancel:
diff --git a/modules/stream_filter/smooth/smooth.c b/modules/stream_filter/smooth/smooth.c
index 07e8391..01281cc 100644
--- a/modules/stream_filter/smooth/smooth.c
+++ b/modules/stream_filter/smooth/smooth.c
@@ -404,8 +404,10 @@ static int Open( vlc_object_t *p_this )
p_sys->b_cache = false;
p_sys->sms_streams = vlc_array_new();
+ p_sys->selected_st = vlc_array_new();
p_sys->download.chunks = vlc_array_new();
- if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks ) )
+ if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks ||
+ !p_sys->selected_st ) )
{
free( p_sys );
return VLC_ENOMEM;
@@ -423,34 +425,14 @@ static int Open( vlc_object_t *p_this )
p_sys->i_tracks = vlc_array_count( p_sys->sms_streams );
- /* FIXME */
- p_sys->i_selected_tracks = 2; /* one video track and one audio track */
-
- /* Choose first video stream available */
- sms_stream_t *vsms = NULL;
+ /* Choose first video / audio / subtitle stream available */
+ sms_stream_t *tmp = NULL, *selected = NULL;
for( unsigned i = 0; i < p_sys->i_tracks; i++ )
{
- vsms = vlc_array_item_at_index( p_sys->sms_streams, i );
- if( vsms->type == VIDEO_ES )
- {
- msg_Dbg( s, "Video stream chosen is %s", vsms->name );
- p_sys->vstream = vsms;
- break;
- }
- }
-
- /* Choose first audio stream available */
- sms_stream_t *asms = NULL;
- for( unsigned i = 0; i < p_sys->i_tracks; i++ )
- {
- asms = vlc_array_item_at_index( p_sys->sms_streams, i );
- //if( asms->type == AUDIO_ES && !strcmp( asms->name, "audio_eng" ) )
- if( asms->type == AUDIO_ES )
- {
- msg_Dbg( s, "Audio stream chosen is %s", asms->name );
- p_sys->astream = asms;
- break;
- }
+ tmp = vlc_array_item_at_index( p_sys->sms_streams, i );
+ selected = SMS_GET_SELECTED_ST( tmp->type );
+ if( !selected )
+ vlc_array_append( p_sys->selected_st, tmp );
}
/* Choose lowest quality for the first chunks */
@@ -498,7 +480,8 @@ static void Close( vlc_object_t *p_this )
vlc_mutex_lock( &p_sys->download.lock_wait );
p_sys->b_close = true;
/* Negate the condition variable's predicate */
- p_sys->download.vlead = p_sys->download.alead = 0;
+ for( int i = 0; i < 3; i++ )
+ p_sys->download.lead[i] = 0;
p_sys->playback.toffset = 0;
vlc_cond_signal(&p_sys->download.wait);
vlc_mutex_unlock( &p_sys->download.lock_wait );
@@ -544,9 +527,7 @@ static chunk_t *get_chunk( stream_t *s, const bool wait )
p_sys->playback.index );
return NULL;
}
- if( !p_sys->b_live &&
- p_sys->download.aindex >= (p_sys->vstream->vod_chunks_nb -1) &&
- p_sys->download.vindex >= (p_sys->astream->vod_chunks_nb -1) )
+ if( NO_MORE_CHUNKS )
{
vlc_mutex_unlock( &p_sys->download.lock_wait );
msg_Info( s, "No more chunks, end of the VOD" );
@@ -580,7 +561,8 @@ static int sms_Read( stream_t *s, uint8_t *p_read, int i_read )
if( chunk->read_pos >= (int)chunk->size )
{
- if( chunk->type == VIDEO_ES || !p_sys->vstream )
+ if( chunk->type == VIDEO_ES ||
+ ( !SMS_GET_SELECTED_ST( VIDEO_ES ) && chunk->type == AUDIO_ES ) )
{
vlc_mutex_lock( &p_sys->download.lock_wait );
p_sys->playback.toffset += chunk->duration;
@@ -727,7 +709,8 @@ static int chunk_Seek( stream_t *s, const uint64_t pos )
p_sys->b_tseek = true;
p_sys->time_pos = p_sys->vod_duration * pos / FAKE_STREAM_SIZE;
- p_sys->download.vlead = p_sys->download.alead = 0;
+ for( int i = 0; i < 3; i++ )
+ p_sys->download.lead[i] = 0;
p_sys->playback.toffset = 0;
vlc_cond_signal( &p_sys->download.wait);
diff --git a/modules/stream_filter/smooth/smooth.h b/modules/stream_filter/smooth/smooth.h
index da8283d..32adda6 100644
--- a/modules/stream_filter/smooth/smooth.h
+++ b/modules/stream_filter/smooth/smooth.h
@@ -89,12 +89,9 @@ 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; /* array of sms_stream_t */
- sms_stream_t *vstream; /* current video stream */
- sms_stream_t *astream; /* current audio stream */
- sms_stream_t *tstream; /* current text stream */
+ vlc_array_t *sms_streams; /* available streams */
+ vlc_array_t *selected_st; /* selected streams */
unsigned i_tracks; /* Total number of tracks in the Manifest */
- unsigned i_selected_tracks;
sms_queue_t *bws; /* Measured bandwidths of the N last chunks */
uint64_t vod_duration; /* total duration of the VOD media */
int64_t time_pos;
@@ -103,13 +100,10 @@ struct stream_sys_t
/* Download */
struct sms_download_s
{
- uint64_t alead; // how much audio/video/text data is
- uint64_t vlead; // available (downloaded),
- uint64_t tlead; // in seconds / TimeScale
+ uint64_t lead[3]; /* how much audio/video/text data is available
+ (downloaded), in seconds / TimeScale */
- unsigned aindex; /* current audio chunk for download */
- unsigned vindex; /* video */
- unsigned sindex; /* spu */
+ unsigned ck_index[3]; /* current chunk for download */
uint64_t next_chunk_offset;
vlc_array_t *chunks; /* chunks that have been downloaded */
@@ -164,6 +158,12 @@ struct stream_sys_t
slice += 4; \
} 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_queue_t *sms_queue_init( const int );
int sms_queue_put( sms_queue_t *, const uint64_t );
uint64_t sms_queue_avg( sms_queue_t *);
@@ -176,5 +176,9 @@ 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 *);
+int index_to_es_cat( int );
+int es_cat_to_index( int );
#endif
diff --git a/modules/stream_filter/smooth/utils.c b/modules/stream_filter/smooth/utils.c
index 9b57f66..be27c03 100644
--- a/modules/stream_filter/smooth/utils.c
+++ b/modules/stream_filter/smooth/utils.c
@@ -202,3 +202,63 @@ 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 *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;
+ }
+ return NULL;
+}
+
+int es_cat_to_index( int i_cat )
+{
+ switch( i_cat )
+ {
+ case VIDEO_ES:
+ return 0;
+ case AUDIO_ES:
+ return 1;
+ case SPU_ES:
+ return 2;
+ default:
+ return -1;
+ }
+}
+
+int index_to_es_cat( int index )
+{
+ switch( index )
+ {
+ case 0:
+ return VIDEO_ES;
+ case 1:
+ return AUDIO_ES;
+ case 2:
+ return SPU_ES;
+ default:
+ return -1;
+ }
+}
+
+bool no_more_chunks( unsigned *indexes, vlc_array_t *streams )
+{
+ sms_stream_t *sms = NULL;
+ int count = vlc_array_count( streams );
+ unsigned ck_index;
+ for( int i = 0; i < count; i++ )
+ {
+ 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 true;
+}
--
1.7.9.5
More information about the vlc-devel
mailing list