diff --git a/configure.ac b/configure.ac
index c04857c..4e7c760 100644
--- a/configure.ac
+++ b/configure.ac
@@ -944,7 +944,7 @@ AC_CHECK_HEADERS(zlib.h, [ have_zlib=yes ], [ have_zlib=no ])
 AM_CONDITIONAL(HAVE_ZLIB, [ test "${have_zlib}" = "yes" ])
 if test "${have_zlib}" = "yes"
 then
-  VLC_ADD_LIBS([access_http gme mp4 skins2 sap mkv unzip zip],[-lz])
+  VLC_ADD_LIBS([access_http gme mp4 skins2 sap smoothstream mkv unzip zip],[-lz])
   PKG_CHECK_MODULES([MINIZIP], [minizip] , [ have_minizip=yes ], [
     AC_CHECK_HEADERS([unzip.h], [ 
       have_minizip=yes
@@ -3215,7 +3215,7 @@ AC_ARG_ENABLE(libsysfs,
 
 AS_IF([test "${enable_libsysfs}" != "no"],[
   AC_CHECK_HEADERS(sysfs/libsysfs.h, [
-    VLC_ADD_LIBS([mp4 mkv],[-lsysfs])
+    VLC_ADD_LIBS([mp4 mkv smoothstream],[-lsysfs])
   ] )
 ])
 
diff --git a/modules/demux/Modules.am b/modules/demux/Modules.am
index ca4ca22..c4dc945 100644
--- a/modules/demux/Modules.am
+++ b/modules/demux/Modules.am
@@ -31,6 +31,8 @@ SOURCES_vc1 = vc1.c
 SOURCES_demux_cdg = cdg.c
 SOURCES_smf = smf.c
 SOURCES_dirac = dirac.c
+SOURCES_smoothstream = smoothstream.c ./mp4/libmp4.c ./mp4/drms.c
+LTLIB_smoothstream = -lz
 
 libvlc_LTLIBRARIES += \
 	libaiff_plugin.la \
@@ -50,6 +52,7 @@ libvlc_LTLIBRARIES += \
 	librawvid_plugin.la \
 	libreal_plugin.la \
 	libsmf_plugin.la \
+	libsmoothstream_plugin.la \
 	libsubtitle_plugin.la \
 	libtta_plugin.la \
 	libty_plugin.la \
diff --git a/modules/demux/mp4/libmp4.c b/modules/demux/mp4/libmp4.c
index f8869a5..524e692 100644
--- a/modules/demux/mp4/libmp4.c
+++ b/modules/demux/mp4/libmp4.c
@@ -476,6 +476,129 @@ static int MP4_ReadBox_mvhd(  stream_t *p_stream, MP4_Box_t *p_box )
     MP4_READBOX_EXIT( 1 );
 }
 
+static int MP4_ReadBox_mfhd(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_mfhd_t );
+
+    MP4_GET4BYTES( p_box->data.p_mfhd->i_sequence_number );
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"mfhd\" sequence number %d",
+       		p_box->data.p_mfhd->i_sequence_number );
+#endif
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_tfhd(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    MP4_READBOX_ENTER( MP4_Box_data_tfhd_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_tfhd );
+
+    MP4_GET4BYTES( p_box->data.p_tfhd->i_track_ID );
+
+    if( p_box->data.p_tfhd->i_version == 0 )
+    {
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+	    MP4_GET8BYTES( p_box->data.p_tfhd->i_base_data_offset );
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+	    MP4_GET4BYTES( p_box->data.p_tfhd->i_sample_description_index );
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+	    MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_duration );
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+	    MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_size );
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+	    MP4_GET4BYTES( p_box->data.p_tfhd->i_default_sample_flags );
+
+#ifdef MP4_VERBOSE
+	char psz_base[128] = "\0";
+	char psz_desc[128] = "\0";
+	char psz_dura[128] = "\0";
+	char psz_size[128] = "\0";
+	char psz_flag[128] = "\0";
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+	    snprintf(psz_base, sizeof(psz_base), "base offset %lld", p_box->data.p_tfhd->i_base_data_offset);
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_SAMPLE_DESC_INDEX )
+	    snprintf(psz_desc, sizeof(psz_desc), "sample description index %d", p_box->data.p_tfhd->i_sample_description_index);
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+	    snprintf(psz_dura, sizeof(psz_dura), "sample duration %d", p_box->data.p_tfhd->i_default_sample_duration);
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+	    snprintf(psz_size, sizeof(psz_size), "sample size %d", p_box->data.p_tfhd->i_default_sample_size);
+	if( p_box->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+	    snprintf(psz_flag, sizeof(psz_flag), "sample flags 0x%x", p_box->data.p_tfhd->i_default_sample_flags);
+
+	msg_Dbg( p_stream, "read box: \"tfhd\" version %d flags 0x%x track ID %d %s %s %s %s %s",
+		    p_box->data.p_tfhd->i_version,
+	 	    p_box->data.p_tfhd->i_flags,
+		    p_box->data.p_tfhd->i_track_ID,
+		    psz_base, psz_desc, psz_dura, psz_size, psz_flag );
+#endif
+    }
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static int MP4_ReadBox_trun(  stream_t *p_stream, MP4_Box_t *p_box )
+{
+    unsigned int i;
+
+    MP4_READBOX_ENTER( MP4_Box_data_trun_t );
+
+    MP4_GETVERSIONFLAGS( p_box->data.p_trun );
+
+    MP4_GET4BYTES( p_box->data.p_trun->i_sample_count );
+
+    if( p_box->data.p_trun->i_flags & MP4_TRUN_DATA_OFFSET )
+	MP4_GET8BYTES( p_box->data.p_trun->i_data_offset );
+    if( p_box->data.p_trun->i_flags & MP4_TRUN_FIRST_FLAGS )
+	MP4_GET4BYTES( p_box->data.p_trun->i_first_sample_flags );
+
+    p_box->data.p_trun->p_samples = 
+      calloc( p_box->data.p_trun->i_sample_count, sizeof(MP4_descriptor_trun_sample_t) );
+    if ( p_box->data.p_trun->p_samples == NULL )
+      MP4_READBOX_EXIT( 0 );
+
+    for( i=0; i<p_box->data.p_trun->i_sample_count; i++ )
+    {
+      	MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+	if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION )
+	    MP4_GET4BYTES( p_sample->i_duration );
+	if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE )
+	    MP4_GET4BYTES( p_sample->i_size );
+	if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS )
+	    MP4_GET4BYTES( p_sample->i_flags );
+	if( p_box->data.p_trun->i_flags & MP4_TRUN_SAMPLE_TIME_OFFSET )
+	    MP4_GET4BYTES( p_sample->i_composition_time_offset );
+    }
+
+#ifdef MP4_VERBOSE
+    msg_Dbg( p_stream, "read box: \"trun\" version %d flags 0x%x sample count %d",
+		  p_box->data.p_trun->i_version,
+		  p_box->data.p_trun->i_flags,
+		  p_box->data.p_trun->i_sample_count );
+#if 1
+    for( i=0; i<p_box->data.p_trun->i_sample_count; i++ )
+    {
+      	MP4_descriptor_trun_sample_t *p_sample = &p_box->data.p_trun->p_samples[i];
+	msg_Dbg( p_stream, "read box: \"trun\" sample %4.4d flags 0x%x duration %d size %d composition time offset %d",
+	    		i, p_sample->i_flags, p_sample->i_duration,
+		       	p_sample->i_size, p_sample->i_composition_time_offset );
+
+    }
+#endif
+	  	    
+#endif
+
+    MP4_READBOX_EXIT( 1 );
+}
+
+static void MP4_FreeBox_trun( MP4_Box_t *p_box )
+{
+    FREENULL( p_box->data.p_trun->p_samples );
+}
+
+
+
 static int MP4_ReadBox_tkhd(  stream_t *p_stream, MP4_Box_t *p_box )
 {
     unsigned int i;
@@ -2445,6 +2568,7 @@ static int MP4_ReadBox_meta( stream_t *p_stream, MP4_Box_t *p_box )
     return MP4_ReadBoxContainerRaw( p_stream, p_box );
 }
 
