* modules/demux/asf/.cvsignore : put the good one.
authorLaurent Aimar <fenrir@videolan.org>
Tue, 12 Nov 2002 00:54:40 +0000 (00:54 +0000)
committerLaurent Aimar <fenrir@videolan.org>
Tue, 12 Nov 2002 00:54:40 +0000 (00:54 +0000)
 * modules/access/mms : add MMS (Microsoft Media Streaming) access (Support
only TCP, I will try to add UDP and HTTP as well).
 There are some problems with streams selections and we cannot seek, but
anyway it seems to work. (Usefull for some radio web)
 * other: enable mms access by default.

configure.ac.in
modules/Makefile.am
modules/access/mms/.cvsignore [new file with mode: 0644]
modules/access/mms/Modules.am [new file with mode: 0644]
modules/access/mms/asf.h [new file with mode: 0644]
modules/access/mms/mms.c [new file with mode: 0644]
modules/access/mms/mms.h [new file with mode: 0644]
modules/access/mms/var_buffer.h [new file with mode: 0644]
modules/demux/asf/.cvsignore

index f66d6d3..b090df6 100644 (file)
@@ -582,7 +582,7 @@ PLUGINS="${PLUGINS} wav araw"
 dnl
 dnl  Network modules
 dnl
-NETWORK_MODULES="access_udp access_http access_rtp ipv4"
+NETWORK_MODULES="access_udp access_http access_rtp ipv4 access_mms"
 
 dnl
 dnl  Accelerated modules
index f6f8d79..9e69819 100644 (file)
@@ -4,6 +4,7 @@ EXTRA_DIST = \
        access/dvd/Modules.am \
        access/dvdplay/Modules.am \
        access/dvdread/Modules.am \
+       access/mms/Modules.am \
        access/satellite/Modules.am \
        access/v4l/Modules.am \
        access/vcd/Modules.am \
