* mms/* : begining of a m$-http-for-asf-streaming support.
authorLaurent Aimar <fenrir@videolan.org>
Sun, 20 Apr 2003 19:29:43 +0000 (19:29 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Sun, 20 Apr 2003 19:29:43 +0000 (19:29 +0000)
 Proxy aren't yet supported. Use mmsh to force it, else mms will try it
at the end (after mmst and mmsu). Some http url are in fact mmsh but
not yet auto-detected.
 *Please report* not working url and any regression for mmst and mmsu.

modules/access/mms/Modules.am
modules/access/mms/asf.c [new file with mode: 0644]
modules/access/mms/asf.h
modules/access/mms/mms.c
modules/access/mms/mms.h
modules/access/mms/mmsh.c [new file with mode: 0644]
modules/access/mms/mmsh.h [new file with mode: 0644]
modules/access/mms/mmstu.c [new file with mode: 0644]
modules/access/mms/mmstu.h [new file with mode: 0644]

index fc84f75..062e4e2 100644 (file)
@@ -1,8 +1,12 @@
 SOURCES_access_mms = \
        modules/access/mms/mms.c \
        modules/access/mms/mms.h \
+       modules/access/mms/mmsh.c \
+       modules/access/mms/mmsh.h \
+       modules/access/mms/mmstu.c \
+       modules/access/mms/mmstu.h \
        modules/access/mms/buffer.c \
        modules/access/mms/buffer.h \
        modules/access/mms/asf.h \
+       modules/access/mms/asf.c \
        $(NULL)
-
diff --git a/modules/access/mms/asf.c b/modules/access/mms/asf.c
new file mode 100644 (file)
index 0000000..13fa386
--- /dev/null
@@ -0,0 +1,330 @@
+/*****************************************************************************
+ * asf.c: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: asf.c,v 1.1 2003/04/20 19:29:43 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+#include <stdlib.h>
+
+#include <vlc/vlc.h>
+
+#include "asf.h"
+#include "buffer.h"
+
+
+static int CmpGuid( const guid_t *p_guid1, const guid_t *p_guid2 )
+{
+    return( ( p_guid1->v1 == p_guid2->v1 &&
+              p_guid1->v2 == p_guid2->v2 &&
+              p_guid1->v3 == p_guid2->v3 &&
+              p_guid1->v4[0] == p_guid2->v4[0] &&
+              p_guid1->v4[1] == p_guid2->v4[1] &&
+              p_guid1->v4[2] == p_guid2->v4[2] &&
+              p_guid1->v4[3] == p_guid2->v4[3] &&
+              p_guid1->v4[4] == p_guid2->v4[4] &&
+              p_guid1->v4[5] == p_guid2->v4[5] &&
+              p_guid1->v4[6] == p_guid2->v4[6] &&
+              p_guid1->v4[7] == p_guid2->v4[7] ) ? 1 : 0 );
+}
+
+void E_( GenerateGuid )( guid_t *p_guid )
+{
+    int i;
+
+    srand( mdate() & 0xffffffff );
+
+    /* FIXME should be generated using random data */
+    p_guid->v1 = 0xbabac001;
+    p_guid->v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
+    p_guid->v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
+    for( i = 0; i < 8; i++ )
+    {
+        p_guid->v4[i] = ( (uint64_t)rand() * 256 ) / RAND_MAX;
+    }
+}
+
+void E_( asf_HeaderParse )  ( asf_header_t *hdr,
+                              uint8_t *p_header, int i_header )
+{
+    var_buffer_t buffer;
+    guid_t      guid;
+    uint64_t    i_size;
+    int         i;
+
+    for( i = 0; i < 128; i++ )
+    {
+        hdr->stream[i].i_cat = ASF_STREAM_UNKNOWN;
+    }
+
+    //fprintf( stderr, " ---------------------header:%d\n", i_header );
+    var_buffer_initread( &buffer, p_header, i_header );
+
+    var_buffer_getguid( &buffer, &guid );
+
+    if( !CmpGuid( &guid, &asf_object_header_guid ) )
+    {
+//        XXX Error
+//        fprintf( stderr, " ---------------------ERROR------\n" );
+    }
+    var_buffer_getmemory( &buffer, NULL, 30 - 16 );
+
+    for( ;; )
+    {
+        //fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
+
+        var_buffer_getguid( &buffer, &guid );
+        i_size = var_buffer_get64( &buffer );
+
+        //fprintf( stderr, "  guid=0x%8.8x-0x%4.4x-0x%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x size=%lld\n",
+        //                  guid.v1,guid.v2, guid.v3,
+        //                  guid.v4[0],guid.v4[1],guid.v4[2],guid.v4[3],
+        //                  guid.v4[4],guid.v4[5],guid.v4[6],guid.v4[7],
+        //                  i_size );
+
+        if( CmpGuid( &guid, &asf_object_file_properties_guid ) )
+        {
+            var_buffer_getmemory( &buffer, NULL, 16 );
+            hdr->i_file_size            = var_buffer_get64( &buffer );
+            var_buffer_getmemory( &buffer, NULL, 8 );
+            hdr->i_data_packets_count   = var_buffer_get64( &buffer );
+            var_buffer_getmemory( &buffer, NULL, 8+8+8+4);
+            hdr->i_min_data_packet_size = var_buffer_get32( &buffer );
+
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 - 16 - 8 - 8 - 8 - 8-8-8-4 - 4);
+        }
+        else if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
+        {
+            int     i_stream_id;
+            guid_t  stream_type;
+            //msg_Dbg( p_input, "found stream_properties" );
+
+            var_buffer_getguid( &buffer, &stream_type );
+            var_buffer_getmemory( &buffer, NULL, 32 );
+            i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
+
+            //fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
+
+            if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
+            {
+                //fprintf( stderr, "\nvideo stream[%d] found\n", i_stream_id );
+                //msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
+                hdr->stream[i_stream_id].i_cat = ASF_STREAM_VIDEO;
+            }
+            else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
+            {
+                //fprintf( stderr, "\naudio stream[%d] found\n", i_stream_id );
+                //msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
+                hdr->stream[i_stream_id].i_cat = ASF_STREAM_AUDIO;
+            }
+            else
+            {
+//                msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
+                hdr->stream[i_stream_id].i_cat = ASF_STREAM_UNKNOWN;
+            }
+        }
+        else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
+        {
+            int     i_count;
+            uint8_t i_stream_id;
+
+            i_count = var_buffer_get16( &buffer );
+            i_size -= 2;
+            while( i_count > 0 )
+            {
+                i_stream_id = var_buffer_get16( &buffer )&0x7f;
+                hdr->stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
+                i_count--;
+                i_size -= 6;
+            }
+            //fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
+        }
+        else
+        {
+            //fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
+            // skip unknown guid
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
+        }
+
+        if( var_buffer_readempty( &buffer ) )
+        {
+            return;
+        }
+    }
+}
+
+void E_( asf_StreamSelect ) ( asf_header_t *hdr,
+                              int i_bitrate_max,
+                              vlc_bool_t b_all, vlc_bool_t b_audio, vlc_bool_t b_video )
+{
+    /* XXX FIXME use mututal eclusion information */
+    int i;
+    int i_audio, i_video;
+    int i_bitrate_total;
+    char *psz_stream;
+
+    i_audio = 0;
+    i_video = 0;
+    i_bitrate_total = 0;
+    if( b_all )
+    {
+        /* select all valid stream */
+        for( i = 1; i < 128; i++ )
+        {
+            if( hdr->stream[i].i_cat != ASF_STREAM_UNKNOWN )
+            {
+                hdr->stream[i].i_selected = 1;
+            }
+        }
+        return;
+    }
+    else
+    {
+        for( i = 0; i < 128; i++ )
+        {
+            hdr->stream[i].i_selected = 0; /* by default, not selected */
+        }
+    }
+
+#if 0
+    psz_stream = config_GetPsz( p_input, "mms-stream" );
+
+    if( psz_stream && *psz_stream )
+    {
+        char *psz_tmp = psz_stream;
+        while( *psz_tmp )
+        {
+            if( *psz_tmp == ',' )
+            {
+                psz_tmp++;
+            }
+            else
+            {
+                int i_stream;
+                i_stream = atoi( psz_tmp );
+                while( *psz_tmp != '\0' && *psz_tmp != ',' )
+                {
+                    psz_tmp++;
+                }
+
+                if( i_stream > 0 && i_stream < 128 &&
+                    stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
+                {
+                    stream[i_stream].i_selected = 1;
+                }
+            }
+        }
+        FREE( psz_stream );
+        return;
+    }
+    FREE( psz_stream );
+#endif
+
+    /* big test:
+     * select a stream if
+     *    - no audio nor video stream
+     *    - or:
+     *         - if i_bitrate_max not set keep the highest bitrate
+     *         - if i_bitrate_max is set, keep stream that make we used best
+     *           quality regarding i_bitrate_max
+     *
+     * XXX: little buggy:
+     *        - it doesn't use mutual exclusion info..
+     *        - when selecting a better stream we could select
+     *        something that make i_bitrate_total> i_bitrate_max
+     */
+    for( i = 1; i < 128; i++ )
+    {
+        if( hdr->stream[i].i_cat == ASF_STREAM_UNKNOWN )
+        {
+            continue;
+        }
+        else if( hdr->stream[i].i_cat == ASF_STREAM_AUDIO && b_audio &&
+                 ( i_audio <= 0 ||
+                    ( ( ( hdr->stream[i].i_bitrate > hdr->stream[i_audio].i_bitrate &&
+                          ( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_audio].i_bitrate
+                                            < i_bitrate_max || !i_bitrate_max) ) ||
+                        ( hdr->stream[i].i_bitrate < hdr->stream[i_audio].i_bitrate &&
+                              i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
+                      ) )  ) )
+        {
+            /* unselect old stream */
+            if( i_audio > 0 )
+            {
+                hdr->stream[i_audio].i_selected = 0;
+                if( hdr->stream[i_audio].i_bitrate> 0 )
+                {
+                    i_bitrate_total -= hdr->stream[i_audio].i_bitrate;
+                }
+            }
+
+            hdr->stream[i].i_selected = 1;
+            if( hdr->stream[i].i_bitrate> 0 )
+            {
+                i_bitrate_total += hdr->stream[i].i_bitrate;
+            }
+            i_audio = i;
+        }
+        else if( hdr->stream[i].i_cat == ASF_STREAM_VIDEO && b_video &&
+                 ( i_video <= 0 ||
+                    (
+                        ( ( hdr->stream[i].i_bitrate > hdr->stream[i_video].i_bitrate &&
+                            ( i_bitrate_total + hdr->stream[i].i_bitrate - hdr->stream[i_video].i_bitrate
+                                            < i_bitrate_max || !i_bitrate_max) ) ||
+                          ( hdr->stream[i].i_bitrate < hdr->stream[i_video].i_bitrate &&
+                            i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
+                        ) ) )  )
+        {
+            /* unselect old stream */
+
+            if( i_video > 0 )
+            {
+                hdr->stream[i_video].i_selected = 0;
+                if( hdr->stream[i_video].i_bitrate> 0 )
+                {
+                    i_bitrate_total -= hdr->stream[i_video].i_bitrate;
+                }
+            }
+
+            hdr->stream[i].i_selected = 1;
+            if( hdr->stream[i].i_bitrate> 0 )
+            {
+                i_bitrate_total += hdr->stream[i].i_bitrate;
+            }
+            i_video = i;
+        }
+
+    }
+#if 0
+    if( i_bitrate_max > 0 )
+    {
+        msg_Dbg( p_input,
+                 "requested bitrate:%d real bitrate:%d",
+                 i_bitrate_max, i_bitrate_total );
+    }
+    else
+    {
+        msg_Dbg( p_input,
+                 "total bitrate:%d",
+                 i_bitrate_total );
+    }
+#endif
+}
+
index a90788b..aedbe90 100644 (file)
@@ -2,7 +2,7 @@
  * asf.h: MMS access plug-in
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: asf.h,v 1.4 2003/03/02 18:17:58 fenrir Exp $
+ * $Id: asf.h,v 1.5 2003/04/20 19:29:43 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
  *
  ****************************************************************************/
 
+#define ASF_STREAM_VIDEO    0x0001
+#define ASF_STREAM_AUDIO    0x0002
+#define ASF_STREAM_UNKNOWN  0xffff
+
+typedef struct asf_stream_s
+{
+    int i_id;       /* 1 -> 127 */
+    int i_cat;      /* ASF_STREAM_VIDEO, ASF_STREAM_AUDIO */
+    int i_bitrate;  /* -1 if unknown */
+    int i_selected;
+
+} asf_stream_t;
+
+typedef struct
+{
+    int64_t      i_file_size;
+    int64_t      i_data_packets_count;
+    int32_t      i_min_data_packet_size;
+
+    asf_stream_t stream[128];
+
+} asf_header_t;
+
+
 typedef struct guid_s
 {
     uint32_t v1; /* le */
@@ -36,36 +60,13 @@ typedef struct guid_s
     uint8_t  v4[8];
 } guid_t;
 
-static inline int CmpGuid( const guid_t *p_guid1, const guid_t *p_guid2 )
-{
-    return( ( p_guid1->v1 == p_guid2->v1 &&
-              p_guid1->v2 == p_guid2->v2 &&
-              p_guid1->v3 == p_guid2->v3 &&
-              p_guid1->v4[0] == p_guid2->v4[0] &&
-              p_guid1->v4[1] == p_guid2->v4[1] &&
-              p_guid1->v4[2] == p_guid2->v4[2] &&
-              p_guid1->v4[3] == p_guid2->v4[3] &&
-              p_guid1->v4[4] == p_guid2->v4[4] &&
-              p_guid1->v4[5] == p_guid2->v4[5] &&
-              p_guid1->v4[6] == p_guid2->v4[6] &&
-              p_guid1->v4[7] == p_guid2->v4[7] ) ? 1 : 0 );
-}
-
-static void GenerateGuid( guid_t *p_guid )
-{
-    int i;
-
-    srand( mdate() & 0xffffffff );
-
-    /* FIXME should be generated using random data */
-    p_guid->v1 = 0xbabac001;
-    p_guid->v2 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
-    p_guid->v3 = ( (uint64_t)rand() << 16 ) / RAND_MAX;
-    for( i = 0; i < 8; i++ )
-    {
-        p_guid->v4[i] = ( (uint64_t)rand() * 256 ) / RAND_MAX;
-    }
-}
+
+void E_( GenerateGuid )     ( guid_t * );
+void E_( asf_HeaderParse )  ( asf_header_t *, uint8_t *, int );
+void E_( asf_StreamSelect ) ( asf_header_t *,
+                              int i_bitrate_max, vlc_bool_t b_all, vlc_bool_t b_audio,
+                              vlc_bool_t b_video );
+
 
 #define GUID_FMT "%8.8x-%4.4x-%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x"
 #define GUID_PRINT( guid )  \
index e9b9983..e3ad0e8 100644 (file)
@@ -1,8 +1,8 @@
 /*****************************************************************************
- * mms.c: MMS access plug-in
+ * mms.c: MMS over tcp, udp and http access plug-in
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mms.c,v 1.31 2003/03/30 18:14:35 gbazin Exp $
+ * $Id: mms.c,v 1.32 2003/04/20 19:29:43 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
  *****************************************************************************/
 
 
-/*
- * TODO:
- *  - clean code, break huge code block
- *  - fix memory leak
- *  - begin udp support...
- */
-
 /*****************************************************************************
  * Preamble
  *****************************************************************************/
 #include <stdlib.h>
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <string.h>
-#include <errno.h>
-#include <fcntl.h>
 
 #include <vlc/vlc.h>
 #include <vlc/input.h>
 
-#ifdef HAVE_UNISTD_H
-#   include <unistd.h>
-#endif
-
-#ifdef WIN32
-#   include <winsock2.h>
-#   include <ws2tcpip.h>
-#   ifndef IN_MULTICAST
-#       define IN_MULTICAST(a) IN_CLASSD(a)
-#   endif
-#else
-#   include <sys/socket.h>
-#   include <netinet/in.h>
-#   if HAVE_ARPA_INET_H
-#      include <arpa/inet.h>
-#   elif defined( SYS_BEOS )
-#      include <net/netdb.h>
-#   endif
-#endif
-
-#include "network.h"
-#include "asf.h"
-#include "buffer.h"
 #include "mms.h"
 
-#undef MMS_DEBUG
-
 /****************************************************************************
  * NOTES:
  *  MMSProtocole documentation found at http://get.to/sdp
 /*****************************************************************************
  * Local prototypes
  *****************************************************************************/
-static int  Open        ( vlc_object_t * );
-static void Close       ( vlc_object_t * );
-
-static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
-                          size_t i_len );
-static void Seek        ( input_thread_t *, off_t );
-static int  SetProgram  ( input_thread_t *, pgrm_descriptor_t * );
-
-
-static int MMSOpen( input_thread_t  *, url_t *, int, char * );
-
-static int MMSStart  ( input_thread_t  *, uint32_t );
-static int MMSStop  ( input_thread_t  *p_input );
-
-static int MMSClose  ( input_thread_t  * );
-
-
-static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
-static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
-
-static int  mms_HeaderMediaRead( input_thread_t *, int );
-
-static int  mms_ReceivePacket( input_thread_t * );
-
-static void mms_ParseURL( url_t *p_url, char *psz_url );
 
+struct access_sys_t
+{
+    int i_proto;
 
+};
 
-/*
- * XXX DON'T FREE MY MEMORY !!! XXX
- * non mais :P
- */
+static int  Open        ( vlc_object_t * );
+static void Close       ( vlc_object_t * );
 
-/*
- * Ok, ok, j'le ferai plus...
- */
-/*
- * Merci :))
- */
-/*
- * Vous pourriez signer vos commentaires (même si on voit bien qui peut
- * écrire ce genre de trucs :p), et écrire en anglais, bordel de
- * merde :p.
- */
 
 /*****************************************************************************
  * Module descriptor
@@ -141,153 +69,54 @@ vlc_module_begin();
         add_bool( "mms-all", 0, NULL,
                   "force selection of all streams",
                   "force selection of all streams", VLC_TRUE );
-
+#if 0
         add_string( "mms-stream", NULL, NULL,
                     "streams selection",
                     "force this stream selection", VLC_TRUE );
+#endif
         add_integer( "mms-maxbitrate", 0, NULL,
                      "max bitrate",
                      "set max bitrate for auto streams selections", VLC_FALSE );
     add_shortcut( "mms" );
     add_shortcut( "mmsu" );
     add_shortcut( "mmst" );
+    add_shortcut( "mmsh" );
     set_callbacks( Open, Close );
 vlc_module_end();
 
-#define BUF_SIZE 200000
 
 static int Open( vlc_object_t *p_this )
 {
-    access_t    *p_access;
-    int         i_proto;
-    char        *psz_network;
-    int         i_status;
-
     input_thread_t  *p_input = (input_thread_t*)p_this;
 
-    /* *** allocate p_access_data *** */
-    p_input->p_access_data =
-        (void*)p_access = malloc( sizeof( access_t ) );
-    memset( p_access, 0, sizeof( access_t ) );
-
-
-    /* *** Parse URL and get server addr/port and path *** */
-    mms_ParseURL( &p_access->url, p_input->psz_name );
-    if( p_access->url.psz_server_addr == NULL ||
-        !( *p_access->url.psz_server_addr ) )
-    {
-        FREE( p_access->url.psz_private );
-        msg_Err( p_input, "invalid server name" );
-        return( -1 );
-    }
-    if( p_access->url.i_server_port == 0 )
-    {
-        p_access->url.i_server_port = 1755; /* default port */
-    }
-    if( p_access->url.i_bind_port == 0 )
-    {
-        p_access->url.i_bind_port = 7000;   /* default port */
-    }
+    int i_err;
 
 
-    /* *** connect to this server *** */
-    /* 1: look at  requested protocol (udp/tcp) */
-    i_proto = MMS_PROTO_AUTO;
     if( *p_input->psz_access )
     {
         if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
         {
-            i_proto = MMS_PROTO_UDP;
+            return MMSTUOpen( p_input );
         }
         else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
         {
-            i_proto = MMS_PROTO_TCP;
+            return MMSTUOpen( p_input );
         }
-    }
-    /* 2: look at ip version ipv4/ipv6 */
-    psz_network = "";
-    if( config_GetInt( p_input, "ipv4" ) )
-    {
-        psz_network = "ipv4";
-    }
-    else if( config_GetInt( p_input, "ipv6" ) )
-    {
-        psz_network = "ipv6";
-    }
-    /* 3: connect */
-    if( i_proto == MMS_PROTO_AUTO )
-    {   /* first try with TCP */
-        i_status =
-            MMSOpen( p_input, &p_access->url, MMS_PROTO_TCP, psz_network );
-        if( i_status < 0 )
-        {   /* then with UDP */
-            i_status =
-             MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network );
+        else if( !strncmp( p_input->psz_access, "mmsh", 4 ) )
+        {
+            return MMSHOpen( p_input );
         }
     }
-    else
-    {
-
-        i_status =
-            MMSOpen( p_input, &p_access->url, i_proto, psz_network );
-    }
-
-    if( i_status < 0 )
-    {
-        msg_Err( p_input, "cannot connect to server" );
-        FREE( p_access->url.psz_private );
-        return( -1 );
-    }
-    msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
-
-
-    /* *** set exported functions *** */
-    p_input->pf_read = Read;
-    p_input->pf_seek = Seek;
-    p_input->pf_set_program = SetProgram;
-    p_input->pf_set_area = NULL;
-
-    p_input->p_private = NULL;
 
-    /* *** finished to set some variable *** */
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-    p_input->stream.b_pace_control = 0;
-    p_input->stream.p_selected_area->i_tell = 0;
-    /*
-     * i_flags_broadcast
-     *  yy xx ?? ??
-     *  broadcast    yy=0x02, xx= 0x00
-     *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
-     */
-    if( p_access->i_packet_count <= 0 || ( p_access->i_flags_broadcast >> 24 ) == 0x02 )
-    {
-        p_input->stream.b_seekable = 0;
-        p_input->stream.p_selected_area->i_size = 0;
-    }
-    else
-    {
-        p_input->stream.b_seekable = 1;
-        p_input->stream.p_selected_area->i_size =
-            p_access->i_header +
-            p_access->i_packet_count * p_access->i_packet_length;
-    }
 
-    p_input->stream.i_method = INPUT_METHOD_NETWORK;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
+    i_err = MMSTUOpen( p_input );
 
-    /* *** Start stream *** */
-    if( MMSStart( p_input, 0xffffffff ) < 0 )
+    if( i_err )
     {
-        msg_Err( p_input, "cannot start stream" );
-        MMSClose( p_input );
-        FREE( p_access->url.psz_private );
-        return( -1 );
+        i_err = MMSHOpen( p_input );
     }
 
-    /* Update default_pts to a suitable value for mms access */
-    p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
-
-    return( 0 );
+    return i_err;
 }
 
 /*****************************************************************************
@@ -296,1668 +125,130 @@ static int Open( vlc_object_t *p_this )
 static void Close( vlc_object_t *p_this )
 {
     input_thread_t *  p_input = (input_thread_t *)p_this;
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-
-    /* close connection with server */
-    MMSClose( p_input );
-
-    /* free memory */
-    FREE( p_access->url.psz_private );
-
-    FREE( p_input->p_access_data );
-}
-
-/*****************************************************************************
- * SetProgram: do nothing
- *****************************************************************************/
-static int SetProgram( input_thread_t * p_input,
-                       pgrm_descriptor_t * p_program )
-{
-    return( 0 );
-}
-
-/*****************************************************************************
- * Seek: try to go at the right place
- *****************************************************************************/
-static void Seek( input_thread_t * p_input, off_t i_pos )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    uint32_t    i_packet;
-    uint32_t    i_offset;
-    var_buffer_t    buffer;
-
-    if( i_pos < 0 )
-    {
-        return;
-    }
-
-    vlc_mutex_lock( &p_input->stream.stream_lock );
-
-    if( i_pos < p_access->i_header)
-    {
-
-        if( p_access->i_pos < p_access->i_header )
-        {
-            /* no need to restart stream, it was already one
-             * or no stream was yet read */
-            p_access->i_pos = i_pos;
-            return;
-        }
-        else
-        {
-            i_packet = 0xffffffff;
-            i_offset = 0;
-        }
-    }
-    else
-    {
-        i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length;
-        i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length;
-    }
-    msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
-
-    MMSStop( p_input );
-    msg_Dbg( p_input, "stream stopped (seek)" );
-
-    /* *** restart stream *** */
-    var_buffer_initwrite( &buffer, 0 );
-    var_buffer_add64( &buffer, 0 ); /* seek point in second */
-    var_buffer_add32( &buffer, 0xffffffff );
-    var_buffer_add32( &buffer, i_packet ); // begin from start
-    var_buffer_add8( &buffer, 0xff ); // stream time limit
-    var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
-    var_buffer_add8( &buffer, 0xff ); //
-    var_buffer_add8( &buffer, 0x00 ); // don't use limit
-    var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
-
-    mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
-                     buffer.p_data, buffer.i_data );
-
-    var_buffer_free( &buffer );
-
+    access_sys_t   *  p_sys   = p_input->p_access_data;
 
