X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=modules%2Faccess%2Fmms%2Fmms.c;h=861d8e7964bb2a07b030d761c5cf55b3b9e8b02f;hb=4b664e9ca09f63ee33bc297b2f22422bb74f03af;hp=9625b9fe02613ba6367ee6b6e88a00337b8abd89;hpb=5b2cc57acdd134f28cdb47c5a19419eae9adbb41;p=vlc diff --git a/modules/access/mms/mms.c b/modules/access/mms/mms.c index 9625b9fe02..861d8e7964 100644 --- a/modules/access/mms/mms.c +++ b/modules/access/mms/mms.c @@ -2,7 +2,7 @@ * mms.c: MMS access plug-in ***************************************************************************** * Copyright (C) 2001, 2002 VideoLAN - * $Id: mms.c,v 1.3 2002/11/13 20:28:13 fenrir Exp $ + * $Id: mms.c,v 1.18 2003/02/07 23:36:55 marcari Exp $ * * Authors: Laurent Aimar * @@ -10,7 +10,7 @@ * 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 @@ -33,6 +33,7 @@ * Preamble *****************************************************************************/ #include +#include #include #include #include @@ -56,14 +57,21 @@ # endif #else # include +# include +# if HAVE_ARPA_INET_H +# include +# elif defined( SYS_BEOS ) +# include +# endif #endif #include "network.h" #include "asf.h" -#include "var_buffer.h" +#include "buffer.h" #include "mms.h" + /**************************************************************************** - * NOTES: + * NOTES: * MMSProtocole documentation found at http://get.to/sdp ****************************************************************************/ @@ -75,16 +83,14 @@ static void Close ( vlc_object_t * ); static int Read ( input_thread_t * p_input, byte_t * p_buffer, size_t i_len ); -static ssize_t NetRead ( input_thread_t * p_input, input_socket_t * p_socket, - 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 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 MMSStop ( input_thread_t *p_input ); static int MMSClose ( input_thread_t * ); @@ -95,35 +101,51 @@ static int mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t static int mms_HeaderMediaRead( input_thread_t *, int ); static int mms_ReceivePacket( input_thread_t * ); - + static void mms_ParseURL( url_t *p_url, char *psz_url ); -/* +/* * XXX DON'T FREE MY MEMORY !!! XXX * non mais :P */ -/* +/* * Ok, ok, j'le ferai plus... */ - +/* + * Merci :)) + */ +/* + * Vous pourriez signer vos commentaires (même si on voit bien qui peut + * écrire ce genre de trucs :p), et écrire en anglais, bordel de + * merde :p. + */ /***************************************************************************** * Module descriptor *****************************************************************************/ +#define CACHING_TEXT N_("caching value in ms") +#define CACHING_LONGTEXT N_( \ + "Allows you to modify the default caching value for mms streams. This " \ + "value should be set in miliseconds units." ) + vlc_module_begin(); set_description( _("MMS access module") ); set_capability( "access", 0 ); add_category_hint( "stream", NULL ); - add_bool( "mms-all", 0, NULL, + add_integer( "mms-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL, + CACHING_TEXT, CACHING_LONGTEXT ); + + add_bool( "mms-all", 0, NULL, "force selection of all streams", "force selection of all streams" ); + add_string( "mms-stream", NULL, NULL, "streams selection", "force this stream selection" ); - add_integer( "mms-maxbitrate", 0, NULL, + add_integer( "mms-maxbitrate", 0, NULL, "max bitrate", "set max bitrate for auto streams selections" ); add_shortcut( "mms" ); @@ -144,28 +166,29 @@ static int Open( vlc_object_t *p_this ) input_thread_t *p_input = (input_thread_t*)p_this; /* *** allocate p_access_data *** */ - p_input->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 || + 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 + { + p_access->url.i_server_port = 1755; /* default port */ + } + if( p_access->url.i_bind_port == 0 ) + { + p_access->url.i_bind_port = 7000; /* default port */ } - + /* *** connect to this server *** */ /* 1: look at requested protocol (udp/tcp) */ @@ -193,47 +216,50 @@ static int Open( vlc_object_t *p_this ) } /* 3: connect */ if( i_proto == MMS_PROTO_AUTO ) - { // first try with TCP - i_status = + { /* 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 = + { /* then with UDP */ + i_status = MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network ); } } else { - i_status = + 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 ?? + + p_input->p_private = NULL; /* *** 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; + if( p_access->i_proto == MMS_PROTO_UDP ) + { + p_input->stream.b_connected = 0; + } + else + { + p_input->stream.b_connected = 1; + } p_input->stream.p_selected_area->i_tell = 0; if( p_access->i_packet_count <= 0 ) { @@ -242,12 +268,12 @@ static int Open( vlc_object_t *p_this ) } else { - p_input->stream.b_seekable = 0; - p_input->stream.p_selected_area->i_size = - p_access->i_header + + p_input->stream.b_seekable = 1; + p_input->stream.p_selected_area->i_size = + p_access->i_header + p_access->i_packet_count * p_access->i_packet_length; } - + p_input->stream.i_method = INPUT_METHOD_NETWORK; vlc_mutex_unlock( &p_input->stream.stream_lock ); @@ -257,10 +283,12 @@ static int Open( vlc_object_t *p_this ) msg_Err( p_input, "cannot start stream" ); MMSClose( p_input ); FREE( p_access->url.psz_private ); - FREE( p_access->p_cmd ); return( -1 ); } - + + /* Update default_pts to a suitable value for mms access */ + p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000; + return( 0 ); } @@ -271,13 +299,14 @@ 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 ); + + FREE( p_input->p_access_data ); } /***************************************************************************** @@ -294,30 +323,33 @@ static int SetProgram( input_thread_t * p_input, *****************************************************************************/ static void Seek( input_thread_t * p_input, off_t i_pos ) { - /* - * FIXME + /* + * FIXME * Don't work * Probably some bad or missing command * - * + * */ -#if 0 +#if 1 access_t *p_access = (access_t*)p_input->p_access_data; uint32_t i_packet; uint32_t i_offset; - + var_buffer_t buffer; + if( i_pos < 0 ) { return; - } - msg_Dbg( p_input, "seeking to %lld, header size:%d", i_pos, p_access->i_header ); + } + + vlc_mutex_lock( &p_input->stream.stream_lock ); + if( i_pos < p_access->i_header) { if( p_access->i_pos < p_access->i_header ) { - /* no need to restart stream, it was already one + /* no need to restart stream, it was already one * or no stream was yet read */ p_access->i_pos = i_pos; return; @@ -333,11 +365,57 @@ static void Seek( input_thread_t * p_input, off_t i_pos ) i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length; i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length; } + msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet ); MMSStop( p_input ); - MMSStart( p_input, i_packet ); + msg_Dbg( p_input, "stream stopped (seek)" ); + + /* *** restart stream *** */ + var_buffer_initwrite( &buffer, 0 ); + var_buffer_add64( &buffer, 0 ); /* seek point in second */ + var_buffer_add32( &buffer, 0xffffffff ); + var_buffer_add32( &buffer, i_packet ); // begin from start + var_buffer_add8( &buffer, 0xff ); // stream time limit + var_buffer_add8( &buffer, 0xff ); // on 3bytes ... + var_buffer_add8( &buffer, 0xff ); // + var_buffer_add8( &buffer, 0x00 ); // don't use limit + var_buffer_add32( &buffer, p_access->i_media_packet_id_type ); + + mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff, + buffer.p_data, buffer.i_data ); + + var_buffer_free( &buffer ); + + + for( ;; ) + { + mms_HeaderMediaRead( p_input, MMS_PACKET_CMD ); + if( p_access->i_command == 0x1e ) + { + msg_Dbg( p_input, "received 0x1e (seek)" ); + break; + } + } + + for( ;; ) + { + mms_HeaderMediaRead( p_input, MMS_PACKET_CMD ); + if( p_access->i_command == 0x05 ) + { + msg_Dbg( p_input, "received 0x05 (seek)" ); + break; + } + } + + /* get a packet */ + mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ); + msg_Dbg( p_input, "Streaming restarted" ); + p_access->i_media_used += i_offset; p_access->i_pos = i_pos; + p_input->stream.p_selected_area->i_tell = i_pos; + vlc_mutex_unlock( &p_input->stream.stream_lock ); + #endif } @@ -349,14 +427,14 @@ static int Read ( input_thread_t * p_input, byte_t * p_buffer, 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, + memcpy( p_buffer, p_access->p_header + p_access->i_pos, i_copy ); } @@ -368,15 +446,15 @@ static int Read ( input_thread_t * p_input, byte_t * p_buffer, { if( p_access->i_media_used < p_access->i_media ) { - i_copy = __MIN( i_len - i_data , + i_copy = __MIN( i_len - i_data , p_access->i_media - p_access->i_media_used ); - memcpy( p_buffer + i_data, + 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 && + else if( p_access->p_media != NULL && p_access->i_media_used < p_access->i_packet_length ) { i_copy = __MIN( i_len - i_data, @@ -388,7 +466,8 @@ static int Read ( input_thread_t * p_input, byte_t * p_buffer, } else { - if( mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 ); + if( p_access->i_eos + || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 ) { p_access->i_pos += i_data; return( i_data ); @@ -400,60 +479,6 @@ static int Read ( input_thread_t * p_input, byte_t * p_buffer, return( i_data ); } -/***************************************************************************** - * NetRead: read on a file descriptor, checking b_die periodically - *****************************************************************************/ -static ssize_t NetRead( input_thread_t * p_input, input_socket_t * p_socket, - byte_t * p_buffer, size_t i_len ) -{ -#ifdef UNDER_CE - return -1; - -#else - struct timeval timeout; - fd_set fds; - int i_ret; - - /* Initialize file descriptor set */ - FD_ZERO( &fds ); - FD_SET( p_socket->i_handle, &fds ); - - /* We'll wait 0.5 second if nothing happens */ - timeout.tv_sec = 0; - timeout.tv_usec = 500000; - - /* Find if some data is available */ - i_ret = select( p_socket->i_handle + 1, &fds, - NULL, NULL, &timeout ); - - if( i_ret == -1 && errno != EINTR ) - { - msg_Err( p_input, "network select error (%s)", strerror(errno) ); - } - else if( i_ret > 0 ) - { - ssize_t i_recv = recv( p_socket->i_handle, p_buffer, i_len, 0 ); - - if( i_recv > 0 ) - { - vlc_mutex_lock( &p_input->stream.stream_lock ); - p_input->stream.p_selected_area->i_tell += i_recv; - vlc_mutex_unlock( &p_input->stream.stream_lock ); - } - - if( i_recv < 0 ) - { - msg_Err( p_input, "recv failed (%s)", strerror(errno) ); - } - - return i_recv; - } - - return 0; - -#endif -} - static void asf_HeaderParse( mms_stream_t stream[128], uint8_t *p_header, int i_header ) { @@ -461,23 +486,27 @@ static void asf_HeaderParse( mms_stream_t stream[128], guid_t guid; uint64_t i_size; int i; - + for( i = 0; i < 128; i++ ) { stream[i].i_cat = MMS_STREAM_UNKNOWN; } +// fprintf( stderr, " ---------------------header:%d\n", i_header ); var_buffer_initread( &buffer, p_header, i_header ); - + var_buffer_getguid( &buffer, &guid ); + if( !CmpGuid( &guid, &asf_object_header_guid ) ) { // XXX Error +// fprintf( stderr, " ---------------------ERROR------\n" ); } var_buffer_getmemory( &buffer, NULL, 30 - 16 ); - + for( ;; ) { +// fprintf( stderr, " ---------------------data:%d\n", buffer.i_data ); if( var_buffer_readempty( &buffer ) ) { return; @@ -489,14 +518,15 @@ static void asf_HeaderParse( mms_stream_t stream[128], { 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 ); - + + // fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 ); + var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1); + if( CmpGuid( &stream_type, &asf_object_stream_type_video ) ) { // msg_Dbg( p_input, "video stream[%d] found", i_stream_id ); @@ -517,7 +547,7 @@ static void asf_HeaderParse( mms_stream_t stream[128], { int i_count; uint8_t i_stream_id; - + i_count = var_buffer_get16( &buffer ); i_size -= 2; while( i_count > 0 ) @@ -527,22 +557,25 @@ static void asf_HeaderParse( mms_stream_t stream[128], i_count--; i_size -= 6; } +// fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24); var_buffer_getmemory( &buffer, NULL, i_size - 24 ); } - else + else { // skip unknown guid var_buffer_getmemory( &buffer, NULL, i_size - 24 ); +// fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24); } } } -static void mms_StreamSelect( input_thread_t * p_input, +static void mms_StreamSelect( input_thread_t * p_input, mms_stream_t stream[128] ) { /* XXX FIXME use mututal eclusion information */ int i; int i_audio, i_video; + int b_audio, b_video; int i_bitrate_total; int i_bitrate_max; char *psz_stream; @@ -551,7 +584,8 @@ static void mms_StreamSelect( input_thread_t * p_input, i_video = 0; i_bitrate_total = 0; i_bitrate_max = config_GetInt( p_input, "mms-maxbitrate" ); - + b_audio = config_GetInt( p_input, "audio" ); + b_video = config_GetInt( p_input, "video" ); if( config_GetInt( p_input, "mms-all" ) ) { /* select all valid stream */ @@ -603,14 +637,44 @@ static void mms_StreamSelect( input_thread_t * p_input, } FREE( psz_stream ); + /* big test: + * select a stream if + * - no audio nor video stream + * - or: + * - if i_bitrate_max not set keep the highest bitrate + * - if i_bitrate_max is set, keep stream that make we used best + * quality regarding i_bitrate_max + * + * XXX: little buggy: + * - it doesn't use mutual exclusion info.. + * - when selecting a better stream we could select + * something that make i_bitrate_total> i_bitrate_max + */ for( i = 1; i < 128; i++ ) { if( stream[i].i_cat == MMS_STREAM_UNKNOWN ) { continue; } - else if( stream[i].i_cat == MMS_STREAM_AUDIO && i_audio <= 0 ) + else if( stream[i].i_cat == MMS_STREAM_AUDIO && b_audio && + ( i_audio <= 0 || + ( ( ( stream[i].i_bitrate > stream[i_audio].i_bitrate && + ( i_bitrate_total + stream[i].i_bitrate - stream[i_audio].i_bitrate + < i_bitrate_max || !i_bitrate_max) ) || + ( stream[i].i_bitrate < stream[i_audio].i_bitrate && + i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max ) + ) ) ) ) { + /* unselect old stream */ + if( i_audio > 0 ) + { + stream[i_audio].i_selected = 0; + if( stream[i_audio].i_bitrate> 0 ) + { + i_bitrate_total -= stream[i_audio].i_bitrate; + } + } + stream[i].i_selected = 1; if( stream[i].i_bitrate> 0 ) { @@ -618,8 +682,24 @@ static void mms_StreamSelect( input_thread_t * p_input, } i_audio = i; } - else if( stream[i].i_cat == MMS_STREAM_VIDEO && i_video <= 0 ) + else if( stream[i].i_cat == MMS_STREAM_VIDEO && b_video && + ( i_video <= 0 || + ( + ( ( stream[i].i_bitrate > stream[i_video].i_bitrate && + ( i_bitrate_total + stream[i].i_bitrate - stream[i_video].i_bitrate + < i_bitrate_max || !i_bitrate_max) ) || + ( stream[i].i_bitrate < stream[i_video].i_bitrate && + i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max ) + ) ) ) ) { + /* unselect old stream */ + + stream[i_video].i_selected = 0; + if( stream[i_video].i_bitrate> 0 ) + { + i_bitrate_total -= stream[i_video].i_bitrate; + } + stream[i].i_selected = 1; if( stream[i].i_bitrate> 0 ) { @@ -627,47 +707,19 @@ static void mms_StreamSelect( input_thread_t * p_input, } i_video = i; } - else if( i_bitrate_max > 0 ) - { - int i_index; - // select this stream if it's bitrate is lower or upper - if( stream[i].i_cat == MMS_STREAM_AUDIO ) - { - i_index = i_audio; - } - else - { - i_index = i_video; - } -#define MMS_SELECT_XCHG( i1, i2 ) \ - stream[i1].i_selected = 0; \ - i_bitrate_total -= stream[i1].i_bitrate; \ - stream[i2].i_selected = 1; \ - i_bitrate_total += stream[i2].i_bitrate - - if( stream[i].i_bitrate > 0 ) - { - if( stream[i].i_bitrate < stream[i_index].i_bitrate && - i_bitrate_total >= i_bitrate_max ) - { - MMS_SELECT_XCHG( i_index, i ); - } - else if( stream[i].i_bitrate > stream[i_index].i_bitrate && - i_bitrate_total < i_bitrate_max ) - { - MMS_SELECT_XCHG( i, i_index ); - } - } - if( stream[i].i_cat == MMS_STREAM_AUDIO ) - { - i_audio = i; - } - else - { - i_video = i; - } - - } + + } + if( i_bitrate_max > 0 ) + { + msg_Dbg( p_input, + "requested bitrate:%d real bitrate:%d", + i_bitrate_max, i_bitrate_total ); + } + else + { + msg_Dbg( p_input, + "total bitrate:%d", + i_bitrate_total ); } } @@ -707,40 +759,79 @@ static int MMSOpen( input_thread_t *p_input, 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" ); + msg_Err( p_input, "failed to open a connection (tcp)" ); 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_access->socket_tcp.i_handle = socket_desc.i_handle; + p_input->i_mtu = 0; /*socket_desc.i_mtu;*/ + msg_Dbg( p_input, + "connection(tcp) with \"%s:%d\" successful", p_url->psz_server_addr, p_url->i_server_port ); /* *** Bind port if UDP protocol is selected *** */ - // TODO if( b_udp ) { - msg_Err( p_input, - "MMS/UDP not yet implemented" ); - // close socket + if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr ) + { + struct sockaddr_in name; + socklen_t i_namelen = sizeof( struct sockaddr_in ); + + if( getsockname( p_access->socket_tcp.i_handle, + (struct sockaddr*)&name, &i_namelen ) < 0 ) + { + + msg_Err( p_input, "for udp you have to provide bind address (mms://@ (FIXME)" ); #if defined( UNDER_CE ) - CloseHandle( (HANDLE)p_access->socket_server.i_handle ); + CloseHandle( (HANDLE)p_access->socket_tcp.i_handle ); #elif defined( WIN32 ) - closesocket( p_access->socket_server.i_handle ); + closesocket( p_access->socket_tcp.i_handle ); #else - close( p_access->socket_server.i_handle ); + close( p_access->socket_tcp.i_handle ); #endif - return( -1 ); + return( -1 ); + } + p_access->psz_bind_addr = inet_ntoa( name.sin_addr ); + } + else + { + p_access->psz_bind_addr = strdup( p_url->psz_bind_addr ); + } + socket_desc.i_type = NETWORK_UDP; + socket_desc.psz_server_addr = ""; + socket_desc.i_server_port = 0; + socket_desc.psz_bind_addr = p_access->psz_bind_addr; + socket_desc.i_bind_port = p_url->i_bind_port; + p_input->p_private = (void*)&socket_desc; + if( !( p_network = module_Need( p_input, "network", psz_network ) ) ) + { + msg_Err( p_input, "failed to open a connection (udp)" ); +#if defined( UNDER_CE ) + CloseHandle( (HANDLE)p_access->socket_tcp.i_handle ); +#elif defined( WIN32 ) + closesocket( p_access->socket_tcp.i_handle ); +#else + close( p_access->socket_tcp.i_handle ); +#endif + return( -1 ); + } + module_Unneed( p_input, p_network ); + p_access->socket_udp.i_handle = socket_desc.i_handle; + p_input->i_mtu = 0;/*socket_desc.i_mtu; FIXME */ + + } + else + { + p_access->psz_bind_addr = NULL; } /* *** Init context for mms prototcol *** */ - GenerateGuid( &p_access->guid ); // used to identify client by server - msg_Dbg( p_input, - "generated guid: "GUID_FMT, + 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_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; @@ -753,17 +844,22 @@ static int MMSOpen( input_thread_t *p_input, p_access->i_media_used = 0; p_access->i_pos = 0; + p_access->i_buffer_tcp = 0; + p_access->i_buffer_udp = 0; + p_access->p_cmd = NULL; + p_access->i_cmd = 0; + p_access->i_eos = 0; /* *** send command 1 : connection request *** */ var_buffer_initwrite( &buffer, 0 ); var_buffer_add16( &buffer, 0x001c ); var_buffer_add16( &buffer, 0x0003 ); - sprintf( tmp, + 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 */ @@ -793,7 +889,7 @@ static int MMSOpen( input_thread_t *p_input, 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, + 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, @@ -801,17 +897,26 @@ static int MMSOpen( input_thread_t *p_input, 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" ); + if( b_udp ) + { + sprintf( tmp, + "\\\\%s\\UDP\\%d", + p_access->psz_bind_addr, + p_url->i_bind_port ); + } + else + { + sprintf( tmp, "\\\\127.0.0.1\\TCP\\1242" ); + } var_buffer_addUTF16( &buffer, tmp ); var_buffer_add16( &buffer, '0' ); - + mms_CommandSend( p_input, 0x02, /* connexion request */ 0x00000000, /* flags, FIXME */ @@ -820,10 +925,10 @@ static int MMSOpen( input_thread_t *p_input, buffer.i_data ); /* *** response from server, should be 0x02 or 0x03 *** */ - mms_CommandRead( p_input, 0x02, 0 ); + mms_CommandRead( p_input, 0x02, 0x03 ); if( p_access->i_command == 0x03 ) { - msg_Err( p_input, + msg_Err( p_input, "%s protocol selection failed", b_udp ? "UDP" : "TCP" ); var_buffer_free( &buffer ); MMSClose( p_input ); @@ -833,14 +938,13 @@ static int MMSOpen( input_thread_t *p_input, { 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, + + mms_CommandSend( p_input, 0x05, p_access->i_command_level, 0xffffffff, @@ -849,19 +953,19 @@ static int MMSOpen( input_thread_t *p_input, /* *** 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 + /* FIXME */ var_buffer_free( &buffer ); MMSClose( p_input ); return( -1 ); } if( p_access->i_command != 0x06 ) { - msg_Err( p_input, + msg_Err( p_input, "unknown answer (0x%x instead of 0x06)", p_access->i_command ); var_buffer_free( &buffer ); @@ -869,7 +973,7 @@ static int MMSOpen( input_thread_t *p_input, return( -1 ); } - // 1 for file ok, 2 for authen ok + /* 1 for file ok, 2 for authen ok */ switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) ) { case 0x0001: @@ -887,7 +991,7 @@ static int MMSOpen( input_thread_t *p_input, return( -1 ); } - p_access->i_flags_broadcast = + 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 ); @@ -908,9 +1012,12 @@ static int MMSOpen( input_thread_t *p_input, p_access->i_packet_count, p_access->i_max_bit_rate, p_access->i_header_size ); - + + /* XXX XXX dirty hack XXX XXX */ + p_input->i_mtu = 3 * p_access->i_packet_length; + /* *** send command 15 *** */ - + var_buffer_reinitwrite( &buffer, 0 ); var_buffer_add32( &buffer, 0 ); var_buffer_add32( &buffer, 0x8000 ); @@ -920,7 +1027,7 @@ static int MMSOpen( input_thread_t *p_input, 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, + mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00, buffer.p_data, buffer.i_data ); /* *** wait for reponse *** */ @@ -928,7 +1035,7 @@ static int MMSOpen( input_thread_t *p_input, if( p_access->i_command != 0x11 ) { - msg_Err( p_input, + msg_Err( p_input, "unknown answer (0x%x instead of 0x11)", p_access->i_command ); var_buffer_free( &buffer ); @@ -944,22 +1051,22 @@ static int MMSOpen( input_thread_t *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, + /* get all streams properties, + * + * TODO : stream bitrates properties(optional) + * and bitrate mutual exclusion(optional) */ + asf_HeaderParse( p_access->stream, p_access->p_header, p_access->i_header ); mms_StreamSelect( p_input, p_access->stream ); /* *** now select stream we want to receive *** */ - // TODO take care of stream bitrate TODO + /* TODO take care of stream bitrate TODO */ i_streams = 0; i_first = -1; var_buffer_reinitwrite( &buffer, 0 ); /* for now, select first audio and video stream */ for( i = 1; i < 128; i++ ) { - + if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN ) { i_streams++; @@ -975,26 +1082,26 @@ static int MMSOpen( input_thread_t *p_input, if( p_access->stream[i].i_selected ) { var_buffer_add16( &buffer, 0x0000 ); - msg_Info( p_input, + msg_Info( p_input, "selecting stream[0x%x] %s (%d kb/s)", i, - ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ? + ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ? "audio" : "video" , p_access->stream[i].i_bitrate / 1024); } else { var_buffer_add16( &buffer, 0x0002 ); - msg_Info( p_input, + msg_Info( p_input, "ignoring stream[0x%x] %s (%d kb/s)", i, - ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ? + ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ? "audio" : "video" , p_access->stream[i].i_bitrate / 1024); } } - } + } if( i_streams == 0 ) { @@ -1007,12 +1114,12 @@ static int MMSOpen( input_thread_t *p_input, 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)", + msg_Err( p_input, + "unknown answer (0x%x instead of 0x21)", p_access->i_command ); var_buffer_free( &buffer ); MMSClose( p_input ); @@ -1037,32 +1144,31 @@ static int MMSStart ( input_thread_t *p_input, uint32_t i_packet ) /* *** 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_add64( &buffer, 0 ); /* seek point in second */ + var_buffer_add32( &buffer, 0xffffffff ); var_buffer_add32( &buffer, i_packet ); // begin from start var_buffer_add8( &buffer, 0xff ); // stream time limit var_buffer_add8( &buffer, 0xff ); // on 3bytes ... var_buffer_add8( &buffer, 0xff ); // var_buffer_add8( &buffer, 0x00 ); // don't use limit - var_buffer_add32( &buffer, p_access->i_media_packet_id_type ); - - mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff, + 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)", + 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" ); @@ -1077,7 +1183,7 @@ 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 *** */ + /* *** stop stream but keep connection alive *** */ mms_CommandSend( p_input, 0x09, p_access->i_command_level, @@ -1095,7 +1201,7 @@ static int MMSClose ( input_thread_t *p_input ) msg_Dbg( p_input, "Connection closed" ); - /* *** tell server that we will disconnect *** */ + /* *** tell server that we will disconnect *** */ mms_CommandSend( p_input, 0x0d, p_access->i_command_level, @@ -1103,24 +1209,25 @@ static int MMSClose ( input_thread_t *p_input ) NULL, 0 ); /* *** close sockets *** */ #if defined( UNDER_CE ) - CloseHandle( (HANDLE)p_access->socket_server.i_handle ); + CloseHandle( (HANDLE)p_access->socket_tcp.i_handle ); #elif defined( WIN32 ) - closesocket( p_access->socket_server.i_handle ); + closesocket( p_access->socket_tcp.i_handle ); #else - close( p_access->socket_server.i_handle ); + close( p_access->socket_tcp.i_handle ); #endif if( p_access->i_proto == MMS_PROTO_UDP ) { #if defined( UNDER_CE ) - CloseHandle( (HANDLE)p_access->socket_data.i_handle ); + CloseHandle( (HANDLE)p_access->socket_udp.i_handle ); #elif defined( WIN32 ) - closesocket( p_access->socket_data.i_handle ); + closesocket( p_access->socket_udp.i_handle ); #else - close( p_access->socket_data.i_handle ); + close( p_access->socket_udp.i_handle ); #endif } - + + FREE( p_access->p_cmd ); FREE( p_access->p_media ); FREE( p_access->p_header ); @@ -1133,7 +1240,7 @@ static int MMSClose ( input_thread_t *p_input ) } /***************************************************************************** - * mms_ParseURL : parse an url string and fill an url_t + * mms_ParseURL : parse an url string and fill an url_t *****************************************************************************/ static void mms_ParseURL( url_t *p_url, char *psz_url ) { @@ -1141,19 +1248,20 @@ static void mms_ParseURL( url_t *p_url, char *psz_url ) 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 != '/' ) + while( *psz_parser && + *psz_parser != ':' && *psz_parser != '/' && *psz_parser != '@' ) { psz_parser++; - } + } if( *psz_parser == ':' ) { @@ -1170,13 +1278,58 @@ static void mms_ParseURL( url_t *p_url, char *psz_url ) { psz_server_port = ""; } + + if( *psz_parser == '@' ) + { + char *psz_bind_port; + + *psz_parser = '\0'; + psz_parser++; + + p_url->psz_bind_addr = psz_parser; + + while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' ) + { + psz_parser++; + } + + if( *psz_parser == ':' ) + { + *psz_parser = '\0'; + psz_parser++; + psz_bind_port = psz_parser; + + while( *psz_parser && *psz_parser != '/' ) + { + psz_parser++; + } + } + else + { + psz_bind_port = ""; + } + if( *psz_bind_port ) + { + p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 ); + } + else + { + p_url->i_bind_port = 0; + } + } + else + { + p_url->psz_bind_addr = ""; + p_url->i_bind_port = 0; + } + if( *psz_parser == '/' ) { *psz_parser = '\0'; psz_parser++; p_url->psz_path = psz_parser; } - + if( *psz_server_port ) { p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 ); @@ -1187,55 +1340,32 @@ static void mms_ParseURL( url_t *p_url, char *psz_url ) } } -static int mms_ReadData( input_thread_t *p_input, - uint8_t *p_data, - int i_data ) -{ - access_t *p_access = (access_t*)p_input->p_access_data; - - int i_read; - - while( i_data > 0 ) - { - i_read = NetRead( p_input, &p_access->socket_server, 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, +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, 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 ); @@ -1251,8 +1381,8 @@ static int mms_CommandSend( input_thread_t *p_input, } /* send it */ - if( send( p_access->socket_server.i_handle, - buffer.p_data, + if( send( p_access->socket_tcp.i_handle, + buffer.p_data, buffer.i_data, 0 ) == -1 ) { @@ -1262,64 +1392,426 @@ static int mms_CommandSend( input_thread_t *p_input, var_buffer_free( &buffer ); return( 0 ); -} +} -static int mms_ReceiveCommand( input_thread_t *p_input ) +static int NetFillBuffer( input_thread_t *p_input ) +{ +#ifdef UNDER_CE + return -1; +#else + access_t *p_access = (access_t*)p_input->p_access_data; + struct timeval timeout; + fd_set fds; + int i_ret; + + /* FIXME when using udp */ + ssize_t i_tcp, i_udp; + ssize_t i_tcp_read, i_udp_read; + int i_handle_max; + + /* Initialize file descriptor set */ + FD_ZERO( &fds ); + + i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp; + + if( p_access->i_proto == MMS_PROTO_UDP ) + { + i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp; + } + else + { + i_udp = 0; /* there isn't udp socket */ + } + + i_handle_max = 0; + if( i_tcp > 0 ) + { + FD_SET( p_access->socket_tcp.i_handle, &fds ); + i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle ); + } + if( i_udp > 0 ) + { + FD_SET( p_access->socket_udp.i_handle, &fds ); + i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle ); + } + + if( i_handle_max == 0 ) + { + msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp ); + return( 0 ); + } + else + { +// msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp ); + } + + /* We'll wait 0.5 second if nothing happens */ + timeout.tv_sec = 0; + timeout.tv_usec = 500000; + + /* Find if some data is available */ + i_ret = select( i_handle_max + 1, + &fds, + NULL, NULL, &timeout ); + + if( i_ret == -1 && errno != EINTR ) + { + msg_Err( p_input, "network select error (%s)", strerror(errno) ); + return -1; + } + + if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) ) + { + i_tcp_read = + recv( p_access->socket_tcp.i_handle, + p_access->buffer_tcp + p_access->i_buffer_tcp, + i_tcp + MMS_BUFFER_SIZE/2, 0 ); + } + else + { + i_tcp_read = 0; + } + + if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) ) + { + i_udp_read = recv( p_access->socket_udp.i_handle, + p_access->buffer_udp + p_access->i_buffer_udp, + i_udp + MMS_BUFFER_SIZE/2, 0 ); + } + else + { + i_udp_read = 0; + } + +#if 1 + if( p_access->i_proto == MMS_PROTO_UDP ) + { + msg_Dbg( p_input, + "filling buffer TCP:%d+%d UDP:%d+%d", + p_access->i_buffer_tcp, + i_tcp_read, + p_access->i_buffer_udp, + i_udp_read ); + } + else + { + msg_Dbg( p_input, + "filling buffer TCP:%d+%d", + p_access->i_buffer_tcp, + i_tcp_read ); + } +#endif + p_access->i_buffer_tcp += i_tcp_read; + p_access->i_buffer_udp += i_udp_read; + + return( i_tcp_read + i_udp_read); +#endif +} + +static int mms_ParseCommand( input_thread_t *p_input, + uint8_t *p_data, + int i_data, + int *pi_used ) { -#define GET32( i_pos ) \ + #define GET32( i_pos ) \ ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \ ( p_access->p_cmd[i_pos + 2] << 16 ) + \ ( p_access->p_cmd[i_pos + 3] << 24 ) ) access_t *p_access = (access_t*)p_input->p_access_data; + int i_length; + uint32_t i_id; + + if( p_access->p_cmd ) + { + free( p_access->p_cmd ); + } + p_access->i_cmd = i_data; + p_access->p_cmd = malloc( i_data ); + memcpy( p_access->p_cmd, p_data, i_data ); + + *pi_used = i_data; /* by default */ + + if( i_data < MMS_CMD_HEADERSIZE ) + { + msg_Warn( p_input, "truncated command (header incomplete)" ); + p_access->i_command = 0; + return( -1 ); + } + i_id = GetDWLE( p_data + 4 ); + i_length = GetDWLE( p_data + 8 ) + 16; + + if( i_id != 0xb00bface ) + { + msg_Err( p_input, + "incorrect command header (0x%x)", i_id ); + p_access->i_command = 0; + return( -1 ); + } + + if( i_length > p_access->i_cmd ) + { + msg_Warn( p_input, + "truncated command (missing %d bytes)", + i_length - i_data ); + p_access->i_command = 0; + return( -1 ); + } + else if( i_length < p_access->i_cmd ) + { + p_access->i_cmd = i_length; + *pi_used = i_length; + } + + msg_Dbg( p_input, + "recv command start_sequence:0x%8.8x command_id:0x%8.8x length:%d len8:%d sequence 0x%8.8x len8_II:%d dir_comm:0x%8.8x", + GET32( 0 ), + GET32( 4 ), + GET32( 8 ), + /* 12: protocol type "MMS " */ + GET32( 16 ), + GET32( 20 ), + /* 24: unknown (0) */ + /* 28: unknown (0) */ + GET32( 32 ), + GET32( 36 ) + /* 40: switches */ + /* 44: extra */ ); + + p_access->i_command = GET32( 36 ) & 0xffff; + + return( MMS_PACKET_CMD ); +} + +static int mms_ParsePacket( input_thread_t *p_input, + uint8_t *p_data, size_t i_data, + int *pi_used ) +{ + access_t *p_access = (access_t*)p_input->p_access_data; + int i_packet_seq_num; + size_t i_packet_length; + uint32_t i_packet_id; + + uint8_t *p_packet; + + +// *pi_used = i_data; /* default */ + *pi_used = i_data; /* default */ + if( i_data <= 8 ) + { + msg_Warn( p_input, "truncated packet (header incomplete)" ); + return( -1 ); + } + + i_packet_id = p_data[4]; + i_packet_seq_num = GetDWLE( p_data ); + i_packet_length = GetWLE( p_data + 6 ); + + + if( i_packet_length > i_data || i_packet_length <= 8) + { + msg_Warn( p_input, + "truncated packet (missing %d bytes)", + i_packet_length - i_data ); + *pi_used = 0; + return( -1 ); + } + else if( i_packet_length < i_data ) + { + *pi_used = i_packet_length; + } + + if( i_packet_id == 0xff ) + { + msg_Warn( p_input, + "receive MMS UDP pair timing" ); + return( MMS_PACKET_UDP_TIMING ); + } - do + if( i_packet_id != p_access->i_header_packet_id_type && + i_packet_id != p_access->i_media_packet_id_type ) { - int i_length; - // see for UDP mode + msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id ); + return( -1 ); + } + + /* we now have a media or a header packet */ + p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader + memcpy( p_packet, p_data + 8, i_packet_length - 8 ); + + if( i_packet_seq_num != p_access->i_packet_seq_num ) + { + /* FIXME for udp could be just wrong order ? */ + msg_Warn( p_input, + "detected packet lost (%d != %d)", + i_packet_seq_num, + p_access->i_packet_seq_num ); + p_access->i_packet_seq_num = i_packet_seq_num; + } + p_access->i_packet_seq_num++; - /* *** Read complete command *** */ - p_access->i_cmd = NetRead( p_input, &p_access->socket_server, - p_access->p_cmd, BUF_SIZE ); - if( p_access->i_cmd < 12 ) + 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; +/* msg_Dbg( p_input, + "receive header packet (%d bytes)", + i_packet_length - 8 ); */ + + return( MMS_PACKET_HEADER ); + } + else + { + FREE( p_access->p_media ); + p_access->p_media = p_packet; + p_access->i_media = i_packet_length - 8; + p_access->i_media_used = 0; +/* msg_Dbg( p_input, + "receive media packet (%d bytes)", + i_packet_length - 8 ); */ + + return( MMS_PACKET_MEDIA ); + } +} + +static int mms_ReceivePacket( input_thread_t *p_input ) +{ + access_t *p_access = (access_t*)p_input->p_access_data; + int i_packet_tcp_type; + int i_packet_udp_type; + + for( ;; ) + { + if( NetFillBuffer( p_input ) < 0 ) { - msg_Warn( p_input, "failed to receive command" ); - p_access->i_command = 0; - return( -1 ); + msg_Warn( p_input, "cannot fill buffer" ); + continue; + } + /* TODO udp */ + + i_packet_tcp_type = -1; + i_packet_udp_type = -1; + + if( p_access->i_buffer_tcp > 0 ) + { + int i_used; + + if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface ) + { + i_packet_tcp_type = + mms_ParseCommand( p_input, + p_access->buffer_tcp, + p_access->i_buffer_tcp, + &i_used ); + + } + else + { + i_packet_tcp_type = + mms_ParsePacket( p_input, + p_access->buffer_tcp, + p_access->i_buffer_tcp, + &i_used ); + } + if( i_used < MMS_BUFFER_SIZE ) + { + memmove( p_access->buffer_tcp, + p_access->buffer_tcp + i_used, + MMS_BUFFER_SIZE - i_used ); + } + p_access->i_buffer_tcp -= i_used; } - i_length = GetDWLE( p_access->p_cmd + 8 ) + 16; - if( i_length > p_access->i_cmd ) + else if( p_access->i_buffer_udp > 0 ) { - if( mms_ReadData( p_input, - p_access->p_cmd + p_access->i_cmd, - i_length - p_access->i_cmd ) < 0 ) + int i_used; +#if 0 + if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface ) { - msg_Warn( p_input, "failed to receive command" ); - p_access->i_command = 0; - return( -1 ); + i_packet_tcp_type = + mms_ParseCommand( p_input, + p_access->buffer_tcp, + p_access->i_buffer_tcp, + &i_used ); + + } + else +#endif + { + i_packet_tcp_type = + mms_ParsePacket( p_input, + p_access->buffer_udp, + p_access->i_buffer_udp, + &i_used ); + } + if( i_used < MMS_BUFFER_SIZE ) + { + memmove( p_access->buffer_udp, + p_access->buffer_udp + i_used, + MMS_BUFFER_SIZE - i_used ); } + p_access->i_buffer_udp -= i_used; + } + else + { + i_packet_udp_type = -1; + } + + if( i_packet_tcp_type == MMS_PACKET_CMD && + p_access->i_command == 0x1b ) + { + mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 ); + i_packet_tcp_type = -1; + } + + if( i_packet_tcp_type != -1 ) + { + return( i_packet_tcp_type ); + } + else if( i_packet_udp_type != -1 ) + { + return( i_packet_udp_type ); } - msg_Dbg( p_input, "received %d bytes", p_access->i_cmd ); + } +} + +static int mms_ReceiveCommand( input_thread_t *p_input ) +{ + access_t *p_access = (access_t*)p_input->p_access_data; + + for( ;; ) + { + int i_used; + int i_status; + NetFillBuffer( p_input ); + + i_status = mms_ParseCommand( p_input, + p_access->buffer_tcp, + p_access->i_buffer_tcp, + &i_used ); + if( i_used < MMS_BUFFER_SIZE ) + { + memmove( p_access->buffer_tcp, + p_access->buffer_tcp + i_used, + MMS_BUFFER_SIZE - i_used ); + } + p_access->i_buffer_tcp -= i_used; - 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( i_status < 0 ) + { + return( -1 ); + } if( p_access->i_command == 0x1b ) { mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 ); } - - } while( p_access->i_command == 0x1b ); + else + { + break; + } + } return( 0 ); } @@ -1348,7 +1840,7 @@ static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_comma } else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 ) { - return( 0 ); + return( 0 ); } else { @@ -1356,9 +1848,11 @@ static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_comma { case 0x03: msg_Warn( p_input, "socket closed by server" ); + p_access->i_eos = 1; return( -1 ); case 0x1e: msg_Warn( p_input, "end of media stream" ); + p_access->i_eos = 1; return( -1 ); default: break; @@ -1371,150 +1865,11 @@ static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_comma } - -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( ;; ) - { - i_read = NetRead( p_input, &p_access->socket_server, preheader, 8 ); - if( i_read < 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; @@ -1523,13 +1878,13 @@ static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type ) if( i_status < 0 ) { i_count++; - msg_Warn( p_input, + msg_Warn( p_input, "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX ); msleep( MMS_RETRY_SLEEP ); } - else if( i_status == i_type ) + else if( i_status == i_type || i_type == MMS_PACKET_ANY ) { - return( 0 ); + return( i_type ); } else if( i_status == MMS_PACKET_CMD ) { @@ -1537,28 +1892,28 @@ static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type ) { case 0x03: msg_Warn( p_input, "socket closed by server" ); + p_access->i_eos = 1; return( -1 ); case 0x1e: msg_Warn( p_input, "end of media stream" ); + p_access->i_eos = 1; return( -1 ); case 0x20: - /* XXX not too dificult to be done EXCEPT that we - * need to restart demuxer... and I don't see how we - * could do that :p */ - msg_Err( p_input, + /* XXX not too dificult to be done EXCEPT that we + * need to restart demuxer... and I don't see how we + * could do that :p */ + msg_Err( p_input, "reinitialization needed --> unsupported" ); + p_access->i_eos = 1; return( -1 ); default: break; } } } - msg_Err( p_input, + msg_Err( p_input, "cannot receive %s (abording)", ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" ); return( -1 ); } - - -