diff --git a/modules/access/mms/.cvsignore b/modules/access/mms/.cvsignore
new file mode 100644 (file)
index 0000000..ec96903
--- /dev/null
@@ -0,0 +1,2 @@
+.deps
+.dirstamp
diff --git a/modules/access/mms/Modules.am b/modules/access/mms/Modules.am
new file mode 100644 (file)
index 0000000..469414b
--- /dev/null
@@ -0,0 +1,6 @@
+SOURCES_access_mms = modules/access/mms/mms.c
+
+noinst_HEADERS += modules/access/mms/mms.h \
+                  modules/access/mms/var_buffer.h \
+                  modules/access/mms/asf.h
+
diff --git a/modules/access/mms/asf.h b/modules/access/mms/asf.h
new file mode 100644 (file)
index 0000000..d5930e9
--- /dev/null
@@ -0,0 +1,126 @@
+/*****************************************************************************
+ * asf.h: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: asf.h,v 1.1 2002/11/12 00:54:40 fenrir Exp $
+ *
+ * Authors: Christophe Massiot <massiot@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.
+ *****************************************************************************/
+
+/****************************************************************************
+ * XXX:
+ *  Definitions and data duplicated from asf demuxers but I want access
+ * and demux plugins to be independant
+ *
+ ****************************************************************************/
+
+typedef struct guid_s
+{   
+    u32 v1; /* le */
+    u16 v2; /* le */
+    u16 v3; /* le */
+    u8  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 inline 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 = ( (u64)rand() << 16 ) / RAND_MAX;
+    p_guid->v3 = ( (u64)rand() << 16 ) / RAND_MAX;
+    for( i = 0; i < 8; i++ )
+    {
+        p_guid->v4[i] = ( (u64)rand() * 256 ) / RAND_MAX;
+    }
+}
+
+#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 )  \
+    (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]
+
+static const guid_t asf_object_header_guid =
+{
+    0x75B22630,
+    0x668E,
+    0x11CF,
+    { 0xA6,0xD9, 0x00,0xAA,0x00,0x62,0xCE,0x6C }
+};
+
+static const guid_t asf_object_stream_properties_guid =
+{
+    0xB7DC0791,
+    0xA9B7,
+    0x11CF,
+    { 0x8E,0xE6, 0x00,0xC0,0x0C,0x20,0x53,0x65 }
+};
+
+static const guid_t asf_object_stream_type_audio =
+{
+    0xF8699E40,
+    0x5B4D,
+    0x11CF,
+    { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
+};
+
+static const guid_t asf_object_stream_type_video =
+{
+    0xbc19efc0,
+    0x5B4D,
+    0x11CF,
+    { 0xA8,0xFD, 0x00,0x80,0x5F,0x5C,0x44,0x2B }
+};
+
+static const guid_t asf_object_bitrate_properties_guid =
+{
+    0x7BF875CE,
+    0x468D,
+    0x11D1,
+    { 0x8D,0x82,0x00,0x60,0x97,0xC9,0xA2,0xB2 }
+};
+
+static const guid_t asf_object_bitrate_mutual_exclusion_guid =
+{
+    0xD6E229DC,
+    0x35DA,
+    0x11D1,
+    { 0x90,0x34,0x00,0xA0,0xC9,0x03,0x49,0xBE }
+};
+
+
diff --git a/modules/access/mms/mms.c b/modules/access/mms/mms.c
new file mode 100644 (file)
index 0000000..051e7d1
--- /dev/null
@@ -0,0 +1,1365 @@
+/*****************************************************************************
+ * mms.c: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mms.c,v 1.1 2002/11/12 00:54:40 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:
+ *  - clean code, break huge code block
+ *  - fix memory leak
+ *  - begin udp support...
+ */
+
+/*****************************************************************************
+ * Preamble
+ *****************************************************************************/
+#include <stdlib.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>
+#elif defined( _MSC_VER ) && defined( _WIN32 )
+#   include <io.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>
+#endif
+
+#include "network.h"
+#include "asf.h"
+#include "var_buffer.h"
+#include "mms.h"
+/****************************************************************************
+ * 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 );   // Not used
+
+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
+ */
+#define INPUT_FDNETWORKCLOSE( p_input ) \
+    { \
+        void *__p_access = p_input->p_access_data; \
+        input_socket_t *__p_socket = malloc( sizeof( input_socket_t ) ); \
+        memcpy( __p_socket, __p_access, sizeof( input_socket_t ) ); \
+        p_input->p_access_data = (void*)__p_socket; \
+        input_FDNetworkClose( p_input ); \
+        p_input->p_access_data = __p_access; \
+    }
+        
+
+
+/*****************************************************************************
+ * Module descriptor
+ *****************************************************************************/
+vlc_module_begin();
+    set_description( _("MMS access module") );
+    set_capability( "access", 0 );
+    add_shortcut( "mms" );
+    add_shortcut( "mmsu" );
+    add_shortcut( "mmst" );
+    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 ) );
+
+    p_access->p_cmd = malloc( BUF_SIZE );
+
+
+    /* *** 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 );
+        FREE( p_access->p_cmd );
+        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
+    }
+    
+
+    /* *** 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_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
+    {
+
+        i_status = 
+            MMSOpen( p_input, &p_access->url, i_proto, psz_network );
+    }
+
+    if( i_status < 0 )
+    {
+        // all sockets are closed
+        msg_Err( p_input, "cannot connect to server" );
+        FREE( p_access->url.psz_private );
+        FREE( p_access->p_cmd );
+        return( -1 );
+    }
+    msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
+
+    // all sockets are open
+    
+    
+    /* *** 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; // XXX ??
+
+    /* *** finished to set some variable *** */
+    vlc_mutex_lock( &p_input->stream.stream_lock );
+    /* those data could be different for UDP/TCP */
+    p_input->stream.b_pace_control = 0;
+    p_input->stream.p_selected_area->i_tell = 0;
+    if( p_access->i_packet_count <= 0 )
+    {
+        p_input->stream.b_seekable = 0;
+        p_input->stream.p_selected_area->i_size = 0;
+    }
+    else
+    {
+        p_input->stream.b_seekable = 0;
+        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 );
+
+    /* *** Start stream *** */
+    if( MMSStart( p_input, 0xffffffff ) < 0 )
+    {
+        msg_Err( p_input, "cannot start stream" );
+        MMSClose( p_input );
+        FREE( p_access->url.psz_private );
+        FREE( p_access->p_cmd );
+        return( -1 );
+    }
+                           
+    return( 0 );
+}
+
+/*****************************************************************************
+ * Close: free unused data structures
+ *****************************************************************************/
+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_access->p_cmd );
+}
+
+/*****************************************************************************
+ * 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 )
+{
+    /* 
+     * FIXME  
+     * Don't work
+     * Probably some bad or missing command
+     *
+     * 
+     */
+#if 0
+
+    access_t    *p_access = (access_t*)p_input->p_access_data;
+    uint32_t    i_packet;
+    uint32_t    i_offset;
+    
+    if( i_pos < 0 )
+    {
+        return;
+    }    
+    msg_Dbg( p_input, "seeking to %lld, header size:%d", i_pos, p_access->i_header );
+    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;
+    }
+
+    MMSStop( p_input );
+    MMSStart( p_input, i_packet );
+    p_access->i_media_used += i_offset;
+    p_access->i_pos = i_pos;
+#endif
+}
+
+static int  Read        ( input_thread_t * p_input, byte_t * p_buffer,
+                          size_t i_len )
+{
+    access_t    *p_access = (access_t*)p_input->p_access_data;
+    size_t      i_data;
+    size_t      i_copy;
+
+    i_data = 0;
+    
+    /* *** 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;
+    }
+
+    /* *** now send data if needed *** */
+    while( i_data < i_len )
+    {
+        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( mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 );
+            {
+                p_access->i_pos += i_data;
+                return( i_data );
+            }
+        }
+    }
+
+    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;
+    
+    for( i = 0; i < 128; i++ )
+    {
+        stream[i].i_cat = MMS_STREAM_UNKNOWN;
+    }
+
+    var_buffer_initread( &buffer, p_header, i_header );
+    
+    var_buffer_getguid( &buffer, &guid );
+    if( !CmpGuid( &guid, &asf_object_header_guid ) )
+    {
+//        XXX Error
+    }
+    var_buffer_getmemory( &buffer, NULL, 30 - 16 );
+    
+    for( ;; )
+    {
+        if( var_buffer_readempty( &buffer ) )
+        {
+            return;
+        }
+
+        var_buffer_getguid( &buffer, &guid );
+        i_size = var_buffer_get64( &buffer );
+        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;
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1 );
+            
+            if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
+            {
+//                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 ) )
+            {
+//                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;
+            }
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
+        }
+        else            
+        {
+            // skip unknown guid
+            var_buffer_getmemory( &buffer, NULL, i_size - 24 );
+        }
+    }
+}
+
+/****************************************************************************
+ * 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;
+    int          b_audio;
+    int          b_video;
+
+
+    /* *** 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" );
+        return( -1 );
+    }
+    module_Unneed( p_input, p_network );
+    p_access->socket_server.i_handle = socket_desc.i_handle;
+    p_input->i_mtu    = socket_desc.i_mtu;  // FIXME
+    msg_Dbg( p_input, 
+             "connection with \"%s:%d\" successful",
+             p_url->psz_server_addr,
+             p_url->i_server_port );
+
+    /* *** Bind port if UDP protocol is selected *** */
+    // TODO
+    if( b_udp )
+    {
+        msg_Err( p_input,
+                 "MMS/UDP not yet implemented" );
+        // close socket
+        p_access->_socket = p_access->socket_server;
+        INPUT_FDNETWORKCLOSE( p_input );
+        return( -1 );
+    }
+    /* *** Default socket is the one for server communication *** */
+    p_access->_socket = p_access->socket_server;
+
+    /* *** 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;
+
+    /* *** 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 );
+
+    mms_CommandRead( p_input, 0x01, 0 );
+    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 );
+    // FIXME wrong for UDP FIXME
+    sprintf( tmp, "\\\\127.0.0.1\\%s\\1242", b_udp ? "UDP" : "TCP" );
+    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, 0 );
+    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, "/" );
+    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 );
+    
+    /* *** 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 *** */
+    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 );
+    }
+    /* *** 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 );
+    
+    /* *** 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 */
+    b_audio = 0;
+    b_video = 0;
+    for( i = 1; i < 128; i++ )
+    {
+
+        if( ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO && !b_audio )||
+            ( p_access->stream[i].i_cat == MMS_STREAM_VIDEO && !b_video ) )
+        {
+            i_streams++;
+            if( i_first == -1 )
+            {   
+                i_first = i;
+                var_buffer_add16( &buffer, 0x0000 ); // on
+            }   
+            else
+            {
+                var_buffer_add16( &buffer, 0xffff );
+                var_buffer_add16( &buffer, i );
+                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);
+            if( p_access->stream[i].i_cat == MMS_STREAM_AUDIO )
+            {
+                b_audio = 1;
+            }
+            if( p_access->stream[i].i_cat == MMS_STREAM_VIDEO )
+            {
+                b_video = 1;
+            }
+
+        }
+        else if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
+        {
+            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);
+        }
+    } 
+
+    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 )
+    {
+        msg_Err( p_input, 
+                 "unknown answer (0x%x instead of 0x21)", 
+                 p_access->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_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, 0xffffffff ); // begin from start
+    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 *** */
+    p_access->_socket = p_access->socket_server;
+    INPUT_FDNETWORKCLOSE( p_input );
+
+    if( p_access->i_proto == MMS_PROTO_UDP )
+    {
+        p_access->_socket = p_access->socket_data;
+        INPUT_FDNETWORKCLOSE( p_input );
+    }
+    
+    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++;
+    } 
+
+    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 == '/' )
+    {
+        *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;
+    }
+}
+
+static int mms_ReadData( input_thread_t *p_input,
+                         uint8_t  *p_data,
+                         int i_data )
+{
+    int i_read;
+
+    while( i_data > 0 )
+    {
+        i_read = input_FDNetworkRead( p_input, p_data, i_data );
+        if( i_read < 0 )
+        {
+            msg_Err( p_input, "failed to read data" );
+            return( -1 );
+        }
+        i_data -= i_read;
+        p_data += i_read;
+    }
+    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_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.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  mms_ReceiveCommand( input_thread_t *p_input )
+{
+#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;
+
+    do
+    {
+        int i_length;
+        // see for UDP mode
+
+        /* *** Read complete command *** */
+        p_access->i_cmd = 
+            input_FDNetworkRead( p_input, p_access->p_cmd, BUF_SIZE );
+        if( p_access->i_cmd < 12 )
+        {
+            msg_Warn( p_input, "failed to receive command" );
+            p_access->i_command = 0;
+            return( -1 );
+        }
+        i_length = GetDWLE( p_access->p_cmd + 8 ) + 16;
+        if( i_length > p_access->i_cmd )
+        {
+            if( mms_ReadData( p_input, 
+                              p_access->p_cmd + p_access->i_cmd,
+                              i_length - p_access->i_cmd ) < 0 )
+            {
+                msg_Warn( p_input, "failed to receive command" );
+                p_access->i_command = 0;
+                return( -1 );
+            }
+        }
+
+        msg_Dbg( p_input, "received %d bytes", p_access->i_cmd );
+
+        p_access->i_command = GET32( 36 ) & 0xffff;
+        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 ),
+                 GET32( 16 ),
+                 GET32( 20 ),
+                 GET32( 32 ),
+                 GET32( 36 ),
+                 GET32( 40 ) );
+
+        if( p_access->i_command == 0x1b )
+        {
+            mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
+        }
+
+    } while( p_access->i_command == 0x1b );
+
+    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_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" );
+                    return( -1 );
+                case 0x1e:
+                    msg_Warn( p_input, "end of media stream" );
+                    return( -1 );
+                default:
+                    break;
+            }
+        }
+    }
+    msg_Warn( p_input, "failed to receive command (abording)" );
+
+    return( -1 );
+}
+
+
+
+static int mms_ReceivePacket( input_thread_t *p_input )
+{
+    access_t    *p_access = (access_t*)p_input->p_access_data;
+    uint8_t     preheader[8];
+    int         i_read;
+
+    if( p_access->i_proto == MMS_PROTO_UDP )
+    {
+        return( -1 );
+    }
+    else
+    {
+        for( ;; )
+        {
+            if( ( i_read = input_FDNetworkRead( p_input, preheader, 8 ) ) < 8 )
+            {
+                msg_Warn( p_input, "cannot read preheader" );
+                return( -1 );
+            }
+            /* preheader format :
+             * u32 i_sequence_number
+             * u8  i_packet_id
+             * u8  i_udp_sequence/i_tcp_flags
+             * u16 i_length
+             */
+            if( preheader[4] == p_access->i_header_packet_id_type ||
+                preheader[4] == p_access->i_media_packet_id_type ||
+                preheader[4] == 0xff )// udp timing pair
+            {
+                int i_packet_seq_num;
+                int i_packet_length;
+                int i_packet_id;
+
+                uint8_t  *p_packet;
+                
+                i_packet_seq_num = GetDWLE( preheader );
+                i_packet_length = GetWLE( preheader + 6 );
+                i_packet_id = preheader[4];
+                
+                /* *** read complete packet *** */
+                if( i_packet_length <= 8 )
+                {
+                    msg_Err( p_input,
+                             "empty or broken packet" );
+                    return( -1 );
+                }
+                p_packet = malloc( i_packet_length - 8 );
+                if( mms_ReadData( p_input, 
+                                  p_packet,
+                                  i_packet_length - 8 ) < 0 )
+                {
+                    msg_Err( p_input,
+                             "cannot read data" );
+                }
+
+                
+                if( i_packet_id == 0xff )
+                {
+                    msg_Warn( p_input,
+                              "receive MMS UDP pair timing" );
+                    free( p_packet );
+                    return( MMS_PACKET_UDP_TIMING );
+                }
+                else
+                {
+                    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 )
+                    {
+                        FREE( p_access->p_header );
+                        p_access->p_header = p_packet;
+                        p_access->i_header = 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;
+                        return( MMS_PACKET_MEDIA );
+                    }
+                }
+            }
+            else
+            {
+                int i_packet_length;
+                // command ?
+                if( GetDWLE( preheader + 4 ) != 0xb00bface )
+                {
+                    msg_Err( p_input, 
+                             "incorrect command header (0x%x)",
+                              GetDWLE( preheader + 4 ) );
+                }
+                memcpy( p_access->p_cmd, preheader, 8 );
+                if( mms_ReadData( p_input, 
+                                  p_access->p_cmd + 8,
+                                  8 ) < 0 )
+                {
+                    msg_Err( p_input,
+                             "cannot read data" );
+                }
+                p_access->i_cmd = 16;
+                i_packet_length = GetDWLE( p_access->p_cmd + 8 );
+                if( mms_ReadData( p_input, 
+                                  p_access->p_cmd + 16,
+                                  i_packet_length ) < 0 )
+                {
+                    msg_Err( p_input,
+                             "cannot read data" );
+                }
+                p_access->i_cmd += i_packet_length;
+                p_access->i_command = GetDWLE( p_access->p_cmd + 36 ) & 0xffff;
+                if( p_access->i_command == 0x1b )
+                {
+                    mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
+                }
+                else
+                {
+                    return( MMS_PACKET_CMD );
+                }
+
+            }
+        }
+    }
+}
+
+
+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 )
+        {
+            return( 0 );
+        }
+        else if( i_status == MMS_PACKET_CMD )
+        {
+            switch( p_access->i_command )
+            {
+                case 0x03:
+                    msg_Warn( p_input, "socket closed by server" );
+                    return( -1 );
+                case 0x1e:
+                    msg_Warn( p_input, "end of media stream" );
+                    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" );
+                    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/mms.h b/modules/access/mms/mms.h
new file mode 100644 (file)
index 0000000..e490289
--- /dev/null
@@ -0,0 +1,130 @@
+/*****************************************************************************
+ * mms.h: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: mms.h,v 1.1 2002/11/12 00:54:40 fenrir Exp $
+ *
+ * Authors: Christophe Massiot <massiot@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.
+ *****************************************************************************/
+
+/* url: [/]host[:port][/path] */
+typedef struct url_s
+{
+    char    *psz_server_addr;
+    int     i_server_port;
+    char    *psz_path;
+
+    // private
+    char *psz_private;
+} url_t;
+
+#define FREE( p ) if( p ) free( p )
+
+
+#define MMS_PROTO_AUTO  0
+#define MMS_PROTO_TCP   1
+#define MMS_PROTO_UDP   2
+
+#define MMS_PACKET_CMD          0
+#define MMS_PACKET_HEADER       1
+#define MMS_PACKET_MEDIA        2
+#define MMS_PACKET_UDP_TIMING    3
+    
+
+#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;
+
+    
+typedef struct access_s
+{
+    /* XXX must be the first field because of __input_FD* XXX */
+    input_socket_t      _socket;
+    
+    int                 i_proto;        // MMS_PROTO_TCP, MMS_PROTO_UDP
+    input_socket_t      socket_server;  // TCP socket for communication with server
+    input_socket_t      socket_data;    // Optional UDP socket for data(media/header packet) 
+                                        // send by server
+
+    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
+    
+    /* 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
+    int         i_media;
+    int         i_media_used;
+    
+    // extracted informations
+    int         i_command;
+
+    // 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;
+    int         i_packet_length;
+    uint32_t    i_packet_count;
+    int         i_max_bit_rate;
+    int         i_header_size;
+    
+} access_t;
+
+
+static inline uint16_t GetWLE( u8 *p_buff )
+{
+    return( (p_buff[0]) + ( p_buff[1] <<8 ) );
+}
+
+static inline uint32_t GetDWLE( u8 *p_buff )
+{
+    return( p_buff[0] + ( p_buff[1] <<8 ) +
+            ( p_buff[2] <<16 ) + ( p_buff[3] <<24 ) );
+}
+
diff --git a/modules/access/mms/var_buffer.h b/modules/access/mms/var_buffer.h
new file mode 100644 (file)
index 0000000..c71e321
--- /dev/null
@@ -0,0 +1,256 @@
+/*****************************************************************************
+ * var_buffer.h: MMS access plug-in
+ *****************************************************************************
+ * Copyright (C) 2001, 2002 VideoLAN
+ * $Id: var_buffer.h,v 1.1 2002/11/12 00:54:40 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.
+ *****************************************************************************/
+
+typedef struct var_buffer_s
+{
+    uint8_t *p_data;    // pointer on data
+    int     i_data;     // number of bytes set in p_data
+
+    // private
+    int    i_size;     // size of p_data memory allocated
+} var_buffer_t;
+
+
+/*****************************************************************************
+ * Macro/Function to create/manipulate buffer 
+ *****************************************************************************/
+static inline int       var_buffer_initwrite( var_buffer_t *p_buf, 
+                                              int i_default_size );
+static inline int       var_buffer_reinitwrite( var_buffer_t *p_buf, 
+                                                int i_default_size );
+static inline void var_buffer_add8 ( var_buffer_t *p_buf, uint8_t  i_byte );
+static inline void var_buffer_add16( var_buffer_t *p_buf, uint16_t i_word );
+static inline void var_buffer_add32( var_buffer_t *p_buf, uint32_t i_word );
+static inline void var_buffer_add64( var_buffer_t *p_buf, uint64_t i_word );
+static inline void var_buffer_addmemory( var_buffer_t *p_buf, 
+                                         void *p_mem, int i_mem );
+static inline void var_buffer_addUTF16( var_buffer_t *p_buf, char *p_str );
+static inline void var_buffer_free( var_buffer_t *p_buf );
+
+
+static inline void      var_buffer_initread( var_buffer_t *p_buf,
+                                             void *p_data, int i_data );
+static inline uint8_t   var_buffer_get8 ( var_buffer_t *p_buf );
+static inline uint16_t  var_buffer_get16( var_buffer_t *p_buf );
+static inline uint32_t  var_buffer_get32( var_buffer_t *p_buf );
+static inline uint64_t  var_buffer_get64( var_buffer_t *p_buf );
+static inline int       var_buffer_getmemory ( var_buffer_t *p_buf, 
+                                               void *p_mem, int i_mem );
+static inline int       var_buffer_readempty( var_buffer_t *p_buf );
+static inline void      var_buffer_getguid( var_buffer_t *p_buf, 
+                                            guid_t *p_guid );
+
+
+
+/*****************************************************************************
+ *****************************************************************************/
+
+static inline int var_buffer_initwrite( var_buffer_t *p_buf, 
+                                        int i_default_size )
+{
+    p_buf->i_size =  ( i_default_size > 0 ) ? i_default_size : 2048;
+    p_buf->i_data = 0;
+    if( !( p_buf->p_data = malloc( p_buf->i_size ) ) )
+    {
+        return( -1 );
+    }
+    return( 0 );
+}
+static inline int var_buffer_reinitwrite( var_buffer_t *p_buf, 
+                                          int i_default_size )
+{
+    p_buf->i_data = 0;
+    if( p_buf->i_size < i_default_size ) 
+    {
+        p_buf->i_size = i_default_size;
+        if( p_buf->p_data )
+        {
+            free( p_buf->p_data );
+        }
+        p_buf->p_data = malloc( p_buf->i_size );
+    }
+    if( !p_buf->p_data )
+    {
+        p_buf->i_size =  ( i_default_size > 0 ) ? i_default_size : 2048;
+        p_buf->p_data = malloc( p_buf->i_size );
+    }
+    if( !p_buf->p_data )
+    {
+        return( -1 );
+    }
+    return( 0 );
+}
+
+static inline void var_buffer_add8 ( var_buffer_t *p_buf, uint8_t  i_byte )
+{
+    /* check if there is enough data */
+    if( p_buf->i_data >= p_buf->i_size )
+    {
+        p_buf->i_size += 1024;
+        p_buf->p_data = realloc( p_buf->p_data, p_buf->i_size );
+    }
+    p_buf->p_data[p_buf->i_data] = i_byte&0xff;
+    p_buf->i_data++;
+}
+
+static inline void var_buffer_add16( var_buffer_t *p_buf, uint16_t i_word )
+{
+    var_buffer_add8( p_buf, i_word&0xff );
+    var_buffer_add8( p_buf, ( i_word >> 8 )&0xff );
+}
+static inline void var_buffer_add32( var_buffer_t *p_buf, uint32_t i_dword )
+{
+    var_buffer_add16( p_buf, i_dword&0xffff );
+    var_buffer_add16( p_buf, ( i_dword >> 16 )&0xffff );
+}
+static inline void var_buffer_add64( var_buffer_t *p_buf, uint64_t i_long )
+{
+    var_buffer_add32( p_buf, i_long&0xffffffff );
+    var_buffer_add32( p_buf, ( i_long >> 32 )&0xffffffff );
+}
+
+
+static inline void var_buffer_addmemory( var_buffer_t *p_buf, 
+                                         void *p_mem, int i_mem )
+{    
+    /* check if there is enough data */
+    if( p_buf->i_data + i_mem >= p_buf->i_size )
+    {
+        p_buf->i_size += i_mem + 1024;
+        p_buf->p_data = realloc( p_buf->p_data, p_buf->i_size );
+    }
+    
+    memcpy( p_buf->p_data + p_buf->i_data,
+            p_mem,
+            i_mem );
+    p_buf->i_data += i_mem;
+}
+
+static inline void var_buffer_addUTF16( var_buffer_t *p_buf, char *p_str )
+{
+    int i;
+    if( !p_str )
+    {
+        var_buffer_add16( p_buf, 0 );
+    }
+    else
+    {
+        for( i = 0; i < strlen( p_str ) + 1; i++ ) // and 0
+        {
+            var_buffer_add16( p_buf, p_str[i] );
+        }
+    }
+}
+
+static inline void     var_buffer_free( var_buffer_t *p_buf )
+{
+    if( p_buf->p_data )
+    {
+        free( p_buf->p_data );
+    }
+    p_buf->i_data = 0;
+    p_buf->i_size = 0;
+}
+
+static inline void var_buffer_initread( var_buffer_t *p_buf,
+                                        void *p_data, int i_data )
+{
+    p_buf->i_size = i_data;
+    p_buf->i_data = 0;
+    p_buf->p_data = p_data;
+}
+
+static inline uint8_t  var_buffer_get8 ( var_buffer_t *p_buf )
+{
+    uint8_t  i_byte;
+    if( p_buf->i_data >= p_buf->i_size )
+    {
+        return( 0 );
+    }
+    i_byte = p_buf->p_data[p_buf->i_data];
+    p_buf->i_data++;
+    return( i_byte );
+}
+
+
+static inline uint16_t var_buffer_get16( var_buffer_t *p_buf )
+{
+    uint16_t i_b1, i_b2;
+    
+    i_b1 = var_buffer_get8( p_buf );
+    i_b2 = var_buffer_get8( p_buf );
+
+    return( i_b1 + ( i_b2 << 8 ) );
+
+}
+static inline uint32_t var_buffer_get32( var_buffer_t *p_buf )
+{
+    uint32_t i_w1, i_w2;
+    
+    i_w1 = var_buffer_get16( p_buf );
+    i_w2 = var_buffer_get16( p_buf );
+
+    return( i_w1 + ( i_w2 << 16 ) );
+}
+static inline uint64_t var_buffer_get64( var_buffer_t *p_buf )
+{
+    uint64_t i_dw1, i_dw2;
+    
+    i_dw1 = var_buffer_get32( p_buf );
+    i_dw2 = var_buffer_get32( p_buf );
+
+    return( i_dw1 + ( i_dw2 << 32 ) );
+}
+static inline int var_buffer_getmemory ( var_buffer_t *p_buf, 
+                                         void *p_mem, int i_mem )
+{
+    int i_copy;
+
+    i_copy = __MIN( i_mem, p_buf->i_size - p_buf->i_data );
+    if( i_copy > 0 && p_mem != NULL)
+    {
+        memcpy( p_mem, p_buf + p_buf->i_data, i_copy );
+    }
+    p_buf->i_data += i_copy;
+    return( i_copy );
+}
+
+static inline int var_buffer_readempty( var_buffer_t *p_buf )
+{
+    return( ( p_buf->i_data >= p_buf->i_size ) ? 1 : 0 );
+}
+
+static inline void var_buffer_getguid( var_buffer_t *p_buf, guid_t *p_guid )
+{
+    int i;
+    
+    p_guid->v1 = var_buffer_get32( p_buf );
+    p_guid->v2 = var_buffer_get16( p_buf );
+    p_guid->v3 = var_buffer_get16( p_buf );
+
+    for( i = 0; i < 8; i++ )
+    {
+        p_guid->v4[i] = var_buffer_get8( p_buf );
+    }
+}
+
index 435f39e..ec96903 100644 (file)
@@ -1,4 +1,2 @@
-.dep
-*.lo
-*.o.*
-*.lo.*
+.deps
+.dirstamp