[vlc-devel] [PATCH] Add Smooth Streaming module

Frédéric Yhuel fyhuel at viotech.net
Wed Jul 18 17:27:20 CEST 2012


Test it:

***** Live *****
- http://demo.anevia.com:3128/live/disk1/live1/ss-ss/manifest
- http://demo.anevia.com:3129/live/disk1/live2/ss-ss/manifest

***** VOD *****
- http://demo.anevia.com:3131/vod/disk1/content2/ss-ss/Manifest
- http://demo.anevia.com:3130/vod/disk1/content1/ss-ss/Manifest

This one is WVC1/WMAP content, it kinda works:
- http://mediadl.microsoft.com/mediadl/iisnet/smoothmedia/Experience/BigBuckBunny_720p.ism/Manifest
---
 modules/stream_filter/Modules.am          |    3 +-
 modules/stream_filter/smooth/downloader.c |  626 ++++++++++++++++-------------
 modules/stream_filter/smooth/smooth.c     |  614 ++++++++++++++--------------
 modules/stream_filter/smooth/smooth.h     |   58 +--
 modules/stream_filter/smooth/utils.c      |   56 ++-
 5 files changed, 741 insertions(+), 616 deletions(-)

diff --git a/modules/stream_filter/Modules.am b/modules/stream_filter/Modules.am
index 6d8d94a..e14f84e 100644
--- a/modules/stream_filter/Modules.am
+++ b/modules/stream_filter/Modules.am
@@ -1,5 +1,4 @@
-SUBDIRS = dash
-SUBDIRS = smooth
+SUBDIRS = dash smooth
 
 SOURCES_decomp = decomp.c
 SOURCES_stream_filter_record = record.c