-    for( ;; )
+    if( p_sys->i_proto == MMS_PROTO_TCP || p_sys->i_proto == MMS_PROTO_UDP )
     {
-        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
-        if( p_access->i_command == 0x1e )
-        {
-            msg_Dbg( p_input, "received 0x1e (seek)" );
-            break;
-        }
+        MMSTUClose( p_input );
     }
-
-    for( ;; )
+    else if( p_sys->i_proto == MMS_PROTO_HTTP )
     {
-        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
-        if( p_access->i_command == 0x05 )
-        {
-            msg_Dbg( p_input, "received 0x05 (seek)" );
-            break;
-        }
+        MMSHClose( p_input );
     }
-
-    /* get a packet */
-    mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
-    msg_Dbg( p_input, "Streaming restarted" );
-
-    p_access->i_media_used += i_offset;
-    p_access->i_pos = i_pos;
-    p_input->stream.p_selected_area->i_tell = i_pos;
-    vlc_mutex_unlock( &p_input->stream.stream_lock );
 }
 
-static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
-                          size_t i_len )
+/****************************************************************************
+ * parse hostname:port/path@username:password
+ * FIXME ipv6 ip will be baddly parsed (contain ':' )
+ ****************************************************************************/
+url_t *E_( url_new )  ( char * psz_url )
 {
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    size_t      i_data;
-    size_t      i_copy;
+    url_t *p_url = malloc( sizeof( url_t ) );
 
-    i_data = 0;
+    char  *psz_dup    = strdup( psz_url );
+    char  *psz_parser = psz_dup;
 
-    /* *** send header if needed ** */
-    if( p_access->i_pos < p_access->i_header )
-    {
-        i_copy = __MIN( i_len, p_access->i_header - p_access->i_pos );
-        if( i_copy > 0 )
-        {
-            memcpy( p_buffer,
-                    p_access->p_header + p_access->i_pos,
-                    i_copy );
-        }
-        i_data += i_copy;
-    }
+    char  *psz_tmp;
 
-    /* *** now send data if needed *** */
-    while( i_data < i_len )
+    /* 1: get hostname:port */
+    while( *psz_parser == '/' )
     {
-        if( p_access->i_media_used < p_access->i_media )
-        {
-            i_copy = __MIN( i_len - i_data ,
-                            p_access->i_media - p_access->i_media_used );
-            memcpy( p_buffer + i_data,
-                    p_access->p_media + p_access->i_media_used,
-                    i_copy );
-            i_data += i_copy;
-            p_access->i_media_used += i_copy;
-        }
-        else if( p_access->p_media != NULL &&
-                 p_access->i_media_used < p_access->i_packet_length )
-        {
-            i_copy = __MIN( i_len - i_data,
-                            p_access->i_packet_length - p_access->i_media_used);
-            memset( p_buffer + i_data, 0, i_copy );
-
-            i_data += i_copy;
-            p_access->i_media_used += i_copy;
-        }
-        else
-        {
-            if( p_access->i_eos
-                 || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )
-            {
-                p_access->i_pos += i_data;
-                return( i_data );
-            }
-        }
+        psz_parser++;
     }
 
-    p_access->i_pos += i_data;
-    return( i_data );
-}
-
-static void asf_HeaderParse( mms_stream_t stream[128],
-                             uint8_t *p_header, int i_header )
-{
-    var_buffer_t buffer;
-    guid_t      guid;
-    uint64_t    i_size;
-    int         i;
+    psz_tmp = psz_parser;
 
-    for( i = 0; i < 128; i++ )
+    while( *psz_parser &&
+           *psz_parser != ':' &&  *psz_parser != '/' && *psz_parser != '@' )
     {
-        stream[i].i_cat = MMS_STREAM_UNKNOWN;
+        psz_parser++;
     }
 
-    //fprintf( stderr, " ---------------------header:%d\n", i_header );
-    var_buffer_initread( &buffer, p_header, i_header );
-
-    var_buffer_getguid( &buffer, &guid );
-
-    if( !CmpGuid( &guid, &asf_object_header_guid ) )
-    {
-//        XXX Error
-//        fprintf( stderr, " ---------------------ERROR------\n" );
-    }
-    var_buffer_getmemory( &buffer, NULL, 30 - 16 );
+    p_url->psz_host     = strndup( psz_tmp, psz_parser - psz_tmp );
 
-    for( ;; )
+    if( *psz_parser == ':' )
     {
-        //fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
-
-        var_buffer_getguid( &buffer, &guid );
-        i_size = var_buffer_get64( &buffer );
-
-        //fprintf( stderr, "  guid=0x%8.8x-0x%4.4x-0x%4.4x-%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x%2.2x size=%lld\n",
-        //                  guid.v1,guid.v2, guid.v3,
-        //                  guid.v4[0],guid.v4[1],guid.v4[2],guid.v4[3],
-        //                  guid.v4[4],guid.v4[5],guid.v4[6],guid.v4[7],
-        //                  i_size );
-
-        if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
-        {
-            int     i_stream_id;
-            guid_t  stream_type;
-            //msg_Dbg( p_input, "found stream_properties" );
-
-            var_buffer_getguid( &buffer, &stream_type );
-            var_buffer_getmemory( &buffer, NULL, 32 );
-            i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
-
-            //fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
-            var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
-
-            if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
-            {
-                //fprintf( stderr, "\nvideo stream[%d] found\n", i_stream_id );
-                //msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
-                stream[i_stream_id].i_cat = MMS_STREAM_VIDEO;
-            }
-            else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
-            {
-                //fprintf( stderr, "\naudio stream[%d] found\n", i_stream_id );
-                //msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
-                stream[i_stream_id].i_cat = MMS_STREAM_AUDIO;
-            }
-            else
-            {
-//                msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
-                stream[i_stream_id].i_cat = MMS_STREAM_UNKNOWN;
-            }
-        }
-        else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
-        {
-            int     i_count;
-            uint8_t i_stream_id;
-
-            i_count = var_buffer_get16( &buffer );
-            i_size -= 2;
-            while( i_count > 0 )
-            {
-                i_stream_id = var_buffer_get16( &buffer )&0x7f;
-                stream[i_stream_id].i_bitrate =  var_buffer_get32( &buffer );
-                i_count--;
-                i_size -= 6;
-            }
-            //fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
-            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
-        }
-        else
-        {
-            //fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
-            // skip unknown guid
-            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
-        }
-
-        if( var_buffer_readempty( &buffer ) )
-        {
-            return;
-        }
-    }
-}
-
-static void mms_StreamSelect( input_thread_t * p_input,
-                              mms_stream_t stream[128] )
-{
-    /* XXX FIXME use mututal eclusion information */
-    int i;
-    int i_audio, i_video;
-    int b_audio, b_video;
-    int i_bitrate_total;
-    int i_bitrate_max;
-    char *psz_stream;
+        psz_parser++;
+        psz_tmp = psz_parser;
 
-    i_audio = 0;
-    i_video = 0;
-    i_bitrate_total = 0;
-    i_bitrate_max = config_GetInt( p_input, "mms-maxbitrate" );
-    b_audio = config_GetInt( p_input, "audio" );
-    b_video = config_GetInt( p_input, "video" );
-    if( config_GetInt( p_input, "mms-all" ) )
-    {
-        /* select all valid stream */
-        for( i = 1; i < 128; i++ )
+        while( *psz_parser && *psz_parser != '/' && *psz_parser != '@' )
         {
-            if( stream[i].i_cat != MMS_STREAM_UNKNOWN )
-            {
-                stream[i].i_selected = 1;
-            }
+            psz_parser++;
         }
-        return;
+        p_url->i_port = atoi( psz_tmp );
     }
     else
     {
-        for( i = 0; i < 128; i++ )
-        {
-            stream[i].i_selected = 0; /* by default, not selected */
-        }
+        p_url->i_port = 0;
     }
-    psz_stream = config_GetPsz( p_input, "mms-stream" );
 
-    if( psz_stream && *psz_stream )
+    /* 2: get path */
+    if( *psz_parser == '/' )
     {
-        char *psz_tmp = psz_stream;
-        while( *psz_tmp )
-        {
-            if( *psz_tmp == ',' )
-            {
-                psz_tmp++;
-            }
-            else
-            {
-                int i_stream;
-                i_stream = atoi( psz_tmp );
-                while( *psz_tmp != '\0' && *psz_tmp != ',' )
-                {
-                    psz_tmp++;
-                }
-
-                if( i_stream > 0 && i_stream < 128 &&
-                    stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
-                {
-                    stream[i_stream].i_selected = 1;
-                }
-            }
-        }
-        FREE( psz_stream );
-        return;
-    }
-    FREE( psz_stream );
+        //psz_parser++;
 
-    /* big test:
-     * select a stream if
-     *    - no audio nor video stream
-     *    - or:
-     *         - if i_bitrate_max not set keep the highest bitrate
-     *         - if i_bitrate_max is set, keep stream that make we used best
-     *           quality regarding i_bitrate_max
-     *
-     * XXX: little buggy:
-     *        - it doesn't use mutual exclusion info..
-     *        - when selecting a better stream we could select
-     *        something that make i_bitrate_total> i_bitrate_max
-     */
-    for( i = 1; i < 128; i++ )
-    {
-        if( stream[i].i_cat == MMS_STREAM_UNKNOWN )
-        {
-            continue;
-        }
-        else if( stream[i].i_cat == MMS_STREAM_AUDIO && b_audio &&
-                 ( i_audio <= 0 ||
-                    ( ( ( stream[i].i_bitrate > stream[i_audio].i_bitrate &&
-                          ( i_bitrate_total + stream[i].i_bitrate - stream[i_audio].i_bitrate
-                                            < i_bitrate_max || !i_bitrate_max) ) ||
-                        ( stream[i].i_bitrate < stream[i_audio].i_bitrate &&
-                              i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
-                      ) )  ) )
-        {
-            /* unselect old stream */
-            if( i_audio > 0 )
-            {
-                stream[i_audio].i_selected = 0;
-                if( stream[i_audio].i_bitrate> 0 )
-                {
-                    i_bitrate_total -= stream[i_audio].i_bitrate;
-                }
-            }
+        psz_tmp = psz_parser;
 
-            stream[i].i_selected = 1;
-            if( stream[i].i_bitrate> 0 )
-            {
-                i_bitrate_total += stream[i].i_bitrate;
-            }
-            i_audio = i;
-        }
-        else if( stream[i].i_cat == MMS_STREAM_VIDEO && b_video &&
-                 ( i_video <= 0 ||
-                    (
-                        ( ( stream[i].i_bitrate > stream[i_video].i_bitrate &&
-                            ( i_bitrate_total + stream[i].i_bitrate - stream[i_video].i_bitrate
-                                            < i_bitrate_max || !i_bitrate_max) ) ||
-                          ( stream[i].i_bitrate < stream[i_video].i_bitrate &&
-                            i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
-                        ) ) )  )
+        while( *psz_parser && *psz_parser != '@' )
         {
-            /* unselect old stream */
-
-            stream[i_video].i_selected = 0;
-            if( stream[i_video].i_bitrate> 0 )
-            {
-                i_bitrate_total -= stream[i_video].i_bitrate;
-            }
-
-            stream[i].i_selected = 1;
-            if( stream[i].i_bitrate> 0 )
-            {
-                i_bitrate_total += stream[i].i_bitrate;
-            }
-            i_video = i;
+            psz_parser++;
         }
 
-    }
-    if( i_bitrate_max > 0 )
-    {
-        msg_Dbg( p_input,
-                 "requested bitrate:%d real bitrate:%d",
-                 i_bitrate_max, i_bitrate_total );
+        p_url->psz_path = strndup( psz_tmp, psz_parser - psz_tmp );
     }
     else
     {
-        msg_Dbg( p_input,
-                 "total bitrate:%d",
-                 i_bitrate_total );
-    }
-}
-
-/****************************************************************************
- * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
- ****************************************************************************/
-static int MMSOpen( input_thread_t  *p_input,
-                       url_t *p_url,
-                       int  i_proto,
-                       char *psz_network ) /* "", "ipv4", "ipv6" */
-{
-    module_t    *p_network;
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-
-    network_socket_t    socket_desc;
-    int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
-
-    var_buffer_t buffer;
-    char         tmp[4096];
-    uint16_t     *p;
-    int          i_server_version;
-    int          i_tool_version;
-    int          i_update_player_url;
-    int          i_encryption_type;
-    int          i;
-    int          i_streams;
-    int          i_first;
-
-
-    /* *** Open a TCP connection with server *** */
-    msg_Dbg( p_input, "waiting for connection..." );
-    socket_desc.i_type = NETWORK_TCP;
-    socket_desc.psz_server_addr = p_url->psz_server_addr;
-    socket_desc.i_server_port   = p_url->i_server_port;
-    socket_desc.psz_bind_addr   = "";
-    socket_desc.i_bind_port     = 0;
-    p_input->p_private = (void*)&socket_desc;
-    if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
-    {
-        msg_Err( p_input, "failed to open a connection (tcp)" );
-        return( -1 );
+        p_url->psz_path = strdup( "" );
     }
-    module_Unneed( p_input, p_network );
-    p_access->socket_tcp.i_handle = socket_desc.i_handle;
-    p_input->i_mtu    = 0; /*socket_desc.i_mtu;*/
-    msg_Dbg( p_input,
-             "connection(tcp) with \"%s:%d\" successful",
-             p_url->psz_server_addr,
-             p_url->i_server_port );
 
-    /* *** Bind port if UDP protocol is selected *** */
-    if( b_udp )
+    /* 3: usrname and password */
+    if( *psz_parser == '@' )
     {
-        if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr )
-        {
-            struct sockaddr_in name;
-            socklen_t i_namelen = sizeof( struct sockaddr_in );
+        psz_parser++;
 
-            if( getsockname( p_access->socket_tcp.i_handle,
-                             (struct sockaddr*)&name, &i_namelen ) < 0 )
-            {
+        psz_tmp = psz_parser;
 
-                msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
-#if defined( UNDER_CE )
-                CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
-                closesocket( p_access->socket_tcp.i_handle );
-#else
-                close( p_access->socket_tcp.i_handle );
-#endif
-                return( -1 );
-            }
-            p_access->psz_bind_addr = inet_ntoa( name.sin_addr );
-        }
-        else
+        while( *psz_parser && *psz_parser != ':' )
         {
-            p_access->psz_bind_addr = strdup( p_url->psz_bind_addr );
-        }
-        socket_desc.i_type = NETWORK_UDP;
-        socket_desc.psz_server_addr = "";
-        socket_desc.i_server_port   = 0;
-        socket_desc.psz_bind_addr   = p_access->psz_bind_addr;
-        socket_desc.i_bind_port     = p_url->i_bind_port;
-        p_input->p_private = (void*)&socket_desc;
-        if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
-        {
-            msg_Err( p_input, "failed to open a connection (udp)" );
-#if defined( UNDER_CE )
-            CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
-            closesocket( p_access->socket_tcp.i_handle );
-#else
-            close( p_access->socket_tcp.i_handle );
-#endif
-            return( -1 );
+            psz_parser++;
         }
-        module_Unneed( p_input, p_network );
-        p_access->socket_udp.i_handle = socket_desc.i_handle;
-        p_input->i_mtu    = 0;/*socket_desc.i_mtu;  FIXME */
-
-    }
-    else
-    {
-        p_access->psz_bind_addr = NULL;
-    }
-
-    /* *** Init context for mms prototcol *** */
-    GenerateGuid( &p_access->guid );    /* used to identify client by server */
-    msg_Dbg( p_input,
-             "generated guid: "GUID_FMT,
-             GUID_PRINT( p_access->guid ) );
-    p_access->i_command_level = 1;          /* updated after 0x1A command */
-    p_access->i_seq_num = 0;
-    p_access->i_media_packet_id_type  = 0x04;
-    p_access->i_header_packet_id_type = 0x02;
-    p_access->i_proto = i_proto;
-    p_access->i_packet_seq_num = 0;
-    p_access->p_header = NULL;
-    p_access->i_header = 0;
-    p_access->p_media = NULL;
-    p_access->i_media = 0;
-    p_access->i_media_used = 0;
-
-    p_access->i_pos = 0;
-    p_access->i_buffer_tcp = 0;
-    p_access->i_buffer_udp = 0;
-    p_access->p_cmd = NULL;
-    p_access->i_cmd = 0;
-    p_access->i_eos = 0;
-
-    /* *** send command 1 : connection request *** */
-    var_buffer_initwrite( &buffer, 0 );
-    var_buffer_add16( &buffer, 0x001c );
-    var_buffer_add16( &buffer, 0x0003 );
-    sprintf( tmp,
-             "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
-             GUID_PRINT( p_access->guid ),
-             p_url->psz_server_addr );
-    var_buffer_addUTF16( &buffer, tmp );
 
-    mms_CommandSend( p_input,
-                     0x01,          /* connexion request */
-                     0x00000000,    /* flags, FIXME */
-                     0x0004000b,    /* ???? */
-                     buffer.p_data,
-                     buffer.i_data );
+        p_url->psz_username = strndup( psz_tmp, psz_parser - psz_tmp );
 
-    if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )
-    {
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-
-    i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
-    i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
-    i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
-    i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
-    p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
-#define GETUTF16( psz, size ) \
-    { \
-        int i; \
-        psz = malloc( size + 1); \
-        for( i = 0; i < size; i++ ) \
-        { \
-            psz[i] = p[i]; \
-        } \
-        psz[size] = '\0'; \
-        p += 2 * ( size ); \
-    }
-    GETUTF16( p_access->psz_server_version, i_server_version );
-    GETUTF16( p_access->psz_tool_version, i_tool_version );
-    GETUTF16( p_access->psz_update_player_url, i_update_player_url );
-    GETUTF16( p_access->psz_encryption_type, i_encryption_type );
-#undef GETUTF16
-    msg_Dbg( p_input,
-             "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
-             p_access->psz_server_version,
-             p_access->psz_tool_version,
-             p_access->psz_update_player_url,
-             p_access->psz_encryption_type );
-
-    /* *** should make an 18 command to make data timing *** */
-
-    /* *** send command 2 : transport protocol selection *** */
-    var_buffer_reinitwrite( &buffer, 0 );
-    var_buffer_add32( &buffer, 0x00000000 );
-    var_buffer_add32( &buffer, 0x000a0000 );
-    var_buffer_add32( &buffer, 0x00000002 );
-    if( b_udp )
-    {
-        sprintf( tmp,
-                 "\\\\%s\\UDP\\%d",
-                 p_access->psz_bind_addr,
-                 p_url->i_bind_port );
-    }
-    else
-    {
-        sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
-    }
-    var_buffer_addUTF16( &buffer, tmp );
-    var_buffer_add16( &buffer, '0' );
-
-    mms_CommandSend( p_input,
-                     0x02,          /* connexion request */
-                     0x00000000,    /* flags, FIXME */
-                     0xffffffff,    /* ???? */
-                     buffer.p_data,
-                     buffer.i_data );
-
-    /* *** response from server, should be 0x02 or 0x03 *** */
-    mms_CommandRead( p_input, 0x02, 0x03 );
-    if( p_access->i_command == 0x03 )
-    {
-        msg_Err( p_input,
-                 "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-    else if( p_access->i_command != 0x02 )
-    {
-        msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
-    }
-
-    /* *** send command 5 : media file name/path requested *** */
-    var_buffer_reinitwrite( &buffer, 0 );
-    var_buffer_add64( &buffer, 0 );
-    var_buffer_addUTF16( &buffer, p_url->psz_path );
-
-    mms_CommandSend( p_input,
-                     0x05,
-                     p_access->i_command_level,
-                     0xffffffff,
-                     buffer.p_data,
-                     buffer.i_data );
-
-    /* *** wait for reponse *** */
-    mms_CommandRead( p_input, 0x1a, 0x06 );
-
-    /* test if server send 0x1A answer */
-    if( p_access->i_command == 0x1A )
-    {
-        msg_Err( p_input, "id/password requested (not yet supported)" );
-        /*  FIXME */
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-    if( p_access->i_command != 0x06 )
-    {
-        msg_Err( p_input,
-                 "unknown answer (0x%x instead of 0x06)",
-                 p_access->i_command );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-
-    /*  1 for file ok, 2 for authen ok */
-    switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
-    {
-        case 0x0001:
-            msg_Dbg( p_input, "Media file name/path accepted" );
-            break;
-        case 0x0002:
-            msg_Dbg( p_input, "Authentication accepted" );
-            break;
-        case -1:
-        default:
-        msg_Err( p_input, "error while asking for file %d",
-                 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-
-    p_access->i_flags_broadcast =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
-    p_access->i_media_length =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
-    p_access->i_packet_length =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
-    p_access->i_packet_count =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
-    p_access->i_max_bit_rate =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
-    p_access->i_header_size =
-        GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
-
-    msg_Dbg( p_input,
-             "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
-             p_access->i_flags_broadcast,
-             p_access->i_media_length,
-             p_access->i_packet_length,
-             p_access->i_packet_count,
-             p_access->i_max_bit_rate,
-             p_access->i_header_size );
-
-    /* XXX XXX dirty hack XXX XXX */
-    p_input->i_mtu    = 3 * p_access->i_packet_length;
-
-    /* *** send command 15 *** */
-
-    var_buffer_reinitwrite( &buffer, 0 );
-    var_buffer_add32( &buffer, 0 );
-    var_buffer_add32( &buffer, 0x8000 );
-    var_buffer_add32( &buffer, 0xffffffff );
-    var_buffer_add32( &buffer, 0x00 );
-    var_buffer_add32( &buffer, 0x00 );
-    var_buffer_add32( &buffer, 0x00 );
-    var_buffer_add64( &buffer, 0x40ac200000000000 );
-    var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
-    mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00,
-                     buffer.p_data, buffer.i_data );
-
-    /* *** wait for reponse *** */
-    mms_CommandRead( p_input, 0x11, 0 );
-
-    if( p_access->i_command != 0x11 )
-    {
-        msg_Err( p_input,
-                 "unknown answer (0x%x instead of 0x11)",
-                 p_access->i_command );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-    /* *** now read header packet *** */
-    /* XXX could be split over multiples packets */
-    for( ;; )
-    {
-        if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
-        {
-            msg_Err( p_input, "cannot receive header" );
-            var_buffer_free( &buffer );
-            MMSClose( p_input );
-            return( -1 );
-        }
-        if( p_access->i_header >= p_access->i_header_size )
+        if( *psz_parser == ':' )
         {
-            msg_Dbg( p_input,
-                     "header complete(%d)",
-                     p_access->i_header );
-            break;
-        }
-        msg_Dbg( p_input,
-                 "header incomplete (%d/%d), reading more",
-                 p_access->i_header,
-                 p_access->i_header_size );
-    }
-
-    /* *** parse header and get stream and their id *** */
-    /* get all streams properties,
-     *
-     * TODO : stream bitrates properties(optional)
-     *        and bitrate mutual exclusion(optional) */
-    asf_HeaderParse( p_access->stream,
-                     p_access->p_header, p_access->i_header );
-    mms_StreamSelect( p_input, p_access->stream );
-    /* *** now select stream we want to receive *** */
-    /* TODO take care of stream bitrate TODO */
-    i_streams = 0;
-    i_first = -1;
-    var_buffer_reinitwrite( &buffer, 0 );
-    /* for now, select first audio and video stream */
-    for( i = 1; i < 128; i++ )
-    {
+            psz_parser++;
 
-        if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
+            p_url->psz_password = strdup( psz_parser );
+        }
+        else
         {
-            i_streams++;
-            if( i_first != -1 )
-            {
-                var_buffer_add16( &buffer, 0xffff );
-                var_buffer_add16( &buffer, i );
-            }
-            else
-            {
-                i_first = i;
-            }
-            if( p_access->stream[i].i_selected )
-            {
-                var_buffer_add16( &buffer, 0x0000 );
-                msg_Info( p_input,
-                          "selecting stream[0x%x] %s (%d kb/s)",
-                          i,
-                          ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
-                                                  "audio" : "video" ,
-                          p_access->stream[i].i_bitrate / 1024);
-            }
-            else
-            {
-                var_buffer_add16( &buffer, 0x0002 );
-                msg_Info( p_input,
-                          "ignoring stream[0x%x] %s (%d kb/s)",
-                          i,
-                          ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO  ) ?
-                                    "audio" : "video" ,
-                          p_access->stream[i].i_bitrate / 1024);
-
-            }
+            p_url->psz_password = strdup( "" );
         }
     }
-
-    if( i_streams == 0 )
-    {
-        msg_Err( p_input, "cannot find any stream" );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
-    }
-    mms_CommandSend( p_input, 0x33,
-                     i_streams,
-                     0xffff | ( i_first << 16 ),
-                     buffer.p_data, buffer.i_data );
-
-    mms_CommandRead( p_input, 0x21, 0 );
-    if( p_access->i_command != 0x21 )
+    else
     {
-        msg_Err( p_input,
-                 "unknown answer (0x%x instead of 0x21)",
-                 p_access->i_command );
-        var_buffer_free( &buffer );
-        MMSClose( p_input );
-        return( -1 );
+        p_url->psz_username = strdup( "" );
+        p_url->psz_password = strdup( "" );
     }
-
-
-    var_buffer_free( &buffer );
-
-    msg_Info( p_input, "connection sucessful" );
-
-    return( 0 );
+#if 0
+    fprintf( stderr,
+             "host=`%s' port=%d path=`%s' username=`%s' password=`%s'\n",
+             p_url->psz_host,
+             p_url->i_port,
+             p_url->psz_path,
+             p_url->psz_username,
+             p_url->psz_password );
+#endif
+    free( psz_dup );
+    return p_url;
 }
 
-/****************************************************************************
- * MMSStart : Start streaming
- ****************************************************************************/
-static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
+void   E_( url_free ) ( url_t * p_url )
 {
-    access_t        *p_access = (access_t*)p_input->p_access_data;
-    var_buffer_t    buffer;
-
-    /* *** start stream from packet 0 *** */
-    var_buffer_initwrite( &buffer, 0 );
-    var_buffer_add64( &buffer, 0 ); /* seek point in second */
-    var_buffer_add32( &buffer, 0xffffffff );
-    var_buffer_add32( &buffer, i_packet ); // begin from start
-    var_buffer_add8( &buffer, 0xff ); // stream time limit
-    var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
-    var_buffer_add8( &buffer, 0xff ); //
-    var_buffer_add8( &buffer, 0x00 ); // don't use limit
-    var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
-
-    mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
-                     buffer.p_data, buffer.i_data );
-
-    var_buffer_free( &buffer );
-
-    mms_CommandRead( p_input, 0x05, 0 );
-
-    if( p_access->i_command != 0x05 )
-    {
-        msg_Err( p_input,
-                 "unknown answer (0x%x instead of 0x05)",
-                 p_access->i_command );
-        return( -1 );
-    }
-    else
-    {
-        /* get a packet */
-        mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
-        msg_Dbg( p_input, "Streaming started" );
-        return( 0 );
-    }
-}
-
-/****************************************************************************
- * MMSStop : Stop streaming
- ****************************************************************************/
-static int MMSStop  ( input_thread_t  *p_input )
-{
-    access_t        *p_access = (access_t*)p_input->p_access_data;
-
-    /* *** stop stream but keep connection alive *** */
-    mms_CommandSend( p_input,
-                     0x09,
-                     p_access->i_command_level,
-                     0x001fffff,
-                     NULL, 0 );
-    return( 0 );
-}
-
-/****************************************************************************
- * MMSClose : Close streaming and connection
- ****************************************************************************/
-static int MMSClose  ( input_thread_t  *p_input )
-{
-    access_t        *p_access = (access_t*)p_input->p_access_data;
-
-    msg_Dbg( p_input, "Connection closed" );
-
-    /* *** tell server that we will disconnect *** */
-    mms_CommandSend( p_input,
-                     0x0d,
-                     p_access->i_command_level,
-                     0x00000001,
-                     NULL, 0 );
-    /* *** close sockets *** */
-#if defined( UNDER_CE )
-    CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
-#elif defined( WIN32 )
-    closesocket( p_access->socket_tcp.i_handle );
-#else
-    close( p_access->socket_tcp.i_handle );
-#endif
-
-    if( p_access->i_proto == MMS_PROTO_UDP )
-    {
-#if defined( UNDER_CE )
-        CloseHandle( (HANDLE)p_access->socket_udp.i_handle );
-#elif defined( WIN32 )
-        closesocket( p_access->socket_udp.i_handle );
-#else
-        close( p_access->socket_udp.i_handle );
-#endif
-    }
-
-    FREE( p_access->p_cmd );
-    FREE( p_access->p_media );
-    FREE( p_access->p_header );
-
-    FREE( p_access->psz_server_version );
-    FREE( p_access->psz_tool_version );
-    FREE( p_access->psz_update_player_url );
-    FREE( p_access->psz_encryption_type );
-
-    return( 0 );
-}
-
-/*****************************************************************************
- * mms_ParseURL : parse an url string and fill an url_t
- *****************************************************************************/
-static void mms_ParseURL( url_t *p_url, char *psz_url )
-{
-    char *psz_parser;
-    char *psz_server_port;
-
-    p_url->psz_private = strdup( psz_url );
-
-    psz_parser = p_url->psz_private;
-
-    while( *psz_parser == '/' )
-    {
-        psz_parser++;
-    }
-    p_url->psz_server_addr = psz_parser;
-
-    while( *psz_parser &&
-           *psz_parser != ':' &&  *psz_parser != '/' && *psz_parser != '@' )
-    {
-        psz_parser++;
-    }
-
-    if( *psz_parser == ':' )
-    {
-        *psz_parser = '\0';
-        psz_parser++;
-        psz_server_port = psz_parser;
-
-        while( *psz_parser && *psz_parser != '/' )
-        {
-            psz_parser++;
-        }
-    }
-    else
-    {
-        psz_server_port = "";
-    }
-
-    if( *psz_parser == '@' )
-    {
-        char *psz_bind_port;
-
-        *psz_parser = '\0';
-        psz_parser++;
-
-        p_url->psz_bind_addr = psz_parser;
-
-        while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
-        {
-            psz_parser++;
-        }
-
-        if( *psz_parser == ':' )
-        {
-            *psz_parser = '\0';
-            psz_parser++;
-            psz_bind_port = psz_parser;
-
-            while( *psz_parser && *psz_parser != '/' )
-            {
-                psz_parser++;
-            }
-        }
-        else
-        {
-            psz_bind_port = "";
-        }
-        if( *psz_bind_port )
-        {
-            p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
-        }
-        else
-        {
-            p_url->i_bind_port = 0;
-        }
-    }
-    else
-    {
-        p_url->psz_bind_addr = "";
-        p_url->i_bind_port = 0;
-    }
-
-    if( *psz_parser == '/' )
-    {
-        *psz_parser = '\0';
-        psz_parser++;
-        p_url->psz_path = psz_parser;
-    }
-
-    if( *psz_server_port )
-    {
-        p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
-    }
-    else
-    {
-        p_url->i_server_port = 0;
-    }
-}
-
-/****************************************************************************
- *
- * MMS specific functions
- *
- ****************************************************************************/
-
-static int mms_CommandSend( input_thread_t *p_input,
-                             int i_command,
-                             uint32_t i_prefix1, uint32_t i_prefix2,
-                             uint8_t *p_data, int i_data )
-{
-    var_buffer_t buffer;
-
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int i_data_by8;
-
-    i_data_by8 = ( i_data + 7 ) / 8;
-
-    /* first init uffer */
-    var_buffer_initwrite( &buffer, 0 );
-
-    var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
-    var_buffer_add32( &buffer, 0xB00BFACE );
-    /* size after protocol type */
-    var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
-    var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
-    var_buffer_add32( &buffer, i_data_by8 + 4 );
-    var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
-    var_buffer_add64( &buffer, 0 );
-    var_buffer_add32( &buffer, i_data_by8 + 2 );
-    var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
-    var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
-    var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
-
-    /* specific command data */
-    if( p_data && i_data > 0 )
-    {
-        var_buffer_addmemory( &buffer, p_data, i_data );
-    }
-
-    /* send it */
-    if( send( p_access->socket_tcp.i_handle,
-              buffer.p_data,
-              buffer.i_data,
-              0 ) == -1 )
-    {
-        msg_Err( p_input, "failed to send command" );
-        return( -1 );
-    }
-
-    var_buffer_free( &buffer );
-    return( 0 );
-}
-
-static int  NetFillBuffer( input_thread_t *p_input )
-{
-#ifdef UNDER_CE
-    return -1;
-#else
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    struct timeval  timeout;
-    fd_set          fds;
-    int             i_ret;
-
-    /* FIXME when using udp */
-    ssize_t i_tcp, i_udp;
-    ssize_t i_tcp_read, i_udp_read;
-    int i_handle_max;
-
-    /* Initialize file descriptor set */
-    FD_ZERO( &fds );
-
-    i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp;
-
-    if( p_access->i_proto == MMS_PROTO_UDP )
-    {
-        i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp;
-    }
-    else
-    {
-        i_udp = 0;  /* there isn't udp socket */
-    }
-
-    i_handle_max = 0;
-    if( i_tcp > 0 )
-    {
-        FD_SET( p_access->socket_tcp.i_handle, &fds );
-        i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle );
-    }
-    if( i_udp > 0 )
-    {
-        FD_SET( p_access->socket_udp.i_handle, &fds );
-        i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle );
-    }
-
-    if( i_handle_max == 0 )
-    {
-        msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
-        return( 0 );
-    }
-    else
-    {
-//        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
-    }
-
-    /* We'll wait 0.5 second if nothing happens */
-    timeout.tv_sec = 0;
-    timeout.tv_usec = 500000;
-
-    /* Find if some data is available */
-    while( (i_ret = select( i_handle_max + 1, &fds,
-                            NULL, NULL, &timeout )) == 0
-           || (i_ret < 0 && errno == EINTR) )
-    {
-        FD_ZERO( &fds );
-        if( i_tcp > 0 ) FD_SET( p_access->socket_tcp.i_handle, &fds );
-        if( i_udp > 0 ) FD_SET( p_access->socket_udp.i_handle, &fds );
-        timeout.tv_sec = 0;
-        timeout.tv_usec = 500000;
-
-        if( p_input->b_die || p_input->b_error )
-        {
-            return 0;
-        }
-    }
-
-    if( i_ret < 0 )
-    {
-        msg_Err( p_input, "network select error (%s)", strerror(errno) );
-        return -1;
-    }
-
-    if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) )
-    {
-        i_tcp_read =
-            recv( p_access->socket_tcp.i_handle,
-                  p_access->buffer_tcp + p_access->i_buffer_tcp,
-                  i_tcp + MMS_BUFFER_SIZE/2, 0 );
-    }
-    else
-    {
-        i_tcp_read = 0;
-    }
-
-    if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) )
-    {
-        i_udp_read = recv( p_access->socket_udp.i_handle,
-                           p_access->buffer_udp + p_access->i_buffer_udp,
-                           i_udp + MMS_BUFFER_SIZE/2, 0 );
-    }
-    else
-    {
-        i_udp_read = 0;
-    }
-
-#if MMS_DEBUG
-    if( p_access->i_proto == MMS_PROTO_UDP )
-    {
-        msg_Dbg( p_input,
-                 "filling buffer TCP:%d+%d UDP:%d+%d",
-                 p_access->i_buffer_tcp,
-                 i_tcp_read,
-                 p_access->i_buffer_udp,
-                 i_udp_read );
-    }
-    else
-    {
-        msg_Dbg( p_input,
-                 "filling buffer TCP:%d+%d",
-                 p_access->i_buffer_tcp,
-                 i_tcp_read );
-    }
-#endif
-    if( i_tcp_read > 0 )
-    {
-        p_access->i_buffer_tcp += i_tcp_read;
-    }
-    if( i_udp_read > 0 )
-    {
-        p_access->i_buffer_udp += i_udp_read;
-    }
-
-    return( i_tcp_read + i_udp_read);
-#endif
-}
-
-static int  mms_ParseCommand( input_thread_t *p_input,
-                              uint8_t *p_data,
-                              int i_data,
-                              int *pi_used )
-{
- #define GET32( i_pos ) \
-    ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
-      ( p_access->p_cmd[i_pos + 2] << 16 ) + \
-      ( p_access->p_cmd[i_pos + 3] << 24 ) )
-
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int         i_length;
-    uint32_t    i_id;
-
-    if( p_access->p_cmd )
-    {
-        free( p_access->p_cmd );
-    }
-    p_access->i_cmd = i_data;
-    p_access->p_cmd = malloc( i_data );
-    memcpy( p_access->p_cmd, p_data, i_data );
-
-    *pi_used = i_data; /* by default */
-
-    if( i_data < MMS_CMD_HEADERSIZE )
-    {
-        msg_Warn( p_input, "truncated command (header incomplete)" );
-        p_access->i_command = 0;
-        return( -1 );
-    }
-    i_id =  GetDWLE( p_data + 4 );
-    i_length = GetDWLE( p_data + 8 ) + 16;
-
-    if( i_id != 0xb00bface )
-    {
-        msg_Err( p_input,
-                 "incorrect command header (0x%x)", i_id );
-        p_access->i_command = 0;
-        return( -1 );
-    }
-
-    if( i_length > p_access->i_cmd )
-    {
-        msg_Warn( p_input,
-                  "truncated command (missing %d bytes)",
-                   i_length - i_data  );
-        p_access->i_command = 0;
-        return( -1 );
-    }
-    else if( i_length < p_access->i_cmd )
-    {
-        p_access->i_cmd = i_length;
-        *pi_used = i_length;
-    }
-
-    msg_Dbg( p_input,
-             "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x",
-             GET32( 0 ),
-             GET32( 4 ),
-             GET32( 8 ),
-             /* 12: protocol type "MMS " */
-             GET32( 16 ),
-             GET32( 20 ),
-             /* 24: unknown (0) */
-             /* 28: unknown (0) */
-             GET32( 32 ),
-             GET32( 36 )
-             /* 40: switches */
-             /* 44: extra */ );
-
-    p_access->i_command = GET32( 36 ) & 0xffff;
-
-    return( MMS_PACKET_CMD );
-}
-
-static int  mms_ParsePacket( input_thread_t *p_input,
-                             uint8_t *p_data, size_t i_data,
-                             int *pi_used )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int i_packet_seq_num;
-    size_t i_packet_length;
-    uint32_t i_packet_id;
-
-    uint8_t  *p_packet;
-
-
-    *pi_used = i_data; /* default */
-    if( i_data <= 8 )
-    {
-        msg_Warn( p_input, "truncated packet (header incomplete)" );
-        return( -1 );
-    }
-
-    i_packet_id = p_data[4];
-    i_packet_seq_num = GetDWLE( p_data );
-    i_packet_length = GetWLE( p_data + 6 );
-
-    //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
-
-    if( i_packet_length > i_data || i_packet_length <= 8)
-    {
-        msg_Dbg( p_input,
-                 "truncated packet (missing %d bytes)",
-                 i_packet_length - i_data  );
-        *pi_used = 0;
-        return( -1 );
-    }
-    else if( i_packet_length < i_data )
-    {
-        *pi_used = i_packet_length;
-    }
-
-    if( i_packet_id == 0xff )
-    {
-        msg_Warn( p_input,
-                  "receive MMS UDP pair timing" );
-        return( MMS_PACKET_UDP_TIMING );
-    }
-
-    if( i_packet_id != p_access->i_header_packet_id_type &&
-        i_packet_id != p_access->i_media_packet_id_type )
-    {
-        msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
-        return( -1 );
-    }
-
-    /* we now have a media or a header packet */
-    p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
-    memcpy( p_packet, p_data + 8, i_packet_length - 8 );
-
-    if( i_packet_seq_num != p_access->i_packet_seq_num )
-    {
-        /* FIXME for udp could be just wrong order ? */
-        msg_Warn( p_input,
-                  "detected packet lost (%d != %d)",
-                  i_packet_seq_num,
-                  p_access->i_packet_seq_num );
-        p_access->i_packet_seq_num = i_packet_seq_num;
-    }
-    p_access->i_packet_seq_num++;
-
-    if( i_packet_id == p_access->i_header_packet_id_type )
-    {
-        if( p_access->p_header )
-        {
-            p_access->p_header = realloc( p_access->p_header,
-                                          p_access->i_header + i_packet_length - 8 );
-            memcpy( &p_access->p_header[p_access->i_header],
-                    p_packet,
-                    i_packet_length - 8 );
-            p_access->i_header += i_packet_length - 8;
-
-            free( p_packet );
-        }
-        else
-        {
-            p_access->p_header = p_packet;
-            p_access->i_header = i_packet_length - 8;
-        }
-/*        msg_Dbg( p_input,
-                 "receive header packet (%d bytes)",
-                 i_packet_length - 8 ); */
-
-        return( MMS_PACKET_HEADER );
-    }
-    else
-    {
-        FREE( p_access->p_media );
-        p_access->p_media = p_packet;
-        p_access->i_media = i_packet_length - 8;
-        p_access->i_media_used = 0;
-/*        msg_Dbg( p_input,
-                 "receive media packet (%d bytes)",
-                 i_packet_length - 8 ); */
-
-        return( MMS_PACKET_MEDIA );
-    }
-}
-
-static int mms_ReceivePacket( input_thread_t *p_input )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int i_packet_tcp_type;
-    int i_packet_udp_type;
-
-    for( ;; )
-    {
-        if( NetFillBuffer( p_input ) < 0 )
-        {
-            msg_Warn( p_input, "cannot fill buffer" );
-            continue;
-        }
-
-        i_packet_tcp_type = -1;
-        i_packet_udp_type = -1;
-
-        if( p_access->i_buffer_tcp > 0 )
-        {
-            int i_used;
-
-            if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
-            {
-                i_packet_tcp_type =
-                    mms_ParseCommand( p_input,
-                                      p_access->buffer_tcp,
-                                      p_access->i_buffer_tcp,
-                                      &i_used );
-
-            }
-            else
-            {
-                i_packet_tcp_type =
-                    mms_ParsePacket( p_input,
-                                     p_access->buffer_tcp,
-                                     p_access->i_buffer_tcp,
-                                     &i_used );
-            }
-            if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
-            {
-                memmove( p_access->buffer_tcp,
-                         p_access->buffer_tcp + i_used,
-                         MMS_BUFFER_SIZE - i_used );
-            }
-            p_access->i_buffer_tcp -= i_used;
-        }
-        else if( p_access->i_buffer_udp > 0 )
-        {
-            int i_used;
-
-            i_packet_udp_type =
-                mms_ParsePacket( p_input,
-                                 p_access->buffer_udp,
-                                 p_access->i_buffer_udp,
-                                 &i_used );
-
-            if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
-            {
-                memmove( p_access->buffer_udp,
-                         p_access->buffer_udp + i_used,
-                         MMS_BUFFER_SIZE - i_used );
-            }
-            p_access->i_buffer_udp -= i_used;
-        }
-
-        if( i_packet_tcp_type == MMS_PACKET_CMD &&
-                p_access->i_command == 0x1b )
-        {
-            mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
-            i_packet_tcp_type = -1;
-        }
-
-        if( i_packet_tcp_type != -1 )
-        {
-            return( i_packet_tcp_type );
-        }
-        else if( i_packet_udp_type != -1 )
-        {
-            return( i_packet_udp_type );
-        }
-
-    }
-}
-
-static int  mms_ReceiveCommand( input_thread_t *p_input )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-
-    for( ;; )
-    {
-        int i_used;
-        int i_status;
-
-        if( NetFillBuffer( p_input ) < 0 )
-        {
-            msg_Warn( p_input, "cannot fill buffer" );
-            continue;
-        }
-        if( p_access->i_buffer_tcp > 0 )
-        {
-            i_status = mms_ParseCommand( p_input,
-                                  p_access->buffer_tcp,
-                                  p_access->i_buffer_tcp,
-                                  &i_used );
-            if( i_used < MMS_BUFFER_SIZE )
-            {
-                memmove( p_access->buffer_tcp,
-                         p_access->buffer_tcp + i_used,
-                         MMS_BUFFER_SIZE - i_used );
-            }
-            p_access->i_buffer_tcp -= i_used;
-
-            if( i_status < 0 )
-            {
-                return( -1 );
-            }
-
-            if( p_access->i_command == 0x1b )
-            {
-                mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
-            }
-            else
-            {
-                break;
-            }
-        }
-        else
-        {
-            return( -1 );
-        }
-    }
-
-    return( 0 );
+    free( p_url->psz_host );
+    free( p_url->psz_path );
+    free( p_url->psz_username );
+    free( p_url->psz_password );
+    free( p_url );
 }
