X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fmms%2Fmmstu.c;h=69beb8f45b6eb25e21413cac537c5d6138c47944;hb=be378fbc80c384e2541517d6853b59411b7e67de;hp=701049581690538333c0550a5ee129d59c445b6e;hpb=5deafc168b81ecbd650b150bfc8a1bb86cf24eab;p=vlc diff --git a/modules/access/mms/mmstu.c b/modules/access/mms/mmstu.c index 7010495816..69beb8f45b 100644 --- a/modules/access/mms/mmstu.c +++ b/modules/access/mms/mmstu.c @@ -1,8 +1,8 @@ /***************************************************************************** * mms.c: MMS access plug-in ***************************************************************************** - * Copyright (C) 2001, 2002 VideoLAN - * $Id: mmstu.c,v 1.7 2004/01/21 16:56:16 fenrir Exp $ + * Copyright (C) 2001, 2002 the VideoLAN team + * $Id$ * * Authors: Laurent Aimar * @@ -18,45 +18,43 @@ * * 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. + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA. *****************************************************************************/ /***************************************************************************** * Preamble *****************************************************************************/ -#include -#include -#include -#include -#include -#include -#include +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include +#include -#include -#include +#include #ifdef HAVE_UNISTD_H # include #endif - -#ifdef WIN32 -# include -# include -# ifndef IN_MULTICAST -# define IN_MULTICAST(a) IN_CLASSD(a) -# endif -#else -# include -# include -# if HAVE_ARPA_INET_H -# include -# elif defined( SYS_BEOS ) -# include -# endif +#ifdef HAVE_FCNTL_H +# include +#endif +#ifdef HAVE_SYS_TIME_H +# include +#endif +#ifdef HAVE_SYS_TYPES_H +# include +#endif +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_POLL +# include #endif -#include "network.h" +#include +#include "vlc_url.h" #include "asf.h" #include "buffer.h" @@ -73,83 +71,79 @@ /***************************************************************************** * Local prototypes *****************************************************************************/ -int E_( MMSTUOpen ) ( input_thread_t * ); -void E_( MMSTUClose ) ( input_thread_t * ); - - -static ssize_t Read ( input_thread_t * p_input, byte_t * p_buffer, - size_t i_len ); -static void Seek ( input_thread_t *, off_t ); +int MMSTUOpen ( access_t * ); +void MMSTUClose ( access_t * ); -static int MMSOpen( input_thread_t *, url_t *, int ); -static int MMSStart ( input_thread_t *, uint32_t ); -static int MMSStop ( input_thread_t *p_input ); +static ssize_t Read( access_t *, uint8_t *, size_t ); +static int Seek( access_t *, int64_t ); +static int Control( access_t *, int, va_list ); -static int MMSClose ( input_thread_t * ); +static int MMSOpen ( access_t *, vlc_url_t *, int ); +static int MMSStart( access_t *, uint32_t ); +static int MMSStop ( access_t * ); +static void MMSClose( access_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_CommandRead( access_t *p_access, int i_command1, int i_command2 ); +static int mms_CommandSend( access_t *, int, uint32_t, uint32_t, uint8_t *, int ); -static int mms_HeaderMediaRead( input_thread_t *, int ); +static int mms_HeaderMediaRead( access_t *, int ); -static int mms_ReceivePacket( input_thread_t * ); +static int mms_ReceivePacket( access_t * ); +static void KeepAliveThread( vlc_object_t *p_this ); -/* - * 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 ) +int MMSTUOpen( access_t *p_access ) { access_sys_t *p_sys; int i_proto; int i_status; - vlc_value_t val; - /* *** allocate p_sys_data *** */ - p_input->p_access_data = p_sys = malloc( sizeof( access_sys_t ) ); + /* Set up p_access */ + p_access->pf_read = Read; + p_access->pf_block = NULL; + p_access->pf_control = Control; + p_access->pf_seek = Seek; + p_access->info.i_update = 0; + p_access->info.i_size = 0; + p_access->info.i_pos = 0; + p_access->info.b_eof = false; + p_access->info.i_title = 0; + p_access->info.i_seekpoint = 0; + p_access->p_sys = p_sys = malloc( sizeof( access_sys_t ) ); + if( !p_sys ) return VLC_ENOMEM; memset( p_sys, 0, sizeof( access_sys_t ) ); + p_sys->i_timeout = var_CreateGetInteger( p_access, "mms-timeout" ); - /* *** Parse URL and get server addr/port and path *** */ - p_sys->p_url = E_( url_new )( p_input->psz_name ); + vlc_mutex_init( &p_sys->lock_netwrite ); - if( *p_sys->p_url->psz_host == '\0' ) + /* *** Parse URL and get server addr/port and path *** */ + vlc_UrlParse( &p_sys->url, p_access->psz_path, 0 ); + if( p_sys->url.psz_host == NULL || *p_sys->url.psz_host == '\0' ) { - E_( url_free )( p_sys->p_url ); - msg_Err( p_input, "invalid server name" ); + msg_Err( p_access, "invalid server name" ); + vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); + free( p_sys ); return VLC_EGENERIC; } - if( p_sys->p_url->i_port <= 0 ) + if( p_sys->url.i_port <= 0 ) { - p_sys->p_url->i_port = 1755; + p_sys->url.i_port = 1755; } /* *** connect to this server *** */ /* look at requested protocol (udp/tcp) */ i_proto = MMS_PROTO_AUTO; - if( *p_input->psz_access ) + if( *p_access->psz_access ) { - if( !strncmp( p_input->psz_access, "mmsu", 4 ) ) + if( !strncmp( p_access->psz_access, "mmsu", 4 ) ) { i_proto = MMS_PROTO_UDP; } - else if( !strncmp( p_input->psz_access, "mmst", 4 ) ) + else if( !strncmp( p_access->psz_access, "mmst", 4 ) ) { i_proto = MMS_PROTO_TCP; } @@ -157,72 +151,65 @@ int E_( MMSTUOpen ) ( input_thread_t *p_input ) /* connect */ if( i_proto == MMS_PROTO_AUTO ) - { /* first try with TCP */ - if( ( i_status = MMSOpen( p_input, p_sys->p_url, MMS_PROTO_TCP ) ) ) - { /* then with UDP */ - i_status = MMSOpen( p_input, p_sys->p_url, MMS_PROTO_UDP ); + { /* first try with TCP and then UDP*/ + if( ( i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_TCP ) ) ) + { + i_status = MMSOpen( p_access, &p_sys->url, MMS_PROTO_UDP ); } } else { - i_status = MMSOpen( p_input, p_sys->p_url, i_proto ); + i_status = MMSOpen( p_access, &p_sys->url, i_proto ); } if( i_status ) { - msg_Err( p_input, "cannot connect to server" ); - E_( url_free )( p_sys->p_url ); + msg_Err( p_access, "cannot connect to server" ); + vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); + free( p_sys ); return VLC_EGENERIC; } - 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; + msg_Dbg( p_access, "connected to %s:%d", p_sys->url.psz_host, p_sys->url.i_port ); /* * 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->asfh.i_data_packets_count > 0 ) + { + p_sys->i_packet_count = p_sys->asfh.i_data_packets_count; + } 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; + p_sys->b_seekable = false; } 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_sys->b_seekable = true; + p_access->info.i_size = + (uint64_t)p_sys->i_header + + (uint64_t)p_sys->i_packet_count * (uint64_t)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 ) + if( MMSStart( p_access, 0xffffffff ) < 0 ) { - msg_Err( p_input, "cannot start stream" ); - MMSClose( p_input ); - E_( url_free )( p_sys->p_url ); + msg_Err( p_access, "cannot start stream" ); + MMSTUClose ( p_access ); return VLC_EGENERIC; } - /* Update default_pts to a suitable value for mms access */ - var_Get( p_input, "mms-caching", &val ); - p_input->i_pts_delay = val.i_int * 1000; + /* Keep the connection alive when paused */ + p_sys->p_keepalive_thread = vlc_object_create( p_access, sizeof( mmstu_keepalive_thread_t ) ); + p_sys->p_keepalive_thread->p_access = p_access; + p_sys->p_keepalive_thread->b_paused = false; + p_sys->p_keepalive_thread->b_thread_error = false; + if( vlc_thread_create( p_sys->p_keepalive_thread, "mmstu keepalive thread", KeepAliveThread, + VLC_THREAD_PRIORITY_LOW, false) ) + p_sys->p_keepalive_thread->b_thread_error = true; return VLC_SUCCESS; } @@ -230,45 +217,144 @@ int E_( MMSTUOpen ) ( input_thread_t *p_input ) /***************************************************************************** * Close: free unused data structures *****************************************************************************/ -void E_( MMSTUClose ) ( input_thread_t *p_input ) +void MMSTUClose( access_t *p_access ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; + + vlc_object_kill( p_sys->p_keepalive_thread ); + if( !p_sys->p_keepalive_thread->b_thread_error ) + vlc_thread_join( p_sys->p_keepalive_thread ); + vlc_object_release( p_sys->p_keepalive_thread ); /* close connection with server */ - MMSClose( p_input ); + MMSClose( p_access ); /* free memory */ - E_( url_free )( p_sys->p_url ); + vlc_UrlClean( &p_sys->url ); + vlc_mutex_destroy( &p_sys->lock_netwrite ); free( p_sys ); } +/***************************************************************************** + * Control: + *****************************************************************************/ +static int Control( access_t *p_access, int i_query, va_list args ) +{ + access_sys_t *p_sys = p_access->p_sys; + bool *pb_bool; + bool b_bool; + int *pi_int; + int64_t *pi_64; + int i_int; + vlc_value_t val; + + switch( i_query ) + { + /* */ + case ACCESS_CAN_SEEK: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = p_sys->b_seekable; + break; + + case ACCESS_CAN_FASTSEEK: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = false; + break; + + case ACCESS_CAN_PAUSE: + pb_bool = (bool*)va_arg( args, bool* ); + *pb_bool = true; + break; + + case ACCESS_CAN_CONTROL_PACE: + pb_bool = (bool*)va_arg( args, bool* ); + +#if 0 /* Disable for now until we have a clock synchro algo + * which works with something else than MPEG over UDP */ + *pb_bool = false; +#endif + *pb_bool = true; + break; + + /* */ + case ACCESS_GET_MTU: + pi_int = (int*)va_arg( args, int * ); + *pi_int = 3 * p_sys->i_packet_length; + break; + + case ACCESS_GET_PTS_DELAY: + pi_64 = (int64_t*)va_arg( args, int64_t * ); + var_Get( p_access, "mms-caching", &val ); + *pi_64 = (int64_t)var_GetInteger( p_access, "mms-caching" ) * INT64_C(1000); + break; + + case ACCESS_GET_PRIVATE_ID_STATE: + i_int = (int)va_arg( args, int ); + pb_bool = (bool *)va_arg( args, bool * ); + + if( i_int < 0 || i_int > 127 ) + return VLC_EGENERIC; + *pb_bool = p_sys->asfh.stream[i_int].i_selected ? true : false; + break; + + /* */ + case ACCESS_SET_PAUSE_STATE: + b_bool = (bool)va_arg( args, int ); + if( b_bool ) + { + MMSStop( p_access ); + vlc_object_lock( p_sys->p_keepalive_thread ); + p_sys->p_keepalive_thread->b_paused = true; + vlc_object_unlock( p_sys->p_keepalive_thread ); + } + else + { + Seek( p_access, p_access->info.i_pos ); + vlc_object_lock( p_sys->p_keepalive_thread ); + p_sys->p_keepalive_thread->b_paused = false; + vlc_object_unlock( p_sys->p_keepalive_thread ); + } + break; + + case ACCESS_GET_TITLE_INFO: + case ACCESS_SET_TITLE: + case ACCESS_SET_SEEKPOINT: + case ACCESS_SET_PRIVATE_ID_STATE: + case ACCESS_GET_CONTENT_TYPE: + return VLC_EGENERIC; + + + default: + msg_Warn( p_access, "unimplemented query in control" ); + return VLC_EGENERIC; + + } + return VLC_SUCCESS; +} + /***************************************************************************** * Seek: try to go at the right place *****************************************************************************/ -static void Seek( input_thread_t * p_input, off_t i_pos ) +static int Seek( access_t * p_access, int64_t i_pos ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; uint32_t i_packet; uint32_t i_offset; - var_buffer_t buffer; + var_buffer_t buffer; if( i_pos < 0 ) - { - return; - } - - vlc_mutex_lock( &p_input->stream.stream_lock ); + return VLC_EGENERIC; if( i_pos < p_sys->i_header) { - if( p_sys->i_pos < p_sys->i_header ) + if( p_access->info.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; + p_access->info.i_pos = i_pos; + return VLC_SUCCESS; } else { @@ -281,10 +367,10 @@ static void Seek( input_thread_t * p_input, off_t i_pos ) 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 ); + msg_Dbg( p_access, "seeking to %"PRId64 " (packet:%d)", i_pos, i_packet ); - MMSStop( p_input ); - msg_Dbg( p_input, "stream stopped (seek)" ); + MMSStop( p_access ); + msg_Dbg( p_access, "stream stopped (seek)" ); /* *** restart stream *** */ var_buffer_initwrite( &buffer, 0 ); @@ -297,109 +383,120 @@ static void Seek( input_thread_t * p_input, off_t i_pos ) 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, + mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff, buffer.p_data, buffer.i_data ); var_buffer_free( &buffer ); - for( ;; ) + while( vlc_object_alive (p_access) ) { - mms_HeaderMediaRead( p_input, MMS_PACKET_CMD ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } + if( p_sys->i_command == 0x1e ) { - msg_Dbg( p_input, "received 0x1e (seek)" ); + msg_Dbg( p_access, "received 0x1e (seek)" ); break; } } - for( ;; ) + while( vlc_object_alive (p_access) ) { - mms_HeaderMediaRead( p_input, MMS_PACKET_CMD ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_CMD ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } if( p_sys->i_command == 0x05 ) { - msg_Dbg( p_input, "received 0x05 (seek)" ); + msg_Dbg( p_access, "received 0x05 (seek)" ); break; } } /* get a packet */ - mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ); - msg_Dbg( p_input, "Streaming restarted" ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) + { + p_access->info.b_eof = true; + return VLC_EGENERIC; + } + + msg_Dbg( p_access, "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 ); + p_access->info.i_pos = i_pos; + p_access->info.b_eof = false; + + return VLC_SUCCESS; } -static ssize_t Read ( input_thread_t * p_input, byte_t * p_buffer, - size_t i_len ) +/***************************************************************************** + * Read: + *****************************************************************************/ +static ssize_t Read( access_t *p_access, uint8_t *p_buffer, size_t i_len ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; size_t i_data; size_t i_copy; - i_data = 0; - - /* *** send header if needed ** */ - if( p_sys->i_pos < p_sys->i_header ) + if( p_access->info.b_eof ) { - 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; + return 0; } + i_data = 0; + /* *** now send data if needed *** */ while( i_data < i_len ) { - if( p_sys->i_media_used < p_sys->i_media ) + if( p_access->info.i_pos < p_sys->i_header ) + { + i_copy = __MIN( i_len, p_sys->i_header - p_access->info.i_pos ); + memcpy( &p_buffer[i_data], &p_sys->p_header[p_access->info.i_pos], i_copy ); + i_data += i_copy; + p_access->info.i_pos += i_copy; + } + else 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 ); + 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; + p_access->info.i_pos += 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 ); + memset( &p_buffer[i_data], 0, i_copy ); i_data += i_copy; p_sys->i_media_used += i_copy; + p_access->info.i_pos += i_copy; } - else + else if( p_access->info.b_eof || + mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) { - if( p_sys->i_eos - || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 ) - { - p_sys->i_pos += i_data; - return( i_data ); - } + break; } } - p_sys->i_pos += i_data; - return( 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 ) +static int MMSOpen( access_t *p_access, vlc_url_t *p_url, int i_proto ) { - access_sys_t *p_sys = p_input->p_access_data; - int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0; + access_sys_t *p_sys = p_access->p_sys; + int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0; var_buffer_t buffer; char tmp[4096]; @@ -411,18 +508,18 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) int i; int i_streams; int i_first; + char *mediapath; /* *** Open a TCP connection with server *** */ - msg_Dbg( p_input, "waiting for connection..." ); - p_sys->socket_tcp.i_handle = net_OpenTCP( p_input, p_url->psz_host, p_url->i_port ); - if( p_sys->socket_tcp.i_handle < 0 ) + msg_Dbg( p_access, "waiting for connection..." ); + p_sys->i_handle_tcp = net_ConnectTCP( p_access, p_url->psz_host, p_url->i_port ); + if( p_sys->i_handle_tcp < 0 ) { - msg_Err( p_input, "failed to open a connection (tcp)" ); + msg_Err( p_access, "failed to open a connection (tcp)" ); return VLC_EGENERIC; } - p_input->i_mtu = 0; - msg_Dbg( p_input, + msg_Dbg( p_access, "connection(tcp) with \"%s:%d\" successful", p_url->psz_host, p_url->i_port ); @@ -430,38 +527,29 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) /* *** 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 ) + if( net_GetSockAddress( p_sys->i_handle_tcp, p_sys->sz_bind_addr, + NULL ) ) { - - msg_Err( p_input, "for udp you have to provide bind address (mms://@ (FIXME)" ); - net_Close( p_sys->socket_tcp.i_handle ); + net_Close( p_sys->i_handle_tcp ); return VLC_EGENERIC; } - p_sys->psz_bind_addr = inet_ntoa( name.sin_addr ); - p_sys->socket_udp.i_handle = net_OpenUDP( p_input, p_sys->psz_bind_addr, 7000, "", 0 ); - if( p_sys->socket_udp.i_handle < 0 ) + p_sys->i_handle_udp = net_ListenUDP1( (vlc_object_t *)p_access, p_sys->sz_bind_addr, + 7000 ); + if( p_sys->i_handle_udp < 0 ) { - msg_Err( p_input, "failed to open a connection (udp)" ); - net_Close( p_sys->socket_tcp.i_handle ); + msg_Err( p_access, "failed to open a connection (udp)" ); + net_Close( p_sys->i_handle_tcp ); return VLC_EGENERIC; } - msg_Dbg( p_input, + msg_Dbg( p_access, "connection(udp) at \"%s:%d\" successful", - p_sys->psz_bind_addr, 7000 ); - } - else - { - p_sys->psz_bind_addr = NULL; + p_sys->sz_bind_addr, 7000 ); } /* *** Init context for mms prototcol *** */ - E_( GenerateGuid )( &p_sys->guid ); /* used to identify client by server */ - msg_Dbg( p_input, + GenerateGuid ( &p_sys->guid ); /* used to identify client by server */ + msg_Dbg( p_access, "generated guid: "GUID_FMT, GUID_PRINT( p_sys->guid ) ); p_sys->i_command_level = 1; /* updated after 0x1A command */ @@ -476,12 +564,12 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) p_sys->i_media = 0; p_sys->i_media_used = 0; - p_sys->i_pos = 0; + p_access->info.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; + p_access->info.b_eof = false; /* *** send command 1 : connection request *** */ var_buffer_initwrite( &buffer, 0 ); @@ -493,17 +581,17 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) p_url->psz_host ); var_buffer_addUTF16( &buffer, tmp ); - mms_CommandSend( p_input, + mms_CommandSend( p_access, 0x01, /* connexion request */ 0x00000000, /* flags, FIXME */ 0x0004000b, /* ???? */ buffer.p_data, buffer.i_data ); - if( mms_CommandRead( p_input, 0x01, 0 ) < 0 ) + if( mms_CommandRead( p_access, 0x01, 0 ) < 0 ) { var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } @@ -521,14 +609,14 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) psz[i] = p[i]; \ } \ psz[size] = '\0'; \ - p += 2 * ( size ); \ + p += ( 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, + msg_Dbg( p_access, "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"", p_sys->psz_server_version, p_sys->psz_tool_version, @@ -546,7 +634,7 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) { sprintf( tmp, "\\\\%s\\UDP\\%d", - p_sys->psz_bind_addr, + p_sys->sz_bind_addr, 7000 ); // FIXME } else @@ -556,7 +644,7 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) var_buffer_addUTF16( &buffer, tmp ); var_buffer_add16( &buffer, '0' ); - mms_CommandSend( p_input, + mms_CommandSend( p_access, 0x02, /* connexion request */ 0x00000000, /* flags, FIXME */ 0xffffffff, /* ???? */ @@ -564,26 +652,33 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) buffer.i_data ); /* *** response from server, should be 0x02 or 0x03 *** */ - mms_CommandRead( p_input, 0x02, 0x03 ); + mms_CommandRead( p_access, 0x02, 0x03 ); if( p_sys->i_command == 0x03 ) { - msg_Err( p_input, + msg_Err( p_access, "%s protocol selection failed", b_udp ? "UDP" : "TCP" ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } else if( p_sys->i_command != 0x02 ) { - msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" ); + msg_Warn( p_access, "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, + /* media file path shouldn't start with / character */ + mediapath = p_url->psz_path; + if ( *mediapath == '/' ) + { + mediapath++; + } + var_buffer_addUTF16( &buffer, mediapath ); + + mms_CommandSend( p_access, 0x05, p_sys->i_command_level, 0xffffffff, @@ -591,24 +686,24 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) buffer.i_data ); /* *** wait for reponse *** */ - mms_CommandRead( p_input, 0x1a, 0x06 ); + mms_CommandRead( p_access, 0x1a, 0x06 ); /* test if server send 0x1A answer */ if( p_sys->i_command == 0x1A ) { - msg_Err( p_input, "id/password requested (not yet supported)" ); + msg_Err( p_access, "id/password requested (not yet supported)" ); /* FIXME */ var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } if( p_sys->i_command != 0x06 ) { - msg_Err( p_input, + msg_Err( p_access, "unknown answer (0x%x instead of 0x06)", p_sys->i_command ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return( -1 ); } @@ -616,17 +711,17 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) switch( GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) ) { case 0x0001: - msg_Dbg( p_input, "Media file name/path accepted" ); + msg_Dbg( p_access, "media file name/path accepted" ); break; case 0x0002: - msg_Dbg( p_input, "Authentication accepted" ); + msg_Dbg( p_access, "authentication accepted" ); break; case -1: default: - msg_Err( p_input, "error while asking for file %d", + msg_Err( p_access, "error while asking for file %d", GetDWLE( p_sys->p_cmd + MMS_CMD_HEADERSIZE ) ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } @@ -643,18 +738,17 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) 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", + msg_Dbg( p_access, + "answer 0x06 flags:0x%8.8x media_length:%us " + "packet_length:%ul 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, + (unsigned)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 ); @@ -667,45 +761,45 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) var_buffer_add64( &buffer, (((uint64_t)0x40ac2000)<<32) ); var_buffer_add32( &buffer, p_sys->i_header_packet_id_type ); var_buffer_add32( &buffer, 0x00 ); - mms_CommandSend( p_input, 0x15, p_sys->i_command_level, 0x00, + mms_CommandSend( p_access, 0x15, p_sys->i_command_level, 0x00, buffer.p_data, buffer.i_data ); /* *** wait for reponse *** */ /* Commented out because it fails on some stream (no 0x11 answer) */ #if 0 - mms_CommandRead( p_input, 0x11, 0 ); + mms_CommandRead( p_access, 0x11, 0 ); if( p_sys->i_command != 0x11 ) { - msg_Err( p_input, + msg_Err( p_access, "unknown answer (0x%x instead of 0x11)", p_sys->i_command ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return( -1 ); } #endif /* *** now read header packet *** */ /* XXX could be split over multiples packets */ - msg_Dbg( p_input, "reading header" ); + msg_Dbg( p_access, "reading header" ); for( ;; ) { - if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 ) + if( mms_HeaderMediaRead( p_access, MMS_PACKET_HEADER ) < 0 ) { - msg_Err( p_input, "cannot receive header" ); + msg_Err( p_access, "cannot receive header" ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } if( p_sys->i_header >= p_sys->i_header_size ) { - msg_Dbg( p_input, + msg_Dbg( p_access, "header complete(%d)", p_sys->i_header ); break; } - msg_Dbg( p_input, + msg_Dbg( p_access, "header incomplete (%d/%d), reading more", p_sys->i_header, p_sys->i_header_size ); @@ -716,13 +810,13 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) * * TODO : stream bitrates properties(optional) * and bitrate mutual exclusion(optional) */ - E_( asf_HeaderParse )( &p_sys->asfh, + 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" ) ); + asf_StreamSelect( &p_sys->asfh, + var_CreateGetInteger( p_access, "mms-maxbitrate" ), + var_CreateGetInteger( p_access, "mms-all" ), + var_CreateGetInteger( p_access, "audio" ), + var_CreateGetInteger( p_access, "video" ) ); /* *** now select stream we want to receive *** */ /* TODO take care of stream bitrate TODO */ @@ -748,7 +842,7 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) if( p_sys->asfh.stream[i].i_selected ) { var_buffer_add16( &buffer, 0x0000 ); - msg_Info( p_input, + msg_Info( p_access, "selecting stream[0x%x] %s (%d kb/s)", i, ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO ) ? @@ -758,7 +852,7 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) else { var_buffer_add16( &buffer, 0x0002 ); - msg_Info( p_input, + msg_Info( p_access, "ignoring stream[0x%x] %s (%d kb/s)", i, ( p_sys->asfh.stream[i].i_cat == ASF_STREAM_AUDIO ) ? @@ -771,31 +865,31 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) if( i_streams == 0 ) { - msg_Err( p_input, "cannot find any stream" ); + msg_Err( p_access, "cannot find any stream" ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } - mms_CommandSend( p_input, 0x33, + mms_CommandSend( p_access, 0x33, i_streams, 0xffff | ( i_first << 16 ), buffer.p_data, buffer.i_data ); - mms_CommandRead( p_input, 0x21, 0 ); + mms_CommandRead( p_access, 0x21, 0 ); if( p_sys->i_command != 0x21 ) { - msg_Err( p_input, + msg_Err( p_access, "unknown answer (0x%x instead of 0x21)", p_sys->i_command ); var_buffer_free( &buffer ); - MMSClose( p_input ); + MMSClose( p_access ); return VLC_EGENERIC; } var_buffer_free( &buffer ); - msg_Info( p_input, "connection sucessful" ); + msg_Info( p_access, "connection successful" ); return VLC_SUCCESS; } @@ -803,9 +897,9 @@ static int MMSOpen( input_thread_t *p_input, url_t *p_url, int i_proto ) /**************************************************************************** * MMSStart : Start streaming ****************************************************************************/ -static int MMSStart ( input_thread_t *p_input, uint32_t i_packet ) +static int MMSStart( access_t *p_access, uint32_t i_packet ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; var_buffer_t buffer; /* *** start stream from packet 0 *** */ @@ -819,38 +913,39 @@ static int MMSStart ( input_thread_t *p_input, uint32_t i_packet ) 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, + mms_CommandSend( p_access, 0x07, p_sys->i_command_level, 0x0001ffff, buffer.p_data, buffer.i_data ); var_buffer_free( &buffer ); - mms_CommandRead( p_input, 0x05, 0 ); + mms_CommandRead( p_access, 0x05, 0 ); if( p_sys->i_command != 0x05 ) { - msg_Err( p_input, + msg_Err( p_access, "unknown answer (0x%x instead of 0x05)", p_sys->i_command ); - return( -1 ); + return -1; } else { /* get a packet */ - mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ); - msg_Dbg( p_input, "Streaming started" ); - return( 0 ); + if( mms_HeaderMediaRead( p_access, MMS_PACKET_MEDIA ) < 0 ) + return -1; + msg_Dbg( p_access, "streaming started" ); + return 0; } } /**************************************************************************** * MMSStop : Stop streaming ****************************************************************************/ -static int MMSStop ( input_thread_t *p_input ) +static int MMSStop( access_t *p_access ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; /* *** stop stream but keep connection alive *** */ - mms_CommandSend( p_input, + mms_CommandSend( p_access, 0x09, p_sys->i_command_level, 0x001fffff, @@ -861,36 +956,34 @@ static int MMSStop ( input_thread_t *p_input ) /**************************************************************************** * MMSClose : Close streaming and connection ****************************************************************************/ -static int MMSClose ( input_thread_t *p_input ) +static void MMSClose( access_t *p_access ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; - msg_Dbg( p_input, "Connection closed" ); + msg_Dbg( p_access, "Connection closed" ); /* *** tell server that we will disconnect *** */ - mms_CommandSend( p_input, + mms_CommandSend( p_access, 0x0d, p_sys->i_command_level, 0x00000001, NULL, 0 ); /* *** close sockets *** */ - net_Close( p_sys->socket_tcp.i_handle ); + net_Close( p_sys->i_handle_tcp ); if( p_sys->i_proto == MMS_PROTO_UDP ) { - net_Close( p_sys->socket_udp.i_handle ); + net_Close( p_sys->i_handle_udp ); } - FREE( p_sys->p_cmd ); - FREE( p_sys->p_media ); - FREE( p_sys->p_header ); + FREENULL( p_sys->p_cmd ); + FREENULL( p_sys->p_media ); + FREENULL( 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 ); + FREENULL( p_sys->psz_server_version ); + FREENULL( p_sys->psz_tool_version ); + FREENULL( p_sys->psz_update_player_url ); + FREENULL( p_sys->psz_encryption_type ); } /**************************************************************************** @@ -898,20 +991,19 @@ static int MMSClose ( input_thread_t *p_input ) * 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 ) +static int mms_CommandSend( access_t *p_access, int i_command, + uint32_t i_prefix1, uint32_t i_prefix2, + uint8_t *p_data, int i_data_old ) { var_buffer_t buffer; + access_sys_t *p_sys = p_access->p_sys; + int i_data_by8, i_ret; + int i_data = i_data_old; - access_sys_t *p_sys = p_input->p_access_data; - int i_data_by8; + while( i_data & 0x7 ) i_data++; + i_data_by8 = i_data >> 3; - i_data_by8 = ( i_data + 7 ) / 8; - - /* first init uffer */ + /* first init buffer */ var_buffer_initwrite( &buffer, 0 ); var_buffer_add32( &buffer, 0x00000001 ); /* start sequence */ @@ -930,41 +1022,42 @@ static int mms_CommandSend( input_thread_t *p_input, /* specific command data */ if( p_data && i_data > 0 ) { - var_buffer_addmemory( &buffer, p_data, i_data ); + var_buffer_addmemory( &buffer, p_data, i_data_old ); } + /* Append padding to the command data */ + var_buffer_add64( &buffer, 0 ); + /* send it */ - if( send( p_sys->socket_tcp.i_handle, - buffer.p_data, - buffer.i_data, - 0 ) == -1 ) + vlc_mutex_lock( &p_sys->lock_netwrite ); + i_ret = net_Write( p_access, p_sys->i_handle_tcp, NULL, buffer.p_data, + buffer.i_data - ( 8 - ( i_data - i_data_old ) ) ); + vlc_mutex_unlock( &p_sys->lock_netwrite ); + if( i_ret != buffer.i_data - ( 8 - ( i_data - i_data_old ) ) ) { - msg_Err( p_input, "failed to send command" ); - return( -1 ); + msg_Err( p_access, "failed to send command" ); + return VLC_EGENERIC; } var_buffer_free( &buffer ); - return( 0 ); + return VLC_SUCCESS; } -static int NetFillBuffer( input_thread_t *p_input ) +static int NetFillBuffer( access_t *p_access ) { #ifdef UNDER_CE return -1; + #else - access_sys_t *p_sys = p_input->p_access_data; - struct timeval timeout; - fd_set fds; + access_sys_t *p_sys = p_access->p_sys; int i_ret; + struct pollfd ufd[2]; + unsigned timeout, nfd; /* FIXME when using udp */ ssize_t i_tcp, i_udp; ssize_t i_tcp_read, i_udp_read; - int i_handle_max; - int i_try; - - /* Initialize file descriptor set */ - FD_ZERO( &fds ); + int i_try = 0; i_tcp = MMS_BUFFER_SIZE/2 - p_sys->i_buffer_tcp; @@ -977,116 +1070,104 @@ static int NetFillBuffer( input_thread_t *p_input ) i_udp = 0; /* there isn't udp socket */ } - i_handle_max = 0; - if( i_tcp > 0 ) + if( ( i_udp <= 0 ) && ( 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 ); + msg_Warn( p_access, "nothing to read %d:%d", (int)i_tcp, (int)i_udp ); + return 0; } else { -// msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp ); + /* msg_Warn( p_access, "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; - i_try = 0; /* Find if some data is available */ - while( (i_ret = select( i_handle_max + 1, &fds, - NULL, NULL, &timeout )) == 0 - || (i_ret < 0 && errno == EINTR) ) + do { i_try++; - 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( i_try > 2 && ( p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0 ) ) + /* Initialize file descriptor set */ + memset (ufd, 0, sizeof (ufd)); + nfd = 0; + + if( i_tcp > 0 ) { - return 0; + ufd[nfd].fd = p_sys->i_handle_tcp; + ufd[nfd].events = POLLIN; + nfd++; } - if( p_input->b_die || p_input->b_error ) + if( i_udp > 0 ) { - return 0; + ufd[nfd].fd = p_sys->i_handle_tcp; + ufd[nfd].events = POLLIN; + nfd++; } - msg_Dbg( p_input, "NetFillBuffer: trying again (select)" ); - } + + /* We'll wait 0.5 second if nothing happens */ + timeout = 500; + + if( i_try * timeout > p_sys->i_timeout ) + { + msg_Err(p_access, "no data received"); + return -1; + } + + if( i_try > 3 && (p_sys->i_buffer_tcp > 0 || p_sys->i_buffer_udp > 0) ) + { + return -1; + } + + if( !vlc_object_alive (p_access) || p_access->b_error ) return -1; + + //msg_Dbg( p_access, "NetFillBuffer: trying again (select)" ); + + } while( !(i_ret = poll( ufd, nfd, timeout)) || + (i_ret < 0 && errno == EINTR) ); if( i_ret < 0 ) { - msg_Err( p_input, "network select error (%s)", strerror(errno) ); + msg_Err( p_access, "network poll error (%m)" ); return -1; } - if( i_tcp > 0 && FD_ISSET( p_sys->socket_tcp.i_handle, &fds ) ) + i_tcp_read = i_udp_read = 0; + + if( ( i_tcp > 0 ) && ufd[0].revents ) { i_tcp_read = - recv( p_sys->socket_tcp.i_handle, + recv( p_sys->i_handle_tcp, 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 ) ) + if( i_udp > 0 && ufd[i_tcp > 0].revents ) { - i_udp_read = recv( p_sys->socket_udp.i_handle, + i_udp_read = recv( p_sys->i_handle_udp, p_sys->buffer_udp + p_sys->i_buffer_udp, i_udp + MMS_BUFFER_SIZE/2, 0 ); } - else - { - i_udp_read = 0; - } -#if MMS_DEBUG +#ifdef 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 ); + msg_Dbg( p_access, "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 ); + msg_Dbg( p_access, "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); + 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, +static int mms_ParseCommand( access_t *p_access, uint8_t *p_data, int i_data, int *pi_used ) @@ -1096,14 +1177,11 @@ static int mms_ParseCommand( input_thread_t *p_input, ( 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; + access_sys_t *p_sys = p_access->p_sys; int i_length; uint32_t i_id; - if( p_sys->p_cmd ) - { - free( 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 ); @@ -1112,28 +1190,28 @@ static int mms_ParseCommand( input_thread_t *p_input, if( i_data < MMS_CMD_HEADERSIZE ) { - msg_Warn( p_input, "truncated command (header incomplete)" ); + msg_Warn( p_access, "truncated command (header incomplete)" ); p_sys->i_command = 0; - return( -1 ); + return -1; } i_id = GetDWLE( p_data + 4 ); i_length = GetDWLE( p_data + 8 ) + 16; if( i_id != 0xb00bface ) { - msg_Err( p_input, + msg_Err( p_access, "incorrect command header (0x%x)", i_id ); p_sys->i_command = 0; - return( -1 ); + return -1; } if( i_length > p_sys->i_cmd ) { - msg_Warn( p_input, + msg_Warn( p_access, "truncated command (missing %d bytes)", i_length - i_data ); p_sys->i_command = 0; - return( -1 ); + return -1; } else if( i_length < p_sys->i_cmd ) { @@ -1141,7 +1219,7 @@ static int mms_ParseCommand( input_thread_t *p_input, *pi_used = i_length; } - msg_Dbg( p_input, + msg_Dbg( p_access, "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 ), @@ -1157,15 +1235,16 @@ static int mms_ParseCommand( input_thread_t *p_input, /* 44: extra */ ); p_sys->i_command = GET32( 36 ) & 0xffff; +#undef GET32 - return( MMS_PACKET_CMD ); + return MMS_PACKET_CMD; } -static int mms_ParsePacket( input_thread_t *p_input, +static int mms_ParsePacket( access_t *p_access, uint8_t *p_data, size_t i_data, int *pi_used ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; int i_packet_seq_num; size_t i_packet_length; uint32_t i_packet_id; @@ -1176,23 +1255,23 @@ static int mms_ParsePacket( input_thread_t *p_input, *pi_used = i_data; /* default */ if( i_data <= 8 ) { - msg_Warn( p_input, "truncated packet (header incomplete)" ); - return( -1 ); + msg_Warn( p_access, "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 ); + //msg_Warn( p_access, "------->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 ); + /* msg_Dbg( p_access, + "truncated packet (Declared %d bytes, Actual %d bytes)", + i_packet_length, i_data ); */ *pi_used = 0; - return( -1 ); + return -1; } else if( i_packet_length < i_data ) { @@ -1201,7 +1280,7 @@ static int mms_ParsePacket( input_thread_t *p_input, if( i_packet_id == 0xff ) { - msg_Warn( p_input, + msg_Warn( p_access, "receive MMS UDP pair timing" ); return( MMS_PACKET_UDP_TIMING ); } @@ -1209,8 +1288,8 @@ static int mms_ParsePacket( input_thread_t *p_input, 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 ); + msg_Warn( p_access, "incorrect Packet Id Type (0x%x)", i_packet_id ); + return -1; } /* we now have a media or a header packet */ @@ -1219,14 +1298,15 @@ static int mms_ParsePacket( input_thread_t *p_input, if( i_packet_seq_num != p_sys->i_packet_seq_num ) { +#if 0 /* FIXME for udp could be just wrong order ? */ - msg_Warn( p_input, + msg_Warn( p_access, "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; +#endif } - p_sys->i_packet_seq_num++; + p_sys->i_packet_seq_num = i_packet_seq_num + 1; if( i_packet_id == p_sys->i_header_packet_id_type ) { @@ -1246,38 +1326,62 @@ static int mms_ParsePacket( input_thread_t *p_input, p_sys->p_header = p_packet; p_sys->i_header = i_packet_length - 8; } -/* msg_Dbg( p_input, +/* msg_Dbg( p_access, "receive header packet (%d bytes)", i_packet_length - 8 ); */ - return( MMS_PACKET_HEADER ); + return MMS_PACKET_HEADER; } else { - FREE( p_sys->p_media ); + FREENULL( 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, +/* msg_Dbg( p_access, "receive media packet (%d bytes)", i_packet_length - 8 ); */ - return( MMS_PACKET_MEDIA ); + return MMS_PACKET_MEDIA; } } -static int mms_ReceivePacket( input_thread_t *p_input ) +static int mms_ReceivePacket( access_t *p_access ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; int i_packet_tcp_type; int i_packet_udp_type; for( ;; ) { - if( NetFillBuffer( p_input ) < 0 ) + bool b_refill = true; + + /* first if we need to refill buffer */ + if( p_sys->i_buffer_tcp >= MMS_CMD_HEADERSIZE ) { - msg_Warn( p_input, "cannot fill buffer" ); - continue; + if( GetDWLE( p_sys->buffer_tcp + 4 ) == 0xb00bface ) + { + if( GetDWLE( p_sys->buffer_tcp + 8 ) + 16 <= + (uint32_t)p_sys->i_buffer_tcp ) + { + b_refill = false; + } + } + else if( GetWLE( p_sys->buffer_tcp + 6 ) <= p_sys->i_buffer_tcp ) + { + b_refill = false; + } + } + if( p_sys->i_proto == MMS_PROTO_UDP && p_sys->i_buffer_udp >= 8 && + GetWLE( p_sys->buffer_udp + 6 ) <= p_sys->i_buffer_udp ) + { + b_refill = false; + } + + if( b_refill && NetFillBuffer( p_access ) < 0 ) + { + msg_Warn( p_access, "cannot fill buffer" ); + return -1; } i_packet_tcp_type = -1; @@ -1290,24 +1394,19 @@ static int mms_ReceivePacket( input_thread_t *p_input ) 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 ); + mms_ParseCommand( p_access, 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 ); + mms_ParsePacket( p_access, 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, + memmove( p_sys->buffer_tcp, p_sys->buffer_tcp + i_used, MMS_BUFFER_SIZE - i_used ); } p_sys->i_buffer_tcp -= i_used; @@ -1317,75 +1416,67 @@ static int mms_ReceivePacket( input_thread_t *p_input ) int i_used; i_packet_udp_type = - mms_ParsePacket( p_input, - p_sys->buffer_udp, - p_sys->i_buffer_udp, - &i_used ); + mms_ParsePacket( p_access, 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, + 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 ) + if( i_packet_tcp_type == MMS_PACKET_CMD && p_sys->i_command == 0x1b ) { - mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 ); + mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 ); i_packet_tcp_type = -1; } if( i_packet_tcp_type != -1 ) { - return( i_packet_tcp_type ); + return i_packet_tcp_type; } else if( i_packet_udp_type != -1 ) { - return( i_packet_udp_type ); + return i_packet_udp_type; } - } } -static int mms_ReceiveCommand( input_thread_t *p_input ) +static int mms_ReceiveCommand( access_t *p_access ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; for( ;; ) { int i_used; int i_status; - if( NetFillBuffer( p_input ) < 0 ) + if( NetFillBuffer( p_access ) < 0 ) { - msg_Warn( p_input, "cannot fill buffer" ); - continue; + msg_Warn( p_access, "cannot fill buffer" ); + return VLC_EGENERIC; } if( p_sys->i_buffer_tcp > 0 ) { - i_status = mms_ParseCommand( p_input, - p_sys->buffer_tcp, - p_sys->i_buffer_tcp, - &i_used ); + i_status = mms_ParseCommand( p_access, 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, + 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 ); + return VLC_EGENERIC; } if( p_sys->i_command == 0x1b ) { - mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 ); + mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 ); } else { @@ -1394,26 +1485,26 @@ static int mms_ReceiveCommand( input_thread_t *p_input ) } else { - return( -1 ); + return VLC_EGENERIC; } } - return( 0 ); + return VLC_SUCCESS; } #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 ) +static int mms_CommandRead( access_t *p_access, int i_command1, + int i_command2 ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; int i_count; int i_status; for( i_count = 0; i_count < MMS_RETRY_MAX; ) { - - i_status = mms_ReceiveCommand( p_input ); + i_status = mms_ReceiveCommand( p_access ); if( i_status < 0 || p_sys->i_command == 0 ) { i_count++; @@ -1421,84 +1512,110 @@ static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_comma } else if( i_command1 == 0 && i_command2 == 0) { - return( 0 ); + return VLC_SUCCESS; } - else if( p_sys->i_command == i_command1 || p_sys->i_command == i_command2 ) + else if( p_sys->i_command == i_command1 || + p_sys->i_command == i_command2 ) { - return( 0 ); + return VLC_SUCCESS; } else { switch( p_sys->i_command ) { case 0x03: - msg_Warn( p_input, "socket closed by server" ); - p_sys->i_eos = 1; - return( -1 ); + msg_Warn( p_access, "socket closed by server" ); + p_access->info.b_eof = true; + return VLC_EGENERIC; case 0x1e: - msg_Warn( p_input, "end of media stream" ); - p_sys->i_eos = 1; - return( -1 ); + msg_Warn( p_access, "end of media stream" ); + p_access->info.b_eof = true; + return VLC_EGENERIC; default: break; } } } - msg_Warn( p_input, "failed to receive command (abording)" ); + p_access->info.b_eof = true; + msg_Warn( p_access, "failed to receive command (aborting)" ); - return( -1 ); + return VLC_EGENERIC; } -static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type ) +static int mms_HeaderMediaRead( access_t *p_access, int i_type ) { - access_sys_t *p_sys = p_input->p_access_data; + access_sys_t *p_sys = p_access->p_sys; int i_count; for( i_count = 0; i_count < MMS_RETRY_MAX; ) { int i_status; - i_status = mms_ReceivePacket( p_input ); + if( !vlc_object_alive (p_access) ) + return -1; + + i_status = mms_ReceivePacket( p_access ); if( i_status < 0 ) { i_count++; - msg_Warn( p_input, - "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX ); + msg_Warn( p_access, "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 ); + 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 ); + msg_Warn( p_access, "socket closed by server" ); + p_access->info.b_eof = true; + return -1; case 0x1e: - msg_Warn( p_input, "end of media stream" ); - p_sys->i_eos = 1; - return( -1 ); + msg_Warn( p_access, "end of media stream" ); + p_access->info.b_eof = true; + 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, + msg_Err( p_access, "reinitialization needed --> unsupported" ); - p_sys->i_eos = 1; - return( -1 ); + p_access->info.b_eof = true; + return -1; default: break; } } } - msg_Err( p_input, - "cannot receive %s (abording)", - ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" ); - return( -1 ); + + msg_Err( p_access, "cannot receive %s (aborting)", + ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" ); + p_access->info.b_eof = true; + return -1; } +static void KeepAliveThread( vlc_object_t *p_this ) +{ + mmstu_keepalive_thread_t *p_thread = (mmstu_keepalive_thread_t *) p_this; + access_t *p_access = p_thread->p_access; + bool b_paused; + bool b_was_paused = false; + + vlc_object_lock( p_thread ); + while( vlc_object_alive( p_thread) ) + { + b_paused = p_thread->b_paused; + + if( b_paused && b_was_paused ) + mms_CommandSend( p_access, 0x1b, 0, 0, NULL, 0 ); + + b_was_paused = b_paused; + vlc_object_timedwait( p_thread, mdate() + 10000000 ); + } + vlc_object_unlock( p_thread ); +}