diff --git a/modules/stream_filter/smooth/downloader.c b/modules/stream_filter/smooth/downloader.c
index 37c2ff4..66dee81 100644
--- a/modules/stream_filter/smooth/downloader.c
+++ b/modules/stream_filter/smooth/downloader.c
@@ -35,11 +35,10 @@
 static char *ConstructUrl( const char *template, const char *base_url,
         uint64_t bandwidth, uint64_t start_time )
 {
-    char *frag;
-    char *end;
-    char *qual;
+    char *frag, *end, *qual;
     char *url_template = strdup( template );
     char *saveptr = NULL;
+
     qual = strtok_r( url_template, "{", &saveptr );
     strtok_r( NULL, "}", &saveptr );
     frag = strtok_r( NULL, "{", &saveptr );
@@ -49,7 +48,9 @@ static char *ConstructUrl( const char *template, const char *base_url,
 
     if( asprintf( &url, "%s/%s%"PRIu64"%s%"PRIu64"%s", base_url, qual,
                 bandwidth, frag, start_time, end) < 0 )
+    {
        return NULL;
+    }
 
     free( url_template );
     return url;
@@ -57,119 +58,130 @@ static char *ConstructUrl( const char *template, const char *base_url,
 
 static chunk_t * chunk_Get( sms_stream_t *sms, int64_t start_time )
 {
-    vlc_mutex_lock( &sms->lock );
     int len = vlc_array_count( sms->chunks );
     for( int i = 0; i < len; i++ )
     {
         chunk_t * chunk = vlc_array_item_at_index( sms->chunks, i );
+        if( !chunk ) return NULL;
+
         if( chunk->start_time <= start_time &&
                 chunk->start_time + chunk->duration > start_time )
         {
-            vlc_mutex_unlock( &sms->lock );
             return chunk;
         }
     }
-    vlc_mutex_unlock( &sms->lock );
     return NULL;
 }
 
+static unsigned set_track_id( chunk_t *chunk, unsigned tid )
+{
+    uint32_t size, type;
+    assert( chunk->data );
+    uint8_t *slice = chunk->data->p_buffer;
+    assert( slice );
+
+    SMS_GET4BYTES( size );
+    SMS_GETFOURCC( type );
+    assert( type == ATOM_moof );
+
+    SMS_GET4BYTES( size );
+    SMS_GETFOURCC( type );
+    assert( type == ATOM_mfhd );
+    slice += size - 8;
+
+    SMS_GET4BYTES( size );
+    SMS_GETFOURCC( type );
+    assert( type == ATOM_traf );
+
+    SMS_GET4BYTES( size );
+    SMS_GETFOURCC( type );
+    assert( type == ATOM_tfhd );
+
+    unsigned ret = bswap32( ((uint32_t *)slice)[1] );
+    ((uint32_t *)slice)[1] = bswap32( tid );
+
+    return ret;
+}
+
 static int sms_Download( stream_t *s, chunk_t *chunk, char *url )
 {
-    assert( chunk );
     stream_sys_t *p_sys = s->p_sys;
 
-    msg_Dbg( s, "chunk url is %s\n", url );
-    if( url == NULL )
-        return VLC_ENOMEM;
-
     stream_t *p_ts = stream_UrlNew( s, url );
     free( url );
     if( p_ts == NULL )
         return VLC_EGENERIC;
 
-    chunk->size = stream_Size( p_ts );
-    assert( chunk->size > 0 );
+    int64_t size = stream_Size( p_ts );
+
+    chunk->size = size;
+    chunk->offset = p_sys->download.next_chunk_offset;
+    p_sys->download.next_chunk_offset += chunk->size;
+
+    chunk->data = block_Alloc( size );
 
-    chunk->data = block_Alloc( chunk->size );
     if( chunk->data == NULL )
     {
         stream_Delete( p_ts );
         return VLC_ENOMEM;
     }
 
-    msg_Dbg( s, "sms_Download: gonna dl %i bytes", (int)chunk->size );
-
-    enum{ BLOCK_SIZE = 8192 };
-    int len, read = 0;
-    int to_read = chunk->size;
-    uint8_t *dst = chunk->data->p_buffer;
-    int64_t size;
-    while( to_read > 0 && vlc_object_alive( s ) )
+    int read = stream_Read( p_ts, chunk->data->p_buffer, size );
+    if( read < size )
     {
-        size = stream_Size( p_ts );
-        if( size != chunk->size )
-        {
-            msg_Err( s, "chunk size changed! old is %"PRIi64", new is %"PRIi64,
-                    chunk->size, size );
-            return VLC_EGENERIC;
-        }
-        len = __MIN( to_read, BLOCK_SIZE );
-        read = stream_Read( p_ts, dst, len );
-        if( read < len )
-        {
-            msg_Err( s, "sms_Download: I requested %i bytes, "\
-                    "but I got only %i", len, read );
-            return VLC_EGENERIC;
-        }
-        dst += len;
-        to_read -= len;
+        msg_Warn( s, "sms_Download: I requested %"PRIi64" bytes, "\
+                "but I got only %i", size, read );
+        chunk->data = block_Realloc( chunk->data, 0, read );
     }
-    msg_Dbg( s, "sms_Download: I dld %i bytes", read );
+
+    stream_Delete( p_ts );
 
     vlc_mutex_lock( &p_sys->download.lock_wait );
-    vlc_array_append( p_sys->download.dld_chunks, chunk );
-    vlc_mutex_unlock( &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;
-    stream_Delete( p_ts );
+
+    vlc_mutex_unlock( &p_sys->download.lock_wait );
 
     return VLC_SUCCESS;
 }
 
 #ifdef DISABLE_BANDWIDTH_ADAPTATION
-static uint16_t BandwidthAdaptation( stream_t *s,
+static unsigned BandwidthAdaptation( stream_t *s,
         sms_stream_t *sms, uint64_t *bandwidth )
 {
     return sms->download_qlvl;
 }
 #else
 
-static uint16_t BandwidthAdaptation( stream_t *s,
-        sms_stream_t *sms, uint64_t *bandwidth )
+static unsigned BandwidthAdaptation( stream_t *s,
+        sms_stream_t *sms, uint64_t bandwidth )
 {
     if( sms->type != VIDEO_ES )
         return sms->download_qlvl;
+
     uint64_t bw_candidate = 0;
     quality_level_t *qlevel;
-    uint16_t ret = sms->download_qlvl;
-    msg_Dbg( s, "bw is %"PRIu64"", *bandwidth );
+    unsigned ret = sms->download_qlvl;
+    //msg_Dbg( s, "bw is %"PRIu64"", *bandwidth );
 
     for( unsigned i = 0; i < sms->qlevel_nb; i++ )
     {
         qlevel = vlc_array_item_at_index( sms->qlevels, i );
-        if( qlevel->Bitrate < (*bandwidth - *bandwidth / 3) &&
+        assert( qlevel );
+
+        if( qlevel->Bitrate < (bandwidth - bandwidth / 3) &&
                 qlevel->Bitrate > bw_candidate )
         {
             bw_candidate = qlevel->Bitrate;
             ret = qlevel->id;
         }
     }
-    if( bw_candidate )
-        *bandwidth = bw_candidate;
+
     return ret;
 }
 #endif
@@ -179,17 +191,19 @@ static int get_new_chunks( stream_t *s, chunk_t *ck )
     stream_sys_t *p_sys = s->p_sys;
 
     uint8_t *slice = ck->data->p_buffer;
+    assert( slice );
     uint8_t version, fragment_count;
     uint32_t size, type, flags;
     sms_stream_t *sms;
+    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;
-    UUID_t uuid;
-    TfrfBoxDataFields_t *tfrf_df;
 
     SMS_GET4BYTES( size );
     SMS_GETFOURCC( type );
@@ -203,164 +217,147 @@ static int get_new_chunks( stream_t *s, chunk_t *ck )
     SMS_GET4BYTES( size );
     SMS_GETFOURCC( type );
     assert( type == ATOM_traf );
+
     for(;;)
     {
-        if( slice > ck->data->p_buffer + ck->data->i_buffer - 8 )
-        {
-            msg_Err( s, "No uuid box found :-(" );
-            return VLC_EGENERIC;
-        }
         SMS_GET4BYTES( size );
         assert( size > 1 );
         SMS_GETFOURCC( type );
-        if( type == ATOM_uuid )
-            break;
-        else
-            slice += size - 8;
-    }
-
-    GetUUID( &uuid, slice);
-    slice += 16;
-    if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
-    {
-        SMS_GET1BYTE( version );
-        SMS_GET3BYTES( flags );
-
-        SMS_GET1BYTE( fragment_count );
-        tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
-        if( unlikely( tfrf_df == NULL ) )
-            return VLC_EGENERIC;
-        for( uint8_t i = 0; i < fragment_count; i++ )
+        if( type == ATOM_mdat )
         {
-            SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
-            SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
+            msg_Err( s, "No uuid box found :-(" );
+            return VLC_EGENERIC;
         }
-
-        msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
-                "fragment count %"PRIu8, version, flags, fragment_count );
-
-        for( uint8_t i = 0; i < fragment_count; i++ )
+        else if( type == ATOM_uuid )
         {
-            int64_t dur = tfrf_df[i].i_fragment_duration;
-            int64_t stime = tfrf_df[i].i_fragment_abs_time;
-            msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "\
-                        "fragment abs time %"PRIu64, dur, stime);
-
-            if( !chunk_Get( sms, stime ) )
-                chunk_New( sms, dur, stime );
+            GetUUID( &uuid, slice);
+            if( !CmpUUID( &uuid, &TfrfBoxUUID ) )
+                break;
         }
-        free( tfrf_df );
-
+        slice += size - 8;
     }
-    else if( !CmpUUID( &uuid, &TfxdBoxUUID ) )
-    {
-        msg_Err( s, "TfxdBox parsing no yet implemented" );
+
+    slice += 16;
+    SMS_GET1BYTE( version );
+    SMS_GET3BYTES( flags );
+    SMS_GET1BYTE( fragment_count );
+
+    tfrf_df = calloc( fragment_count, sizeof( TfrfBoxDataFields_t ) );
+    if( unlikely( tfrf_df == NULL ) )
         return VLC_EGENERIC;
-    }
-    else
+
+    for( uint8_t i = 0; i < fragment_count; i++ )
     {
-        msg_Err( s, "Unknown uuid box :-(" );
-        return VLC_EGENERIC;
+        SMS_GET4or8BYTES( tfrf_df[i].i_fragment_abs_time );
+        SMS_GET4or8BYTES( tfrf_df[i].i_fragment_duration );
     }
 
-    return VLC_SUCCESS;
-}
+    msg_Dbg( s, "read box: \"tfrf\" version %d, flags 0x%x, "\
+            "fragment count %"PRIu8, version, flags, fragment_count );
 
-/* Set track ID */
-static uint16_t set_track_id( chunk_t *chunk, uint32_t tid )
-{
-    uint8_t *slice = chunk->data->p_buffer;
-    uint32_t type;
-    for( size_t stop = chunk->data->i_buffer; stop > 0; )
+    for( uint8_t i = 0; i < fragment_count; i++ )
     {
-        slice = memchr( slice , 't', stop );
-        if( slice == NULL )
-            return 0;
-        SMS_GETFOURCC( type );
-        if( type == ATOM_tfhd )
-            break;
-        else
-        {
-            slice = __MAX( slice - 4 + 1, chunk->data->p_buffer + 1 );
-            stop = (size_t)chunk->data->i_buffer -
-                    (size_t)(slice - chunk->data->p_buffer);
-        }
+        int64_t dur = tfrf_df[i].i_fragment_duration;
+        int64_t stime = tfrf_df[i].i_fragment_abs_time;
+        msg_Dbg( s, "\"tfrf\" fragment duration %"PRIu64", "\
+                    "fragment abs time %"PRIu64, dur, stime);
+
+        if( !chunk_Get( sms, stime + dur ) )
+            chunk_New( sms, dur, stime );
     }
-    if( slice > chunk->data->p_buffer + chunk->data->i_buffer - 12 )
-        return 0;
+    free( tfrf_df );
 
-    uint32_t ret = bswap32( ((uint32_t *)slice)[1] );
-    ((uint32_t *)slice)[1] = bswap32( tid );
-    return ret;
+    return VLC_SUCCESS;
 }
 
-#define STRA_SIZE 312
-#define SMOO_SIZE (STRA_SIZE * 3 + 8)
+#define STRA_SIZE 338
+#define SMOO_SIZE (STRA_SIZE * 3 + 24) /* 1038 */
+
+/* SmooBox is a very simple MP4 box, used only to pass information
+ * to the demux layer. As this box is not aimed to travel accross networks,
+ * simplicity of the design is better than compactness */
 static int build_smoo_box( stream_t *s, uint8_t *smoo_box )
 {
     stream_sys_t *p_sys = s->p_sys;
-    sms_stream_t *sms;
+    sms_stream_t *sms = NULL;
+    bool disable_audio = var_InheritBool( s, "smooth-disable-audio" );
 
     /* smoo */
     memset( smoo_box, 0, SMOO_SIZE );
     smoo_box[2] = (SMOO_SIZE & 0xff00)>>8;
     smoo_box[3] = SMOO_SIZE & 0xff;
-    smoo_box[4] = 's';
-    smoo_box[5] = 'm';
-    smoo_box[6] = 'o';
-    smoo_box[7] = 'o';
+    smoo_box[4] = 'u';
+    smoo_box[5] = 'u';
+    smoo_box[6] = 'i';
+    smoo_box[7] = 'd';
+
+    /* UUID is e1da72ba-24d7-43c3-a6a5-1b5759a1a92c */
+    ((uint32_t *)smoo_box)[2] = bswap32( 0xe1da72ba );
+    ((uint32_t *)smoo_box)[3] = bswap32( 0x24d743c3 );
+    ((uint32_t *)smoo_box)[4] = bswap32( 0xa6a51b57 );
+    ((uint32_t *)smoo_box)[5] = bswap32( 0x59a1a92c );
 
     uint8_t *stra_box;
     for( int i = 0; i < 3; i++ )
     {
+        sms = NULL;
         stra_box = smoo_box + i * STRA_SIZE;
 
-        stra_box[10] = (STRA_SIZE & 0xff00)>>8;
-        stra_box[11] = STRA_SIZE & 0xff;
-        stra_box[12] = 's';
-        stra_box[13] = 't';
-        stra_box[14] = 'r';
-        stra_box[15] = 'a';
+        stra_box[26] = (STRA_SIZE & 0xff00)>>8;
+        stra_box[27] = STRA_SIZE & 0xff;
+        stra_box[28] = 'u';
+        stra_box[29] = 'u';
+        stra_box[30] = 'i';
+        stra_box[31] = 'd';
+
+        /* UUID is b03ef770-33bd-4bac-96c7-bf25f97e2447 */
+        ((uint32_t *)stra_box)[8] = bswap32( 0xb03ef770 );
+        ((uint32_t *)stra_box)[9] = bswap32( 0x33bd4bac );
+        ((uint32_t *)stra_box)[10] = bswap32( 0x96c7bf25 );
+        ((uint32_t *)stra_box)[11] = bswap32( 0xf97e2447 );
 
         if( i == 0)
         {
-            stra_box[16] = VIDEO_ES;
+            stra_box[48] = VIDEO_ES;
             sms = p_sys->vstream;
         }
         else if( i == 1 )
         {
-            stra_box[16] = AUDIO_ES;
-            sms = p_sys->astream;
+            stra_box[48] = AUDIO_ES;
+            if( !disable_audio )
+                sms = p_sys->astream;
         }
         else if( i == 2 )
         {
-            stra_box[16] = SPU_ES;
+            stra_box[48] = SPU_ES;
             sms = p_sys->tstream;
         }
 
-        stra_box[17] = 0; /* reserved */
+        stra_box[49] = 0; /* reserved */
         if( sms == NULL )
             continue;
-        stra_box[18] = (sms->id & 0xff00)>>8;
-        stra_box[19] = sms->id & 0xff;
+        stra_box[50] = (sms->id & 0xff00)>>8;
+        stra_box[51] = sms->id & 0xff;
 
-        ((uint32_t *)stra_box)[5] = bswap32( sms->timescale );
+        ((uint32_t *)stra_box)[13] = bswap32( sms->timescale );
+        ((uint64_t *)stra_box)[7] = bswap64( p_sys->vod_duration );
 
         quality_level_t * qlvl = get_qlevel( sms, sms->download_qlvl );
 
-        ((uint32_t *)stra_box)[6] = bswap32( qlvl->FourCC );
-        ((uint32_t *)stra_box)[7] = bswap32( qlvl->Bitrate );
-        ((uint32_t *)stra_box)[8] = bswap32( qlvl->MaxWidth );
-        ((uint32_t *)stra_box)[9] = bswap32( qlvl->MaxHeight );
-        ((uint32_t *)stra_box)[10] = bswap32( qlvl->SamplingRate );
-        ((uint32_t *)stra_box)[11] = bswap32( qlvl->Channels );
-        ((uint32_t *)stra_box)[12] = bswap32( qlvl->BitsPerSample );
-        ((uint32_t *)stra_box)[13] = bswap32( qlvl->PacketSize );
-        ((uint32_t *)stra_box)[14] = bswap32( qlvl->AudioTag );
-
-        stra_box[60] = stra_box[61] = stra_box[62] = 0; /* reserved */
-        stra_box[63] = strlen( qlvl->CodecPrivateData );
-        char *dst = (char *)(stra_box + 64);
+        ((uint32_t *)stra_box)[16] = bswap32( qlvl->FourCC );
+        ((uint32_t *)stra_box)[17] = bswap32( qlvl->Bitrate );
+        ((uint32_t *)stra_box)[18] = bswap32( qlvl->MaxWidth );
+        ((uint32_t *)stra_box)[19] = bswap32( qlvl->MaxHeight );
+        ((uint32_t *)stra_box)[20] = bswap32( qlvl->SamplingRate );
+        ((uint32_t *)stra_box)[21] = bswap32( qlvl->Channels );
+        ((uint32_t *)stra_box)[22] = bswap32( qlvl->BitsPerSample );
+        ((uint32_t *)stra_box)[23] = bswap32( qlvl->PacketSize );
+        ((uint32_t *)stra_box)[24] = bswap32( qlvl->AudioTag );
+        ((uint16_t *)stra_box)[50] = bswap16( qlvl->nBlockAlign );
+
+        stra_box[102] = stra_box[103] = stra_box[104] = 0; /* reserved */
+        stra_box[105] = strlen( qlvl->CodecPrivateData );
+        char *dst = (char *)(stra_box + 106);
         strncpy( dst, qlvl->CodecPrivateData, 256 );
     }
 
@@ -372,31 +369,36 @@ static chunk_t *build_init_chunk( stream_t *s )
     chunk_t *ret = calloc( 1, sizeof( chunk_t ) );
     if( unlikely( ret == NULL ) )
         return NULL;
-    vlc_mutex_init( &ret->lock );
+
     ret->size = SMOO_SIZE;
     ret->data = block_Alloc( SMOO_SIZE );
     if( !ret->data )
         return NULL;
+
     build_smoo_box( s, ret->data->p_buffer );
 
     return ret;
 }
 
-static int Download( stream_t *s, sms_stream_t *sms, uint64_t *next_chunk_offset )
+static int Download( stream_t *s, sms_stream_t *sms )
 {
     stream_sys_t *p_sys = s->p_sys;
 
-    assert( sms );
-
+    static unsigned bw_count = 0;
     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;
+    }
 
     quality_level_t *qlevel = get_qlevel( sms, sms->download_qlvl );
+    assert( qlevel );
+
     chunk_t *chunk = chunk_Get( sms, start_time );
     if( !chunk )
     {
@@ -404,29 +406,26 @@ static int Download( stream_t *s, sms_stream_t *sms, uint64_t *next_chunk_offset
                 "start time = %"PRIu64"", sms->name, start_time );
         return VLC_EGENERIC;
     }
-
-    vlc_mutex_lock( &chunk->lock );
     if( chunk->data != NULL )
     {
         /* Segment already downloaded */
-        vlc_mutex_unlock( &chunk->lock );
+        msg_Warn( s, "Segment already downloaded" );
         return VLC_SUCCESS;
     }
 
     chunk->type = sms->type;
-    char *url = ConstructUrl( sms->url_template,
-                                 p_sys->base_url,
-                                 qlevel->Bitrate,
-                                 chunk->start_time );
+
+    char *url = ConstructUrl( sms->url_template, p_sys->base_url,
+                                  qlevel->Bitrate, chunk->start_time );
 
     /* sanity check - can we download this chunk on time? */
     uint64_t avg_bw = sms_queue_avg( p_sys->bws );
     if( (avg_bw > 0) && (qlevel->Bitrate > 0) )
     {
         /* duration in ms */
-        uint32_t chunk_duration = chunk->duration * 1000 / sms->timescale;
+        unsigned chunk_duration = chunk->duration * 1000 / sms->timescale;
         uint64_t size = chunk_duration * qlevel->Bitrate / 1000; /* bits */
-        uint32_t estimated = (uint32_t)(size * 1000 / avg_bw);
+        unsigned estimated = size * 1000 / avg_bw;
         if( estimated > chunk_duration )
         {
             msg_Warn( s,"downloading of chunk %d would take %d ms, "\
@@ -438,61 +437,87 @@ static int Download( stream_t *s, sms_stream_t *sms, uint64_t *next_chunk_offset
     mtime_t start = mdate();
     if( sms_Download( s, chunk, url ) != VLC_SUCCESS )
     {
-        msg_Err( s, "downloaded chunk %"PRIu32" from stream %s at quality\
-            %"PRIu32" failed", chunk->sequence, sms->name, qlevel->Bitrate );
-        vlc_mutex_unlock( &chunk->lock );
+        msg_Err( s, "downloaded chunk %u from stream %s at quality\
+            %u failed", chunk->sequence, sms->name, qlevel->Bitrate );
         return VLC_EGENERIC;
     }
     mtime_t duration = mdate() - start;
 
-    chunk->offset = *next_chunk_offset;
-    *next_chunk_offset += chunk->size;
-    if( p_sys->b_live )
-        get_new_chunks( s, chunk );
-    uint16_t real_id = set_track_id( chunk, sms->id );
+    unsigned real_id = set_track_id( chunk, sms->id );
     if( real_id == 0)
     {
-        vlc_mutex_unlock( &chunk->lock );
         msg_Err( s, "tfhd box not found or invalid chunk" );
         return VLC_EGENERIC;
     }
-    msg_Dbg( s, "chunk ID was %i and is now %i", real_id, sms->id );
-    vlc_mutex_unlock( &chunk->lock );
 
-    msg_Dbg( s, "downloaded chunk %d from stream %s at quality %"PRIu32"",
+    //msg_Dbg( s, "chunk ID was %i and is now %i", real_id, sms->id );
+
+    if( p_sys->b_live )
+        get_new_chunks( s, chunk );
+
+    vlc_mutex_lock( &p_sys->download.lock_wait );
+    vlc_array_append( p_sys->download.chunks, chunk );
+    vlc_cond_signal( &p_sys->download.wait );
+    vlc_mutex_unlock( &p_sys->download.lock_wait );
+
+    msg_Info( s, "downloaded chunk %d from stream %s at quality %u",
                 chunk->sequence, sms->name, qlevel->Bitrate );
+
+    uint64_t actual_lead = chunk->start_time + chunk->duration;
     if( sms->type == AUDIO_ES )
-        p_sys->download.aindex++;
+    {
+        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++;
+    {
+        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 )
-        p_sys->download.sindex++;
-
-    if( sms->type != VIDEO_ES )
-        return VLC_SUCCESS;
+    {
+        p_sys->download.sindex = chunk->sequence;
+        p_sys->download.tlead = __MIN( p_sys->download.tlead, actual_lead );
+    }
 
     unsigned dur_ms = __MAX( 1, duration / 1000 );
     uint64_t bw = chunk->size * 8 * 1000 / dur_ms; /* bits / s */
     sms_queue_put( p_sys->bws, bw );
     avg_bw = sms_queue_avg( p_sys->bws );
-    if( ( (qlevel->Bitrate < avg_bw - avg_bw / 3) || (qlevel->Bitrate > avg_bw) )
-            && chunk->sequence > 1 )
+
+    if( sms->type != VIDEO_ES )
+        return VLC_SUCCESS;
+
+    /* Track could get disabled in mp4 demux if we trigger adaption too soon. */
+    if( chunk->sequence <= 1 )
+        return VLC_SUCCESS;
+
+    unsigned new_qlevel_id = BandwidthAdaptation( s, sms, avg_bw );
+    quality_level_t *new_qlevel = get_qlevel( sms, new_qlevel_id );
+    assert( new_qlevel );
+
+    fprintf( p_sys->bw_record, "%u %"PRIu64"\n", bw_count, bw );
+    fprintf( p_sys->avg_bw_rcd, "%u %"PRIu64"\n", bw_count, avg_bw );
+    fprintf( p_sys->ql_lvl_rcd, "%u %u\n", bw_count, new_qlevel->Bitrate );
+    bw_count++;
+
+    if( new_qlevel->Bitrate != qlevel->Bitrate )
     {
-        uint16_t new_qlevel_id = BandwidthAdaptation( s, sms, &avg_bw );
-        quality_level_t *new_qlevel = get_qlevel( sms, new_qlevel_id );
+        msg_Warn( s, "detected %s bandwidth (%u) stream",
+                 (new_qlevel->Bitrate >= qlevel->Bitrate) ? "faster" : "lower", new_qlevel->Bitrate );
 
-        /* FIXME: we need an average here */
-        if( (new_qlevel) && (new_qlevel->Bitrate != qlevel->Bitrate) )
-        {
-            msg_Warn( s, "detected %s bandwidth (%"PRIu64") stream",
-                     (avg_bw >= qlevel->Bitrate) ? "faster" : "lower", avg_bw );
-            sms->download_qlvl = new_qlevel_id;
+        sms->download_qlvl = new_qlevel_id;
 
-            chunk_t *new_init_ck = build_init_chunk( s );
-            vlc_mutex_lock( &p_sys->download.lock_wait );
-            vlc_array_append( p_sys->download.dld_chunks, new_init_ck );
-            vlc_mutex_unlock( &p_sys->download.lock_wait );
-        }
+        chunk_t *new_init_ck = build_init_chunk( s );
+        assert( new_init_ck );
+
+        new_init_ck->offset = p_sys->download.next_chunk_offset;
+        p_sys->download.next_chunk_offset += new_init_ck->size;
+
+        vlc_mutex_lock( &p_sys->download.lock_wait );
+        vlc_array_append( p_sys->download.chunks, new_init_ck );
+        vlc_mutex_unlock( &p_sys->download.lock_wait );
     }
     return VLC_SUCCESS;
 }
@@ -501,127 +526,176 @@ void* sms_Thread( void *p_this )
 {
     stream_t *s = (stream_t *)p_this;
     stream_sys_t *p_sys = s->p_sys;
-    int64_t lead=0, time_left=0;
-    uint64_t next_chunk_offset = 0;
-    sms_stream_t *vsms, *asms;
-    vsms = p_sys->vstream;
-    asms = p_sys->astream;
-    assert( vsms );
-    assert( asms );
+
+    const char *bw_record_path = "/tmp/smooth_bw_record.dat";
+    const char *ql_lvl_rcd_path = "/tmp/smooth_ql_lvl_rcd.dat";
+    const char *avg_bw_rcd_path = "/tmp/smooth_avg_bw_rcd.dat";
+    p_sys->bw_record = fopen( bw_record_path, "w" );
+    p_sys->ql_lvl_rcd = fopen( ql_lvl_rcd_path, "w" );
+    p_sys->avg_bw_rcd = fopen( avg_bw_rcd_path, "w" );
+    assert( p_sys->bw_record );
+    assert( p_sys->ql_lvl_rcd );
+    assert( p_sys->avg_bw_rcd );
+
+    sms_stream_t *vsms = p_sys->vstream;
+    sms_stream_t *asms = p_sys->astream;
+    assert( vsms ); assert( asms );
 
     /* 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 );
 
     chunk_t *init_ck = build_init_chunk( s );
+    assert( init_ck );
+
     vlc_mutex_lock( &p_sys->download.lock_wait );
-    vlc_array_append( p_sys->download.dld_chunks, init_ck );
+    vlc_array_append( p_sys->download.chunks, init_ck );
     vlc_mutex_unlock( &p_sys->download.lock_wait );
 
+    p_sys->download.next_chunk_offset = init_ck->size;
+
     int canc = vlc_savecancel();
 
-    vlc_mutex_lock( &asms->lock );
-    vlc_mutex_lock( &vsms->lock );
-    chunk_t *third_video_chunk = vlc_array_item_at_index( vsms->chunks, 0 );
-    chunk_t *third_audio_chunk = vlc_array_item_at_index( asms->chunks, 0 );
+    chunk_t *video_chunk = vlc_array_item_at_index( vsms->chunks, 0 );
+    chunk_t *audio_chunk = vlc_array_item_at_index( asms->chunks, 0 );
+    assert( video_chunk ); assert( audio_chunk );
 
     /* 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 */
-    int64_t amid = third_audio_chunk->duration / 2;
-    int64_t vmid = third_video_chunk->duration / 2;
+    int64_t amid = audio_chunk->duration / 2;
+    int64_t vmid = video_chunk->duration / 2;
 
-    if( third_audio_chunk->start_time > third_video_chunk->start_time + vmid )
+    if( audio_chunk->start_time > video_chunk->start_time + vmid )
     {
-        third_video_chunk = vlc_array_item_at_index( vsms->chunks, 1 );
+        video_chunk = vlc_array_item_at_index( vsms->chunks, 1 );
     }
-    else if ( third_video_chunk->start_time >
-                    third_audio_chunk->start_time + amid )
+    else if ( video_chunk->start_time > audio_chunk->start_time + amid )
     {
-        third_audio_chunk = vlc_array_item_at_index( asms->chunks, 1 );
+        audio_chunk = vlc_array_item_at_index( asms->chunks, 1 );
     }
-    vlc_mutex_unlock( &asms->lock );
-    vlc_mutex_unlock( &vsms->lock );
-    bool disable_audio = var_CreateGetBool( s, "smooth-disable-audio" );
+
+    bool disable_audio = var_InheritBool( s, "smooth-disable-audio" );
     if( p_sys->b_live )
     {
-        p_sys->download.vlead = third_video_chunk->start_time +
-            p_sys->timescale / 1000;
+        p_sys->download.vlead = video_chunk->start_time + p_sys->timescale / 1000;
         if( disable_audio )
             p_sys->download.alead = UINT64_MAX;
         else
-            p_sys->download.alead = third_audio_chunk->start_time +
-                p_sys->timescale / 1000;
+            p_sys->download.alead = audio_chunk->start_time + p_sys->timescale / 1000;
     }
 
-    if( Download( s, vsms, &next_chunk_offset ) != VLC_SUCCESS )
+    if( Download( s, vsms ) != VLC_SUCCESS )
     {
-        p_sys->b_error = true;
         goto cancel;
     }
     if( !disable_audio )
     {
-        if( Download( s, asms, &next_chunk_offset ) != VLC_SUCCESS )
-        {
-            p_sys->b_error = true;
+        if( Download( s, asms ) != VLC_SUCCESS )
             goto cancel;
-        }
     }
 
-    while( vlc_object_alive( s ) )
+    int64_t lead = 0;
+
+    while( 1 )
     {
-        /* Is there a new chunk to process? */
-        if( p_sys->download.aindex >= (asms->vod_chunks_nb - 1) &&
-            p_sys->download.vindex >= (vsms->vod_chunks_nb - 1) &&
-                                                    !p_sys->b_live )
-           break;
-        time_left = p_sys->vod_duration - p_sys->playback.toffset;
-        if( time_left > 60 * p_sys->timescale || p_sys->b_live )
+        /* XXX replace magic number 20 by a value depending on
+         * LookAheadFragmentCount and DVRWindowLength */
+        vlc_mutex_lock( &p_sys->download.lock_wait );
+
+        if( p_sys->b_close )
         {
-            /* wait */
-            vlc_mutex_lock( &p_sys->download.lock_wait );
-            if( p_sys->download.vlead >= p_sys->playback.toffset )
-                lead = p_sys->download.vlead - p_sys->playback.toffset;
-            else
-                lead = 0;
-            while( lead > 20 * p_sys->timescale + third_video_chunk->start_time )
-            {
-                msg_Dbg( s, "sms_Thread is waiting!" );
-                msg_Dbg( s, "toffset is %"PRIu64" and vlead is %"PRIu64,
-                        p_sys->playback.toffset,
-                        p_sys->download.vlead - third_video_chunk->start_time );
-                vlc_cond_timedwait( &p_sys->download.wait,
-                        &p_sys->download.lock_wait, mdate() + 100000 );
-                lead = p_sys->download.vlead - p_sys->playback.toffset;
-                if( !vlc_object_alive( s ) )
-                    break;
-            }
             vlc_mutex_unlock( &p_sys->download.lock_wait );
+            break;
         }
 
-        msg_Dbg( s, "I escaped the waiting cond !!!" );
-        if( p_sys->download.alead < p_sys->download.vlead )
-            if( Download( s, asms, &next_chunk_offset ) != VLC_SUCCESS )
-            {
-                    p_sys->b_error = true;
-                    break;
-            }
+        lead = __MIN( p_sys->download.vlead, p_sys->download.alead )
+            - p_sys->playback.toffset;
+
+        while( (lead > 10 * p_sys->timescale + video_chunk->start_time) ||
+                /* If there is no new chunk to process, we wait */
+                (
+                    !p_sys->b_live &&
+                    p_sys->download.aindex >= (asms->vod_chunks_nb -1) &&
+                    p_sys->download.vindex >= (vsms->vod_chunks_nb - 1)
+                )
+             )
+        {
+#if 0
+            msg_Info( s, "sms_Thread is waiting!" );
+            msg_Info( s, "toffset is %"PRIu64" vlead is %"PRIu64", alead is %"PRIu64", "\
+                    "and lead is %"PRIi64,
+                    p_sys->playback.toffset,
+                    p_sys->download.vlead - video_chunk->start_time,
+                    p_sys->download.alead - video_chunk->start_time,
+                    lead );
+#endif
+            vlc_cond_wait( &p_sys->download.wait, &p_sys->download.lock_wait );
+            lead = __MIN( p_sys->download.vlead, p_sys->download.alead )
+                - p_sys->playback.toffset;
 
-        if( p_sys->download.vlead <= p_sys->download.alead )
-            if( Download( s, vsms, &next_chunk_offset) != VLC_SUCCESS )
+            if( p_sys->b_close )
+                break;
+        }
+
+        if( p_sys->b_tseek )
+        {
+            int count = vlc_array_count( p_sys->download.chunks );
+            chunk_t *ck = NULL;
+            for( int i = 0; i < count; i++ )
             {
-                    p_sys->b_error = true;
-                    break;
+                ck = vlc_array_item_at_index( p_sys->download.chunks, i );
+                assert( ck );
+                ck->read_pos = 0;
+                if( ck->data == NULL )
+                    continue;
+                block_Release( ck->data );
+                ck->data = NULL;
             }
 
-        /* download succeeded */
-        vlc_mutex_lock( &p_sys->download.lock_wait );
-        vlc_cond_signal( &p_sys->download.wait );
+            vlc_array_destroy( p_sys->download.chunks );
+            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;
+            p_sys->download.next_chunk_offset = 0;
+
+            p_sys->playback.boffset = 0;
+            p_sys->playback.index = 0;
+
+            chunk_t *new_init_ck = build_init_chunk( s );
+            assert( new_init_ck );
+
+            new_init_ck->offset = p_sys->download.next_chunk_offset;
+            p_sys->download.next_chunk_offset += new_init_ck->size;
+
+            vlc_array_append( p_sys->download.chunks, new_init_ck );
+            p_sys->b_tseek = false;
+        }
         vlc_mutex_unlock( &p_sys->download.lock_wait );
+
+        if( p_sys->download.alead < p_sys->download.vlead )
+        {
+            if( Download( s, asms ) != VLC_SUCCESS )
+                    break;
+        }
+        else if( p_sys->download.vlead <= p_sys->download.alead )
+        {
+            if( Download( s, vsms ) != VLC_SUCCESS )
+                    break;
+        }
+        /* let reader thread breath. That avoids video track
+         * to get de-selected in certain cases */
+        msleep( 100000 );
     }
 
 cancel:
+    assert( fclose( p_sys->bw_record ) != EOF );
+    assert( fclose( p_sys->ql_lvl_rcd ) != EOF );
+    assert( fclose( p_sys->avg_bw_rcd ) != EOF );
+    p_sys->b_error = true;
     msg_Warn(s, "Canceling download thread!");
     vlc_restorecancel( canc );
     return NULL;
diff --git a/modules/stream_filter/smooth/smooth.c b/modules/stream_filter/smooth/smooth.c
index e56dda1..9f21c84 100644
--- a/modules/stream_filter/smooth/smooth.c
+++ b/modules/stream_filter/smooth/smooth.c
@@ -39,12 +39,19 @@
 #include <vlc_charset.h>
 #include <vlc_stream.h>
 #include <vlc_es.h>
+#include <vlc_codecs.h>
 
 #include "smooth.h"
+#include "../../demux/mp4/libmp4.h"
 
 #define DA_TEXT N_("Disable audio stream")
 #define DA_LONGTEXT N_("Disable audio stream")
 
+/* I make the assumption that when the demux want to do a *time* seek,
+ * then p_sys->download->boffset > FAKE_STREAM_SIZE, and thus FAKE_STREAM_SIZE
+ * should be small enough. 1000 seems to be a sensible choice. See also
+ * chunk_Seek() comments to understand properly */
+#define FAKE_STREAM_SIZE 1000
 /*****************************************************************************
  * Module descriptor
  *****************************************************************************/
@@ -63,33 +70,63 @@ vlc_module_begin()
         change_safe()
 vlc_module_end()
 
-static int   Read( stream_t *, void *, unsigned int );
-static int   Peek( stream_t *, const uint8_t **, unsigned int );
+static int   Read( stream_t *, void *, unsigned );
+static int   Peek( stream_t *, const uint8_t **, unsigned );
 static int   Control( stream_t *, int , va_list );
 
 static bool isSmoothStreaming( stream_t *s )
 {
     const uint8_t *peek;
-    const char *conv_peek;
+    char *peeked = malloc( 512 );
+    if( unlikely( !peeked ) )
+        return false;
     const char *needle = "<SmoothStreamingMedia";
+    const char *encoding = NULL;
+    bool ret = false;
 
-    int i_size = stream_Peek( s->p_source, &peek, 1024 );
-    if(  i_size < 1024 )
+    int i_size = stream_Peek( s->p_source, &peek, 512 );
+    if(  i_size < 512 )
+    {
+        free( peeked );
         return false;
+    }
+
+    memcpy( peeked, peek, 512 );
+    peeked[511] = peeked[510] = '\0';
 
-    if( strstr( (const char*)peek, needle ) != NULL )
-        return true;
+    if( strstr( (const char *)peeked, needle ) != NULL )
+        ret = true;
     else
     /* maybe it's utf-16 encoding, should we also test other encodings? */
     {
-        conv_peek = FromCharset( "UTF-16", peek, 1024 );
-        if( conv_peek != NULL )
-            if( strstr( conv_peek, needle ) != NULL )
-                return true;
+        if( !memcmp( peeked, "\xFF\xFE", 2 ) )
+            encoding = "UTF-16LE";
+        else if( !memcmp( peeked, "\xFE\xFF", 2 ) )
+            encoding = "UTF-16BE";
+        else
+        {
+            free( peeked );
+            return false;
+        }
+        peeked = FromCharset( encoding, peeked, 512 );
+
+        if( strstr( peeked, needle ) != NULL )
+            ret = true;
     }
-    return false;
+    free( peeked );
+    return ret;
 }
 
+#if 0
+static void print_chunk( stream_t *s, chunk_t *ck )
+{
+    msg_Info( s, "chunk %u type %i: duration is %"PRIu64", stime is %"PRIu64", "\
+            "size is %i, offset is %"PRIu64", read_pos is %i.",
+            ck->sequence, ck->type, ck->duration,
+            ck->start_time, ck->size, ck->offset, ck->read_pos );
+}
+#endif
+
 static int parse_Manifest( stream_t *s )
 {
     stream_sys_t *p_sys = s->p_sys;
@@ -111,25 +148,30 @@ static int parse_Manifest( stream_t *s )
     if( !vlc_reader )
     {
         msg_Err( s, "Failed to open source for parsing" );
+        xml_Delete( vlc_xml );
+        return VLC_EGENERIC;
     }
 
     const char *node;
     char *stream_name = NULL;
+    uint8_t *WaveFormatEx;
     int stream_type = UNKNOWN_ES;
     sms_stream_t *sms = NULL;
     quality_level_t *ql = NULL;
     int64_t start_time = 0, duration = 0;
     int64_t computed_start_time = 0, computed_duration = 0;
-    uint32_t next_track_id = 1;
-    uint32_t next_qid = 1;
-    enum{ TIMESCALE = 10000000 };
-    uint32_t Subtype = 0;
+    unsigned next_track_id = 1;
+    unsigned next_qid = 1;
+    int loop_count = 0;
+    bool b_weird = false;
 
+#define TIMESCALE 10000000
     while( (type = xml_ReaderNextNode( vlc_reader, &node )) > 0 )
     {
         switch( type )
         {
             case XML_READER_STARTELEM:
+
                 if( !strcmp( node, "SmoothStreamingMedia" ) )
                 {
                     while( (name = xml_ReaderNextAttr( vlc_reader, &value )) )
@@ -146,7 +188,6 @@ static int parse_Manifest( stream_t *s )
 
                 if( !strcmp( node, "StreamIndex" ) )
                 {
-                    Subtype = 0;
                     sms = sms_New();
                     if( unlikely( !sms ) )
                         return VLC_ENOMEM;
@@ -181,9 +222,6 @@ static int parse_Manifest( stream_t *s )
                             sms->qlevel_nb = strtoul( value, NULL, 10 );
                         if( !strcmp( name, "Url" ) )
                             sms->url_template = strdup(value);
-                        if( !strcmp( name, "Subtype" ) )
-                            if( !strcmp( value, "WmaPro" ) )
-                                Subtype = VLC_FOURCC('W', 'M', 'A', 'P' );
                     }
 
                     if( sms && !sms->timescale )
@@ -201,16 +239,6 @@ static int parse_Manifest( stream_t *s )
                     sms->name = stream_name;
                     sms->type = stream_type;
                     vlc_array_append( p_sys->sms_streams, sms );
-
-                    for( unsigned i = 0; i < p_sys->i_tracks; i++ )
-                    {
-                        sms = vlc_array_item_at_index( p_sys->sms_streams, i );
-                        if( (sms->type == stream_type) &&
-                                !(strcmp( stream_name, sms->name )) )
-                            break;
-                        else if( i == p_sys->i_tracks - 1 )
-                            msg_Err( s, "Updating of the manifest failed" );
-                    }
                 }
 
                 if( !strcmp( node, "QualityLevel" ) )
@@ -232,10 +260,22 @@ static int parse_Manifest( stream_t *s )
                         if( !strcmp( name, "CodecPrivateData" ) )
                             ql->CodecPrivateData = strdup( value );
                         if( !strcmp( name, "WaveFormatEx" ) )
-                            ql->CodecPrivateData = strdup( value );
-                        if( !strcmp( name, "MaxWidth" ) )
+                        {
+                            WaveFormatEx = decode_string_hex_to_binary( value );
+                            uint16_t data_len = ((uint16_t *)WaveFormatEx)[8];
+                            ql->CodecPrivateData = strndup( value + 36, data_len * 2 );
+
+                            uint16_t wf_tag = ((uint16_t *)WaveFormatEx)[0];
+                            wf_tag_to_fourcc( wf_tag, &ql->FourCC, NULL );
+
+                            ql->Channels = ((uint16_t *)WaveFormatEx)[1];
+                            ql->SamplingRate = ((uint32_t *)WaveFormatEx)[1];
+                            ql->nBlockAlign = ((uint16_t *)WaveFormatEx)[6];
+                            ql->BitsPerSample = ((uint16_t *)WaveFormatEx)[7];
+                        }
+                        if( !strcmp( name, "MaxWidth" ) || !strcmp( name, "Width" ) )
                             ql->MaxWidth = strtoul( value, NULL, 10 );
-                        if( !strcmp( name, "MaxHeight" ) )
+                        if( !strcmp( name, "MaxHeight" ) || !strcmp( name, "Height" ) )
                             ql->MaxHeight = strtoul( value, NULL, 10 );
                         if( !strcmp( name, "Channels" ) )
                             ql->Channels = strtoul( value, NULL, 10 );
@@ -244,13 +284,12 @@ static int parse_Manifest( stream_t *s )
                         if( !strcmp( name, "BitsPerSample" ) )
                             ql->BitsPerSample = strtoul( value, NULL, 10 );
                     }
-                    if( !ql->FourCC )
-                        ql->FourCC = Subtype;
                     vlc_array_append( sms->qlevels, ql );
                 }
 
                 if( !strcmp( node, "c" ) )
                 {
+                    loop_count++;
                     start_time = duration = -1;
                     while( (name = xml_ReaderNextAttr( vlc_reader, &value )) )
                     {
@@ -268,34 +307,61 @@ static int parse_Manifest( stream_t *s )
                     else if( duration == -1 )
                     {
                         assert( start_time != -1 );
+                        /* Handle weird Manifests which give only the start time
+                         * of the first segment. In those cases, we have to look
+                         * at the start time of the second segment to compute
+                         * the duration of the first one. */
+                        if( loop_count == 1 )
+                        {
+                            b_weird = true;
+                            computed_start_time = start_time;
+                            continue;
+                        }
+
                         computed_duration = start_time - computed_start_time;
-                        computed_start_time = start_time;
+                        if( !b_weird )
+                            computed_start_time = start_time;
                     }
                     else
                     {
-                        computed_start_time = start_time;
-                        computed_duration = duration;
+                        if( b_weird )
+                            computed_duration = start_time - computed_start_time;
+                        else
+                        {
+                            computed_start_time = start_time;
+                            computed_duration = duration;
+                        }
                     }
 
                     if( unlikely( chunk_New( sms, computed_duration,
                                         computed_start_time ) == NULL ) )
+                    {
                         return VLC_ENOMEM;
+                    }
+                    if( b_weird && start_time != -1 )
+                        computed_start_time = start_time;
                 }
                 break;
 
             case XML_READER_ENDELEM:
-                if( !strcmp( node, "StreamIndex" ) )
-                {
-                    stream_name = NULL;
-                    stream_type = UNKNOWN_ES;
-                    computed_start_time = 0;
-                    computed_duration = 0;
-                    next_qid = 1;
-
-                    if( sms->qlevel_nb == 0 )
-                        sms->qlevel_nb = vlc_array_count( sms->qlevels );
-                }
+                if( strcmp( node, "StreamIndex" ) )
+                    break;
+
+                stream_name = NULL;
+                stream_type = UNKNOWN_ES;
+                computed_start_time = 0;
+                computed_duration = 0;
+                loop_count = 0;
+                if( b_weird && !chunk_New( sms, computed_duration, computed_start_time ) )
+                    return VLC_ENOMEM;
+
+                b_weird = false;
+                next_qid = 1;
+
+                if( sms->qlevel_nb == 0 )
+                    sms->qlevel_nb = vlc_array_count( sms->qlevels );
                 break;
+
             case XML_READER_NONE:
                 break;
             case XML_READER_TEXT:
@@ -304,6 +370,7 @@ static int parse_Manifest( stream_t *s )
                 return VLC_EGENERIC;
         }
     }
+#undef TIMESCALE
 
     xml_ReaderDelete( vlc_reader );
     xml_Delete( vlc_xml );
@@ -321,50 +388,36 @@ static int Open( vlc_object_t *p_this )
 
     msg_Info( p_this, "Smooth Streaming (%s)", s->psz_path );
 
-    /* */
     s->p_sys = p_sys = calloc( 1, sizeof(*p_sys ) );
     if( unlikely( p_sys == NULL ) )
         return VLC_ENOMEM;
 
     char *uri = NULL;
-    if( asprintf( &uri,"%s://%s", s->psz_access, s->psz_path ) < 0)
+    if( unlikely( asprintf( &uri, "%s://%s", s->psz_access, s->psz_path ) < 0 ) )
     {
         free( p_sys );
         return VLC_ENOMEM;
     }
-    p_sys->ismc = uri;
 
     /* remove the last part of the url */
-    char *base_url = strdup( uri );
-    char *pos = strrchr( base_url, '/');
+    char *pos = strrchr( uri, '/');
     *pos = '\0';
-    p_sys->base_url = base_url;
+    p_sys->base_url = uri;
 
-    p_sys->download.vlead = 0;
     bool disable_audio = var_InheritBool( s, "smooth-disable-audio" );
-    if( disable_audio )
-        p_sys->download.alead = UINT64_MAX;
-    else
-        p_sys->download.alead = 0;
-    p_sys->download.tlead = 0;
-    p_sys->playback.boffset = 0;
-    /* UINT32_MAX is the index value of the initialization chunk */
-    p_sys->download.vindex = 0;
-    p_sys->download.aindex = 0;
-    p_sys->b_live = false;
-    p_sys->b_cache = true;
-    p_sys->b_error = false;
+    p_sys->download.alead = disable_audio ? UINT64_MAX : 0;
+
+    /* XXX I don't know wether or not we should allow caching */
+    p_sys->b_cache = false;
 
     p_sys->sms_streams = vlc_array_new();
-    p_sys->download.dld_chunks = vlc_array_new();
-    if( p_sys->sms_streams == NULL )
+    p_sys->download.chunks = vlc_array_new();
+    if( unlikely( !p_sys->sms_streams || !p_sys->download.chunks ) )
     {
         free( p_sys );
         return VLC_ENOMEM;
     }
 
-    p_sys->playback.peek_index = p_sys->playback.index = 0;
-
     /* Parse SMS ismc content. */
     if( parse_Manifest( s ) != VLC_SUCCESS )
     {
@@ -376,11 +429,13 @@ static int Open( vlc_object_t *p_this )
        p_sys->b_live = true;
 
     p_sys->i_tracks = vlc_array_count( p_sys->sms_streams );
-    p_sys->i_selected_tracks = 2;
+
+    /* FIXME */
+    p_sys->i_selected_tracks = 2; /* one video track and one audio track */
     if( disable_audio )
         p_sys->i_selected_tracks -= 1;
 
-    /* Choose first video stream available FIXME */
+    /* Choose first video stream available */
     sms_stream_t *vsms = NULL;
     for( unsigned i = 0; i < p_sys->i_tracks; i++ )
     {
@@ -393,7 +448,7 @@ static int Open( vlc_object_t *p_this )
     }
     p_sys->vstream = vsms;
 
-    /* Choose first audio stream available FIXME */
+    /* Choose first audio stream available */
     sms_stream_t *asms = NULL;
     for( unsigned i = 0; i < p_sys->i_tracks; i++ )
     {
@@ -407,29 +462,23 @@ static int Open( vlc_object_t *p_this )
     }
     p_sys->astream = asms;
 
-    /* Choose SMS quality to start with */
-    quality_level_t *wanted = vlc_array_item_at_index( vsms->qlevels, 0 );
-    quality_level_t *qlvl = NULL;
-    for( uint32_t i=1; i < vsms->qlevel_nb; i++ )
-    {
-        qlvl = vlc_array_item_at_index( vsms->qlevels, i );
-        if( qlvl->Bitrate < wanted->Bitrate )
-            wanted = qlvl;
-    }
-    vsms->download_qlvl = wanted->id;
+    /* Choose lowest quality for the first chunks */
+    quality_level_t *wanted, *qlvl;
+    sms_stream_t *sms = NULL;
 
-    wanted = vlc_array_item_at_index( asms->qlevels, 0 );
-    for( uint32_t i = 1; i < asms->qlevel_nb; i++)
+    for( unsigned i = 0; i < p_sys->i_tracks; i++ )
     {
-        qlvl = vlc_array_item_at_index( asms->qlevels, i );
-        if( qlvl->Bitrate < wanted->Bitrate )
-            wanted = qlvl;
+        wanted = qlvl = NULL;
+        sms = vlc_array_item_at_index( p_sys->sms_streams, i );
+        wanted = vlc_array_item_at_index( sms->qlevels, 0 );
+        for( unsigned i=1; i < sms->qlevel_nb; i++ )
+        {
+            qlvl = vlc_array_item_at_index( sms->qlevels, i );
+            if( qlvl->Bitrate < wanted->Bitrate )
+                wanted = qlvl;
+        }
+        sms->download_qlvl = wanted->id;
     }
-    asms->download_qlvl = wanted->id;
-
-
-
-    p_sys->playback.toffset = 0;
 
     vlc_mutex_init( &p_sys->download.lock_wait );
     vlc_cond_init( &p_sys->download.wait );
@@ -441,6 +490,7 @@ static int Open( vlc_object_t *p_this )
 
     if( vlc_clone( &p_sys->thread, sms_Thread, s, VLC_THREAD_PRIORITY_INPUT ) )
     {
+        free( p_sys );
         vlc_mutex_destroy( &p_sys->download.lock_wait );
         vlc_cond_destroy( &p_sys->download.wait );
         return VLC_EGENERIC;
@@ -454,254 +504,141 @@ static void Close( vlc_object_t *p_this )
     stream_t *s = (stream_t*)p_this;
     stream_sys_t *p_sys = s->p_sys;
 
-    msg_Dbg( s, "Joining dl thread" );
+    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;
+    p_sys->playback.toffset = 0;
+    vlc_cond_signal(&p_sys->download.wait);
+    vlc_mutex_unlock( &p_sys->download.lock_wait );
+
     vlc_join( p_sys->thread, NULL );
     vlc_mutex_destroy( &p_sys->download.lock_wait );
     vlc_cond_destroy( &p_sys->download.wait );
-    msg_Dbg( s, "dl thread joined" );
 
     /* Free sms streams */
+    sms_stream_t *sms;
     for( int i = 0; i < vlc_array_count( p_sys->sms_streams ); i++ )
     {
-        sms_stream_t *sms;
-        sms = (sms_stream_t *)vlc_array_item_at_index( p_sys->sms_streams, i );
-        if( sms) sms_Free( sms );
+        sms = vlc_array_item_at_index( p_sys->sms_streams, i );
+        if( sms)
+            sms_Free( sms );
     }
+
     vlc_array_destroy( p_sys->sms_streams );
+    vlc_array_destroy( p_sys->download.chunks );
 
-    if( p_sys->peeked )
-        block_Release( p_sys->peeked );
+    free( p_sys->base_url );
     free( p_sys );
 }
 
-static chunk_t *get_chunk( stream_t *s, uint32_t chunk_index, bool wait )
+static chunk_t *get_chunk( stream_t *s, bool wait )
 {
     stream_sys_t *p_sys = s->p_sys;
-    int count;
+    unsigned count;
     chunk_t *chunk = NULL;
 
     vlc_mutex_lock( &p_sys->download.lock_wait );
-    count = vlc_array_count( p_sys->download.dld_chunks );
-    while( chunk_index >= (uint32_t)count )
+    count = vlc_array_count( p_sys->download.chunks );
+    while( p_sys->playback.index >= count || p_sys->b_tseek )
     {
-        if( !wait || !vlc_object_alive( s ) )
-            goto fail;
-
-        msg_Dbg( s, "get_chunk is waiting !!!" );
-        vlc_cond_timedwait( &p_sys->download.wait,
-                &p_sys->download.lock_wait, mdate() + 100000 );
-        count = vlc_array_count( p_sys->download.dld_chunks );
-    }
-    chunk = vlc_array_item_at_index( p_sys->download.dld_chunks, chunk_index );
-    vlc_mutex_unlock( &p_sys->download.lock_wait );
-    return chunk;
-
-fail:
-    vlc_mutex_unlock( &p_sys->download.lock_wait );
-    msg_Warn( s, "get_chunk failed! (chunk_index %"PRIu32")", chunk_index );
-    return NULL;
-}
-
-static uint64_t GetStreamSize( stream_t *s )
-{
-    /* The returned size will be very approximative, but bitrate adaptation
-     * make computations a tad tricky anyway */
-    stream_sys_t *p_sys = s->p_sys;
-
-    if( p_sys->b_live )
-    {
-        chunk_t *chunk = get_chunk( s, p_sys->playback.index, false );
-        return chunk->size;
-    }
-
-    uint32_t video_chunk_nb = p_sys->vstream->vod_chunks_nb;
-    vlc_mutex_lock( &p_sys->vstream->lock );
-    chunk_t *first_video_chunk = vlc_array_item_at_index(
-            p_sys->vstream->chunks, 0 );
-    vlc_mutex_unlock( &p_sys->vstream->lock );
-    uint64_t chunk_duration = first_video_chunk->duration;
-    uint64_t total_duration = video_chunk_nb * chunk_duration /
-                                                p_sys->timescale;
-    uint64_t bitrate = 500000 /* FIXME */;
-    uint64_t size = bitrate * total_duration;
-
-    return size;
-}
-
-static int chunk_Seek( stream_t *s, const uint64_t pos )
-{
-    stream_sys_t *p_sys = s->p_sys;
-
-    if( pos == p_sys->playback.boffset )
-        return VLC_SUCCESS;
-    chunk_t *chunk = get_chunk( s, p_sys->playback.index, false );
-    if( chunk == NULL )
-        goto fail;
-    if( pos < chunk->offset )
-    {
-        if( p_sys->b_live || !p_sys->b_cache )
+        /* Yes I know, checking for p_sys->b_die is not reliable,
+         * that's why vlc_object_alive() has been deprecated. But if I
+         * understood well, there is no good solution with a stream_filter
+         * module anyaway. */
+        if( !wait || s->b_die || p_sys->b_error )
         {
-            msg_Warn( s, "Can't seek backward outside the current chunk" );
-            return VLC_EGENERIC;
+            vlc_mutex_unlock( &p_sys->download.lock_wait );
+            msg_Warn( s, "get_chunk failed! (playback index %u)",
+                    p_sys->playback.index );
+            return NULL;
         }
-        else
+        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) )
         {
-            msg_Dbg( s, "Seeking backward outside the current chunk" );
-            chunk->read_pos = 0;
-            p_sys->playback.index--;
-            msg_Dbg( s, "Seeking backward, to dld chunk %"PRIu32"",
-                                                        p_sys->playback.index);
-            chunk = get_chunk( s, p_sys->playback.index, false );
-            if( chunk == NULL )
-                goto fail;
-            chunk->read_pos = 0;
-            p_sys->playback.boffset = chunk->offset;
-            return chunk_Seek( s, pos );
+            vlc_mutex_unlock( &p_sys->download.lock_wait );
+            msg_Info( s, "No more chunks, end of the VOD" );
+            return NULL;
         }
-    }
-    else if( pos < chunk->offset + chunk->read_pos )
-    {
-        chunk->read_pos = pos - chunk->offset;
-    }
-    else
-    {
-        assert( pos >= p_sys->playback.boffset );
-        int len = pos - p_sys->playback.boffset;
-        int skipped = Read( s, NULL, len);
-        if( skipped == len )
-            goto success;
-    }
-
-success:
-    chunk = get_chunk( s, p_sys->playback.index, false );
-    if( chunk == NULL )
-        return VLC_EGENERIC;
-    msg_Dbg( s, "Seek successful! We are now at chunk %"PRIu32" type "\
-        "%i, offset %"PRIu64" + %i", chunk->sequence,
-        chunk->type, chunk->offset, chunk->read_pos );
-    return VLC_SUCCESS;
 
-fail:
-    msg_Warn( s, "chunk_Seek failed, maybe not enough dld chunks");
-    return VLC_EGENERIC;
-}
+        msg_Dbg( s, "get_chunk is waiting !!!" );
+        vlc_cond_timedwait( &p_sys->download.wait,
+                &p_sys->download.lock_wait, mdate() + 500000 );
+        count = vlc_array_count( p_sys->download.chunks );
+        msg_Dbg( s, "count is %u, and index is %u", count, p_sys->playback.index );
+    }
+    chunk = vlc_array_item_at_index( p_sys->download.chunks, p_sys->playback.index );
 
-static int Control( stream_t *s, int i_query, va_list args )
-{
-    stream_sys_t *p_sys = s->p_sys;
+    vlc_mutex_unlock( &p_sys->download.lock_wait );
 
-    switch( i_query )
-    {
-        case STREAM_CAN_SEEK:
-            *(va_arg( args, bool * )) = true;
-            break;
-        case STREAM_GET_POSITION:
-            *(va_arg( args, uint64_t * )) = p_sys->playback.boffset;
-            break;
-        case STREAM_SET_POSITION:
-            if( true )
-            {
-                uint64_t pos = (uint64_t)va_arg(args, uint64_t);
-                if (chunk_Seek(s, pos) == VLC_SUCCESS)
-                {
-                    p_sys->playback.boffset = pos;
-                    break;
-                }
-            }
-            return VLC_EGENERIC;
-        case STREAM_GET_SIZE:
-            *(va_arg( args, uint64_t * )) = GetStreamSize( s );
-            break;
-        default:
-            return VLC_EGENERIC;
-    }
-    return VLC_SUCCESS;
+    return chunk;
 }
 
-static int sms_Read( stream_t *s, uint8_t *p_read, unsigned int i_read,
-                                                                   bool peek )
+static int sms_Read( stream_t *s, uint8_t *p_read, int i_read )
 {
     stream_sys_t *p_sys = s->p_sys;
     int copied = 0;
     chunk_t *chunk = NULL;
-    int loop_count = 0;
-    uint32_t *chunk_index;
-    int *position;
-    int peek_pos = 0;
-
-    if( peek )
-        chunk_index = &p_sys->playback.peek_index;
-    else
-        chunk_index = &p_sys->playback.index;
 
     do
     {
-        chunk = get_chunk( s, *chunk_index, true );
+        chunk = get_chunk( s, true );
         if( !chunk )
             return copied;
 
-        if( peek )
+        if( chunk->read_pos >= (int)chunk->size )
         {
-            if( loop_count == 0 ) /* we start at read position */
-                peek_pos = chunk->read_pos;
-            position = &peek_pos;
-        }
-        else
-            position = &chunk->read_pos;
-
-        vlc_mutex_lock( &chunk->lock );
-
-        loop_count++;
-        if( *position >= (int)chunk->size )
-        {
-            if( chunk->type == VIDEO_ES && !peek )
+            if( chunk->type == VIDEO_ES )
             {
-                p_sys->playback.toffset += chunk->duration;
-                /* signal download thread */
                 vlc_mutex_lock( &p_sys->download.lock_wait );
-                vlc_cond_signal( &p_sys->download.wait );
+                p_sys->playback.toffset += chunk->duration;
                 vlc_mutex_unlock( &p_sys->download.lock_wait );
+                vlc_cond_signal( &p_sys->download.wait);
             }
-
-            if( !peek && (!p_sys->b_cache || p_sys->b_live) )
+            if( !p_sys->b_cache || p_sys->b_live )
             {
                 block_Release( chunk->data );
                 chunk->data = NULL;
             }
-            else if( chunk->size > 0 )
-                *position = 0;
 
-            *chunk_index += 1;
+            chunk->read_pos = 0;
+
+            p_sys->playback.index += 1;
             msg_Dbg( s, "Incrementing playback index" );
-            vlc_mutex_unlock( &chunk->lock );
 
             continue;
         }
 
-        if( *position == 0 )
+        if( chunk->read_pos == 0 )
         {
             const char *verb = p_read == NULL ? "skipping" : "reading";
-            msg_Dbg( s, "%s chunk %"PRIu32" (%u bytes), type %i",
-                        peek ? "peeking at" : verb,
-                        chunk->sequence, i_read, chunk->type );
+            msg_Dbg( s, "%s chunk %u (%u bytes), type %i",
+                        verb, chunk->sequence, i_read, chunk->type );
+            /* check integrity */
+            uint32_t type;
+            uint8_t *slice = chunk->data->p_buffer;
+            SMS_GET4BYTES( type );
+            SMS_GETFOURCC( type );
+            assert( type == ATOM_moof || type == ATOM_uuid );
         }
 
         int len = -1;
-        uint8_t *src = chunk->data->p_buffer + *position;
-        if( i_read <= (chunk->size - *position) )
+        uint8_t *src = chunk->data->p_buffer + chunk->read_pos;
+        if( i_read <= chunk->size - chunk->read_pos )
             len = i_read;
         else
-            len = chunk->size - *position;
+            len = chunk->size - chunk->read_pos;
 
         if( len > 0 )
         {
             if( p_read ) /* otherwise caller skips data */
                 memcpy( p_read + copied, src, len );
-            *position += len;
+            chunk->read_pos += len;
             copied += len;
             i_read -= len;
         }
-        vlc_mutex_unlock( &chunk->lock );
+
 
     } while ( i_read > 0 );
 
@@ -716,39 +653,126 @@ static int Read( stream_t *s, void *buffer, unsigned i_read )
     if( p_sys->b_error )
         return 0;
 
-    if( !buffer ) msg_Dbg(s, "Caller skips data (%i bytes)", i_read );
-    else msg_Dbg( s, "Demuxer wants to read %i bytes", i_read );
-
-    length = sms_Read( s, (uint8_t*) buffer, i_read, false );
+    length = sms_Read( s, (uint8_t*) buffer, i_read );
     if( length < 0 )
         return 0;
 
+    /* This call to sms_Read will increment p_sys->playback.index
+     * in case the last chunk we read into is entirely read */
+    sms_Read( s, NULL, 0 );
+
     p_sys->playback.boffset += length;
     if( (unsigned)length < i_read )
-        msg_Warn( s, "could not read %u bytes, only %i!", i_read, length );
+        msg_Warn( s, "could not read %i bytes, only %i!", i_read, length );
+
     return length;
 }
 
-static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned int i_peek )
+/* The MP4 demux should never have to to peek outside the current chunk */
+static int Peek( stream_t *s, const uint8_t **pp_peek, unsigned i_peek )
 {
     stream_sys_t *p_sys = s->p_sys;
-    msg_Dbg( s, "Demuxer wants to peek %i bytes", i_peek );
-    block_t *peeked = p_sys->peeked;
-    p_sys->playback.peek_index = p_sys->playback.index;
 
-    if( peeked == NULL )
-        peeked = block_Alloc ( i_peek );
-    else if( peeked->i_buffer < i_peek)
-        peeked = block_Realloc( peeked, 0, i_peek );
-
-    if( (p_sys->peeked = peeked) == NULL )
+    chunk_t *chunk = get_chunk( s, true );
+    if( chunk )
+        assert( chunk->data );
+    else
         return 0;
 
-    int val = sms_Read( s, peeked->p_buffer, i_peek, true );
+    int bytes = chunk->size - chunk->read_pos;
+    assert( bytes > 0 );
+
+    if( (unsigned)bytes < i_peek )
+    {
+        msg_Err( s, "could not peek %u bytes, only %i!", i_peek, bytes );
+    }
+    msg_Dbg( s, "peeking at chunk %u!", chunk->sequence );
+    *pp_peek = chunk->data->p_buffer + chunk->read_pos;
+
+    return bytes;
+}
+
+/* Not being able to distinguish between a time seek and a byte seek is
+ * annoying. However, if FAKE_STREAM_SIZE is small enough, say 1000,
+ * then we can reasonably assume that pos > 1000 means that the demux
+ * wants to *byte* seek. This is important because if we treat a time seek
+ * as a byte seek, then the demux would get bytes of the current chunk, during
+ * the next call to Peek() or Read(), instead of a new initialization chunk,
+ * followed by the new downloaded chunks, as it is normally the case for a time
+ * seek. And that would result in a bug */
+static int chunk_Seek( stream_t *s, const uint64_t pos )
+{
+    stream_sys_t *p_sys = s->p_sys;
+
+    if( pos == p_sys->playback.boffset )
+        return VLC_SUCCESS;
+
+    chunk_t *chunk = get_chunk( s, false );
+    if( chunk == NULL )
+        return VLC_EGENERIC;
 
-    *pp_peek = peeked->p_buffer;
-    if( (unsigned)val < i_peek )
-        msg_Warn( s, "could not peek %u bytes, only %i!", i_peek, val );
+    bool inside_chunk = pos >= chunk->offset &&
+            pos < (chunk->offset + chunk->size) ? true : false;
 
-    return val;
+    assert( !end_of_chunk );
+
+    if( inside_chunk )
+    {
+        chunk->read_pos = pos - chunk->offset;
+        p_sys->playback.boffset = pos;
+        return VLC_SUCCESS;
+    }
+    else
+    {
+        if( p_sys->b_live )
+        {
+            msg_Err( s, "Cannot seek outside the current chunk for a live stream" );
+            return VLC_EGENERIC;
+        }
+
+        msg_Info( s, "Seeking outside the current chunk" );
+        assert( pos <= FAKE_STREAM_SIZE );
+
+        vlc_mutex_lock( &p_sys->download.lock_wait );
+
+        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;
+        p_sys->playback.toffset = 0;
+
+        vlc_cond_signal( &p_sys->download.wait);
+        vlc_mutex_unlock( &p_sys->download.lock_wait );
+
+        return VLC_SUCCESS;
+    }
+}
+
+static int Control( stream_t *s, int i_query, va_list args )
+{
+    stream_sys_t *p_sys = s->p_sys;
+
+    switch( i_query )
+    {
+        case STREAM_CAN_SEEK:
+            *(va_arg( args, bool * )) = true;
+            break;
+        case STREAM_GET_POSITION:
+            *(va_arg( args, uint64_t * )) = p_sys->playback.boffset;
+            break;
+        case STREAM_SET_POSITION:
+            {
+                uint64_t pos = (uint64_t)va_arg(args, uint64_t);
+                int ret = chunk_Seek(s, pos);
+                if( ret == VLC_SUCCESS )
+                    break;
+                else
+                    return VLC_EGENERIC;
+            }
+        case STREAM_GET_SIZE:
+            *(va_arg( args, uint64_t * )) = FAKE_STREAM_SIZE;
+            break;
+        default:
+            return VLC_EGENERIC;
+    }
+    return VLC_SUCCESS;
 }
diff --git a/modules/stream_filter/smooth/smooth.h b/modules/stream_filter/smooth/smooth.h
index 2499960..5a593d0 100644
--- a/modules/stream_filter/smooth/smooth.h
+++ b/modules/stream_filter/smooth/smooth.h
@@ -43,13 +43,12 @@ typedef struct chunk_s
 {
     int64_t     duration;   /* chunk duration (seconds / TimeScale) */
     int64_t     start_time; /* PTS (seconds / TimeScale) */
-    int64_t     size;       /* chunk size in bytes */
-    uint32_t    sequence;   /* unique sequence number */
+    int         size;       /* chunk size in bytes */
+    unsigned    sequence;   /* unique sequence number */
     uint64_t    offset;     /* offset in the media */
     int         read_pos;   /* position in the chunk */
     int         type;       /* video, audio, or subtitles */
 
-    vlc_mutex_t lock;
     block_t     *data;
 } chunk_t;
 
@@ -57,16 +56,17 @@ typedef struct quality_level_s
 {
     int             Index;
     uint32_t        FourCC;
-    uint32_t        Bitrate;
-    uint32_t        MaxWidth;
-    uint32_t        MaxHeight;
+    unsigned        Bitrate;
+    unsigned        MaxWidth;
+    unsigned        MaxHeight;
     unsigned        SamplingRate;
     unsigned        Channels;
     unsigned        BitsPerSample;
-    uint32_t        PacketSize;
-    uint32_t        AudioTag;
+    unsigned        PacketSize;
+    unsigned        AudioTag;
+    unsigned        nBlockAlign;
     char            *CodecPrivateData; /* hex encoded string */
-    uint16_t        id;
+    unsigned        id;
 
 } quality_level_t;
 
@@ -74,27 +74,25 @@ typedef struct sms_stream_s
 {
     vlc_array_t    *qlevels;       /* list of available Quality Levels */
     vlc_array_t    *chunks;        /* list of chunks */
-    uint32_t       vod_chunks_nb;  /* total num of chunks of the VOD stream */
-    uint32_t       timescale;
-    uint32_t       qlevel_nb;      /* number of quality levels */
-    uint32_t       id;             /* track id, will be set arbitrarily */
+    unsigned       vod_chunks_nb;  /* total num of chunks of the VOD stream */
+    unsigned       timescale;
+    unsigned       qlevel_nb;      /* number of quality levels */
+    unsigned       id;             /* track id, will be set arbitrarily */
     char           *name;
     char           *url_template;
     int            type;
-    uint16_t       download_qlvl; /* current quality level ID for Download() */
-    vlc_mutex_t    lock;
+    unsigned       download_qlvl; /* current quality level ID for Download() */
 
 } sms_stream_t;
 
 struct stream_sys_t
 {
-    char         *ismc;        /* Manifest url */
+    FILE         *bw_record;
+    FILE         *avg_bw_rcd;
+    FILE         *ql_lvl_rcd;
     char         *base_url;    /* URL common part for chunks */
     vlc_thread_t thread;       /* SMS chunk download thread */
 
-    block_t      *peeked;
-
-    /* */
     vlc_array_t  *sms_streams; /* array of sms_stream_t */
     sms_stream_t *vstream;     /* current video stream  */
     sms_stream_t *astream;     /* current audio stream  */
@@ -103,7 +101,8 @@ struct stream_sys_t
     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 */
-    uint32_t     timescale;
+    int64_t      time_pos;
+    unsigned     timescale;
 
     /* Download */
     struct sms_download_s
@@ -112,12 +111,13 @@ struct stream_sys_t
         uint64_t     vlead;       // available (downloaded),
         uint64_t     tlead;       // in seconds / TimeScale
 
-        uint32_t     aindex;      /* current audio chunk for download */
-        uint32_t     vindex;      /*         video                    */
-        uint32_t     sindex;      /*         spu                      */
+        unsigned     aindex;      /* current audio chunk for download */
+        unsigned     vindex;      /*         video                    */
+        unsigned     sindex;      /*         spu                      */
 
-        vlc_array_t  *dld_chunks; /* chunks that have been downloaded */
-        vlc_mutex_t  lock_wait;   /* protect chunk download counter */
+        uint64_t     next_chunk_offset;
+        vlc_array_t  *chunks;     /* chunks that have been downloaded */
+        vlc_mutex_t  lock_wait;   /* protect chunk download counter. */
         vlc_cond_t   wait;        /* some condition to wait on */
     } download;
 
@@ -126,14 +126,15 @@ struct stream_sys_t
     {
         uint64_t    boffset;     /* current byte offset in media */
         uint64_t    toffset;     /* current time offset in media */
-        uint32_t    index;       /* current chunk for playback */
-        uint32_t    peek_index;
+        unsigned    index;       /* current chunk for playback */
     } 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 { \
@@ -170,7 +171,7 @@ struct stream_sys_t
 sms_queue_t *sms_queue_init( int );
 void sms_queue_put( sms_queue_t *, uint64_t );
 uint64_t sms_queue_avg( sms_queue_t *);
-quality_level_t *get_qlevel( sms_stream_t *, uint16_t );
+quality_level_t *get_qlevel( sms_stream_t *, unsigned );
 void* sms_Thread( void *);
 quality_level_t * ql_New( void );
 void ql_Free( quality_level_t *);
@@ -178,5 +179,6 @@ chunk_t *chunk_New( 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 * );
 
 #endif
diff --git a/modules/stream_filter/smooth/utils.c b/modules/stream_filter/smooth/utils.c
index 3eeac36..5a6bd99 100644
--- a/modules/stream_filter/smooth/utils.c
+++ b/modules/stream_filter/smooth/utils.c
@@ -27,14 +27,46 @@
 #include <vlc_common.h>
 #include <vlc_es.h>
 #include <vlc_block.h>
+#include <assert.h>
 
 #include "smooth.h"
 
+static int hex_digit( char c )
+{
+    if (c >= 'A' && c <= 'F')
+        return c - 'A' + 10;
+    else if (c >= 'a' && c <= 'f')
+        return c - 'a' + 10;
+    else if (c >= '0' && c<= '9')
+        return c - '0';
+    else
+        return -1;
+}
+
+uint8_t *decode_string_hex_to_binary( const char *psz_src )
+{
+    int i = 0, j = 0, first_digit, second_digit;
+    int i_len = strlen( psz_src );
+    uint8_t *p_data = malloc ( i_len / 2 );
+
+    if( !p_data )
+        return NULL;
+
+    while( i < i_len )
+    {
+        first_digit = hex_digit( psz_src[i++] );
+        second_digit = hex_digit( psz_src[i++] );
+        p_data[j++] = ( first_digit << 4 ) | second_digit;
+    }
+
+    return p_data;
+}
+
 quality_level_t * ql_New( void )
 {
     quality_level_t *ql = calloc( 1, sizeof( quality_level_t ) );
-    if( unlikely( ql == NULL ) )
-        return NULL;
+    if( unlikely( !ql ) ) return NULL;
+
     ql->Index = -1;
     return ql;
 }
@@ -56,18 +88,13 @@ chunk_t *chunk_New( sms_stream_t* sms, uint64_t duration,\
     chunk->duration = duration;
     chunk->start_time = start_time;
     chunk->type = UNKNOWN_ES;
-    vlc_mutex_lock( &sms->lock );
     chunk->sequence = vlc_array_count( sms->chunks );
     vlc_array_append( sms->chunks, chunk );
-    vlc_mutex_unlock( &sms->lock );
-    vlc_mutex_init( &chunk->lock );
     return chunk;
 }
 
 void chunk_Free( chunk_t *chunk )
 {
-    vlc_mutex_destroy( &chunk->lock );
-
     if( chunk->data )
         block_Release( chunk->data );
     free( chunk );
@@ -77,12 +104,11 @@ void chunk_Free( chunk_t *chunk )
 sms_stream_t * sms_New( void )
 {
     sms_stream_t *sms = calloc( 1, sizeof( sms_stream_t ) );
-    if( unlikely( sms == NULL ) )
-        return NULL;
+    if( unlikely( !sms ) ) return NULL;
+
     sms->qlevels = vlc_array_new();
     sms->chunks = vlc_array_new();
     sms->type = UNKNOWN_ES;
-    vlc_mutex_init( &sms->lock );
     return sms;
 }
 
@@ -92,8 +118,7 @@ void sms_Free( sms_stream_t *sms )
     {
         for( int n = 0; n < vlc_array_count( sms->qlevels ); n++ )
         {
-            quality_level_t *qlevel =\
-                (quality_level_t *)vlc_array_item_at_index( 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 );
@@ -103,8 +128,7 @@ void sms_Free( sms_stream_t *sms )
     {
         for( int n = 0; n < vlc_array_count( sms->chunks ); n++ )
         {
-            chunk_t *chunk =\
-                (chunk_t *)vlc_array_item_at_index( sms->chunks, n );
+            chunk_t *chunk = vlc_array_item_at_index( sms->chunks, n );
             if( chunk) chunk_Free( chunk );
         }
         vlc_array_destroy( sms->chunks );
@@ -114,7 +138,7 @@ void sms_Free( sms_stream_t *sms )
     sms = NULL;
 }
 
-quality_level_t *get_qlevel( sms_stream_t *sms, uint16_t qid )
+quality_level_t *get_qlevel( sms_stream_t *sms, unsigned qid )
 {
     quality_level_t *qlevel = NULL;
     for( unsigned i = 0; i < sms->qlevel_nb; i++ )
@@ -149,6 +173,8 @@ void sms_queue_put( sms_queue_t *queue, uint64_t value )
         FREENULL( last );
 
     item_t *new = malloc( sizeof( item_t ) );
+    assert( new );
+
     new->value = value;
     new->next = queue->first;
     queue->first = new;
-- 
1.7.10.4




More information about the vlc-devel mailing list