-
-#define MMS_RETRY_MAX       10
-#define MMS_RETRY_SLEEP     50000
-
-static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int i_count;
-    int i_status;
-
-    for( i_count = 0; i_count < MMS_RETRY_MAX; )
-    {
-
-        i_status = mms_ReceiveCommand( p_input );
-        if( i_status < 0 || p_access->i_command == 0 )
-        {
-            i_count++;
-            msleep( MMS_RETRY_SLEEP );
-        }
-        else if( i_command1 == 0 && i_command2 == 0)
-        {
-            return( 0 );
-        }
-        else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
-        {
-            return( 0 );
-        }
-        else
-        {
-            switch( p_access->i_command )
-            {
-                case 0x03:
-                    msg_Warn( p_input, "socket closed by server" );
-                    p_access->i_eos = 1;
-                    return( -1 );
-                case 0x1e:
-                    msg_Warn( p_input, "end of media stream" );
-                    p_access->i_eos = 1;
-                    return( -1 );
-                default:
-                    break;
-            }
-        }
-    }
-    msg_Warn( p_input, "failed to receive command (abording)" );
-
-    return( -1 );
-}
-
-
-static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
-{
-    access_t    *p_access = (access_t*)p_input->p_access_data;
-    int         i_count;
-
-    for( i_count = 0; i_count < MMS_RETRY_MAX; )
-    {
-        int i_status;
-
-        i_status = mms_ReceivePacket( p_input );
-        if( i_status < 0 )
-        {
-            i_count++;
-            msg_Warn( p_input,
-                      "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
-            msleep( MMS_RETRY_SLEEP );
-        }
-        else if( i_status == i_type || i_type == MMS_PACKET_ANY )
-        {
-            return( i_type );
-        }
-        else if( i_status == MMS_PACKET_CMD )
-        {
-            switch( p_access->i_command )
-            {
-                case 0x03:
-                    msg_Warn( p_input, "socket closed by server" );
-                    p_access->i_eos = 1;
-                    return( -1 );
-                case 0x1e:
-                    msg_Warn( p_input, "end of media stream" );
-                    p_access->i_eos = 1;
-                    return( -1 );
-                case 0x20:
-                    /* XXX not too dificult to be done EXCEPT that we
-                     * need to restart demuxer... and I don't see how we
-                     * could do that :p */
-                    msg_Err( p_input,
-                             "reinitialization needed --> unsupported" );
-                    p_access->i_eos = 1;
-                    return( -1 );
-                default:
-                    break;
-            }
-        }
-    }
-    msg_Err( p_input,
-             "cannot receive %s (abording)",
-               ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
-    return( -1 );
-}
-
index d81db3a..aa77f32 100644 (file)
@@ -2,7 +2,7 @@
  * mms.h: MMS access plug-in
  *****************************************************************************
  * Copyright (C) 2001, 2002 VideoLAN
- * $Id: mms.h,v 1.8 2003/03/03 01:38:07 fenrir Exp $
+ * $Id: mms.h,v 1.9 2003/04/20 19:29:43 fenrir Exp $
  *
  * Authors: Laurent Aimar <fenrir@via.ecp.fr>
  *
  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
  *****************************************************************************/
 
-/* url: [/]host[:port][/path] */
-typedef struct url_s
-{
-    char    *psz_server_addr;
-    int     i_server_port;
-
-    char    *psz_bind_addr;
-    int     i_bind_port;
-
-    char    *psz_path;
-
-    /* private */
-    char *psz_private;
-} url_t;
-
-#define FREE( p ) if( p ) { free( p );  (p ) = NULL; }
-
-
 #define MMS_PROTO_AUTO  0
 #define MMS_PROTO_TCP   1
 #define MMS_PROTO_UDP   2
+#define MMS_PROTO_HTTP  3
 
-#define MMS_PACKET_ANY          0
-#define MMS_PACKET_CMD          1
-#define MMS_PACKET_HEADER       2
-#define MMS_PACKET_MEDIA        3
-#define MMS_PACKET_UDP_TIMING   4
-
-
-#define MMS_STREAM_VIDEO    0x0001
-#define MMS_STREAM_AUDIO    0x0002
-#define MMS_STREAM_UNKNOWN  0xffff
-
-
-#define MMS_CMD_HEADERSIZE  48
-
-typedef struct mms_stream_s
-{
-    int i_id;       /* 1 -> 127 */
-    int i_cat;      /* MMS_STREAM_VIDEO, MMS_STREAM_AUDIO */
-    int i_bitrate;  /* -1 if unknown */
-    int i_selected;
-
-} mms_stream_t;
-
-#define MMS_BUFFER_SIZE 100000
-typedef struct access_s
-{
-    int                 i_proto;        /* MMS_PROTO_TCP, MMS_PROTO_UDP */
-    input_socket_t      socket_tcp;     /* TCP socket for communication with server */
-    input_socket_t      socket_udp;     /* Optional UDP socket for data(media/header packet) */
-                                        /* send by server */
-    char                *psz_bind_addr; /* used by udp */
-
-    url_t   url;                        /* connect to this server */
-
-    mms_stream_t        stream[128];    /* in asf never more than 1->127 streams */
 
-    off_t               i_pos;          /* position of next byte to be read */
-
-    /* */
-    uint8_t             buffer_tcp[MMS_BUFFER_SIZE];
-    int                 i_buffer_tcp;
-
-    uint8_t             buffer_udp[MMS_BUFFER_SIZE];
-    int                 i_buffer_udp;
-
-    /* data necessary to send data to server */
-    guid_t      guid;
-    int         i_command_level;
-    int         i_seq_num;
-    uint32_t    i_header_packet_id_type;
-    uint32_t    i_media_packet_id_type;
-
-    int         i_packet_seq_num;
-
-    uint8_t     *p_cmd;     /* latest command read */
-    int         i_cmd;      /* allocated at the begining */
-
-    uint8_t     *p_header;  /* allocated by mms_ReadPacket */
-    int         i_header;
-
-    uint8_t     *p_media;   /* allocated by mms_ReadPacket */
-    size_t      i_media;
-    size_t      i_media_used;
-
-    /* extracted informations */
-    int         i_command;
-    int         i_eos;
-
-    /* from 0x01 answer (not yet set) */
-    char        *psz_server_version;
-    char        *psz_tool_version;
-    char        *psz_update_player_url;
-    char        *psz_encryption_type;
-
-    /* from 0x06 answer */
-    uint32_t    i_flags_broadcast;
-    uint32_t    i_media_length;
-    size_t      i_packet_length;
-    uint32_t    i_packet_count;
-    int         i_max_bit_rate;
-    int         i_header_size;
-
-} access_t;
+/* mmst and mmsu */
+int  E_( MMSTUOpen )  ( input_thread_t * );
+void E_( MMSTUClose ) ( input_thread_t * );
 
+/* mmsh */
+int  E_( MMSHOpen )  ( input_thread_t * );
+void E_( MMSHClose ) ( input_thread_t * );
 
 static inline uint16_t GetWLE( uint8_t *p_buff )
 {
@@ -139,3 +46,20 @@ static inline uint32_t GetDWLE( uint8_t *p_buff )
             ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
 }
 
+#define FREE( p ) if( p ) { free( p ); (p) = NULL; }
+
+/* url: [/]host[:port][/path][@username[:password]] */
+typedef struct url_s
+{
+    char    *psz_host;
+    int     i_port;
+
+    char    *psz_path;
+
+    char    *psz_username;
+    char    *psz_password;
+} url_t;
+
+url_t *E_( url_new )  ( char * );
+void   E_( url_free ) ( url_t * );
+
diff --git a/modules/access/mms/mmsh.c b/modules/access/mms/mmsh.c
new file mode 100644 (file)
index 0000000..f219218
--- /dev/null
@@ -0,0 +1,1015 @@
+/*****************************************************************************
+ * mmsh.c:
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mmsh.c,v 1.1 2003/04/20 19:29:43 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+/*
+ * TODO:
+ *  * http_proxy
+ *
+ */
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <string.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#ifdef HAVE_ERRNO_H
+#   include <errno.h>
+#endif
+#ifdef HAVE_FCNTL_H
+#   include <fcntl.h>
+#endif
+#ifdef HAVE_SYS_TIME_H
+#    include <sys/time.h>
+#endif
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#endif
+
+#if defined( UNDER_CE )
+#   include <winsock.h>
+#elif defined( WIN32 )
+#   include <winsock2.h>
+#   include <ws2tcpip.h>
+#   ifndef IN_MULTICAST
+#       define IN_MULTICAST(a) IN_CLASSD(a)
+#   endif
+#else
+#   include <sys/socket.h>
+#endif
+
+#include "network.h"
+#include "asf.h"
+#include "buffer.h"
+
+#include "mms.h"
+#include "mmsh.h"
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+int  E_( MMSHOpen )  ( input_thread_t * );
+void E_( MMSHClose ) ( input_thread_t * );
+
+static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
+                          size_t i_len );
+static void Seek        ( input_thread_t *, off_t );
+
+/****************************************************************************
+ ****************************************************************************
+ *******************                                      *******************
+ *******************       Main functions                 *******************
+ *******************                                      *******************
+ ****************************************************************************
+ ****************************************************************************/
+
+/****************************************************************************
+ * Open: connect to ftp server and ask for file
+ ****************************************************************************/
+int  E_( MMSHOpen )  ( input_thread_t *p_input )
+{
+    access_sys_t    *p_sys;
+
+    uint8_t         *p;
+    http_answer_t   *p_ans;
+    http_field_t    *p_field;
+    chunk_t         ck;
+
+    /* init p_sys */
+    p_sys = malloc( sizeof( access_sys_t ) );
+    p_sys->i_proto = MMS_PROTO_HTTP;
+
+    p_sys->p_socket = NULL;
+    p_sys->i_request_context = 1;
+    p_sys->i_buffer = 0;
+    p_sys->i_buffer_pos = 0;
+    p_sys->b_broadcast = VLC_TRUE;
+    p_sys->p_packet = NULL;
+    p_sys->i_packet_sequence = 0;
+    p_sys->i_packet_used = 0;
+    p_sys->i_packet_length = 0;
+    p_sys->i_pos = 0;
+    E_( GenerateGuid )( &p_sys->guid );
+
+    /* open a tcp connection */
+    p_sys->p_url = E_( url_new )( p_input->psz_name );
+
+    if( *p_sys->p_url->psz_host == '\0' )
+    {
+        msg_Err( p_input, "invalid server addresse" );
+        goto exit_error;
+    }
+    if( p_sys->p_url->i_port <= 0 )
+    {
+        p_sys->p_url->i_port = 80;
+    }
+
+    p_sys->p_socket = NetOpenTCP( p_input, p_sys->p_url );
+    if( !p_sys->p_socket )
+    {
+        msg_Err( p_input, "cannot connect" );
+        goto exit_error;
+    }
+    p_sys->i_request_context = 1;
+
+    /* *** send first request *** */
+    /* FIXME use generateguid */
+    p = &p_sys->buffer[0];
+    p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
+    p += sprintf( p,"Accept: */*\r\n" );
+    p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
+    p += sprintf( p, "Host: %s:%d\r\n", p_sys->p_url->psz_host, p_sys->p_url->i_port );
+    p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=0:0,request-context=%d,max-duration=0\r\n", p_sys->i_request_context++ );
+    //p += sprintf( p, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n" );
+    p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n", GUID_PRINT( p_sys->guid ) );
+    p += sprintf( p, "Connection: Close\r\n\r\n" );
+    NetWrite( p_input, p_sys->p_socket, p_sys->buffer,  p - p_sys->buffer );
+
+
+    if( NetFill ( p_input, p_sys, BUFFER_SIZE ) <= 0 )
+    {
+        msg_Err( p_input, "cannot read answer" );
+        goto exit_error;
+    }
+    NetClose( p_input, p_sys->p_socket );
+
+    p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );
+    if( !p_ans )
+    {
+        msg_Err( p_input, "cannot parse answer" );
+        goto exit_error;
+    }
+
+    if( p_ans->i_error >= 400 )
+    {
+        msg_Err( p_input, "error %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
+        http_answer_free( p_ans );
+        goto exit_error;
+    }
+    else if( p_ans->i_error >= 300 )
+    {
+        msg_Err( p_input, "FIXME redirec unsuported %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
+        http_answer_free( p_ans );
+        goto exit_error;
+    }
+    else if( p_ans->i_body <= 0 )
+    {
+        msg_Err( p_input, "empty answer" );
+        http_answer_free( p_ans );
+        goto exit_error;
+    }
+
+    /* now get features */
+    /* FIXME FIXME test Content-Type to see if it's a plain stream or an asx FIXME */
+    for( p_field = p_ans->p_fields; p_field != NULL; p_field = http_field_find( p_field->p_next, "Pragma" ) )
+    {
+        if( !strncasecmp( p_field->psz_value, "features", 8 ) )
+        {
+            if( strstr( p_field->psz_value, "broadcast" ) )
+            {
+                msg_Dbg( p_input, "stream type = broadcast" );
+                p_sys->b_broadcast = VLC_TRUE;
+            }
+            else if( strstr( p_field->psz_value, "seekable" ) )
+            {
+                msg_Dbg( p_input, "stream type = seekable" );
+                p_sys->b_broadcast = VLC_FALSE;
+            }
+            else
+            {
+                msg_Warn( p_input, "unknow stream types (%s)", p_field->psz_value );
+                p_sys->b_broadcast = VLC_FALSE;
+            }
+        }
+    }
+
+    /* gather header */
+    p_sys->i_header = 0;
+    p_sys->p_header = malloc( p_ans->i_body );
+    do
+    {
+        if( chunk_parse( &ck, p_ans->p_body, p_ans->i_body ) )
+        {
+            msg_Err( p_input, "invalid chunk answer" );
+            goto exit_error;
+        }
+        if( ck.i_type != 0x4824 )
+        {
+            msg_Err( p_input, "invalid chunk (0x%x)", ck.i_type );
+            break;
+        }
+        if( ck.i_data > 0 )
+        {
+            memcpy( &p_sys->p_header[p_sys->i_header],
+                    ck.p_data,
+                    ck.i_data );
+
+            p_sys->i_header += ck.i_data;
+        }
+
+        /* BEURK */
+        p_ans->p_body   += 12 + ck.i_data;
+        p_ans->i_body   -= 12 + ck.i_data;
+
+    } while( p_ans->i_body > 12 );
+
+    http_answer_free( p_ans );
+
+    msg_Dbg( p_input, "complete header size=%d", p_sys->i_header );
+    if( p_sys->i_header <= 0 )
+    {
+        msg_Err( p_input, "header size == 0" );
+        goto exit_error;
+    }
+    /* *** parse header and get stream and their id *** */
+    /* get all streams properties,
+     *
+     * TODO : stream bitrates properties(optional)
+     *        and bitrate mutual exclusion(optional) */
+    E_( asf_HeaderParse )( &p_sys->asfh,
+                           p_sys->p_header, p_sys->i_header );
+    msg_Dbg( p_input, "packet count=%lld packet size=%d",p_sys->asfh.i_data_packets_count, p_sys->asfh.i_min_data_packet_size );
+
+    E_( asf_StreamSelect)( &p_sys->asfh,
+                           config_GetInt( p_input, "mms-maxbitrate" ),
+                           config_GetInt( p_input, "mms-all" ),
+                           config_GetInt( p_input, "audio" ),
+                           config_GetInt( p_input, "video" ) );
+
+    if( mmsh_start( p_input, p_sys, 0 ) )
+    {
+        msg_Err( p_input, "cannot start stream" );
+        goto exit_error;
+    }
+
+    /* *** set exported functions *** */
+    p_input->pf_read = Read;
+    p_input->pf_seek = Seek;
+    p_input->pf_set_program = input_SetProgram;
+    p_input->pf_set_area = NULL;
+
+    p_input->p_private = NULL;
+    //p_input->i_mtu = 5 * p_sys->asfh.i_min_data_packet_size;
+
+    /* *** finished to set some variable *** */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.b_pace_control = 1;
+    if( p_sys->b_broadcast )
+    {
+        p_input->stream.p_selected_area->i_size = 0;
+        p_input->stream.b_seekable = 0;
+    }
+    else
+    {
+        p_input->stream.p_selected_area->i_size = p_sys->asfh.i_file_size;
+        p_input->stream.b_seekable = 1;
+    }
+    p_input->stream.p_selected_area->i_tell = 0;
+    p_input->stream.i_method = INPUT_METHOD_NETWORK;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    /* Update default_pts to a suitable value for ftp access */
+    p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
+
+    p_input->p_access_data = p_sys;
+
+    return( VLC_SUCCESS );
+
+exit_error:
+    E_( url_free )( p_sys->p_url );
+
+    if( p_sys->p_socket )
+    {
+        NetClose( p_input, p_sys->p_socket );
+    }
+    free( p_sys );
+    return( VLC_EGENERIC );
+}
+
+/*****************************************************************************
+ * Close: free unused data structures
+ *****************************************************************************/
+void E_( MMSHClose ) ( input_thread_t *p_input )
+{
+    access_sys_t    *p_sys   = p_input->p_access_data;
+
+    msg_Dbg( p_input, "stopping stream" );
+
+    mmsh_stop( p_input, p_sys );
+
+    free( p_sys );
+}
+
+static int mmsh_get_packet( input_thread_t * p_input, access_sys_t *p_sys, chunk_t *p_ck )
+{
+    int i_mov = p_sys->i_buffer - p_sys->i_buffer_pos;
+
+    if( p_sys->i_buffer_pos > BUFFER_SIZE / 2 )
+    {
+        if( i_mov > 0 )
+        {
+            memmove( &p_sys->buffer[0], 
+                     &p_sys->buffer[p_sys->i_buffer_pos],
+                     i_mov );
+        }
+
+        p_sys->i_buffer     = i_mov;
+        p_sys->i_buffer_pos = 0;
+    }
+
+    if( NetFill( p_input, p_sys, 12 ) < 12 )
+    {
+        msg_Warn( p_input, "cannot fill buffer" );
+        return VLC_EGENERIC;
+    }
+
+    chunk_parse( p_ck, &p_sys->buffer[p_sys->i_buffer_pos], p_sys->i_buffer - p_sys->i_buffer_pos );
+
+    if( p_ck->i_type == 0x4524 )   // Transfer complete
+    {
+        msg_Warn( p_input, "EOF" );
+        return VLC_EGENERIC;
+    }
+    else if( p_ck->i_type != 0x4824 && p_ck->i_type != 0x4424 )
+    {
+        msg_Err( p_input, "invalid chunk FATAL" );
+        return VLC_EGENERIC;
+    }
+
+    if( p_ck->i_data < p_ck->i_size2 - 8 )
+    {
+        if( NetFill( p_input, p_sys, p_ck->i_size2 - 8 - p_ck->i_data ) <= 0 )
+        {
+            msg_Warn( p_input, "cannot fill buffer" );
+            return VLC_EGENERIC;
+        }
+        chunk_parse( p_ck, &p_sys->buffer[p_sys->i_buffer_pos], p_sys->i_buffer - p_sys->i_buffer_pos );
+    }
+
+    if( p_sys->i_packet_sequence != 0 && p_ck->i_sequence != p_sys->i_packet_sequence )
+    {
+        msg_Warn( p_input, "packet lost ?" );
+    }
+
+    p_sys->i_packet_sequence = p_ck->i_sequence + 1;
+    p_sys->i_packet_used   = 0;
+    p_sys->i_packet_length = p_ck->i_data;
+    p_sys->p_packet        = p_ck->p_data;
+
+    p_sys->i_buffer_pos += 12 + p_ck->i_data;
+
+    return VLC_SUCCESS;
+}
+
+
+/*****************************************************************************
+ * Seek: try to go at the right place
+ *****************************************************************************/
+static void Seek( input_thread_t * p_input, off_t i_pos )
+{
+    access_sys_t *p_sys = p_input->p_access_data;
+    chunk_t      ck;
+    off_t        i_offset;
+    off_t        i_packet;
+
+    i_packet = ( i_pos - p_sys->i_header ) / p_sys->asfh.i_min_data_packet_size;
+    i_offset = ( i_pos - p_sys->i_header ) % p_sys->asfh.i_min_data_packet_size;
+
+    msg_Err( p_input, "seeking to "I64Fd, i_pos );
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+
+    mmsh_stop( p_input, p_sys );
+    mmsh_start( p_input, p_sys, i_packet * p_sys->asfh.i_min_data_packet_size );
+
+    for( ;; )
+    {
+        if( mmsh_get_packet( p_input, p_sys, &ck ) )
+        {
+            break;
+        }
+
+        /* skip headers */
+        if( ck.i_type != 0x4824 )
+        {
+            break;
+        }
+        msg_Warn( p_input, "skipping header" );
+    }
+
+    p_sys->i_pos = i_pos;
+    p_sys->i_packet_used += i_offset;
+
+
+    p_input->stream.p_selected_area->i_tell = i_pos;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+}
+
+/*****************************************************************************
+ * Read:
+ *****************************************************************************/
+static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
+                          size_t i_len )
+{
+    access_sys_t *p_sys = p_input->p_access_data;
+    size_t       i_copy;
+    size_t       i_data = 0;
+
+    while( i_data < i_len )
+    {
+        if( p_sys->i_packet_used < p_sys->i_packet_length )
+        {
+            i_copy = __MIN( p_sys->i_packet_length - p_sys->i_packet_used, i_len - i_data );
+
+            memcpy( &p_buffer[i_data],
+                    &p_sys->p_packet[p_sys->i_packet_used],
+                    i_copy );
+
+            i_data += i_copy;
+            p_sys->i_packet_used += i_copy;
+        }
+        else if( p_sys->i_pos + i_data > p_sys->i_header &&
+                 (int)p_sys->i_packet_used < p_sys->asfh.i_min_data_packet_size )
+        {
+            i_copy = __MIN( p_sys->asfh.i_min_data_packet_size - p_sys->i_packet_used, i_len - i_data );
+
+            memset( &p_buffer[i_data], 0, i_copy );
+
+            i_data += i_copy;
+            p_sys->i_packet_used += i_copy;
+        }
+        else
+        {
+            chunk_t ck;
+            /* get a new packet */
+            /* fill enought data (>12) */
+            msg_Dbg( p_input, "waiting data (buffer = %d bytes", p_sys->i_buffer );
+
+            if( mmsh_get_packet( p_input, p_sys, &ck ) )
+            {
+                return 0;
+            }
+        }
+    }
+
+    p_sys->i_pos += i_data;
+
+
+    return( i_data );
+}
+
+
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+/****************************************************************************/
+
+static int mmsh_start( input_thread_t *p_input, access_sys_t *p_sys, off_t i_pos )
+{
+    uint8_t *p;
+    int i_streams = 0;
+    int i;
+    http_answer_t *p_ans;
+
+    msg_Dbg( p_input, "starting stream" );
+
+    p_sys->p_socket = NetOpenTCP( p_input, p_sys->p_url );
+
+    for( i = 1; i < 128; i++ )
+    {
+        if( p_sys->asfh.stream[i].i_selected )
+        {
+            i_streams++;
+        }
+    }
+
+    if( i_streams <= 0 )
+    {
+        msg_Err( p_input, "no stream selected" );
+        return VLC_EGENERIC;
+    }
+
+    p = &p_sys->buffer[0];
+    p += sprintf( p, "GET %s HTTP/1.0\r\n", p_sys->p_url->psz_path );
+    p += sprintf( p,"Accept: */*\r\n" );
+    p += sprintf( p, "User-Agent: NSPlayer/4.1.0.3856\r\n" );
+    p += sprintf( p, "Host: %s:%d\r\n", p_sys->p_url->psz_host, p_sys->p_url->i_port );
+    if( p_sys->b_broadcast )
+    {
+        p += sprintf( p, "Pragma: no-cache,rate=1.000000,request-context=%d\r\n", p_sys->i_request_context++ );
+    }
+    else
+    {
+        p += sprintf( p, "Pragma: no-cache,rate=1.000000,stream-time=0,stream-offset=%u:%u,request-context=%d,max-duration=0\r\n",
+                         (uint32_t)((i_pos >> 32)&0xffffffff), (uint32_t)(i_pos&0xffffffff), p_sys->i_request_context++ );
+    }
+    p += sprintf( p, "Pragma: xPlayStrm=1\r\n" );
+    //p += sprintf( p, "Pragma: xClientGUID={c77e7400-738a-11d2-9add-0020af0a3278}\r\n" );
+    p += sprintf( p, "Pragma: xClientGUID={"GUID_FMT"}\r\n", GUID_PRINT( p_sys->guid ) );
+    p += sprintf( p, "Pragma: stream-switch-count=%d\r\n", i_streams );
+    p += sprintf( p, "Pragma: stream-switch-entry=" );
+    for( i = 0; i < i_streams; i++ )
+    {
+        if( p_sys->asfh.stream[i].i_selected )
+        {
+            p += sprintf( p, "ffff:%d:0 ", p_sys->asfh.stream[i].i_id );
+        }
+        else
+        {
+            p += sprintf( p, "ffff:%d:2 ", p_sys->asfh.stream[i].i_id );
+        }
+    }
+    p += sprintf( p, "\r\n" );
+    p += sprintf( p, "Connection: Close\r\n\r\n" );
+
+
+    NetWrite( p_input, p_sys->p_socket, p_sys->buffer,  p - p_sys->buffer );
+
+    msg_Dbg( p_input, "filling buffer" );
+    /* we read until we found a \r\n\r\n or \n\n */
+    p_sys->i_buffer = 0;
+    p_sys->i_buffer_pos = 0;
+    for( ;; )
+    {
+        int     i_try = 0;
+        int     i_read;
+        uint8_t *p;
+
+        p = &p_sys->buffer[p_sys->i_buffer];
+        i_read =
+            NetRead( p_input, p_sys->p_socket,
+                     &p_sys->buffer[p_sys->i_buffer],
+                      1024 );
+
+        if( i_read == 0 )
+        {
+            if( i_try++ > 12 )
+            {
+                break;
+            }
+            msg_Dbg( p_input, "another try (%d/12)", i_try );
+            continue;
+        }
+
+        if( i_read <= 0 || p_input->b_die || p_input->b_error )
+        {
+            break;
+        }
+        p_sys->i_buffer += i_read;
+        p_sys->buffer[p_sys->i_buffer] = '\0';
+
+        if( strstr( p, "\r\n\r\n" ) || strstr( p, "\n\n" ) )
+        {
+            msg_Dbg( p_input, "body found" );
+            break;
+        }
+        if( p_sys->i_buffer >= BUFFER_SIZE - 1024 )
+        {
+            msg_Dbg( p_input, "buffer size exeded" );
+            break;
+        }
+    }
+
+    p_ans = http_answer_parse( p_sys->buffer, p_sys->i_buffer );
+    if( !p_ans )
+    {
+        msg_Err( p_input, "cannot parse answer" );
+        return VLC_EGENERIC;
+    }
+
+    if( p_ans->i_error < 200 || p_ans->i_error >= 300 )
+    {
+        msg_Err( p_input, "error %d (server return=`%s')", p_ans->i_error, p_ans->psz_answer );
+        http_answer_free( p_ans );
+        return VLC_EGENERIC;
+    }
+
+    if( !p_ans->p_body )
+    {
+        p_sys->i_buffer_pos = 0;
+        p_sys->i_buffer = 0;
+    }
+    else
+    {
+        p_sys->i_buffer_pos = p_ans->p_body - p_sys->buffer;
+    }
+    http_answer_free( p_ans );
+
+    return VLC_SUCCESS;
+}
+
+static void mmsh_stop( input_thread_t *p_input, access_sys_t *p_sys )
+{
+    msg_Dbg( p_input, "closing stream" );
+    NetClose( p_input, p_sys->p_socket );
+}
+
+static ssize_t NetFill( input_thread_t *p_input,
+                        access_sys_t   *p_sys, int i_size )
+{
+    int i_try   = 0;
+    int i_total = 0;
+
+    i_size = __MIN( i_size, BUFFER_SIZE - p_sys->i_buffer );
+    if( i_size <= 0 )
+    {
+        return 0;
+    }
+    
+
+    for( ;; )
+    {
+        int i_read;
+
+        i_read =
+            NetRead( p_input, p_sys->p_socket, &p_sys->buffer[p_sys->i_buffer], i_size );
+
+        if( i_read == 0 )
+        {
+            if( i_try++ > 2 )
+            {
+                break;
+            }
+            msg_Dbg( p_input, "another try %d/2", i_try );
+            continue;
+        }
+
+        if( i_read < 0 || p_input->b_die || p_input->b_error )
+        {
+            break;
+        }
+        i_total += i_read;
+
+        p_sys->i_buffer += i_read;
+        if( i_total >= i_size )
+        {
+            break;
+        }
+    }
+
+    p_sys->buffer[p_sys->i_buffer] = '\0';
+
+    return i_total;
+}
+
+/****************************************************************************
+ * NetOpenTCP:
+ ****************************************************************************/
+static input_socket_t * NetOpenTCP( input_thread_t *p_input, url_t *p_url )
+{
+    input_socket_t   *p_socket;
+    char             *psz_network;
+    module_t         *p_network;
+    network_socket_t socket_desc;
+
+
+    p_socket = malloc( sizeof( input_socket_t ) );
+    memset( p_socket, 0, sizeof( input_socket_t ) );
+
+    psz_network = "";
+    if( config_GetInt( p_input, "ipv4" ) )
+    {
+        psz_network = "ipv4";
+    }
+    else if( config_GetInt( p_input, "ipv6" ) )
+    {
+        psz_network = "ipv6";
+    }
+
+    msg_Dbg( p_input, "waiting for connection..." );
+
+    socket_desc.i_type = NETWORK_TCP;
+    socket_desc.psz_server_addr = p_url->psz_host;
+    socket_desc.i_server_port   = p_url->i_port;
+    socket_desc.psz_bind_addr   = "";
+    socket_desc.i_bind_port     = 0;
+    p_input->p_private = (void*)&socket_desc;
+    if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
+    {
+        msg_Err( p_input, "failed to connect with server" );
+        return NULL;
+    }
+    module_Unneed( p_input, p_network );
+    p_socket->i_handle = socket_desc.i_handle;
+    p_input->i_mtu     = socket_desc.i_mtu;
+
+    msg_Dbg( p_input,
+             "connection with \"%s:%d\" successful",
+             p_url->psz_host,
+             p_url->i_port );
+
+    return p_socket;
+}
+
+/*****************************************************************************
+ * Read: read on a file descriptor, checking b_die periodically
+ *****************************************************************************/
+static ssize_t NetRead( input_thread_t *p_input,
+                        input_socket_t *p_socket,
+                        byte_t *p_buffer, size_t i_len )
+{
+    struct timeval  timeout;
+    fd_set          fds;
+    ssize_t         i_recv;
+    int             i_ret;
+
+    /* Initialize file descriptor set */
+    FD_ZERO( &fds );
+    FD_SET( p_socket->i_handle, &fds );
+
+    /* We'll wait 1 second if nothing happens */
+    timeout.tv_sec  = 1;
+    timeout.tv_usec = 0;
+
+    /* Find if some data is available */
+    while( ( i_ret = select( p_socket->i_handle + 1, &fds,
+                             NULL, NULL, &timeout )) == 0 ||
+#ifdef HAVE_ERRNO_H
+           ( i_ret < 0 && errno == EINTR )
+#endif
+         )
+    {
+        FD_ZERO( &fds );
+        FD_SET( p_socket->i_handle, &fds );
+        timeout.tv_sec  = 1;
+        timeout.tv_usec = 0;
+
+        if( p_input->b_die || p_input->b_error )
+        {
+            return 0;
+        }
+    }
+
+    if( i_ret < 0 )
+    {
+        msg_Err( p_input, "network select error (%s)", strerror(errno) );
+        return -1;
+    }
+
+    i_recv = recv( p_socket->i_handle, p_buffer, i_len, 0 );
+
+    if( i_recv < 0 )
+    {
+        msg_Err( p_input, "recv failed (%s)", strerror(errno) );
+    }
+
+    return i_recv;
+}
+
+static ssize_t NetWrite( input_thread_t *p_input,
+                         input_socket_t *p_socket,
+                         byte_t *p_buffer, size_t i_len )
+{
+    struct timeval  timeout;
+    fd_set          fds;
+    ssize_t         i_send;
+    int             i_ret;
+
+    /* Initialize file descriptor set */
+    FD_ZERO( &fds );
+    FD_SET( p_socket->i_handle, &fds );
+
+    /* We'll wait 1 second if nothing happens */
+    timeout.tv_sec  = 1;
+    timeout.tv_usec = 0;
+
+    /* Find if some data is available */
+    while( ( i_ret = select( p_socket->i_handle + 1, NULL, &fds, NULL, &timeout ) ) == 0 ||
+#ifdef HAVE_ERRNO_H
+           ( i_ret < 0 && errno == EINTR )
+#endif
+         )
+    {
+        FD_ZERO( &fds );
+        FD_SET( p_socket->i_handle, &fds );
+        timeout.tv_sec  = 1;
+        timeout.tv_usec = 0;
+
+        if( p_input->b_die || p_input->b_error )
+        {
+            return 0;
+        }
+    }
+
+    if( i_ret < 0 )
+    {
+        msg_Err( p_input, "network select error (%s)", strerror(errno) );
+        return -1;
+    }
+
+    i_send = send( p_socket->i_handle, p_buffer, i_len, 0 );
+
+    if( i_send < 0 )
+    {
+        msg_Err( p_input, "send failed (%s)", strerror(errno) );
+    }
+
+    return i_send;
+}
+
+static void NetClose( input_thread_t *p_input, input_socket_t *p_socket )
+{
+#if defined( WIN32 ) || defined( UNDER_CE )
+    closesocket( p_socket->i_handle );
+#else
+    close( p_socket->i_handle );
+#endif
+
+    free( p_socket );
+}
+
+static int http_next_line( uint8_t **pp_data, int *pi_data )
+{
+    char *p, *p_end = *pp_data + *pi_data;
+
+    for( p = *pp_data; p < p_end; p++ )
+    {
+        if( p + 1 < p_end && *p == '\n' )
+        {
+            *pi_data = p_end - p - 1;
+            *pp_data = p + 1;
+            return VLC_SUCCESS;
+        }
+        if( p + 2 < p_end && p[0] == '\r' && p[1] == '\n' )
+        {
+            *pi_data = p_end - p - 2;
+            *pp_data = p + 2;
+            return VLC_SUCCESS;
+        }
+    }
+    *pi_data = 0;
+    *pp_data = p_end;
+    return VLC_EGENERIC;
+}
+
+static http_answer_t *http_answer_parse( uint8_t *p_data, int i_data )
+{
+    http_answer_t *ans = malloc( sizeof( http_answer_t ) );
+    http_field_t  **pp_last;
+    char          buffer[1024];
+
+    if( sscanf( p_data, "HTTP/1.%d %d %s", &ans-> i_version, &ans->i_error, buffer ) < 3 )
+    {
+        free( ans );
+        return NULL;
+    }
+    ans->psz_answer = strdup( buffer );
+    fprintf( stderr, "version=%d error=%d answer=%s\n", ans-> i_version, ans->i_error, ans->psz_answer );
+    ans->p_fields = NULL;
+    ans->i_body   = 0;
+    ans->p_body   = 0;
+
+    pp_last = &ans->p_fields;
+
+    for( ;; )
+    {
+        http_field_t  *p_field;
+        uint8_t       *colon;
+
+        if( http_next_line( &p_data, &i_data ) )
+        {
+            return ans;
+        }
+        if( !strncmp( p_data, "\r\n", 2 ) || !strncmp( p_data, "\n", 1 ) )
+        {
+            break;
+        }
+
+        colon = strstr( p_data, ": " );
+        if( colon )
+        {
+            uint8_t *end;
+
+            end = strstr( colon, "\n" ) - 1;
+            if( *end != '\r' )
+            {
+                end++;
+            }
+
+            p_field             = malloc( sizeof( http_field_t ) );
+            p_field->psz_name   = strndup( p_data, colon - p_data );
+            p_field->psz_value  = strndup( colon + 2, end - colon - 2 );
+            p_field->p_next     = NULL;
+
+            *pp_last = p_field;
+            pp_last = &p_field->p_next;
+
+            fprintf( stderr, "field name=`%s' value=`%s'\n", p_field->psz_name, p_field->psz_value );
+        }
+    }
+
+    if( http_next_line( &p_data, &i_data ) )
+    {
+        return ans;
+    }
+
+    ans->p_body = p_data;
+    ans->i_body = i_data;
+    fprintf( stderr, "body size=%d\n", i_data );
+
+    return ans;
+}
+
+static void http_answer_free( http_answer_t *ans )
+{
+    http_field_t  *p_field = ans->p_fields;
+
+    while( p_field )
+    {
+        http_field_t *p_next;
+
+        p_next = p_field->p_next;
+        free( p_field->psz_name );
+        free( p_field->psz_value );
+        free( p_field );
+
+        p_field = p_next;
+    }
+
+    free( ans->psz_answer );
+    free( ans );
+}
+
+static http_field_t *http_field_find( http_field_t *p_field, char *psz_name )
+{
+
+    while( p_field )
+    {
+        if( !strcasecmp( p_field->psz_name, psz_name ) )
+        {
+            return p_field;
+        }
+
+        p_field = p_field->p_next;
+    }
+
+    return NULL;
+}
+static char *http_field_get_value( http_answer_t *ans, char *psz_name )
+{
+    http_field_t  *p_field = ans->p_fields;
+
+    while( p_field )
+    {
+        if( !strcasecmp( p_field->psz_name, psz_name ) )
+        {
+            return p_field->psz_value;
+        }
+
+        p_field = p_field->p_next;
+    }
+
+    return NULL;
+}
+
+
+
+static int chunk_parse( chunk_t *ck, uint8_t *p_data, int i_data )
+{
+    if( i_data < 12 )
+    {
+        return VLC_EGENERIC;
+    }
+
+    ck->i_type      = GetWLE( p_data );
+    ck->i_size      = GetWLE( p_data + 2);
+    ck->i_sequence  = GetDWLE( p_data  + 4);
+    ck->i_unknown   = GetWLE( p_data + 8);
+    ck->i_size2     = GetWLE( p_data + 10);
+
+    ck->p_data      = p_data + 12;
+    ck->i_data      = __MIN( i_data - 12, ck->i_size2 - 8 );
+
+#if 0
+    fprintf( stderr, "type=0x%x size=%d sequence=%d unknown=%d size2=%d data=%d\n",
+             ck->i_type, ck->i_size, ck->i_sequence, ck->i_unknown, ck->i_size2, ck->i_data );
+#endif
+    return VLC_SUCCESS;
+}
+
diff --git a/modules/access/mms/mmsh.h b/modules/access/mms/mmsh.h
new file mode 100644 (file)
index 0000000..99dc689
--- /dev/null
@@ -0,0 +1,124 @@
+/*****************************************************************************
+ * mmsh.h:
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mmsh.h,v 1.1 2003/04/20 19:29:43 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#if 0
+/* url: [/]host[:port][/path][@username[:password]] */
+typedef struct url_s
+{
+    char    *psz_host;
+    int     i_port;
+
+    char    *psz_path;
+
+    char    *psz_username;
+    char    *psz_password;
+} url_t;
+
+static url_t *url_new   ( char * );
+static void   url_free  ( url_t * );
+#endif
+
+typedef struct
+{
+    uint16_t i_type;
+    uint16_t i_size;
+
+    uint32_t i_sequence;
+    uint16_t i_unknown;
+
+    uint16_t i_size2;
+
+    int      i_data;
+    uint8_t  *p_data;
+
+} chunk_t;
+
+static int chunk_parse( chunk_t *, uint8_t *, int );
+
+#define BUFFER_SIZE 150000
+struct access_sys_t
+{
+    int             i_proto;
+
+    input_socket_t  *p_socket;
+    url_t           *p_url;
+
+    int             i_request_context;
+
+    int             i_buffer;
+    int             i_buffer_pos;
+    uint8_t         buffer[BUFFER_SIZE + 1];
+
+    vlc_bool_t      b_broadcast;
+
+    uint8_t         *p_header;
+    int             i_header;
+
+    uint8_t         *p_packet;
+    uint32_t        i_packet_sequence;
+    unsigned int    i_packet_used;
+    unsigned int    i_packet_length;
+
+    off_t           i_pos;
+
+    asf_header_t    asfh;
+    guid_t          guid;
+};
+
+static input_socket_t * NetOpenTCP  ( input_thread_t *, url_t * );
+static ssize_t          NetRead     ( input_thread_t *, input_socket_t *, byte_t *, size_t );
+static ssize_t          NetWrite    ( input_thread_t *, input_socket_t *, byte_t *, size_t );
+static void             NetClose    ( input_thread_t *, input_socket_t * );
+
+
+static ssize_t NetFill( input_thread_t *, access_sys_t *, int );
+
+typedef struct http_field_s
+{
+    char *psz_name;
+    char *psz_value;
+
+    struct http_field_s *p_next;
+
+} http_field_t;
+
+typedef struct
+{
+    int     i_version;
+    int     i_error;
+    char    *psz_answer;
+
+    http_field_t *p_fields;
+
+    uint8_t *p_body;
+    int     i_body;
+
+} http_answer_t;
+
+static http_answer_t    *http_answer_parse  ( uint8_t *, int );
+static void              http_answer_free   ( http_answer_t * );
+static char             *http_field_get_value   ( http_answer_t *, char * );
+static http_field_t     *http_field_find    ( http_field_t *, char * );
+
+static int  mmsh_start( input_thread_t *, access_sys_t *, off_t );
+static void mmsh_stop ( input_thread_t *, access_sys_t * );
diff --git a/modules/access/mms/mmstu.c b/modules/access/mms/mmstu.c
new file mode 100644 (file)
index 0000000..2b40d77
--- /dev/null
@@ -0,0 +1,1561 @@
+/*****************************************************************************
+ * mms.c: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mmstu.c,v 1.1 2003/04/20 19:29:43 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include <vlc/vlc.h>
+#include <vlc/input.h>
+
+#ifdef HAVE_UNISTD_H
+#   include <unistd.h>
+#endif
+
+#ifdef WIN32
+#   include <winsock2.h>
+#   include <ws2tcpip.h>
+#   ifndef IN_MULTICAST
+#       define IN_MULTICAST(a) IN_CLASSD(a)
+#   endif
+#else
+#   include <sys/socket.h>
+#   include <netinet/in.h>
+#   if HAVE_ARPA_INET_H
+#      include <arpa/inet.h>
+#   elif defined( SYS_BEOS )
+#      include <net/netdb.h>
+#   endif
+#endif
+
+#include "network.h"
+#include "asf.h"
+#include "buffer.h"
+
+#include "mms.h"
+#include "mmstu.h"
+
+#undef MMS_DEBUG
+
+/****************************************************************************
+ * NOTES:
+ *  MMSProtocole documentation found at http://get.to/sdp
+ ****************************************************************************/
+
+/*****************************************************************************
+ * Local prototypes
+ *****************************************************************************/
+int  E_( MMSTUOpen )  ( input_thread_t * );
+void E_( MMSTUClose ) ( input_thread_t * );
+
+
+static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
+                          size_t i_len );
+static void Seek        ( input_thread_t *, off_t );
+
+static int MMSOpen( input_thread_t  *, url_t *, int, char * );
+
+static int MMSStart  ( input_thread_t  *, uint32_t );
+static int MMSStop  ( input_thread_t  *p_input );
+
+static int MMSClose  ( input_thread_t  * );
+
+
+static int  mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
+static int  mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
+
+static int  mms_HeaderMediaRead( input_thread_t *, int );
+
+static int  mms_ReceivePacket( input_thread_t * );
+
+//static void mms_ParseURL( url_t *p_url, char *psz_url );
+
+
+
+/*
+ * XXX DON'T FREE MY MEMORY !!! XXX
+ * non mais :P
+ */
+
+/*
+ * Ok, ok, j'le ferai plus...
+ */
+/*
+ * Merci :))
+ */
+/*
+ * Vous pourriez signer vos commentaires (même si on voit bien qui peut
+ * écrire ce genre de trucs :p), et écrire en anglais, bordel de
+ * merde :p.
+ */
+
+int  E_( MMSTUOpen )  ( input_thread_t *p_input )
+{
+    access_sys_t    *p_sys;
+    int         i_proto;
+    char        *psz_network;
+    int         i_status;
+
+    /* *** allocate p_sys_data *** */
+    p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) );
+    memset( p_sys, 0, sizeof( access_sys_t ) );
+
+
+    /* *** Parse URL and get server addr/port and path *** */
+    //mms_ParseURL( &p_sys->url, p_input->psz_name );
+    p_sys->p_url = E_( url_new )( p_input->psz_name );
+
+    if( *p_sys->p_url->psz_host == '\0' )
+    {
+        E_( url_free )( p_sys->p_url );
+        msg_Err( p_input, "invalid server name" );
+        return( -1 );
+    }
+    if( p_sys->p_url->i_port <= 0 )
+    {
+        p_sys->p_url->i_port = 1755;
+    }
+#if 0
+    if( p_sys->url.i_bind_port == 0 )
+    {
+        p_sys->url.i_bind_port = 7000;   /* default port */
+    }
+#endif
+
+    /* *** connect to this server *** */
+    /* 1: look at  requested protocol (udp/tcp) */
+    i_proto = MMS_PROTO_AUTO;
+    if( *p_input->psz_access )
+    {
+        if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
+        {
+            i_proto = MMS_PROTO_UDP;
+        }
+        else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
+        {
+            i_proto = MMS_PROTO_TCP;
+        }
+    }
+    /* 2: look at ip version ipv4/ipv6 */
+    psz_network = "";
+    if( config_GetInt( p_input, "ipv4" ) )
+    {
+        psz_network = "ipv4";
+    }
+    else if( config_GetInt( p_input, "ipv6" ) )
+    {
+        psz_network = "ipv6";
+    }
+    /* 3: connect */
+    if( i_proto == MMS_PROTO_AUTO )
+    {   /* first try with TCP */
+        i_status =
+            MMSOpen( p_input, p_sys->p_url, MMS_PROTO_TCP, psz_network );
+        if( i_status < 0 )
+        {   /* then with UDP */
+            i_status =
+             MMSOpen( p_input, p_sys->p_url, MMS_PROTO_UDP, psz_network );
+        }
+    }
+    else
+    {
+
+        i_status =
+            MMSOpen( p_input, p_sys->p_url, i_proto, psz_network );
+    }
+
+    if( i_status < 0 )
+    {
+        msg_Err( p_input, "cannot connect to server" );
+        E_( url_free )( p_sys->p_url );
+        return( -1 );
+    }
+    msg_Dbg( p_input, "connected to %s:%d", p_sys->p_url->psz_host, p_sys->p_url->i_port );
+
+
+    /* *** set exported functions *** */
+    p_input->pf_read = Read;
+    p_input->pf_seek = Seek;
+    p_input->pf_set_program = input_SetProgram;
+    p_input->pf_set_area = NULL;
+
+    p_input->p_private = NULL;
+
+    /* *** finished to set some variable *** */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    p_input->stream.b_pace_control = 0;
+    p_input->stream.p_selected_area->i_tell = 0;
+    /*
+     * i_flags_broadcast
+     *  yy xx ?? ??
+     *  broadcast    yy=0x02, xx= 0x00
+     *  pre-recorded yy=0x01, xx= 0x80 if video, 0x00 no video
+     */
+    if( p_sys->i_packet_count <= 0 || ( p_sys->i_flags_broadcast >> 24 ) == 0x02 )
+    {
+        p_input->stream.b_seekable = 0;
+        p_input->stream.p_selected_area->i_size = 0;
+    }
+    else
+    {
+        p_input->stream.b_seekable = 1;
+        p_input->stream.p_selected_area->i_size =
+            p_sys->i_header +
+            p_sys->i_packet_count * p_sys->i_packet_length;
+    }
+
+    p_input->stream.i_method = INPUT_METHOD_NETWORK;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+
+    /* *** Start stream *** */
+    if( MMSStart( p_input, 0xffffffff ) < 0 )
+    {
+        msg_Err( p_input, "cannot start stream" );
+        MMSClose( p_input );
+        E_( url_free )( p_sys->p_url );
+        return( -1 );
+    }
+
+    /* Update default_pts to a suitable value for mms access */
+    p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
+
+    return( 0 );
+}
+
+/*****************************************************************************
+ * Close: free unused data structures
+ *****************************************************************************/
+void E_( MMSTUClose ) ( input_thread_t *p_input )
+{
+    access_sys_t    *p_sys = p_input->p_access_data;
+
+    /* close connection with server */
+    MMSClose( p_input );
+
+    /* free memory */
+    E_( url_free )( p_sys->p_url );
+
+    free( p_sys );
+}
+
+/*****************************************************************************
+ * Seek: try to go at the right place
+ *****************************************************************************/
+static void Seek( input_thread_t * p_input, off_t i_pos )
+{
+    access_sys_t    *p_sys = p_input->p_access_data;
+    uint32_t    i_packet;
+    uint32_t    i_offset;
+    var_buffer_t    buffer;
+
+    if( i_pos < 0 )
+    {
+        return;
+    }
+
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+
+    if( i_pos < p_sys->i_header)
+    {
+
+        if( p_sys->i_pos < p_sys->i_header )
+        {
+            /* no need to restart stream, it was already one
+             * or no stream was yet read */
+            p_sys->i_pos = i_pos;
+            return;
+        }
+        else
+        {
+            i_packet = 0xffffffff;
+            i_offset = 0;
+        }
+    }
+    else
+    {
+        i_packet = ( i_pos - p_sys->i_header ) / p_sys->i_packet_length;
+        i_offset = ( i_pos - p_sys->i_header ) % p_sys->i_packet_length;
+    }
+    msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
+
+    MMSStop( p_input );
+    msg_Dbg( p_input, "stream stopped (seek)" );
+
+    /* *** restart stream *** */
+    var_buffer_initwrite( &buffer, 0 );
+    var_buffer_add64( &buffer, 0 ); /* seek point in second */
+    var_buffer_add32( &buffer, 0xffffffff );
+    var_buffer_add32( &buffer, i_packet ); // begin from start
+    var_buffer_add8( &buffer, 0xff ); // stream time limit
+    var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
+    var_buffer_add8( &buffer, 0xff ); //
+    var_buffer_add8( &buffer, 0x00 ); // don't use limit
+    var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
+
+    mms_CommandSend( p_input, 0x07, p_sys->i_command_level, 0x0001ffff,
+                     buffer.p_data, buffer.i_data );
+
+    var_buffer_free( &buffer );
+
+
+    for( ;; )
+    {
+        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
+        if( p_sys->i_command == 0x1e )
+        {
+            msg_Dbg( p_input, "received 0x1e (seek)" );
+            break;
+        }
+    }
+
+    for( ;; )
+    {
+        mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
+        if( p_sys->i_command == 0x05 )
+        {
+            msg_Dbg( p_input, "received 0x05 (seek)" );
+            break;
+        }
+    }
+
+    /* get a packet */
+    mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
+    msg_Dbg( p_input, "Streaming restarted" );
+
+    p_sys->i_media_used += i_offset;
+    p_sys->i_pos = i_pos;
+    p_input->stream.p_selected_area->i_tell = i_pos;
+    vlc_mutex_unlock( &p_input->stream.stream_lock );
+}
+
+static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
+                          size_t i_len )
+{
+    access_sys_t    *p_sys = p_input->p_access_data;
+    size_t      i_data;
+    size_t      i_copy;
+
+    i_data = 0;
+
+    /* *** send header if needed ** */
+    if( p_sys->i_pos < p_sys->i_header )
+    {
+        i_copy = __MIN( i_len, p_sys->i_header - p_sys->i_pos );
+        if( i_copy > 0 )
+        {
+            memcpy( p_buffer,
+                    p_sys->p_header + p_sys->i_pos,
+                    i_copy );
+        }
+        i_data += i_copy;
+    }
+
+    /* *** now send data if needed *** */
+    while( i_data < i_len )
+    {
+        if( p_sys->i_media_used < p_sys->i_media )
+        {
+            i_copy = __MIN( i_len - i_data ,
+                            p_sys->i_media - p_sys->i_media_used );
+            memcpy( p_buffer + i_data,
+                    p_sys->p_media + p_sys->i_media_used,
+                    i_copy );
+            i_data += i_copy;
+            p_sys->i_media_used += i_copy;
+        }
+        else if( p_sys->p_media != NULL &&
+                 p_sys->i_media_used < p_sys->i_packet_length )
+        {
+            i_copy = __MIN( i_len - i_data,
+                            p_sys->i_packet_length - p_sys->i_media_used);
+            memset( p_buffer + i_data, 0, i_copy );
+
+            i_data += i_copy;
+            p_sys->i_media_used += i_copy;
+        }
+        else
+        {
+            if( p_sys->i_eos
+                 || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )
+            {
+                p_sys->i_pos += i_data;
+                return( i_data );
+            }
+        }
+    }
+
+    p_sys->i_pos += i_data;
+    return( i_data );
+}
+
+/****************************************************************************
+ * MMSOpen : Open a connection with the server over mmst or mmsu
+ ****************************************************************************/
+static int MMSOpen( input_thread_t  *p_input,
+                    url_t *p_url,
+                    int  i_proto,
+                    char *psz_network ) /* "", "ipv4", "ipv6" */
+{
+    module_t    *p_network;
+    access_sys_t    *p_sys = p_input->p_access_data;
+
+    network_socket_t    socket_desc;
+    int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
+
+    var_buffer_t buffer;
+    char         tmp[4096];
+    uint16_t     *p;
+    int          i_server_version;
+    int          i_tool_version;
+    int          i_update_player_url;
+    int          i_encryption_type;
+    int          i;
+    int          i_streams;
+    int          i_first;
+
+
+    /* *** Open a TCP connection with server *** */
+    msg_Dbg( p_input, "waiting for connection..." );
+    socket_desc.i_type = NETWORK_TCP;
+    socket_desc.psz_server_addr = p_url->psz_host;
+    socket_desc.i_server_port   = p_url->i_port;
+    socket_desc.psz_bind_addr   = "";
+    socket_desc.i_bind_port     = 0;
+    p_input->p_private = (void*)&socket_desc;
+    if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
+    {
+        msg_Err( p_input, "failed to open a connection (tcp)" );
+        return( -1 );
+    }
+    module_Unneed( p_input, p_network );
+    p_sys->socket_tcp.i_handle = socket_desc.i_handle;
+    p_input->i_mtu    = 0; /*socket_desc.i_mtu;*/
+    msg_Dbg( p_input,
+             "connection(tcp) with \"%s:%d\" successful",
+             p_url->psz_host,
+             p_url->i_port );
+
+    /* *** Bind port if UDP protocol is selected *** */
+    if( b_udp )
+    {
+        struct sockaddr_in name;
+        socklen_t i_namelen = sizeof( struct sockaddr_in );
+
+        if( getsockname( p_sys->socket_tcp.i_handle,
+                         (struct sockaddr*)&name, &i_namelen ) < 0 )
+        {
+
+            msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
+#if defined( UNDER_CE )
+            CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
+#elif defined( WIN32 )
+            closesocket( p_sys->socket_tcp.i_handle );
+#else
+            close( p_sys->socket_tcp.i_handle );
+#endif
+            return( -1 );
+        }
+        p_sys->psz_bind_addr = inet_ntoa( name.sin_addr );
+
+        socket_desc.i_type = NETWORK_UDP;
+        socket_desc.psz_server_addr = "";
+        socket_desc.i_server_port   = 0;
+        socket_desc.psz_bind_addr   = p_sys->psz_bind_addr;
+        socket_desc.i_bind_port     = 7000; //p_url->i_bind_port; FIXME
+        p_input->p_private = (void*)&socket_desc;
+        if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
+        {
+            msg_Err( p_input, "failed to open a connection (udp)" );
+#if defined( UNDER_CE )
+            CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
+#elif defined( WIN32 )
+            closesocket( p_sys->socket_tcp.i_handle );
+#else
+            close( p_sys->socket_tcp.i_handle );
+#endif
+            return( -1 );
+        }
+        module_Unneed( p_input, p_network );
+        p_sys->socket_udp.i_handle = socket_desc.i_handle;
+        p_input->i_mtu    = 0;/*socket_desc.i_mtu;  FIXME */
+
+        msg_Dbg( p_input,
+                 "connection(udp) at \"%s:%d\" successful",
+                 p_sys->psz_bind_addr,
+                 7000 );
+    }
+    else
+    {
+        p_sys->psz_bind_addr = NULL;
+    }
+
+    /* *** Init context for mms prototcol *** */
+    E_( GenerateGuid )( &p_sys->guid );    /* used to identify client by server */
+    msg_Dbg( p_input,
+             "generated guid: "GUID_FMT,
+             GUID_PRINT( p_sys->guid ) );
+    p_sys->i_command_level = 1;          /* updated after 0x1A command */
+    p_sys->i_seq_num = 0;
+    p_sys->i_media_packet_id_type  = 0x04;
+    p_sys->i_header_packet_id_type = 0x02;
+    p_sys->i_proto = i_proto;
+    p_sys->i_packet_seq_num = 0;
+    p_sys->p_header = NULL;
+    p_sys->i_header = 0;
+    p_sys->p_media = NULL;
+    p_sys->i_media = 0;
+    p_sys->i_media_used = 0;
+
+    p_sys->i_pos = 0;
+    p_sys->i_buffer_tcp = 0;
+    p_sys->i_buffer_udp = 0;
+    p_sys->p_cmd = NULL;
+    p_sys->i_cmd = 0;
+    p_sys->i_eos = 0;
+
+    /* *** send command 1 : connection request *** */
+    var_buffer_initwrite( &buffer, 0 );
+    var_buffer_add16( &buffer, 0x001c );
+    var_buffer_add16( &buffer, 0x0003 );
+    sprintf( tmp,
+             "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
+             GUID_PRINT( p_sys->guid ),
+             p_url->psz_host );
+    var_buffer_addUTF16( &buffer, tmp );
+
+    mms_CommandSend( p_input,
+                     0x01,          /* connexion request */
+                     0x00000000,    /* flags, FIXME */
+                     0x0004000b,    /* ???? */
+                     buffer.p_data,
+                     buffer.i_data );
+
+    if( mms_CommandRead( p_input, 0x01, 0 ) < 0 )
+    {
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+
+    i_server_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 32 );
+    i_tool_version = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 36 );
+    i_update_player_url = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 40 );
+    i_encryption_type = GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
+    p = (uint16_t*)( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
+#define GETUTF16( psz, size ) \
+    { \
+        int i; \
+        psz = malloc( size + 1); \
+        for( i = 0; i < size; i++ ) \
+        { \
+            psz[i] = p[i]; \
+        } \
+        psz[size] = '\0'; \
+        p += 2 * ( size ); \
+    }
+    GETUTF16( p_sys->psz_server_version, i_server_version );
+    GETUTF16( p_sys->psz_tool_version, i_tool_version );
+    GETUTF16( p_sys->psz_update_player_url, i_update_player_url );
+    GETUTF16( p_sys->psz_encryption_type, i_encryption_type );
+#undef GETUTF16
+    msg_Dbg( p_input,
+             "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
+             p_sys->psz_server_version,
+             p_sys->psz_tool_version,
+             p_sys->psz_update_player_url,
+             p_sys->psz_encryption_type );
+
+    /* *** should make an 18 command to make data timing *** */
+
+    /* *** send command 2 : transport protocol selection *** */
+    var_buffer_reinitwrite( &buffer, 0 );
+    var_buffer_add32( &buffer, 0x00000000 );
+    var_buffer_add32( &buffer, 0x000a0000 );
+    var_buffer_add32( &buffer, 0x00000002 );
+    if( b_udp )
+    {
+        sprintf( tmp,
+                 "\\\\%s\\UDP\\%d",
+                 p_sys->psz_bind_addr,
+                 7000 ); // FIXME
+    }
+    else
+    {
+        sprintf( tmp, "\\\\192.168.0.1\\TCP\\1242"  );
+    }
+    var_buffer_addUTF16( &buffer, tmp );
+    var_buffer_add16( &buffer, '0' );
+
+    mms_CommandSend( p_input,
+                     0x02,          /* connexion request */
+                     0x00000000,    /* flags, FIXME */
+                     0xffffffff,    /* ???? */
+                     buffer.p_data,
+                     buffer.i_data );
+
+    /* *** response from server, should be 0x02 or 0x03 *** */
+    mms_CommandRead( p_input, 0x02, 0x03 );
+    if( p_sys->i_command == 0x03 )
+    {
+        msg_Err( p_input,
+                 "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+    else if( p_sys->i_command != 0x02 )
+    {
+        msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
+    }
+
+    /* *** send command 5 : media file name/path requested *** */
+    var_buffer_reinitwrite( &buffer, 0 );
+    var_buffer_add64( &buffer, 0 );
+    var_buffer_addUTF16( &buffer, p_url->psz_path );
+
+    mms_CommandSend( p_input,
+                     0x05,
+                     p_sys->i_command_level,
+                     0xffffffff,
+                     buffer.p_data,
+                     buffer.i_data );
+
+    /* *** wait for reponse *** */
+    mms_CommandRead( p_input, 0x1a, 0x06 );
+
+    /* test if server send 0x1A answer */
+    if( p_sys->i_command == 0x1A )
+    {
+        msg_Err( p_input, "id/password requested (not yet supported)" );
+        /*  FIXME */
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+    if( p_sys->i_command != 0x06 )
+    {
+        msg_Err( p_input,
+                 "unknown answer (0x%x instead of 0x06)",
+                 p_sys->i_command );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+
+    /*  1 for file ok, 2 for authen ok */
+    switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) )
+    {
+        case 0x0001:
+            msg_Dbg( p_input, "Media file name/path accepted" );
+            break;
+        case 0x0002:
+            msg_Dbg( p_input, "Authentication accepted" );
+            break;
+        case -1:
+        default:
+        msg_Err( p_input, "error while asking for file %d",
+                 GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+
+    p_sys->i_flags_broadcast =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 12 );
+    p_sys->i_media_length =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 24 );
+    p_sys->i_packet_length =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 44 );
+    p_sys->i_packet_count =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 48 );
+    p_sys->i_max_bit_rate =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 56 );
+    p_sys->i_header_size =
+        GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE + 60 );
+
+    msg_Dbg( p_input,
+             "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
+             p_sys->i_flags_broadcast,
+             p_sys->i_media_length,
+             p_sys->i_packet_length,
+             p_sys->i_packet_count,
+             p_sys->i_max_bit_rate,
+             p_sys->i_header_size );
+
+    /* XXX XXX dirty hack XXX XXX */
+    p_input->i_mtu    = 3 * p_sys->i_packet_length;
+
+    /* *** send command 15 *** */
+
+    var_buffer_reinitwrite( &buffer, 0 );
+    var_buffer_add32( &buffer, 0 );
+    var_buffer_add32( &buffer, 0x8000 );
+    var_buffer_add32( &buffer, 0xffffffff );
+    var_buffer_add32( &buffer, 0x00 );
+    var_buffer_add32( &buffer, 0x00 );
+    var_buffer_add32( &buffer, 0x00 );
+    var_buffer_add64( &buffer, 0x40ac200000000000 );
+    var_buffer_add32( &buffer, p_sys->i_header_packet_id_type );
+    mms_CommandSend( p_input, 0x15, p_sys->i_command_level, 0x00,
+                     buffer.p_data, buffer.i_data );
+
+    /* *** wait for reponse *** */
+    mms_CommandRead( p_input, 0x11, 0 );
+
+    if( p_sys->i_command != 0x11 )
+    {
+        msg_Err( p_input,
+                 "unknown answer (0x%x instead of 0x11)",
+                 p_sys->i_command );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+    /* *** now read header packet *** */
+    /* XXX could be split over multiples packets */
+    for( ;; )
+    {
+        if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
+        {
+            msg_Err( p_input, "cannot receive header" );
+            var_buffer_free( &buffer );
+            MMSClose( p_input );
+            return( -1 );
+        }
+        if( p_sys->i_header >= p_sys->i_header_size )
+        {
+            msg_Dbg( p_input,
+                     "header complete(%d)",
+                     p_sys->i_header );
+            break;
+        }
+        msg_Dbg( p_input,
+                 "header incomplete (%d/%d), reading more",
+                 p_sys->i_header,
+                 p_sys->i_header_size );
+    }
+
+    /* *** parse header and get stream and their id *** */
+    /* get all streams properties,
+     *
+     * TODO : stream bitrates properties(optional)
+     *        and bitrate mutual exclusion(optional) */
+    E_( asf_HeaderParse )( &p_sys->asfh,
+                           p_sys->p_header, p_sys->i_header );
+    E_( asf_StreamSelect)( &p_sys->asfh,
+                           config_GetInt( p_input, "mms-maxbitrate" ),
+                           config_GetInt( p_input, "mms-all" ),
+                           config_GetInt( p_input, "audio" ),
+                           config_GetInt( p_input, "video" ) );
+
+    /* *** now select stream we want to receive *** */
+    /* TODO take care of stream bitrate TODO */
+    i_streams = 0;
+    i_first = -1;
+    var_buffer_reinitwrite( &buffer, 0 );
+    /* for now, select first audio and video stream */
+    for( i = 1; i < 128; i++ )
+    {
+
+        if( p_sys->asfh.stream[i].i_cat != ASF_STREAM_UNKNOWN )
+        {
+            i_streams++;
+            if( i_first != -1 )
+            {
+                var_buffer_add16( &buffer, 0xffff );
+                var_buffer_add16( &buffer, i );
+            }
+            else
+            {
+                i_first = i;
+            }
+            if( p_sys->asfh.stream[i].i_selected )
+            {
+                var_buffer_add16( &buffer, 0x0000 );
+                msg_Info( p_input,
+                          "selecting stream[0x%x] %s (%d kb/s)",
+                          i,
+                          ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
+                                                  "audio" : "video" ,
+                          p_sys->asfh.stream[i].i_bitrate / 1024);
+            }
+            else
+            {
+                var_buffer_add16( &buffer, 0x0002 );
+                msg_Info( p_input,
+                          "ignoring stream[0x%x] %s (%d kb/s)",
+                          i,
+                          ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO  ) ?
+                                    "audio" : "video" ,
+                          p_sys->asfh.stream[i].i_bitrate / 1024);
+
+            }
+        }
+    }
+
+    if( i_streams == 0 )
+    {
+        msg_Err( p_input, "cannot find any stream" );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+    mms_CommandSend( p_input, 0x33,
+                     i_streams,
+                     0xffff | ( i_first << 16 ),
+                     buffer.p_data, buffer.i_data );
+
+    mms_CommandRead( p_input, 0x21, 0 );
+    if( p_sys->i_command != 0x21 )
+    {
+        msg_Err( p_input,
+                 "unknown answer (0x%x instead of 0x21)",
+                 p_sys->i_command );
+        var_buffer_free( &buffer );
+        MMSClose( p_input );
+        return( -1 );
+    }
+
+
+    var_buffer_free( &buffer );
+
+    msg_Info( p_input, "connection sucessful" );
+
+    return( 0 );
+}
+
+/****************************************************************************
+ * MMSStart : Start streaming
+ ****************************************************************************/
+static int MMSStart  ( input_thread_t  *p_input, uint32_t i_packet )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+    var_buffer_t    buffer;
+
+    /* *** start stream from packet 0 *** */
+    var_buffer_initwrite( &buffer, 0 );
+    var_buffer_add64( &buffer, 0 ); /* seek point in second */
+    var_buffer_add32( &buffer, 0xffffffff );
+    var_buffer_add32( &buffer, i_packet ); // begin from start
+    var_buffer_add8( &buffer, 0xff ); // stream time limit
+    var_buffer_add8( &buffer, 0xff ); //  on 3bytes ...
+    var_buffer_add8( &buffer, 0xff ); //
+    var_buffer_add8( &buffer, 0x00 ); // don't use limit
+    var_buffer_add32( &buffer, p_sys->i_media_packet_id_type );
+
+    mms_CommandSend( p_input, 0x07, p_sys->i_command_level, 0x0001ffff,
+                     buffer.p_data, buffer.i_data );
+
+    var_buffer_free( &buffer );
+
+    mms_CommandRead( p_input, 0x05, 0 );
+
+    if( p_sys->i_command != 0x05 )
+    {
+        msg_Err( p_input,
+                 "unknown answer (0x%x instead of 0x05)",
+                 p_sys->i_command );
+        return( -1 );
+    }
+    else
+    {
+        /* get a packet */
+        mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
+        msg_Dbg( p_input, "Streaming started" );
+        return( 0 );
+    }
+}
+
+/****************************************************************************
+ * MMSStop : Stop streaming
+ ****************************************************************************/
+static int MMSStop  ( input_thread_t  *p_input )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+
+    /* *** stop stream but keep connection alive *** */
+    mms_CommandSend( p_input,
+                     0x09,
+                     p_sys->i_command_level,
+                     0x001fffff,
+                     NULL, 0 );
+    return( 0 );
+}
+
+/****************************************************************************
+ * MMSClose : Close streaming and connection
+ ****************************************************************************/
+static int MMSClose  ( input_thread_t  *p_input )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+
+    msg_Dbg( p_input, "Connection closed" );
+
+    /* *** tell server that we will disconnect *** */
+    mms_CommandSend( p_input,
+                     0x0d,
+                     p_sys->i_command_level,
+                     0x00000001,
+                     NULL, 0 );
+    /* *** close sockets *** */
+#if defined( UNDER_CE )
+    CloseHandle( (HANDLE)p_sys->socket_tcp.i_handle );
+#elif defined( WIN32 )
+    closesocket( p_sys->socket_tcp.i_handle );
+#else
+    close( p_sys->socket_tcp.i_handle );
+#endif
+
+    if( p_sys->i_proto == MMS_PROTO_UDP )
+    {
+#if defined( UNDER_CE )
+        CloseHandle( (HANDLE)p_sys->socket_udp.i_handle );
+#elif defined( WIN32 )
+        closesocket( p_sys->socket_udp.i_handle );
+#else
+        close( p_sys->socket_udp.i_handle );
+#endif
+    }
+
+    FREE( p_sys->p_cmd );
+    FREE( p_sys->p_media );
+    FREE( p_sys->p_header );
+
+    FREE( p_sys->psz_server_version );
+    FREE( p_sys->psz_tool_version );
+    FREE( p_sys->psz_update_player_url );
+    FREE( p_sys->psz_encryption_type );
+
+    return( 0 );
+}
+
+/****************************************************************************
+ *
+ * MMS specific functions
+ *
+ ****************************************************************************/
+
+static int mms_CommandSend( input_thread_t *p_input,
+                             int i_command,
+                             uint32_t i_prefix1, uint32_t i_prefix2,
+                             uint8_t *p_data, int i_data )
+{
+    var_buffer_t buffer;
+
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int i_data_by8;
+
+    i_data_by8 = ( i_data + 7 ) / 8;
+
+    /* first init uffer */
+    var_buffer_initwrite( &buffer, 0 );
+
+    var_buffer_add32( &buffer, 0x00000001 );    /* start sequence */
+    var_buffer_add32( &buffer, 0xB00BFACE );
+    /* size after protocol type */
+    var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
+    var_buffer_add32( &buffer, 0x20534d4d );    /* protocol "MMS " */
+    var_buffer_add32( &buffer, i_data_by8 + 4 );
+    var_buffer_add32( &buffer, p_sys->i_seq_num ); p_sys->i_seq_num++;
+    var_buffer_add64( &buffer, 0 );
+    var_buffer_add32( &buffer, i_data_by8 + 2 );
+    var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
+    var_buffer_add32( &buffer, i_prefix1 );    /* command specific */
+    var_buffer_add32( &buffer, i_prefix2 );    /* command specific */
+
+    /* specific command data */
+    if( p_data && i_data > 0 )
+    {
+        var_buffer_addmemory( &buffer, p_data, i_data );
+    }
+
+    /* send it */
+    if( send( p_sys->socket_tcp.i_handle,
+              buffer.p_data,
+              buffer.i_data,
+              0 ) == -1 )
+    {
+        msg_Err( p_input, "failed to send command" );
+        return( -1 );
+    }
+
+    var_buffer_free( &buffer );
+    return( 0 );
+}
+
+static int  NetFillBuffer( input_thread_t *p_input )
+{
+#ifdef UNDER_CE
+    return -1;
+#else
+    access_sys_t        *p_sys = p_input->p_access_data;
+    struct timeval  timeout;
+    fd_set          fds;
+    int             i_ret;
+
+    /* FIXME when using udp */
+    ssize_t i_tcp, i_udp;
+    ssize_t i_tcp_read, i_udp_read;
+    int i_handle_max;
+
+    /* Initialize file descriptor set */
+    FD_ZERO( &fds );
+
+    i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp;
+
+    if( p_sys->i_proto == MMS_PROTO_UDP )
+    {
+        i_udp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_udp;
+    }
+    else
+    {
+        i_udp = 0;  /* there isn't udp socket */
+    }
+
+    i_handle_max = 0;
+    if( i_tcp > 0 )
+    {
+        FD_SET( p_sys->socket_tcp.i_handle, &fds );
+        i_handle_max = __MAX( i_handle_max, p_sys->socket_tcp.i_handle );
+    }
+    if( i_udp > 0 )
+    {
+        FD_SET( p_sys->socket_udp.i_handle, &fds );
+        i_handle_max = __MAX( i_handle_max, p_sys->socket_udp.i_handle );
+    }
+
+    if( i_handle_max == 0 )
+    {
+        msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
+        return( 0 );
+    }
+    else
+    {
+//        msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
+    }
+
+    /* We'll wait 0.5 second if nothing happens */
+    timeout.tv_sec = 0;
+    timeout.tv_usec = 500000;
+
+    /* Find if some data is available */
+    while( (i_ret = select( i_handle_max + 1, &fds,
+                            NULL, NULL, &timeout )) == 0
+           || (i_ret < 0 && errno == EINTR) )
+    {
+        FD_ZERO( &fds );
+        if( i_tcp > 0 ) FD_SET( p_sys->socket_tcp.i_handle, &fds );
+        if( i_udp > 0 ) FD_SET( p_sys->socket_udp.i_handle, &fds );
+        timeout.tv_sec = 0;
+        timeout.tv_usec = 500000;
+
+        if( p_input->b_die || p_input->b_error )
+        {
+            return 0;
+        }
+    }
+
+    if( i_ret < 0 )
+    {
+        msg_Err( p_input, "network select error (%s)", strerror(errno) );
+        return -1;
+    }
+
+    if( i_tcp > 0 && FD_ISSET( p_sys->socket_tcp.i_handle, &fds ) )
+    {
+        i_tcp_read =
+            recv( p_sys->socket_tcp.i_handle,
+                  p_sys->buffer_tcp + p_sys->i_buffer_tcp,
+                  i_tcp + MMS_BUFFER_SIZE/2, 0 );
+    }
+    else
+    {
+        i_tcp_read = 0;
+    }
+
+    if( i_udp > 0 && FD_ISSET( p_sys->socket_udp.i_handle, &fds ) )
+    {
+        i_udp_read = recv( p_sys->socket_udp.i_handle,
+                           p_sys->buffer_udp + p_sys->i_buffer_udp,
+                           i_udp + MMS_BUFFER_SIZE/2, 0 );
+    }
+    else
+    {
+        i_udp_read = 0;
+    }
+
+#if MMS_DEBUG
+    if( p_sys->i_proto == MMS_PROTO_UDP )
+    {
+        msg_Dbg( p_input,
+                 "filling buffer TCP:%d+%d UDP:%d+%d",
+                 p_sys->i_buffer_tcp,
+                 i_tcp_read,
+                 p_sys->i_buffer_udp,
+                 i_udp_read );
+    }
+    else
+    {
+        msg_Dbg( p_input,
+                 "filling buffer TCP:%d+%d",
+                 p_sys->i_buffer_tcp,
+                 i_tcp_read );
+    }
+#endif
+    if( i_tcp_read > 0 )
+    {
+        p_sys->i_buffer_tcp += i_tcp_read;
+    }
+    if( i_udp_read > 0 )
+    {
+        p_sys->i_buffer_udp += i_udp_read;
+    }
+
+    return( i_tcp_read + i_udp_read);
+#endif
+}
+
+static int  mms_ParseCommand( input_thread_t *p_input,
+                              uint8_t *p_data,
+                              int i_data,
+                              int *pi_used )
+{
+ #define GET32( i_pos ) \
+    ( p_sys->p_cmd[i_pos] + ( p_sys->p_cmd[i_pos +1] << 8 ) + \
+      ( p_sys->p_cmd[i_pos + 2] << 16 ) + \
+      ( p_sys->p_cmd[i_pos + 3] << 24 ) )
+
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int         i_length;
+    uint32_t    i_id;
+
+    if( p_sys->p_cmd )
+    {
+        free( p_sys->p_cmd );
+    }
+    p_sys->i_cmd = i_data;
+    p_sys->p_cmd = malloc( i_data );
+    memcpy( p_sys->p_cmd, p_data, i_data );
+
+    *pi_used = i_data; /* by default */
+
+    if( i_data < MMS_CMD_HEADERSIZE )
+    {
+        msg_Warn( p_input, "truncated command (header incomplete)" );
+        p_sys->i_command = 0;
+        return( -1 );
+    }
+    i_id =  GetDWLE( p_data + 4 );
+    i_length = GetDWLE( p_data + 8 ) + 16;
+
+    if( i_id != 0xb00bface )
+    {
+        msg_Err( p_input,
+                 "incorrect command header (0x%x)", i_id );
+        p_sys->i_command = 0;
+        return( -1 );
+    }
+
+    if( i_length > p_sys->i_cmd )
+    {
+        msg_Warn( p_input,
+                  "truncated command (missing %d bytes)",
+                   i_length - i_data  );
+        p_sys->i_command = 0;
+        return( -1 );
+    }
+    else if( i_length < p_sys->i_cmd )
+    {
+        p_sys->i_cmd = i_length;
+        *pi_used = i_length;
+    }
+
+    msg_Dbg( p_input,
+             "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x",
+             GET32( 0 ),
+             GET32( 4 ),
+             GET32( 8 ),
+             /* 12: protocol type "MMS " */
+             GET32( 16 ),
+             GET32( 20 ),
+             /* 24: unknown (0) */
+             /* 28: unknown (0) */
+             GET32( 32 ),
+             GET32( 36 )
+             /* 40: switches */
+             /* 44: extra */ );
+
+    p_sys->i_command = GET32( 36 ) & 0xffff;
+
+    return( MMS_PACKET_CMD );
+}
+
+static int  mms_ParsePacket( input_thread_t *p_input,
+                             uint8_t *p_data, size_t i_data,
+                             int *pi_used )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int i_packet_seq_num;
+    size_t i_packet_length;
+    uint32_t i_packet_id;
+
+    uint8_t  *p_packet;
+
+
+    *pi_used = i_data; /* default */
+    if( i_data <= 8 )
+    {
+        msg_Warn( p_input, "truncated packet (header incomplete)" );
+        return( -1 );
+    }
+
+    i_packet_id = p_data[4];
+    i_packet_seq_num = GetDWLE( p_data );
+    i_packet_length = GetWLE( p_data + 6 );
+
+    //msg_Warn( p_input, "------->i_packet_length=%d, i_data=%d", i_packet_length, i_data );
+
+    if( i_packet_length > i_data || i_packet_length <= 8)
+    {
+        msg_Dbg( p_input,
+                 "truncated packet (missing %d bytes)",
+                 i_packet_length - i_data  );
+        *pi_used = 0;
+        return( -1 );
+    }
+    else if( i_packet_length < i_data )
+    {
+        *pi_used = i_packet_length;
+    }
+
+    if( i_packet_id == 0xff )
+    {
+        msg_Warn( p_input,
+                  "receive MMS UDP pair timing" );
+        return( MMS_PACKET_UDP_TIMING );
+    }
+
+    if( i_packet_id != p_sys->i_header_packet_id_type &&
+        i_packet_id != p_sys->i_media_packet_id_type )
+    {
+        msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
+        return( -1 );
+    }
+
+    /* we now have a media or a header packet */
+    p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
+    memcpy( p_packet, p_data + 8, i_packet_length - 8 );
+
+    if( i_packet_seq_num != p_sys->i_packet_seq_num )
+    {
+        /* FIXME for udp could be just wrong order ? */
+        msg_Warn( p_input,
+                  "detected packet lost (%d != %d)",
+                  i_packet_seq_num,
+                  p_sys->i_packet_seq_num );
+        p_sys->i_packet_seq_num = i_packet_seq_num;
+    }
+    p_sys->i_packet_seq_num++;
+
+    if( i_packet_id == p_sys->i_header_packet_id_type )
+    {
+        if( p_sys->p_header )
+        {
+            p_sys->p_header = realloc( p_sys->p_header,
+                                          p_sys->i_header + i_packet_length - 8 );
+            memcpy( &p_sys->p_header[p_sys->i_header],
+                    p_packet,
+                    i_packet_length - 8 );
+            p_sys->i_header += i_packet_length - 8;
+
+            free( p_packet );
+        }
+        else
+        {
+            p_sys->p_header = p_packet;
+            p_sys->i_header = i_packet_length - 8;
+        }
+/*        msg_Dbg( p_input,
+                 "receive header packet (%d bytes)",
+                 i_packet_length - 8 ); */
+
+        return( MMS_PACKET_HEADER );
+    }
+    else
+    {
+        FREE( p_sys->p_media );
+        p_sys->p_media = p_packet;
+        p_sys->i_media = i_packet_length - 8;
+        p_sys->i_media_used = 0;
+/*        msg_Dbg( p_input,
+                 "receive media packet (%d bytes)",
+                 i_packet_length - 8 ); */
+
+        return( MMS_PACKET_MEDIA );
+    }
+}
+
+static int mms_ReceivePacket( input_thread_t *p_input )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int i_packet_tcp_type;
+    int i_packet_udp_type;
+
+    for( ;; )
+    {
+        if( NetFillBuffer( p_input ) < 0 )
+        {
+            msg_Warn( p_input, "cannot fill buffer" );
+            continue;
+        }
+
+        i_packet_tcp_type = -1;
+        i_packet_udp_type = -1;
+
+        if( p_sys->i_buffer_tcp > 0 )
+        {
+            int i_used;
+
+            if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface )
+            {
+                i_packet_tcp_type =
+                    mms_ParseCommand( p_input,
+                                      p_sys->buffer_tcp,
+                                      p_sys->i_buffer_tcp,
+                                      &i_used );
+
+            }
+            else
+            {
+                i_packet_tcp_type =
+                    mms_ParsePacket( p_input,
+                                     p_sys->buffer_tcp,
+                                     p_sys->i_buffer_tcp,
+                                     &i_used );
+            }
+            if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
+            {
+                memmove( p_sys->buffer_tcp,
+                         p_sys->buffer_tcp + i_used,
+                         MMS_BUFFER_SIZE - i_used );
+            }
+            p_sys->i_buffer_tcp -= i_used;
+        }
+        else if( p_sys->i_buffer_udp > 0 )
+        {
+            int i_used;
+
+            i_packet_udp_type =
+                mms_ParsePacket( p_input,
+                                 p_sys->buffer_udp,
+                                 p_sys->i_buffer_udp,
+                                 &i_used );
+
+            if( i_used > 0 && i_used < MMS_BUFFER_SIZE )
+            {
+                memmove( p_sys->buffer_udp,
+                         p_sys->buffer_udp + i_used,
+                         MMS_BUFFER_SIZE - i_used );
+            }
+            p_sys->i_buffer_udp -= i_used;
+        }
+
+        if( i_packet_tcp_type == MMS_PACKET_CMD &&
+                p_sys->i_command == 0x1b )
+        {
+            mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
+            i_packet_tcp_type = -1;
+        }
+
+        if( i_packet_tcp_type != -1 )
+        {
+            return( i_packet_tcp_type );
+        }
+        else if( i_packet_udp_type != -1 )
+        {
+            return( i_packet_udp_type );
+        }
+
+    }
+}
+
+static int  mms_ReceiveCommand( input_thread_t *p_input )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+
+    for( ;; )
+    {
+        int i_used;
+        int i_status;
+
+        if( NetFillBuffer( p_input ) < 0 )
+        {
+            msg_Warn( p_input, "cannot fill buffer" );
+            continue;
+        }
+        if( p_sys->i_buffer_tcp > 0 )
+        {
+            i_status = mms_ParseCommand( p_input,
+                                  p_sys->buffer_tcp,
+                                  p_sys->i_buffer_tcp,
+                                  &i_used );
+            if( i_used < MMS_BUFFER_SIZE )
+            {
+                memmove( p_sys->buffer_tcp,
+                         p_sys->buffer_tcp + i_used,
+                         MMS_BUFFER_SIZE - i_used );
+            }
+            p_sys->i_buffer_tcp -= i_used;
+
+            if( i_status < 0 )
+            {
+                return( -1 );
+            }
+
+            if( p_sys->i_command == 0x1b )
+            {
+                mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
+            }
+            else
+            {
+                break;
+            }
+        }
+        else
+        {
+            return( -1 );
+        }
+    }
+
+    return( 0 );
+}
+
+#define MMS_RETRY_MAX       10
+#define MMS_RETRY_SLEEP     50000
+
+static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int i_count;
+    int i_status;
+
+    for( i_count = 0; i_count < MMS_RETRY_MAX; )
+    {
+
+        i_status = mms_ReceiveCommand( p_input );
+        if( i_status < 0 || p_sys->i_command == 0 )
+        {
+            i_count++;
+            msleep( MMS_RETRY_SLEEP );
+        }
+        else if( i_command1 == 0 && i_command2 == 0)
+        {
+            return( 0 );
+        }
+        else if( p_sys->i_command == i_command1 || p_sys->i_command == i_command2 )
+        {
+            return( 0 );
+        }
+        else
+        {
+            switch( p_sys->i_command )
+            {
+                case 0x03:
+                    msg_Warn( p_input, "socket closed by server" );
+                    p_sys->i_eos = 1;
+                    return( -1 );
+                case 0x1e:
+                    msg_Warn( p_input, "end of media stream" );
+                    p_sys->i_eos = 1;
+                    return( -1 );
+                default:
+                    break;
+            }
+        }
+    }
+    msg_Warn( p_input, "failed to receive command (abording)" );
+
+    return( -1 );
+}
+
+
+static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
+{
+    access_sys_t        *p_sys = p_input->p_access_data;
+    int          i_count;
+
+    for( i_count = 0; i_count < MMS_RETRY_MAX; )
+    {
+        int i_status;
+
+        i_status = mms_ReceivePacket( p_input );
+        if( i_status < 0 )
+        {
+            i_count++;
+            msg_Warn( p_input,
+                      "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
+            msleep( MMS_RETRY_SLEEP );
+        }
+        else if( i_status == i_type || i_type == MMS_PACKET_ANY )
+        {
+            return( i_type );
+        }
+        else if( i_status == MMS_PACKET_CMD )
+        {
+            switch( p_sys->i_command )
+            {
+                case 0x03:
+                    msg_Warn( p_input, "socket closed by server" );
+                    p_sys->i_eos = 1;
+                    return( -1 );
+                case 0x1e:
+                    msg_Warn( p_input, "end of media stream" );
+                    p_sys->i_eos = 1;
+                    return( -1 );
+                case 0x20:
+                    /* XXX not too dificult to be done EXCEPT that we
+                     * need to restart demuxer... and I don't see how we
+                     * could do that :p */
+                    msg_Err( p_input,
+                             "reinitialization needed --> unsupported" );
+                    p_sys->i_eos = 1;
+                    return( -1 );
+                default:
+                    break;
+            }
+        }
+    }
+    msg_Err( p_input,
+             "cannot receive %s (abording)",
+               ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );
+    return( -1 );
+}
+
diff --git a/modules/access/mms/mmstu.h b/modules/access/mms/mmstu.h
new file mode 100644 (file)
index 0000000..e66f557
--- /dev/null
@@ -0,0 +1,125 @@
+/*****************************************************************************
+ * mms.h: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mmstu.h,v 1.1 2003/04/20 19:29:43 fenrir Exp $
+ *
+ * Authors: Laurent Aimar <fenrir@via.ecp.fr>
+ *
+ * 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., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
+ *****************************************************************************/
+
+#if 0
+/* url: [/]host[:port][/path] */
+typedef struct url_s
+{
+    char    *psz_server_addr;
+    int     i_server_port;
+
+    char    *psz_bind_addr;
+    int     i_bind_port;
+
+    char    *psz_path;
+
+    /* private */
+    char *psz_private;
+} url_t;
+#endif
+
+#define MMS_PACKET_ANY          0
+#define MMS_PACKET_CMD          1
+#define MMS_PACKET_HEADER       2
+#define MMS_PACKET_MEDIA        3
+#define MMS_PACKET_UDP_TIMING   4
+
+
+#define MMS_CMD_HEADERSIZE  48
+
+#if 0
+#define MMS_STREAM_VIDEO    0x0001
+#define MMS_STREAM_AUDIO    0x0002
+#define MMS_STREAM_UNKNOWN  0xffff
+typedef struct mms_stream_s
+{
+    int i_id;       /* 1 -> 127 */
+    int i_cat;      /* MMS_STREAM_VIDEO, MMS_STREAM_AUDIO */
+    int i_bitrate;  /* -1 if unknown */
+    int i_selected;
+
+} mms_stream_t;
+#endif
+
+#define MMS_BUFFER_SIZE 100000
+struct access_sys_t
+{
+    int                 i_proto;        /* MMS_PROTO_TCP, MMS_PROTO_UDP */
+    input_socket_t      socket_tcp;     /* TCP socket for communication with server */
+    input_socket_t      socket_udp;     /* Optional UDP socket for data(media/header packet) */
+                                        /* send by server */
+    char                *psz_bind_addr; /* used by udp */
+
+    url_t               *p_url;         /* connect to this server */
+
+    //asf_stream_t        stream[128];    /* in asf never more than 1->127 streams */
+    asf_header_t        asfh;
+
+    off_t               i_pos;          /* position of next byte to be read */
+
+    /* */
+    uint8_t             buffer_tcp[MMS_BUFFER_SIZE];
+    int                 i_buffer_tcp;
+
+    uint8_t             buffer_udp[MMS_BUFFER_SIZE];
+    int                 i_buffer_udp;
+
+    /* data necessary to send data to server */
+    guid_t      guid;
+    int         i_command_level;
+    int         i_seq_num;
+    uint32_t    i_header_packet_id_type;
+    uint32_t    i_media_packet_id_type;
+
+    int         i_packet_seq_num;
+
+    uint8_t     *p_cmd;     /* latest command read */
+    int         i_cmd;      /* allocated at the begining */
+
+    uint8_t     *p_header;  /* allocated by mms_ReadPacket */
+    int         i_header;
+
+    uint8_t     *p_media;   /* allocated by mms_ReadPacket */
+    size_t      i_media;
+    size_t      i_media_used;
+
+    /* extracted informations */
+    int         i_command;
+    int         i_eos;
+
+    /* from 0x01 answer (not yet set) */
+    char        *psz_server_version;
+    char        *psz_tool_version;
+    char        *psz_update_player_url;
+    char        *psz_encryption_type;
+
+    /* from 0x06 answer */
+    uint32_t    i_flags_broadcast;
+    uint32_t    i_media_length;
+    size_t      i_packet_length;
+    uint32_t    i_packet_count;
+    int         i_max_bit_rate;
+    int         i_header_size;
+
+};
+