+
 /* For generic */
 static int MP4_ReadBox_default( stream_t *p_stream, MP4_Box_t *p_box )
 {
@@ -2691,6 +2815,12 @@ static const struct
     /* iTunes/Quicktime meta info */
     { FOURCC_meta,  MP4_ReadBox_meta,       MP4_FreeBox_Common },
 
+    /* found in smoothstreaming */
+    { FOURCC_traf,  MP4_ReadBoxContainer,      MP4_FreeBox_Common },
+    { FOURCC_mfhd,  MP4_ReadBox_mfhd,          MP4_FreeBox_Common },
+    { FOURCC_tfhd,  MP4_ReadBox_tfhd,          MP4_FreeBox_Common },
+    { FOURCC_trun,  MP4_ReadBox_trun,          MP4_FreeBox_trun },
+
     /* Last entry */
     { 0,             MP4_ReadBox_default,       NULL }
 };
diff --git a/modules/demux/mp4/libmp4.h b/modules/demux/mp4/libmp4.h
index a4e786d..3ebed94 100644
--- a/modules/demux/mp4/libmp4.h
+++ b/modules/demux/mp4/libmp4.h
@@ -810,6 +810,63 @@ typedef struct
 
 } MP4_Box_data_rmqu_t;
 
+typedef struct MP4_Box_data_mfhd_s
+{
+    uint32_t i_sequence_number;
+
+    uint8_t *p_vendor_extension;
+
+} MP4_Box_data_mfhd_t;
+
+#define MP4_TFHD_BASE_DATA_OFFSET     (1UL<<0)
+#define MP4_TFHD_SAMPLE_DESC_INDEX    (1UL<<1)
+#define MP4_TFHD_DFLT_SAMPLE_DURATION (1UL<<3)
+#define MP4_TFHD_DFLT_SAMPLE_SIZE     (1UL<<4)
+#define MP4_TFHD_DFLT_SAMPLE_FLAGS    (1UL<<5)
+typedef struct MP4_Box_data_tfhd_s
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+    uint32_t i_track_ID;
+
+    /* optional fields */
+    uint64_t i_base_data_offset;
+    uint32_t i_sample_description_index;
+    uint32_t i_default_sample_duration;
+    uint32_t i_default_sample_size;
+    uint32_t i_default_sample_flags;
+
+} MP4_Box_data_tfhd_t;
+
+#define MP4_TRUN_DATA_OFFSET         (1UL<<0)
+#define MP4_TRUN_FIRST_FLAGS         (1UL<<2)
+#define MP4_TRUN_SAMPLE_DURATION     (1UL<<8)
+#define MP4_TRUN_SAMPLE_SIZE         (1UL<<9)
+#define MP4_TRUN_SAMPLE_FLAGS        (1UL<<10)
+#define MP4_TRUN_SAMPLE_TIME_OFFSET  (1UL<<11)
+typedef struct MP4_descriptor_trun_sample_t
+{
+      uint32_t i_duration;
+      uint32_t i_size;
+      uint32_t i_flags;
+      uint32_t i_composition_time_offset;
+} MP4_descriptor_trun_sample_t;
+
+typedef struct MP4_Box_data_trun_s
+{
+    uint8_t  i_version;
+    uint32_t i_flags;
+    uint32_t i_sample_count;
+
+    /* optional fields */
+    uint32_t i_data_offset;
+    uint32_t i_first_sample_flags;
+
+    MP4_descriptor_trun_sample_t *p_samples;
+
+} MP4_Box_data_trun_t;
+
+
 typedef struct
 {
     char *psz_text;
@@ -886,6 +943,9 @@ typedef union MP4_Box_data_s
 {
     MP4_Box_data_ftyp_t *p_ftyp;
     MP4_Box_data_mvhd_t *p_mvhd;
+    MP4_Box_data_mfhd_t *p_mfhd;
+    MP4_Box_data_tfhd_t *p_tfhd;
+    MP4_Box_data_trun_t *p_trun;
     MP4_Box_data_tkhd_t *p_tkhd;
     MP4_Box_data_mdhd_t *p_mdhd;
     MP4_Box_data_hdlr_t *p_hdlr;
diff --git a/modules/demux/mp4/mp4.c b/modules/demux/mp4/mp4.c
index c07bb1d..4be858c 100644
--- a/modules/demux/mp4/mp4.c
+++ b/modules/demux/mp4/mp4.c
@@ -349,7 +349,7 @@ static int Open( vlc_object_t * p_this )
     /* the file need to have one moov box */
     if( MP4_BoxCount( p_sys->p_root, "/moov" ) <= 0 )
     {
-        MP4_Box_t *p_foov = MP4_BoxGet( p_sys->p_root, "/foov" );
+        MP4_Box_t *p_foov = MP4_BoxGet( p_sys->p_root, "/moof" );
 
         if( !p_foov )
         {
diff --git a/modules/demux/smoothstream.c b/modules/demux/smoothstream.c
new file mode 100644
index 0000000..0a5f1fa
--- /dev/null
+++ b/modules/demux/smoothstream.c
@@ -0,0 +1,1363 @@
+/*****************************************************************************
+ * smoothstream.c : SmoothStream
+ * vim: set sw=4 cino= :
+ *****************************************************************************
+ * Copyright (C) 2003-2007 the VideoLAN team
+ *
+ * Authors: Luc Saillard <luc at saillard . org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+/*
+ * TODO:
+ *  for the SPS, look into live555
+ *  
+ *       parseH264ConfigStr();
+ *       configSize += vlc_b64_decode_binary_to_buffer( cfg+configSize,
+ *                                         configMax-configSize, psz );
+ */
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+#include <vlc_demux.h>
+#include <vlc_plugin.h>
+#include <vlc_xml.h>
+#include <vlc_strings.h>
+#include <vlc_url.h>
+#include <vlc_codecs.h>
+
+#include <errno.h>
+#include "mp4/libmp4.h"
+
+#define SMS_DEBUG_XML_STREAM 0
+#define SMS_MAX_STREAMS 4
+#define SMS_MAX_BITRATES 16
+
+#define MP4_BOX_HEADERSIZE( p_box )             \
+  ( 8 + ( p_box->i_shortsize == 1 ? 8 : 0 )     \
+      + ( p_box->i_type == FOURCC_uuid ? 16 : 0 ) )
+
+enum sms_stream_type {
+   SMS_STREAM_AUDIO=0,
+   SMS_STREAM_VIDEO,
+};
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+static int  Open ( vlc_object_t * );
+static void Close( vlc_object_t * );
+
+
+vlc_module_begin ()
+    set_description( N_("smooth stream demuxer") )
+    set_category( CAT_INPUT )
+    set_subcategory( SUBCAT_INPUT_DEMUX )
+    set_capability( "demux", 142 )
+    set_callbacks( Open, Close )
+vlc_module_end ()
+
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+struct sms_chunk_t
+{
+    uint64_t i_duration;
+    uint64_t i_time;
+};
+
+struct sms_bitrate_t
+{
+    unsigned int i_index;
+    unsigned int i_bitrate;
+    unsigned int i_width;
+    unsigned int i_height;
+    vlc_fourcc_t i_subtype;	/* WVC1/H264/WmaPro */
+    uint8_t      *p_codec_private_data;
+    size_t        i_codec_private_data_length;
+};
+
+struct sms_stream_t
+{
+    enum sms_stream_type i_type;	/* Video/Audio */
+    vlc_fourcc_t         i_subtype;	/* WVC1/H264/WmaPro */
+    unsigned int         i_chunks;	/* number of chunk for this stream */
+    char                 *p_url;	/* Additionnal parameters to get the url */
+    int64_t		  i_timescale;
+
+    unsigned int          i_bitrate;			/* number of bitrates */
+    struct sms_bitrate_t *bitrates[SMS_MAX_BITRATES];	/* array of bitrates supported for this stream */
+    struct sms_bitrate_t *p_selected_bitrate;		/* current bitrate */
+
+    unsigned int          i_chunk_allocated;
+    struct sms_chunk_t   *chunks;
+
+    es_format_t           fmt;
+    es_out_id_t          *p_es;
+    stream_t		 *p_stream;
+
+    unsigned int          i_sample;	/* Currently sample being play into the chunk downloaded */
+    unsigned int          i_chunk;	/* Currently the chunk downloaded */
+
+};
+
+struct demux_sys_t
+{
+    int64_t		 i_duration;
+    int64_t		 i_timescale;
+    bool		 b_is_live;
+
+    unsigned int         i_stream;	/* Number of streams in streams */
+    struct sms_stream_t *streams[SMS_MAX_STREAMS];
+
+    struct sms_stream_t *stream_audio;
+    struct sms_stream_t *stream_video;
+
+};
+
+static int Demux  ( demux_t * );
+static int Control( demux_t *, int , va_list );
+
+static void sms_free_stream( struct sms_stream_t * );
+static void sms_free_bitrate( struct sms_bitrate_t * );
+
+static int sms_read_manifest( demux_t *p_demux );
+static int sms_stream_begin( demux_t *p_demux );
+
+static char *sms_stream_build_url( demux_t *p_demux, struct sms_stream_t *p_stream );
+
+/*****************************************************************************
+ * DemuxOpen:
+ *****************************************************************************/
+static int  Open ( vlc_object_t *p_this )
+{
+    demux_t *p_demux = (demux_t *)p_this;
+    const uint8_t *p_peek;
+
+    /* A little test to see if it could be a mp4 */
+    if( stream_Peek( p_demux->s, &p_peek, 128 ) < 128 ) return VLC_EGENERIC;
+
+    if( strcasestr( (const char *)p_peek, "<SMOOTHSTREAMINGMEDIA" ) ||
+	demux_IsPathExtension( p_demux, ".ism/Manifest" ) ||
+	demux_IsPathExtension( p_demux, ".ism" ) ||
+        demux_IsForced( p_demux, "sms-open" ) )
+    {
+        ;
+    }
+    else
+        return VLC_EGENERIC;
+
+    DEMUX_INIT_COMMON();
+
+    if (sms_read_manifest( p_demux ) == -1)
+	return VLC_EGENERIC;
+
+    sms_stream_begin( p_demux );
+
+    msg_Dbg( p_demux, "found valid SmoothStream video" );
+
+    return VLC_SUCCESS;
+}
+
+/*****************************************************************************
+ * DemuxClose:
+ *****************************************************************************/
+static void Close( vlc_object_t *p_this )
+{
+    demux_t *p_demux = (demux_t*)p_this;
+    demux_sys_t *p_sys = p_demux->p_sys;
+    unsigned int i;
+
+    for (i=0; i<p_sys->i_stream; i++)
+	sms_free_stream( p_sys->streams[i] );
+
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * Manage and free internal structures
+ *****************************************************************************/
+static void
+sms_free_stream( struct sms_stream_t *p_stream )
+{
+    if( p_stream->p_url )
+	free( p_stream->p_url );
+
+    if( p_stream->chunks )
+	free( p_stream->chunks );
+
+    if (p_stream->p_stream)
+	stream_Delete( p_stream->p_stream );
+
+    es_format_Clean( &p_stream->fmt );
+
+    free( p_stream );
+}
+
+static void
+sms_free_bitrate( struct sms_bitrate_t *p_bitrate )
+{
+    if( p_bitrate->p_codec_private_data )
+	free( p_bitrate->p_codec_private_data );
+    free( p_bitrate );
+}
+
+
+/*****************************************************************************
+ * Utils
+ *****************************************************************************/
+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;
+}
+static size_t
+decode_string_hex_to_binary( uint8_t **pp_dst, const char *psz_src )
+{
+    int i=0, j=0, first_digit, second_digit;
+    int i_len = strlen( psz_src );
+    uint8_t *p_data = *pp_dst = malloc ( i_len/2 );
+
+    if( !p_data )
+	return 0;
+
+    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 i_len / 2;
+}
+
+
+/*****************************************************************************
+ * Functions to parse XML 
+ *****************************************************************************/
+static struct sms_stream_t *
+read_smoothstream_stream_index( demux_t *p_demux, xml_reader_t *p_xml_reader )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    struct sms_stream_t *p_stream;
+    bool b_type_found = false;
+    char *psz_name;
+    char *psz_value;
+   
+    p_stream = calloc( 1, sizeof(struct sms_stream_t) );
+    if( !p_stream )
+	return NULL;
+
+    /* read all StreamIndex attributes */
+    while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+    {
+        psz_name = xml_ReaderName( p_xml_reader );
+        psz_value = xml_ReaderValue( p_xml_reader );
+        if( !psz_name || !psz_value )
+        {
+            msg_Err( p_demux, "invalid xml stream @ <StreamIndex>" );
+            goto error_free_attributes;
+        }
+
+        /* attribute: Type */
+        if( !strcmp( psz_name, "Type" ) )
+        {
+            b_type_found = true;
+            if( !strcmp( psz_value, "video" ) )
+		p_stream->i_type = SMS_STREAM_VIDEO;
+	    else if( !strcmp( psz_value, "audio" ) )
+		p_stream->i_type = SMS_STREAM_AUDIO;
+	    else
+	    {
+		msg_Err( p_demux, "unsupported StreamIndex type (must be video or audio, got %s)", psz_value );
+		goto error_free_attributes;
+	    }
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<StreamIndex> Type=%s", psz_value );
+#endif
+        }
+        /* attribute: Subtype */
+        else if( !strcasecmp( psz_name, "SUBTYPE" ) )
+        {
+            if( !strcmp( psz_value, "WVC1" ) )
+		p_stream->i_subtype = VLC_CODEC_VC1;
+	    else if( !strcmp( psz_value, "H264" ) )
+		p_stream->i_subtype = VLC_CODEC_H264;
+	    else if( !strcmp( psz_value, "WmaPro" ) )
+		p_stream->i_subtype = VLC_CODEC_WMAP;
+	    else if( !strcmp( psz_value, "mp4a" ) )
+		p_stream->i_subtype = VLC_CODEC_MP4A;
+	    else if ( !strlen(psz_value) )
+	    {
+		msg_Warn( p_demux, "No subtype defined, It's a violation of the specification" );
+	    }
+	    else
+	    {
+		msg_Err( p_demux, "unsupported StreamIndex Subtype (must be WVC1, H264, WmaPro got %s)", psz_value );
+		goto error_free_attributes;
+	    }
+
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<StreamIndex> Subtype=%s", psz_value );
+#endif
+        }
+        /* attribute: Chunks */
+        else if( !strcmp( psz_name, "Chunks" ) )
+        {
+	    int i_value;
+	    if( sscanf( psz_value, "%u", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad number of Chunks in <StreamIndex> attribute:\"%s\"", psz_value);
+	    else
+		p_stream->i_chunks = i_value;
+
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<StreamIndex> Chunks=%s", psz_value );
+#endif
+        }
+        /* attribute: Url */
+        else if( !strcmp( psz_name, "Url" ) )
+        {
+	    p_stream->p_url = strdup( psz_value );
+	}
+	else if( !strcmp( psz_name, "TimeScale" ) )
+	{
+	    uint64_t i_value;
+	    if( sscanf( psz_value, "%llu", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for 'TimeScale' in <StreamIndex> attribute:\"%s\"", psz_value);
+	    else
+		p_stream->i_timescale = i_value;
+	}
+
+        /* unknown attribute */
+        else
+            msg_Warn( p_demux, "invalid <StreamIndex> attribute:\"%s\"", psz_name);
+
+        free( psz_name );
+        free( psz_value );
+    }
+
+    if ( !b_type_found )
+    {
+	msg_Err( p_demux, "missing Type @ <StreamIndex>" );
+	goto error;
+    }
+
+    if ( p_stream->i_chunks == 0)
+    {
+	if( p_sys->b_is_live )
+	{
+	    /* We have a live stream. The server put a lot of chunks, each chunk
+	     * contains time in the future, to allow seeking, and download, but
+	     * when we arrive at the end of the list, what can we do ? Using my
+	     * test server, the server sends for 4hours of chunks...
+	     * But we don't have the number of chunks to preallocate ...
+	     */
+	    p_stream->i_chunk_allocated = 300;
+	}
+	else
+	{
+	    msg_Err( p_demux, "Bad number of chunks <StreamIndex>" );
+	    goto error;
+	}
+    }
+    else
+    {
+	p_stream->i_chunk_allocated = p_stream->i_chunks ;
+    }
+
+    p_stream->chunks = calloc( p_stream->i_chunk_allocated, sizeof(struct sms_chunk_t) );
+
+    return p_stream;
+
+error_free_attributes:
+    free( psz_name );
+    free( psz_value );
+
+error:
+    sms_free_stream( p_stream );
+    return NULL;
+}
+
+static struct sms_bitrate_t *
+read_smoothstream_quality_level( demux_t *p_demux, xml_reader_t *p_xml_reader, struct sms_stream_t *p_stream )
+{
+    bool b_bitrate_found = false;
+    struct sms_bitrate_t *p_bitrate;
+    char *psz_name;
+    char *psz_value;
+    int i_value;
+   
+    p_bitrate = calloc( 1, sizeof(struct sms_bitrate_t) );
+    if( !p_bitrate )
+	return NULL;
+
+    /* read all QualityLevel attributes */
+    while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+    {
+        psz_name = xml_ReaderName( p_xml_reader );
+        psz_value = xml_ReaderValue( p_xml_reader );
+        if( !psz_name || !psz_value )
+        {
+            msg_Err( p_demux, "invalid xml stream @ <QualityLevel>" );
+            goto error_free_attributes;
+        }
+
+        /* attribute: Bitrate */
+        if( !strcasecmp( psz_name, "Bitrate" ) )
+        {
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<QualityLevel> Bitrate=%s", psz_value );
+#endif
+
+       	    if( sscanf( psz_value, "%u", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for Bitrate in <QualityLevel> attribute:\"%s\"", psz_value);
+	    else
+	    {
+		p_bitrate->i_bitrate = i_value;
+	    	b_bitrate_found = true;
+	    }
+	}
+        /* attribute: Width */
+	else if( !strcasecmp( psz_name, "Width" ) || !strcasecmp( psz_name, "MaxWidth" ) )
+        {
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<QualityLevel> Width=%s", psz_value );
+#endif
+
+       	    if( sscanf( psz_value, "%u", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for Width in <QualityLevel> attribute:\"%s\"", psz_value);
+	    else
+		p_bitrate->i_width = i_value;
+	}
+        /* attribute: Height */
+	else if( !strcasecmp( psz_name, "Height" ) || !strcasecmp( psz_name, "MaxHeight" ) )
+        {
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<QualityLevel> Height=%s", psz_value );
+#endif
+
+       	    if( sscanf( psz_value, "%u", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for Width in <QualityLevel> attribute:\"%s\"", psz_value);
+	    else
+		p_bitrate->i_height = i_value;
+	}
+        /* attribute: FourCC */
+        else if( !strcasecmp( psz_name, "FourCC" ) )
+        {
+	    vlc_fourcc_t i_type;
+            if( !strcmp( psz_value, "WVC1" ) )
+		i_type = VLC_CODEC_VC1;
+	    else if( !strcmp( psz_value, "H264" ) )
+		i_type = VLC_CODEC_H264;
+	    else if( !strcmp( psz_value, "WmaPro" ) || !strcmp( psz_value, "WMAP") )
+		i_type = VLC_CODEC_WMAP;
+	    else if( !strcmp( psz_value, "mp4a" ) )
+		i_type = VLC_CODEC_MP4A;
+	    else
+	    {
+		msg_Err( p_demux, "unsupported QualityLevel FourCC (must be WVC1 or H264, got %s)", psz_value );
+		goto error_free_attributes;
+	    }
+
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<QualityLevel> FourCC=%s", psz_value );
+#endif
+
+	    if( p_stream->i_subtype && i_type != p_stream->i_subtype )
+	    {
+		msg_Err( p_demux, "this FourCC %s is not the same than the type in the StreamIndex)", psz_value );
+		goto error_free_attributes;
+	    }
+
+	    p_bitrate->i_subtype = i_type;
+        }
+        else if( !strcasecmp( psz_name, "CodecPrivateData" ) )
+        {
+	    p_bitrate->i_codec_private_data_length = 
+		decode_string_hex_to_binary( &p_bitrate->p_codec_private_data, psz_value );
+	}
+        else if( !strcasecmp( psz_name, "WaveFormatEx" ) )
+        {
+	    p_bitrate->i_codec_private_data_length = 
+		decode_string_hex_to_binary( &p_bitrate->p_codec_private_data, psz_value );
+	}
+        /* attribute: Index */
+	else if( !strcasecmp( psz_name, "Index" ) )
+        {
+#if SMS_DEBUG_XML_STREAM
+	    msg_Dbg( p_demux, "<QualityLevel> Index=%s", psz_value );
+#endif
+
+       	    if( sscanf( psz_value, "%u", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for attribute 'Index' in <QualityLevel>:\"%s\"", psz_value);
+	    else
+		p_bitrate->i_index = i_value;
+	}
+        /* unknown attribute */
+        else
+            msg_Warn( p_demux, "invalid <QualityLevel> attribute:\"%s\"", psz_name);
+
+        free( psz_name );
+        free( psz_value );
+    }
+
+    if( !b_bitrate_found )
+    {
+	msg_Err( p_demux, "missing Bitrate @ <QualityLevel>" );
+	goto end_with_error;
+    }
+
+    /* In case the codec was not specified, copy it from StreamIndex node */
+    if( p_bitrate->i_subtype == 0 )
+    {
+	if (p_stream->i_subtype == 0)
+	{
+            msg_Err( p_demux, "no FourCC in this stream bitrate, and no FourCC in the StreamIndex node" );
+	    goto end_with_error;
+	}
+
+	p_bitrate->i_subtype = p_stream->i_subtype;
+    }
+
+    if ( p_stream->i_type == SMS_STREAM_AUDIO )
+    {
+	switch ( p_bitrate->i_subtype )
+	{
+	    case VLC_CODEC_WMAP:
+	    case VLC_CODEC_MP4A:
+		break;
+
+	    default:
+		msg_Err( p_demux, "Bad audio codec in node <QualityLevel>" );
+		goto end_with_error;
+	}
+    }
+    if ( p_stream->i_type == SMS_STREAM_VIDEO )
+    {
+	switch ( p_bitrate->i_subtype )
+	{
+	    case VLC_CODEC_VC1:
+	    case VLC_CODEC_H264:
+		break;
+
+	    default:
+		msg_Err( p_demux, "Bad video codec in node <QualityLevel>" );
+		goto end_with_error;
+	}
+    }
+
+
+    return p_bitrate;
+
+error_free_attributes:
+    free( psz_name );
+    free( psz_value );
+
+end_with_error:
+    sms_free_bitrate( p_bitrate );
+    return NULL;
+}
+
+
+static int
+read_smoothstream_chunck( demux_t *p_demux, xml_reader_t *p_xml_reader, struct sms_stream_t *p_stream )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+    bool b_n_found = false;
+    char *psz_name;
+    char *psz_value;
+    uint64_t i_value, n;
+    uint64_t d=0, t=0;
+
+    /* read all QualityLevel attributes */
+    while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+    {
+        psz_name = xml_ReaderName( p_xml_reader );
+        psz_value = xml_ReaderValue( p_xml_reader );
+        if( !psz_name || !psz_value )
+        {
+            msg_Err( p_demux, "invalid xml stream @ <c>" );
+            goto error_free_attributes;
+        }
+
+        /* attribute: Bitrate */
+        if( !strcmp( psz_name, "n" ) )
+        {
+       	    if( sscanf( psz_value, "%llu", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for n in <c> attribute:\"%s\"", psz_value);
+	    else
+	    {
+		n = i_value;
+		b_n_found = true;
+	    }
+	}
+        /* attribute: d (duration) */
+	else if( !strcmp( psz_name, "d" ) )
+        {
+       	    if( sscanf( psz_value, "%llu", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for d in <c> attribute:\"%s\"", psz_value);
+	    else
+		d = i_value;
+	}
+        /* attribute: t (duration) */
+	else if( !strcmp( psz_name, "t" ) )
+        {
+       	    if( sscanf( psz_value, "%llu", &i_value ) != 1)
+		msg_Warn( p_demux, "Bad value for t in <c> attribute:\"%s\"", psz_value);
+	    else
+		t = i_value;
+	}
+        /* unknown attribute */
+        else
+            msg_Warn( p_demux, "invalid <c> attribute:\"%s\"", psz_name);
+
+        free( psz_name );
+        free( psz_value );
+    }
+
+    if( !b_n_found )
+    {
+	/* Append to node to the list of chunk */
+	n = p_stream->i_chunks++;
+	if( !p_sys->b_is_live )
+	    msg_Warn( p_demux, "missing attribute n for node <c>" );
+    }
+
+    if( n >= p_stream->i_chunk_allocated)
+    {
+	msg_Warn( p_demux, "Reallocation done for n=%lld (old_size=%d)\n", n, p_stream->i_chunk_allocated);
+	/* We need to do reallocation */
+	int new_size = p_stream->i_chunk_allocated * 2;
+	p_stream->chunks = xrealloc( p_stream->chunks, new_size * sizeof(p_stream->chunks[0]) );
+	memset( &(p_stream->chunks[p_stream->i_chunk_allocated]), 0, sizeof(p_stream->chunks[0]) * (new_size-p_stream->i_chunk_allocated) );
+	p_stream->i_chunk_allocated = new_size;
+    }
+
+    if( n>0 )
+    {
+	if (p_stream->chunks[n-1].i_duration == 0)
+	    p_stream->chunks[n-1].i_duration = p_stream->chunks[n].i_time - p_stream->chunks[n-1].i_time;
+
+	if( t == 0 ) {
+	    t = p_stream->chunks[n-1].i_time + p_stream->chunks[n-1].i_duration;
+	}
+    }
+
+    p_stream->chunks[n].i_duration = d;
+    p_stream->chunks[n].i_time = t;
+
+    return VLC_SUCCESS;
+
+error_free_attributes:
+    free( psz_name );
+    free( psz_value );
+
+    return VLC_EGENERIC;
+}
+
+
+static int
+parse_smoothstream_root_node( demux_t *p_demux, xml_reader_t *p_xml_reader )
+{
+  char *psz_eltname = NULL;
+  struct sms_stream_t *p_stream = NULL;
+  demux_sys_t *p_sys = p_demux->p_sys;
+
+  /* Default attribute */
+  p_sys->i_timescale = 10000000;
+
+  /* read attributes from the root node */
+  while( xml_ReaderNextAttr( p_xml_reader ) == VLC_SUCCESS )
+  {
+      char *psz_name;
+      char *psz_value;
+      uint64_t i_value;
+
+      psz_name = xml_ReaderName( p_xml_reader );
+      psz_value = xml_ReaderValue( p_xml_reader );
+      if( !psz_name || !psz_value )
+      {
+	  msg_Err( p_demux, "invalid xml stream @ <c>" );
+	  break;
+      }
+
+      /* attribute: Bitrate */
+      if( !strcmp( psz_name, "IsLive" ) )
+      {
+	  if( !strcasecmp( psz_value, "TRUE" ) )
+	      p_sys->b_is_live = true;
+      }
+
+      else if( !strcmp( psz_name, "Duration" ) )
+      {
+	  if( sscanf( psz_value, "%llu", &i_value ) != 1)
+	      msg_Warn( p_demux, "Bad value for 'Duration' in <SmoothStreamingMedia> attribute:\"%s\"", psz_value);
+	  else
+	      p_sys->i_duration = i_value;
+      }
+
+      else if( !strcmp( psz_name, "TimeScale" ) )
+      {
+	  if( sscanf( psz_value, "%llu", &i_value ) != 1)
+	      msg_Warn( p_demux, "Bad value for 'TimeScale' in <SmoothStreamingMedia> attribute:\"%s\"", psz_value);
+	  else
+	      p_sys->i_timescale = i_value;
+      }
+
+      free( psz_name );
+      free( psz_value );
+  }
+
+  while ( xml_ReaderRead( p_xml_reader ) == 1 )
+  {
+    switch( xml_ReaderNodeType( p_xml_reader ) )
+     {
+      case XML_READER_NONE:
+	break;
+
+      case XML_READER_STARTELEM:
+	if ( psz_eltname )
+	    free ( psz_eltname );
+	psz_eltname = xml_ReaderName( p_xml_reader );
+	if ( !psz_eltname )
+	    goto end_with_error;
+
+#if SMS_DEBUG_XML_STREAM
+	msg_Dbg( p_demux, "element name: %s", psz_eltname );
+#endif
+
+	if ( strcasecmp( psz_eltname, "StreamIndex" ) == 0 )
+	{
+	    p_stream = read_smoothstream_stream_index( p_demux, p_xml_reader );
+	    if( p_stream == NULL )
+		goto end_with_error;
+	}
+
+	else if ( strcasecmp( psz_eltname, "QualityLevel" ) == 0 && p_stream)
+	{
+	    struct sms_bitrate_t *p_bitrate;
+	    p_bitrate = read_smoothstream_quality_level( p_demux, p_xml_reader, p_stream );
+	    if ( p_stream->i_bitrate >= SMS_MAX_BITRATES )
+	    {
+		msg_Err( p_demux, "Max number of bitrates reached, discarded this one" );
+		sms_free_bitrate( p_bitrate );
+	    }
+	    else
+		p_stream->bitrates[p_stream->i_bitrate++] = p_bitrate;
+	}
+
+	else if ( strcasecmp( psz_eltname, "c" ) == 0 && p_stream)
+	{
+	    read_smoothstream_chunck( p_demux, p_xml_reader, p_stream );
+	}
+	else
+	{
+	    msg_Warn( p_demux, "Tag <%s> not supported", psz_eltname );
+	}
+
+	break;
+
+      case XML_READER_ENDELEM:
+	if ( psz_eltname )
+	    free ( psz_eltname );
+	psz_eltname = xml_ReaderName( p_xml_reader );
+	if ( !psz_eltname )
+	    goto end_with_error;
+
+#if SMS_DEBUG_XML_STREAM
+	msg_Dbg( p_demux, "element end: %s", psz_eltname );
+#endif
+
+
+	if ( strcasecmp( psz_eltname, "StreamIndex" ) == 0 )
+	{
+	    if ( p_sys->i_stream >= SMS_MAX_STREAMS )
+	    {
+		msg_Err( p_demux, "Max number of streams reached, discarded this one" );
+		sms_free_stream( p_stream );
+	    }
+	    else
+		p_sys->streams[p_sys->i_stream++] = p_stream;
+	    p_stream = NULL;
+	}
+
+
+	break;
+
+      case XML_READER_TEXT:
+	if ( !psz_eltname )
+	  break;
+
+	char *psz_eltvalue = xml_ReaderValue( p_xml_reader );
+	if( !psz_eltvalue )
+	  goto end_with_error;
+
+	//char *psz_clean = removeWhiteChars( psz_eltvalue );
+	//free( psz_eltvalue );
+	//psz_eltvalue = psz_clean;
+
+#if SMS_DEBUG_XML_STREAM
+	msg_Dbg( p_demux, "  text : <%s>", psz_eltvalue );
+#endif
+	break;
+
+      default:
+	msg_Err( p_demux, "unknown xml node type %d", xml_ReaderNodeType( p_xml_reader ) );
+	break;
+
+    }
+
+  }
+
+  if ( psz_eltname )
+    free ( psz_eltname );
+  return VLC_SUCCESS;
+
+end_with_error:
+  if ( psz_eltname )
+    free ( psz_eltname );
+
+  return VLC_EGENERIC;
+}
+
+
+static int
+sms_read_manifest( demux_t *p_demux )
+{
+    int i_ret = -1;
+    xml_t *p_xml = NULL;
+    xml_reader_t *p_xml_reader = NULL;
+    char *psz_name = NULL;
+
+
+    /* create new xml parser from stream */
+    p_xml = xml_Create( p_demux );
+    if( !p_xml )
+        goto end;
+
+    p_xml_reader = xml_ReaderCreate( p_xml, p_demux->s );
+    if( !p_xml_reader )
+        goto end;
+
+    /* locating the root node */
+    do
+    {
+        if( xml_ReaderRead( p_xml_reader ) != 1 )
+        {
+            msg_Err( p_demux, "can't read xml stream" );
+            goto end;
+        }
+    } while( xml_ReaderNodeType( p_xml_reader ) != XML_READER_STARTELEM );
+
+    /* checking root node name */
+    psz_name = xml_ReaderName( p_xml_reader );
+    if( !psz_name || strcasecmp( psz_name, "smoothstreamingmedia" ) )
+    {
+        msg_Err( p_demux, "invalid root node name: %s", psz_name );
+        free( psz_name );
+        goto end;
+    }
+    free( psz_name );
+
+    msg_Err( p_demux, "successfully find the root node" );
+
+    i_ret = parse_smoothstream_root_node( p_demux, p_xml_reader );
+
+end:
+    if( p_xml_reader )
+        xml_ReaderDelete( p_xml, p_xml_reader );
+
+    if( p_xml )
+        xml_Delete( p_xml );
+
+    return i_ret; /* Needed for correct operation of go back */
+}
+
+static char *
+str_replace(char *psz_src, const char *psz_needle, const char *psz_by)
+{
+    char *p, *string_final, *second_part;
+
+    if (psz_src == NULL)
+	return NULL;
+
+    p = strstr(psz_src, psz_needle);
+    if (p == NULL)
+	return psz_src;
+
+    /*
+     *
+     *   |aaaaaaaaaa{needle}zzzzzzzzzzz|
+     *   ^          ^       ^
+     *   psz_src    |       p+strlen(needle)
+     *              p
+     *
+     */
+    second_part = p + strlen(psz_needle);
+    *p = 0;
+
+    if (asprintf(&string_final, "%s%s%s", psz_src, psz_by, second_part) == -1)
+	return NULL;
+
+    free(psz_src);
+    return string_final;
+}
+
+/*
+ * Build a string to download the chunk.
+ * In the Manifest, we need to replace some text from the string, by dynamic value
+ *
+ * Return a string that must be free with free()
+ * 
+ */
+static char *
+sms_stream_build_url( demux_t *p_demux, struct sms_stream_t *p_stream )
+{
+    char *prefix, *url, *parameters_string, *p;
+    char bitrate_string[64];
+    char start_time[64];
+
+    snprintf(bitrate_string, sizeof(bitrate_string), "%u", p_stream->p_selected_bitrate->i_bitrate);
+
+    if (p_stream->chunks[p_stream->i_chunk].i_time)
+	snprintf(start_time, sizeof(start_time), "%llu", p_stream->chunks[p_stream->i_chunk].i_time );
+    else
+	snprintf(start_time, sizeof(start_time), "%u", 0 );
+
+    msg_Dbg( p_demux, "sms_stream_build_url(): start_time = %s / i_chunk = %d", start_time, p_stream->i_chunk );
+   
+    /* Build the prefix url (by stripping the last word Manifest) */
+    prefix = strdup(p_demux->psz_path);
+    p = strrchr( prefix, '/' );
+    if( p[0] == '/')
+	p[1] = 0;
+
+    /* Build the string parameters, and replace each values, one by one */
+    parameters_string = strdup(p_stream->p_url);
+
+    parameters_string = str_replace(parameters_string, "{bitrate}", bitrate_string);
+    parameters_string = str_replace(parameters_string, "{Bitrate}", bitrate_string);
+    parameters_string = str_replace(parameters_string, "{CustomAttributes}", "");
+    parameters_string = str_replace(parameters_string, "{start time}", start_time);
+    parameters_string = str_replace(parameters_string, "{start_time}", start_time);
+
+    url = NULL;
+    if (asprintf( &url, "%s://%s%s", p_demux->psz_access, prefix, parameters_string) == -1)
+	url = NULL;
+
+    free(parameters_string);
+    free(prefix);
+
+    return url;
+}
+
+
+/*
+ * When the Manifest is loaded into memory, we can choose an video stream
+ * at the best bitrate, and using a known video codec.
+ *
+ * TODO: For now, we just use the first stream with the first bitrate
+ *       We must choose the best codec, and the best bitrate supported
+ */
+static int
+sms_stream_begin( demux_t *p_demux )
+{
+    int i_ret = -1;
+    unsigned int i, j, br;
+    demux_sys_t *p_sys = p_demux->p_sys;
+    struct sms_stream_t *p_stream;
+    struct sms_bitrate_t *p_bitrate;
+
+    /* AUDIO */
+    for( i=0; i<p_sys->i_stream; i++ )
+    {
+	p_stream = p_sys->streams[i];
+	if( p_stream->i_type == SMS_STREAM_AUDIO )
+	{
+	    p_sys->stream_audio = p_stream;
+	    br = 0;
+	    for( j=0; j<p_stream->i_bitrate; j++ )
+	    {
+		p_bitrate = p_stream->bitrates[j];
+		if( br < p_bitrate->i_bitrate )
+		{
+		    p_stream->p_selected_bitrate = p_bitrate;
+		    br = p_bitrate->i_bitrate;
+		}
+	    }
+
+	    /* Initialize audio stream */
+	    p_bitrate = p_stream->p_selected_bitrate;
+	    es_format_Init( &p_stream->fmt, AUDIO_ES, p_bitrate->i_subtype );
+
+	    if( p_bitrate->i_subtype == VLC_CODEC_WMAP)
+	    {
+		p_stream->fmt.audio.i_channels        = GetWLE(  &p_bitrate->p_codec_private_data[2] );
+		p_stream->fmt.audio.i_rate            = GetDWLE( &p_bitrate->p_codec_private_data[4] );
+		p_stream->fmt.i_bitrate         	    = GetDWLE( &p_bitrate->p_codec_private_data[8] ) * 8;
+		p_stream->fmt.audio.i_blockalign      = GetWLE(  &p_bitrate->p_codec_private_data[12] );
+		p_stream->fmt.audio.i_bitspersample   = GetWLE(  &p_bitrate->p_codec_private_data[14] );
+
+		if( p_bitrate->i_codec_private_data_length > sizeof( WAVEFORMATEX ))
+		{
+		    p_stream->fmt.i_extra = __MIN( GetWLE( &p_bitrate->p_codec_private_data[16] ),
+			    p_bitrate->i_codec_private_data_length -
+			    sizeof( WAVEFORMATEX ) );
+		    p_stream->fmt.p_extra = malloc( p_stream->fmt.i_extra );
+		    memcpy( p_stream->fmt.p_extra,
+			    &p_bitrate->p_codec_private_data[sizeof( WAVEFORMATEX )],
+			    p_stream->fmt.i_extra );
+		}
+	    }
+
+	    msg_Info( p_demux, "Select audio stream %4.4s @ bitrate %d", (char *)&p_bitrate->i_subtype, br );
+
+	    p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
+	    //es_format_Clean( &p_stream->fmt );
+
+	    break;
+	}
+    }
+
+
+    /* VIDEO */
+    for( i=0; i<p_sys->i_stream; i++ )
+    {
+	p_stream = p_sys->streams[i];
+	if( p_sys->streams[i]->i_type == SMS_STREAM_VIDEO )
+	{
+	    p_sys->stream_video = p_sys->streams[i];
+
+	    br = 0;
+	    for( j=0; j<p_sys->stream_video->i_bitrate; j++ )
+	    {
+		if( br<p_sys->stream_video->bitrates[j]->i_bitrate )
+		{
+		    p_sys->stream_video->p_selected_bitrate = p_sys->stream_video->bitrates[j];
+		    br = p_sys->stream_video->bitrates[j]->i_bitrate;
+		}
+	    }
+
+	    /* Initialize video stream */
+	    p_bitrate = p_stream->p_selected_bitrate;
+	    es_format_Init( &p_stream->fmt, VIDEO_ES, p_bitrate->i_subtype );
+
+	    p_stream->fmt.video.i_width = p_bitrate->i_width;
+	    p_stream->fmt.video.i_height = p_bitrate->i_height;
+
+	    if( p_bitrate->i_subtype == VLC_CODEC_VC1 )
+	    {
+		p_stream->fmt.i_extra = __MIN( p_bitrate->i_codec_private_data_length, sizeof( VIDEOINFOHEADER ));
+		p_stream->fmt.p_extra = malloc( p_stream->fmt.i_extra );
+		memcpy( p_stream->fmt.p_extra,
+			p_bitrate->p_codec_private_data,
+			p_stream->fmt.i_extra );
+	    }
+	    else if( p_bitrate->i_subtype == VLC_CODEC_H264 )
+	    {
+		
+		p_stream->fmt.i_extra = p_bitrate->i_codec_private_data_length;
+		p_stream->fmt.p_extra = malloc( p_stream->fmt.i_extra );
+		memcpy( p_stream->fmt.p_extra, p_bitrate->p_codec_private_data, p_stream->fmt.i_extra );
+		msg_Info( p_demux, "h264 additional data len=%d [0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x,0x%2.2x]",
+		          p_stream->fmt.i_extra,
+			  ((uint8_t *)p_stream->fmt.p_extra)[0], ((uint8_t *)p_stream->fmt.p_extra)[1], ((uint8_t *)p_stream->fmt.p_extra)[2], ((uint8_t *)p_stream->fmt.p_extra)[3],
+			  ((uint8_t *)p_stream->fmt.p_extra)[4], ((uint8_t *)p_stream->fmt.p_extra)[5], ((uint8_t *)p_stream->fmt.p_extra)[6], ((uint8_t *)p_stream->fmt.p_extra)[7],
+			  ((uint8_t *)p_stream->fmt.p_extra)[8], ((uint8_t *)p_stream->fmt.p_extra)[9], ((uint8_t *)p_stream->fmt.p_extra)[10], ((uint8_t *)p_stream->fmt.p_extra)[11]
+		       	);
+		p_stream->fmt.b_packetized = true;
+	    }
+
+	    msg_Info( p_demux, "Select video stream %4.4s @ bitrate %d", (char *)&p_bitrate->i_subtype, br );
+
+	    p_stream->p_es = es_out_Add( p_demux->out, &p_stream->fmt );
+
+	    break;
+	}
+    }
+
+
+    return i_ret;
+}
+
+static int DemuxStream( demux_t *p_demux, struct sms_stream_t *p_sms_stream )
+{
+    MP4_Box_t *p_box_root;
+    MP4_Box_t *p_mdat, *p_trun, *p_tfhd;
+    block_t *p_bk;
+    const char *psz_stream_type = (p_sms_stream->i_type == SMS_STREAM_AUDIO)?"audio":"video";
+
+
+    //if (p_sms_stream->p_stream == NULL)
+    {
+	/* No chunk was loaded */
+	char *psz_chunk_url = sms_stream_build_url( p_demux, p_sms_stream );
+	msg_Err( p_demux, "Chunk %s url is at %s", psz_stream_type, psz_chunk_url );
+
+	/* open file */
+	p_sms_stream->p_stream = stream_UrlNew( p_demux, psz_chunk_url );
+	if( p_sms_stream->p_stream == NULL )
+	{
+	    msg_Err( p_demux, "couldn't open %s chunck file: %s", psz_stream_type, psz_chunk_url );
+	    free( psz_chunk_url );
+	    return VLC_EGENERIC;
+	}
+
+	free( psz_chunk_url );
+    }
+
+
+    p_box_root = MP4_BoxGetRoot( p_sms_stream->p_stream );
+    if (p_box_root == NULL)
+    {
+	msg_Err( p_demux, "No MP4 root node found for %s stream", psz_stream_type );
+	return VLC_EGENERIC;
+    }
+
+    msg_Dbg( p_demux, "Demux %s stream", psz_stream_type );
+    MP4_BoxDumpStructure( p_sms_stream->p_stream, p_box_root );
+
+    p_trun = MP4_BoxGet( p_box_root, "/moof/traf/trun" );
+    if( p_trun == NULL )
+    {
+	msg_Warn( p_demux, "trun block not found" );
+	return VLC_EGENERIC;
+    }
+
+    p_tfhd = MP4_BoxGet( p_box_root, "/moof/traf/tfhd" );
+    if( p_tfhd == NULL )
+    {
+	msg_Warn( p_demux, "tfhd block not found" );
+	return VLC_EGENERIC;
+    }
+
+    p_mdat = MP4_BoxGet( p_box_root, "/mdat" );
+    if( p_mdat == NULL )
+    {
+	msg_Warn( p_demux, "mdat block not found" );
+	return VLC_EGENERIC;
+    }
+
+    msg_Dbg( p_demux, "p_mdat = %p (pos=%lld) (size=%lld)", p_mdat, p_mdat->i_pos, p_mdat->i_size );
+
+    unsigned int i;
+    int64_t total_chunk_duration = 0;
+    int64_t total_chunk_size = p_mdat->i_size - MP4_BOX_HEADERSIZE(p_mdat);
+    int64_t sample_position = 0;
+    int64_t i_pts = p_sms_stream->chunks[p_sms_stream->i_chunk].i_time/10;
+    for( i=0; i<p_trun->data.p_trun->i_sample_count; i++ )
+    {
+	MP4_descriptor_trun_sample_t *p_sample = p_trun->data.p_trun->p_samples+i;
+	unsigned int sample_flags = 0;
+	uint64_t sample_size = 0;
+	uint64_t sample_duration = 0;
+	uint64_t sample_base_offset = 0;
+
+	if( p_tfhd->data.p_tfhd->i_flags & MP4_TFHD_BASE_DATA_OFFSET )
+	{
+	    sample_base_offset = p_tfhd->data.p_tfhd->i_default_sample_flags;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using default sample base offset %lld", i, sample_base_offset );
+	}
+
+	if( p_tfhd->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_DURATION )
+	{
+	    sample_duration = p_tfhd->data.p_tfhd->i_default_sample_duration;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using default duration %lld", i, sample_duration );
+	}
+
+	if( p_tfhd->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_SIZE )
+	{
+	    sample_size = p_tfhd->data.p_tfhd->i_default_sample_size;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using default sample size %lld", i, sample_size );
+	}
+
+	if( p_tfhd->data.p_tfhd->i_flags & MP4_TFHD_DFLT_SAMPLE_FLAGS )
+	{
+	    sample_flags = p_tfhd->data.p_tfhd->i_default_sample_flags;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using default flags 0x%x", i, sample_flags );
+	}
+
+	if( p_trun->data.p_trun->i_flags & MP4_TRUN_SAMPLE_SIZE)
+	{
+	    sample_size = p_sample->i_size;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using sample size %lld", i, sample_size );
+	}
+
+	if( p_trun->data.p_trun->i_flags & MP4_TRUN_SAMPLE_FLAGS)
+	{
+	    sample_flags = p_sample->i_flags;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using sample flags 0x%x", i, sample_flags );
+	}
+
+	if( p_trun->data.p_trun->i_flags & MP4_TRUN_SAMPLE_DURATION)
+	{
+	    sample_duration = p_sample->i_duration;
+	    msg_Dbg( p_demux, "\"trun\" sample %4.4d using sample duration %lld", i, sample_duration );
+	}
+
+	msg_Dbg( p_demux, "\"trun\" sample %4.4d flags 0x%x duration %lld size %lld sample_base_offset %lld",
+		i, sample_flags, sample_duration, sample_size, sample_base_offset );
+
+	off_t i_pos = p_mdat->i_pos + MP4_BOX_HEADERSIZE(p_mdat) + sample_base_offset + sample_position;
+
+	if( stream_Seek( p_sms_stream->p_stream, i_pos ) )
+	{
+	    msg_Warn( p_demux, "Seek failed to go to %lld", p_mdat->i_pos );
+	    return VLC_EGENERIC;
+	}
+
+	p_bk = stream_Block( p_sms_stream->p_stream, sample_size );
+	if( p_bk == NULL )
+	{
+	    msg_Warn( p_demux, "Cannot allocate new block size %lld", p_mdat->i_size );
+	    return VLC_EGENERIC;
+	}
+
+	if (1)
+	{
+	    char filename[128];
+	    FILE *fd;
+
+	    snprintf(filename, sizeof(filename), "stream_%s-%4.4d-%4.4d.mdat", psz_stream_type, p_sms_stream->i_chunk, i);
+	    msg_Dbg( p_demux, "Saving block to %s", filename );
+	    fd = fopen(filename, "wb");
+
+	    /* Output SPS & PPS */
+#if 0
+	    struct sms_bitrate_t *p_bitrate;
+	    p_bitrate = p_sms_stream->p_selected_bitrate;
+
+	    if( fwrite( p_bitrate->p_codec_private_data, 1, p_bitrate->i_codec_private_data_length, fd ) != p_bitrate->i_codec_private_data_length )
+	    {
+		msg_Err( p_demux, "Failed to save SPS / PPS blocks in %s", filename );
+		fclose(fd);
+		return VLC_EGENERIC;
+	    }
+#endif
+
+	    if( fwrite( p_bk->p_buffer, 1, sample_size, fd ) != sample_size )
+	    {
+		msg_Err( p_demux, "Failed to save block in %s", filename );
+		fclose(fd);
+		return VLC_EGENERIC;
+	    }
+
+	    fclose(fd);
+	}
+
+
+	i_pts += sample_duration/10;
+	i_pts &= INT64_C(0x00ffffffffffffff);
+
+	p_bk->i_dts = VLC_TS_0;
+	//p_bk->i_pts = VLC_TS_0 + i_pts;
+	p_bk->i_pts = VLC_TS_0;
+	es_out_Send( p_demux->out, p_sms_stream->p_es, p_bk );
+
+	sample_position += sample_size;
+
+	total_chunk_duration += sample_duration;
+    }
+    msg_Info( p_demux, "DemuxStream(): total_duration %lld  total_size %lld / sum(sample_size) %lld",
+	      total_chunk_duration, total_chunk_size, sample_position );
+
+
+
+#if 0
+    msg_Warn( p_demux, "send block to upper layer p_bk=%p size=%lld", p_bk, p_mdat->i_size );
+
+    int64_t i_pts = p_sms_stream->chunks[p_sms_stream->i_chunk].i_time/10;
+    i_pts &= INT64_C(0x00ffffffffffffff);
+
+    p_bk->i_pts = VLC_TS_0 + i_pts;
+    es_out_Send( p_demux->out, p_sms_stream->p_es, p_bk );
+#endif
+
+#if 0
+    for( i=0; i<p_trun->data.p_trun->i_sample_count; i++ )
+    {
+	unsigned int i_flags = p_trun->data.p_trun->i_flags;
+	MP4_descriptor_trun_sample_t *p_sample = p_trun->data.p_trun->p_samples;
+
+	if (i_flags & 0x000100)
+	    total_chunk_duration += p_sample->i_duration;
+	else
+	    msg_Warn( p_demux, "no duration into this block %d, FIXME", i );
+
+	if (i_flags & 0x000200)
+	    total_chunk_size += p_sample->i_size;
+	else
+	    msg_Warn( p_demux, "no size into this block %d, FIXME", i );
+
+    }
+#endif
+
+    p_sms_stream->i_chunk++;
+    if (p_sms_stream->i_chunk > p_sms_stream->i_chunks)
+	return VLC_EGENERIC;	/* TODO: finished */
+
+    return 0;
+}
+
+
+static int Demux( demux_t *p_demux )
+{
+    demux_sys_t *p_sys = p_demux->p_sys;
+
+    msg_Err( p_demux, "into the Demux()" );
+    if( p_sys->i_stream == 0 )
+	return VLC_EGENERIC;
+
+    static int a = 0;
+    if (a == 1)
+	return VLC_EGENERIC;
+    a = 1;
+
+    /* audio */
+    if (p_sys->stream_audio)
+    {
+	DemuxStream(p_demux, p_sys->stream_audio);
+    }
+
+    if (p_sys->stream_video)
+    {
+	DemuxStream(p_demux, p_sys->stream_video);
+    }
+
+    return 1;
+}
+
+static int Control( demux_t *p_demux, int i_query, va_list args )
+{
+    VLC_UNUSED(p_demux); VLC_UNUSED(i_query); VLC_UNUSED(args);
+    return VLC_EGENERIC;
+}
+
diff --git a/modules/packetizer/h264.c b/modules/packetizer/h264.c

