1 /*****************************************************************************
2 * mms.c: MMS access plug-in
3 *****************************************************************************
4 * Copyright (C) 2001, 2002 VideoLAN
5 * $Id: mms.c,v 1.14 2002/12/18 14:17:09 sam Exp $
7 * Authors: Laurent Aimar <fenrir@via.ecp.fr>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA.
22 *****************************************************************************/
27 * - clean code, break huge code block
29 * - begin udp support...
32 /*****************************************************************************
34 *****************************************************************************/
36 #include <sys/types.h>
43 #include <vlc/input.h>
47 #elif defined( _MSC_VER ) && defined( _WIN32 )
52 # include <winsock2.h>
53 # include <ws2tcpip.h>
55 # define IN_MULTICAST(a) IN_CLASSD(a)
58 # include <sys/socket.h>
59 # include <netinet/in.h>
61 # include <arpa/inet.h>
62 # elif defined( SYS_BEOS )
63 # include <net/netdb.h>
72 /****************************************************************************
74 * MMSProtocole documentation found at http://get.to/sdp
75 ****************************************************************************/
77 /*****************************************************************************
79 *****************************************************************************/
80 static int Open ( vlc_object_t * );
81 static void Close ( vlc_object_t * );
83 static int Read ( input_thread_t * p_input, byte_t * p_buffer,
85 static void Seek ( input_thread_t *, off_t );
86 static int SetProgram ( input_thread_t *, pgrm_descriptor_t * );
89 static int MMSOpen( input_thread_t *, url_t *, int, char * );
91 static int MMSStart ( input_thread_t *, uint32_t );
92 static int MMSStop ( input_thread_t *p_input );
94 static int MMSClose ( input_thread_t * );
97 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 );
98 static int mms_CommandSend( input_thread_t *, int, uint32_t, uint32_t, uint8_t *, int );
100 static int mms_HeaderMediaRead( input_thread_t *, int );
102 static int mms_ReceivePacket( input_thread_t * );
104 static void mms_ParseURL( url_t *p_url, char *psz_url );
109 * XXX DON'T FREE MY MEMORY !!! XXX
114 * Ok, ok, j'le ferai plus...
120 /*****************************************************************************
122 *****************************************************************************/
123 #define CACHING_TEXT N_("caching value in ms")
124 #define CACHING_LONGTEXT N_( \
125 "Allows you to modify the default caching value for mms streams. This " \
126 "value should be set in miliseconds units." )
129 set_description( _("MMS access module") );
130 set_capability( "access", 0 );
131 add_category_hint( "stream", NULL );
132 add_integer( "mms-caching", 4 * DEFAULT_PTS_DELAY / 1000, NULL,
133 CACHING_TEXT, CACHING_LONGTEXT );
135 add_bool( "mms-all", 0, NULL,
136 "force selection of all streams",
137 "force selection of all streams" );
139 add_string( "mms-stream", NULL, NULL,
141 "force this stream selection" );
142 add_integer( "mms-maxbitrate", 0, NULL,
144 "set max bitrate for auto streams selections" );
145 add_shortcut( "mms" );
146 add_shortcut( "mmsu" );
147 add_shortcut( "mmst" );
148 set_callbacks( Open, Close );
151 #define BUF_SIZE 200000
153 static int Open( vlc_object_t *p_this )
160 input_thread_t *p_input = (input_thread_t*)p_this;
162 /* *** allocate p_access_data *** */
163 p_input->p_access_data =
164 (void*)p_access = malloc( sizeof( access_t ) );
165 memset( p_access, 0, sizeof( access_t ) );
168 /* *** Parse URL and get server addr/port and path *** */
169 mms_ParseURL( &p_access->url, p_input->psz_name );
170 if( p_access->url.psz_server_addr == NULL ||
171 !( *p_access->url.psz_server_addr ) )
173 FREE( p_access->url.psz_private );
174 msg_Err( p_input, "invalid server name" );
177 if( p_access->url.i_server_port == 0 )
179 p_access->url.i_server_port = 1755; /* default port */
181 if( p_access->url.i_bind_port == 0 )
183 p_access->url.i_bind_port = 7000; /* default port */
187 /* *** connect to this server *** */
188 /* 1: look at requested protocol (udp/tcp) */
189 i_proto = MMS_PROTO_AUTO;
190 if( *p_input->psz_access )
192 if( !strncmp( p_input->psz_access, "mmsu", 4 ) )
194 i_proto = MMS_PROTO_UDP;
196 else if( !strncmp( p_input->psz_access, "mmst", 4 ) )
198 i_proto = MMS_PROTO_TCP;
201 /* 2: look at ip version ipv4/ipv6 */
203 if( config_GetInt( p_input, "ipv4" ) )
205 psz_network = "ipv4";
207 else if( config_GetInt( p_input, "ipv6" ) )
209 psz_network = "ipv6";
212 if( i_proto == MMS_PROTO_AUTO )
213 { /* first try with TCP */
215 MMSOpen( p_input, &p_access->url, MMS_PROTO_TCP, psz_network );
217 { /* then with UDP */
219 MMSOpen( p_input, &p_access->url, MMS_PROTO_UDP, psz_network );
226 MMSOpen( p_input, &p_access->url, i_proto, psz_network );
231 msg_Err( p_input, "cannot connect to server" );
232 FREE( p_access->url.psz_private );
235 msg_Dbg( p_input, "connected to %s", p_access->url.psz_server_addr );
238 /* *** set exported functions *** */
239 p_input->pf_read = Read;
240 p_input->pf_seek = Seek;
241 p_input->pf_set_program = SetProgram;
242 p_input->pf_set_area = NULL;
244 p_input->p_private = NULL;
246 /* *** finished to set some variable *** */
247 vlc_mutex_lock( &p_input->stream.stream_lock );
248 if( p_access->i_proto == MMS_PROTO_UDP )
250 p_input->stream.b_pace_control = 0;
254 p_input->stream.b_pace_control = 1;
256 p_input->stream.p_selected_area->i_tell = 0;
257 if( p_access->i_packet_count <= 0 )
259 p_input->stream.b_seekable = 0;
260 p_input->stream.p_selected_area->i_size = 0;
264 p_input->stream.b_seekable = 1;
265 p_input->stream.p_selected_area->i_size =
267 p_access->i_packet_count * p_access->i_packet_length;
270 p_input->stream.i_method = INPUT_METHOD_NETWORK;
271 vlc_mutex_unlock( &p_input->stream.stream_lock );
273 /* *** Start stream *** */
274 if( MMSStart( p_input, 0xffffffff ) < 0 )
276 msg_Err( p_input, "cannot start stream" );
278 FREE( p_access->url.psz_private );
282 /* Update default_pts to a suitable value for mms access */
283 p_input->i_pts_delay = config_GetInt( p_input, "mms-caching" ) * 1000;
288 /*****************************************************************************
289 * Close: free unused data structures
290 *****************************************************************************/
291 static void Close( vlc_object_t *p_this )
293 input_thread_t * p_input = (input_thread_t *)p_this;
294 access_t *p_access = (access_t*)p_input->p_access_data;
296 /* close connection with server */
300 FREE( p_access->url.psz_private );
303 /*****************************************************************************
304 * SetProgram: do nothing
305 *****************************************************************************/
306 static int SetProgram( input_thread_t * p_input,
307 pgrm_descriptor_t * p_program )
312 /*****************************************************************************
313 * Seek: try to go at the right place
314 *****************************************************************************/
315 static void Seek( input_thread_t * p_input, off_t i_pos )
320 * Probably some bad or missing command
326 access_t *p_access = (access_t*)p_input->p_access_data;
336 vlc_mutex_lock( &p_input->stream.stream_lock );
338 if( i_pos < p_access->i_header)
341 if( p_access->i_pos < p_access->i_header )
343 /* no need to restart stream, it was already one
344 * or no stream was yet read */
345 p_access->i_pos = i_pos;
350 i_packet = 0xffffffff;
356 i_packet = ( i_pos - p_access->i_header ) / p_access->i_packet_length;
357 i_offset = ( i_pos - p_access->i_header ) % p_access->i_packet_length;
359 msg_Dbg( p_input, "seeking to "I64Fd " (packet:%d)", i_pos, i_packet );
362 msg_Dbg( p_input, "stream stopped (seek)" );
364 /* *** restart stream *** */
365 var_buffer_initwrite( &buffer, 0 );
366 var_buffer_add64( &buffer, 0 ); /* seek point in second */
367 var_buffer_add32( &buffer, 0xffffffff );
368 var_buffer_add32( &buffer, i_packet ); // begin from start
369 var_buffer_add8( &buffer, 0xff ); // stream time limit
370 var_buffer_add8( &buffer, 0xff ); // on 3bytes ...
371 var_buffer_add8( &buffer, 0xff ); //
372 var_buffer_add8( &buffer, 0x00 ); // don't use limit
373 var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
375 mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
376 buffer.p_data, buffer.i_data );
378 var_buffer_free( &buffer );
383 mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
384 if( p_access->i_command == 0x1e )
386 msg_Dbg( p_input, "received 0x1e (seek)" );
393 mms_HeaderMediaRead( p_input, MMS_PACKET_CMD );
394 if( p_access->i_command == 0x05 )
396 msg_Dbg( p_input, "received 0x05 (seek)" );
402 mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
403 msg_Dbg( p_input, "Streaming restarted" );
405 p_access->i_media_used += i_offset;
406 p_access->i_pos = i_pos;
407 p_input->stream.p_selected_area->i_tell = i_pos;
408 vlc_mutex_unlock( &p_input->stream.stream_lock );
413 static int Read ( input_thread_t * p_input, byte_t * p_buffer,
416 access_t *p_access = (access_t*)p_input->p_access_data;
422 /* *** send header if needed ** */
423 if( p_access->i_pos < p_access->i_header )
425 i_copy = __MIN( i_len, p_access->i_header - p_access->i_pos );
429 p_access->p_header + p_access->i_pos,
435 /* *** now send data if needed *** */
436 while( i_data < i_len )
438 if( p_access->i_media_used < p_access->i_media )
440 i_copy = __MIN( i_len - i_data ,
441 p_access->i_media - p_access->i_media_used );
442 memcpy( p_buffer + i_data,
443 p_access->p_media + p_access->i_media_used,
446 p_access->i_media_used += i_copy;
448 else if( p_access->p_media != NULL &&
449 p_access->i_media_used < p_access->i_packet_length )
451 i_copy = __MIN( i_len - i_data,
452 p_access->i_packet_length - p_access->i_media_used);
453 memset( p_buffer + i_data, 0, i_copy );
456 p_access->i_media_used += i_copy;
461 || mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA ) < 0 )
463 p_access->i_pos += i_data;
469 p_access->i_pos += i_data;
473 static void asf_HeaderParse( mms_stream_t stream[128],
474 uint8_t *p_header, int i_header )
481 for( i = 0; i < 128; i++ )
483 stream[i].i_cat = MMS_STREAM_UNKNOWN;
486 // fprintf( stderr, " ---------------------header:%d\n", i_header );
487 var_buffer_initread( &buffer, p_header, i_header );
489 var_buffer_getguid( &buffer, &guid );
491 if( !CmpGuid( &guid, &asf_object_header_guid ) )
494 // fprintf( stderr, " ---------------------ERROR------\n" );
496 var_buffer_getmemory( &buffer, NULL, 30 - 16 );
500 // fprintf( stderr, " ---------------------data:%d\n", buffer.i_data );
501 if( var_buffer_readempty( &buffer ) )
506 var_buffer_getguid( &buffer, &guid );
507 i_size = var_buffer_get64( &buffer );
508 if( CmpGuid( &guid, &asf_object_stream_properties_guid ) )
512 // msg_Dbg( p_input, "found stream_properties" );
514 var_buffer_getguid( &buffer, &stream_type );
515 var_buffer_getmemory( &buffer, NULL, 32 );
516 i_stream_id = var_buffer_get8( &buffer ) & 0x7f;
518 // fprintf( stderr, " 1---------------------skip:%lld\n", i_size - 24 - 32 - 16 - 1 );
519 var_buffer_getmemory( &buffer, NULL, i_size - 24 - 32 - 16 - 1);
521 if( CmpGuid( &stream_type, &asf_object_stream_type_video ) )
523 // msg_Dbg( p_input, "video stream[%d] found", i_stream_id );
524 stream[i_stream_id].i_cat = MMS_STREAM_VIDEO;
526 else if( CmpGuid( &stream_type, &asf_object_stream_type_audio ) )
528 // msg_Dbg( p_input, "audio stream[%d] found", i_stream_id );
529 stream[i_stream_id].i_cat = MMS_STREAM_AUDIO;
533 // msg_Dbg( p_input, "unknown stream[%d] found", i_stream_id );
534 stream[i_stream_id].i_cat = MMS_STREAM_UNKNOWN;
537 else if ( CmpGuid( &guid, &asf_object_bitrate_properties_guid ) )
542 i_count = var_buffer_get16( &buffer );
546 i_stream_id = var_buffer_get16( &buffer )&0x7f;
547 stream[i_stream_id].i_bitrate = var_buffer_get32( &buffer );
551 // fprintf( stderr, " 2---------------------skip:%lld\n", i_size - 24);
552 var_buffer_getmemory( &buffer, NULL, i_size - 24 );
557 var_buffer_getmemory( &buffer, NULL, i_size - 24 );
558 // fprintf( stderr, " 3---------------------skip:%lld\n", i_size - 24);
563 static void mms_StreamSelect( input_thread_t * p_input,
564 mms_stream_t stream[128] )
566 /* XXX FIXME use mututal eclusion information */
568 int i_audio, i_video;
569 int b_audio, b_video;
577 i_bitrate_max = config_GetInt( p_input, "mms-maxbitrate" );
578 b_audio = config_GetInt( p_input, "audio" );
579 b_video = config_GetInt( p_input, "video" );
580 if( config_GetInt( p_input, "mms-all" ) )
582 /* select all valid stream */
583 for( i = 1; i < 128; i++ )
585 if( stream[i].i_cat != MMS_STREAM_UNKNOWN )
587 stream[i].i_selected = 1;
594 for( i = 0; i < 128; i++ )
596 stream[i].i_selected = 0; /* by default, not selected */
599 psz_stream = config_GetPsz( p_input, "mms-stream" );
601 if( psz_stream && *psz_stream )
603 char *psz_tmp = psz_stream;
606 if( *psz_tmp == ',' )
613 i_stream = atoi( psz_tmp );
614 while( *psz_tmp != '\0' && *psz_tmp != ',' )
619 if( i_stream > 0 && i_stream < 128 &&
620 stream[i_stream].i_cat != MMS_STREAM_UNKNOWN )
622 stream[i_stream].i_selected = 1;
633 * - no audio nor video stream
635 * - if i_bitrate_max not set keep the highest bitrate
636 * - if i_bitrate_max is set, keep stream that make we used best
637 * quality regarding i_bitrate_max
640 * - it doesn't use mutual exclusion info..
641 * - when selecting a better stream we could select
642 * something that make i_bitrate_total> i_bitrate_max
644 for( i = 1; i < 128; i++ )
646 if( stream[i].i_cat == MMS_STREAM_UNKNOWN )
650 else if( stream[i].i_cat == MMS_STREAM_AUDIO && b_audio &&
652 ( ( ( stream[i].i_bitrate > stream[i_audio].i_bitrate &&
653 ( i_bitrate_total + stream[i].i_bitrate - stream[i_audio].i_bitrate
654 < i_bitrate_max || !i_bitrate_max) ) ||
655 ( stream[i].i_bitrate < stream[i_audio].i_bitrate &&
656 i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
659 /* unselect old stream */
662 stream[i_audio].i_selected = 0;
663 if( stream[i_audio].i_bitrate> 0 )
665 i_bitrate_total -= stream[i_audio].i_bitrate;
669 stream[i].i_selected = 1;
670 if( stream[i].i_bitrate> 0 )
672 i_bitrate_total += stream[i].i_bitrate;
676 else if( stream[i].i_cat == MMS_STREAM_VIDEO && b_video &&
679 ( ( stream[i].i_bitrate > stream[i_video].i_bitrate &&
680 ( i_bitrate_total + stream[i].i_bitrate - stream[i_video].i_bitrate
681 < i_bitrate_max || !i_bitrate_max) ) ||
682 ( stream[i].i_bitrate < stream[i_video].i_bitrate &&
683 i_bitrate_max != 0 && i_bitrate_total > i_bitrate_max )
686 /* unselect old stream */
688 stream[i_video].i_selected = 0;
689 if( stream[i_video].i_bitrate> 0 )
691 i_bitrate_total -= stream[i_video].i_bitrate;
694 stream[i].i_selected = 1;
695 if( stream[i].i_bitrate> 0 )
697 i_bitrate_total += stream[i].i_bitrate;
703 if( i_bitrate_max > 0 )
706 "requested bitrate:%d real bitrate:%d",
707 i_bitrate_max, i_bitrate_total );
717 /****************************************************************************
718 * MMSOpen : Open a connection with the server over mmst or mmsu(not yet)
719 ****************************************************************************/
720 static int MMSOpen( input_thread_t *p_input,
723 char *psz_network ) /* "", "ipv4", "ipv6" */
726 access_t *p_access = (access_t*)p_input->p_access_data;
728 network_socket_t socket_desc;
729 int b_udp = ( i_proto == MMS_PROTO_UDP ) ? 1 : 0;
734 int i_server_version;
736 int i_update_player_url;
737 int i_encryption_type;
743 /* *** Open a TCP connection with server *** */
744 msg_Dbg( p_input, "waiting for connection..." );
745 socket_desc.i_type = NETWORK_TCP;
746 socket_desc.psz_server_addr = p_url->psz_server_addr;
747 socket_desc.i_server_port = p_url->i_server_port;
748 socket_desc.psz_bind_addr = "";
749 socket_desc.i_bind_port = 0;
750 p_input->p_private = (void*)&socket_desc;
751 if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
753 msg_Err( p_input, "failed to open a connection (tcp)" );
756 module_Unneed( p_input, p_network );
757 p_access->socket_tcp.i_handle = socket_desc.i_handle;
758 p_input->i_mtu = 0; /*socket_desc.i_mtu;*/
760 "connection(tcp) with \"%s:%d\" successful",
761 p_url->psz_server_addr,
762 p_url->i_server_port );
764 /* *** Bind port if UDP protocol is selected *** */
767 if( !p_url->psz_bind_addr || !*p_url->psz_bind_addr )
769 struct sockaddr_in name;
770 socklen_t i_namelen = sizeof( struct sockaddr_in );
772 if( getsockname( p_access->socket_tcp.i_handle,
773 (struct sockaddr*)&name, &i_namelen ) < 0 )
776 msg_Err( p_input, "for udp you have to provide bind address (mms://<server_addr>@<bind_addr/<path> (FIXME)" );
777 #if defined( UNDER_CE )
778 CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
779 #elif defined( WIN32 )
780 closesocket( p_access->socket_tcp.i_handle );
782 close( p_access->socket_tcp.i_handle );
786 p_access->psz_bind_addr = inet_ntoa( name.sin_addr );
790 p_access->psz_bind_addr = strdup( p_url->psz_bind_addr );
792 socket_desc.i_type = NETWORK_UDP;
793 socket_desc.psz_server_addr = "";
794 socket_desc.i_server_port = 0;
795 socket_desc.psz_bind_addr = p_access->psz_bind_addr;
796 socket_desc.i_bind_port = p_url->i_bind_port;
797 p_input->p_private = (void*)&socket_desc;
798 if( !( p_network = module_Need( p_input, "network", psz_network ) ) )
800 msg_Err( p_input, "failed to open a connection (udp)" );
801 #if defined( UNDER_CE )
802 CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
803 #elif defined( WIN32 )
804 closesocket( p_access->socket_tcp.i_handle );
806 close( p_access->socket_tcp.i_handle );
810 module_Unneed( p_input, p_network );
811 p_access->socket_udp.i_handle = socket_desc.i_handle;
812 p_input->i_mtu = 0;/*socket_desc.i_mtu; FIXME */
817 p_access->psz_bind_addr = NULL;
820 /* *** Init context for mms prototcol *** */
821 GenerateGuid( &p_access->guid ); /* used to identify client by server */
823 "generated guid: "GUID_FMT,
824 GUID_PRINT( p_access->guid ) );
825 p_access->i_command_level = 1; /* updated after 0x1A command */
826 p_access->i_seq_num = 0;
827 p_access->i_media_packet_id_type = 0x04;
828 p_access->i_header_packet_id_type = 0x02;
829 p_access->i_proto = i_proto;
830 p_access->i_packet_seq_num = 0;
831 p_access->p_header = NULL;
832 p_access->i_header = 0;
833 p_access->p_media = NULL;
834 p_access->i_media = 0;
835 p_access->i_media_used = 0;
838 p_access->i_buffer_tcp = 0;
839 p_access->i_buffer_udp = 0;
840 p_access->p_cmd = NULL;
844 /* *** send command 1 : connection request *** */
845 var_buffer_initwrite( &buffer, 0 );
846 var_buffer_add16( &buffer, 0x001c );
847 var_buffer_add16( &buffer, 0x0003 );
849 "NSPlayer/7.0.0.1956; {"GUID_FMT"}; Host: %s",
850 GUID_PRINT( p_access->guid ),
851 p_url->psz_server_addr );
852 var_buffer_addUTF16( &buffer, tmp );
854 mms_CommandSend( p_input,
855 0x01, /* connexion request */
856 0x00000000, /* flags, FIXME */
857 0x0004000b, /* ???? */
861 mms_CommandRead( p_input, 0x01, 0 );
862 i_server_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 32 );
863 i_tool_version = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 36 );
864 i_update_player_url = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 40 );
865 i_encryption_type = GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
866 p = (uint16_t*)( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
867 #define GETUTF16( psz, size ) \
870 psz = malloc( size + 1); \
871 for( i = 0; i < size; i++ ) \
878 GETUTF16( p_access->psz_server_version, i_server_version );
879 GETUTF16( p_access->psz_tool_version, i_tool_version );
880 GETUTF16( p_access->psz_update_player_url, i_update_player_url );
881 GETUTF16( p_access->psz_encryption_type, i_encryption_type );
884 "0x01 --> server_version:\"%s\" tool_version:\"%s\" update_player_url:\"%s\" encryption_type:\"%s\"",
885 p_access->psz_server_version,
886 p_access->psz_tool_version,
887 p_access->psz_update_player_url,
888 p_access->psz_encryption_type );
890 /* *** should make an 18 command to make data timing *** */
892 /* *** send command 2 : transport protocol selection *** */
893 var_buffer_reinitwrite( &buffer, 0 );
894 var_buffer_add32( &buffer, 0x00000000 );
895 var_buffer_add32( &buffer, 0x000a0000 );
896 var_buffer_add32( &buffer, 0x00000002 );
901 p_access->psz_bind_addr,
902 p_url->i_bind_port );
906 sprintf( tmp, "\\\\127.0.0.1\\TCP\\1242" );
908 var_buffer_addUTF16( &buffer, tmp );
909 var_buffer_add16( &buffer, '0' );
911 mms_CommandSend( p_input,
912 0x02, /* connexion request */
913 0x00000000, /* flags, FIXME */
914 0xffffffff, /* ???? */
918 /* *** response from server, should be 0x02 or 0x03 *** */
919 mms_CommandRead( p_input, 0x02, 0x03 );
920 if( p_access->i_command == 0x03 )
923 "%s protocol selection failed", b_udp ? "UDP" : "TCP" );
924 var_buffer_free( &buffer );
928 else if( p_access->i_command != 0x02 )
930 msg_Warn( p_input, "received command isn't 0x02 in reponse to 0x02" );
933 /* *** send command 5 : media file name/path requested *** */
934 var_buffer_reinitwrite( &buffer, 0 );
935 var_buffer_add64( &buffer, 0 );
936 var_buffer_addUTF16( &buffer, p_url->psz_path );
938 mms_CommandSend( p_input,
940 p_access->i_command_level,
945 /* *** wait for reponse *** */
946 mms_CommandRead( p_input, 0x1a, 0x06 );
948 /* test if server send 0x1A answer */
949 if( p_access->i_command == 0x1A )
951 msg_Err( p_input, "id/password requested (not yet supported)" );
953 var_buffer_free( &buffer );
957 if( p_access->i_command != 0x06 )
960 "unknown answer (0x%x instead of 0x06)",
961 p_access->i_command );
962 var_buffer_free( &buffer );
967 /* 1 for file ok, 2 for authen ok */
968 switch( GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) )
971 msg_Dbg( p_input, "Media file name/path accepted" );
974 msg_Dbg( p_input, "Authentication accepted" );
978 msg_Err( p_input, "error while asking for file %d",
979 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE ) );
980 var_buffer_free( &buffer );
985 p_access->i_flags_broadcast =
986 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 12 );
987 p_access->i_media_length =
988 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 24 );
989 p_access->i_packet_length =
990 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 44 );
991 p_access->i_packet_count =
992 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 48 );
993 p_access->i_max_bit_rate =
994 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 56 );
995 p_access->i_header_size =
996 GetDWLE( p_access->p_cmd + MMS_CMD_HEADERSIZE + 60 );
999 "answer 0x06 flags:0x%8.8x media_length:%ds packet_length:%d packet_count:%d max_bit_rate:%d header_size:%d",
1000 p_access->i_flags_broadcast,
1001 p_access->i_media_length,
1002 p_access->i_packet_length,
1003 p_access->i_packet_count,
1004 p_access->i_max_bit_rate,
1005 p_access->i_header_size );
1007 /* XXX XXX dirty hack XXX XXX */
1008 p_input->i_mtu = 3 * p_access->i_packet_length;
1010 /* *** send command 15 *** */
1012 var_buffer_reinitwrite( &buffer, 0 );
1013 var_buffer_add32( &buffer, 0 );
1014 var_buffer_add32( &buffer, 0x8000 );
1015 var_buffer_add32( &buffer, 0xffffffff );
1016 var_buffer_add32( &buffer, 0x00 );
1017 var_buffer_add32( &buffer, 0x00 );
1018 var_buffer_add32( &buffer, 0x00 );
1019 var_buffer_add64( &buffer, 0x40ac200000000000 );
1020 var_buffer_add32( &buffer, p_access->i_header_packet_id_type );
1021 mms_CommandSend( p_input, 0x15, p_access->i_command_level, 0x00,
1022 buffer.p_data, buffer.i_data );
1024 /* *** wait for reponse *** */
1025 mms_CommandRead( p_input, 0x11, 0 );
1027 if( p_access->i_command != 0x11 )
1030 "unknown answer (0x%x instead of 0x11)",
1031 p_access->i_command );
1032 var_buffer_free( &buffer );
1033 MMSClose( p_input );
1036 /* *** now read header packet *** */
1037 if( mms_HeaderMediaRead( p_input, MMS_PACKET_HEADER ) < 0 )
1039 msg_Err( p_input, "cannot receive header" );
1040 var_buffer_free( &buffer );
1041 MMSClose( p_input );
1044 /* *** parse header and get stream and their id *** */
1045 /* get all streams properties,
1047 * TODO : stream bitrates properties(optional)
1048 * and bitrate mutual exclusion(optional) */
1049 asf_HeaderParse( p_access->stream,
1050 p_access->p_header, p_access->i_header );
1051 mms_StreamSelect( p_input, p_access->stream );
1052 /* *** now select stream we want to receive *** */
1053 /* TODO take care of stream bitrate TODO */
1056 var_buffer_reinitwrite( &buffer, 0 );
1057 /* for now, select first audio and video stream */
1058 for( i = 1; i < 128; i++ )
1061 if( p_access->stream[i].i_cat != MMS_STREAM_UNKNOWN )
1066 var_buffer_add16( &buffer, 0xffff );
1067 var_buffer_add16( &buffer, i );
1073 if( p_access->stream[i].i_selected )
1075 var_buffer_add16( &buffer, 0x0000 );
1077 "selecting stream[0x%x] %s (%d kb/s)",
1079 ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ?
1081 p_access->stream[i].i_bitrate / 1024);
1085 var_buffer_add16( &buffer, 0x0002 );
1087 "ignoring stream[0x%x] %s (%d kb/s)",
1089 ( p_access->stream[i].i_cat == MMS_STREAM_AUDIO ) ?
1091 p_access->stream[i].i_bitrate / 1024);
1097 if( i_streams == 0 )
1099 msg_Err( p_input, "cannot find any stream" );
1100 var_buffer_free( &buffer );
1101 MMSClose( p_input );
1104 mms_CommandSend( p_input, 0x33,
1106 0xffff | ( i_first << 16 ),
1107 buffer.p_data, buffer.i_data );
1109 mms_CommandRead( p_input, 0x21, 0 );
1110 if( p_access->i_command != 0x21 )
1113 "unknown answer (0x%x instead of 0x21)",
1114 p_access->i_command );
1115 var_buffer_free( &buffer );
1116 MMSClose( p_input );
1121 var_buffer_free( &buffer );
1123 msg_Info( p_input, "connection sucessful" );
1128 /****************************************************************************
1129 * MMSStart : Start streaming
1130 ****************************************************************************/
1131 static int MMSStart ( input_thread_t *p_input, uint32_t i_packet )
1133 access_t *p_access = (access_t*)p_input->p_access_data;
1134 var_buffer_t buffer;
1136 /* *** start stream from packet 0 *** */
1137 var_buffer_initwrite( &buffer, 0 );
1138 var_buffer_add64( &buffer, 0 ); /* seek point in second */
1139 var_buffer_add32( &buffer, 0xffffffff );
1140 var_buffer_add32( &buffer, i_packet ); // begin from start
1141 var_buffer_add8( &buffer, 0xff ); // stream time limit
1142 var_buffer_add8( &buffer, 0xff ); // on 3bytes ...
1143 var_buffer_add8( &buffer, 0xff ); //
1144 var_buffer_add8( &buffer, 0x00 ); // don't use limit
1145 var_buffer_add32( &buffer, p_access->i_media_packet_id_type );
1147 mms_CommandSend( p_input, 0x07, p_access->i_command_level, 0x0001ffff,
1148 buffer.p_data, buffer.i_data );
1150 var_buffer_free( &buffer );
1152 mms_CommandRead( p_input, 0x05, 0 );
1154 if( p_access->i_command != 0x05 )
1157 "unknown answer (0x%x instead of 0x05)",
1158 p_access->i_command );
1164 mms_HeaderMediaRead( p_input, MMS_PACKET_MEDIA );
1165 msg_Dbg( p_input, "Streaming started" );
1170 /****************************************************************************
1171 * MMSStop : Stop streaming
1172 ****************************************************************************/
1173 static int MMSStop ( input_thread_t *p_input )
1175 access_t *p_access = (access_t*)p_input->p_access_data;
1177 /* *** stop stream but keep connection alive *** */
1178 mms_CommandSend( p_input,
1180 p_access->i_command_level,
1186 /****************************************************************************
1187 * MMSClose : Close streaming and connection
1188 ****************************************************************************/
1189 static int MMSClose ( input_thread_t *p_input )
1191 access_t *p_access = (access_t*)p_input->p_access_data;
1193 msg_Dbg( p_input, "Connection closed" );
1195 /* *** tell server that we will disconnect *** */
1196 mms_CommandSend( p_input,
1198 p_access->i_command_level,
1201 /* *** close sockets *** */
1202 #if defined( UNDER_CE )
1203 CloseHandle( (HANDLE)p_access->socket_tcp.i_handle );
1204 #elif defined( WIN32 )
1205 closesocket( p_access->socket_tcp.i_handle );
1207 close( p_access->socket_tcp.i_handle );
1210 if( p_access->i_proto == MMS_PROTO_UDP )
1212 #if defined( UNDER_CE )
1213 CloseHandle( (HANDLE)p_access->socket_udp.i_handle );
1214 #elif defined( WIN32 )
1215 closesocket( p_access->socket_udp.i_handle );
1217 close( p_access->socket_udp.i_handle );
1221 FREE( p_access->p_cmd );
1222 FREE( p_access->p_media );
1223 FREE( p_access->p_header );
1225 FREE( p_access->psz_server_version );
1226 FREE( p_access->psz_tool_version );
1227 FREE( p_access->psz_update_player_url );
1228 FREE( p_access->psz_encryption_type );
1233 /*****************************************************************************
1234 * mms_ParseURL : parse an url string and fill an url_t
1235 *****************************************************************************/
1236 static void mms_ParseURL( url_t *p_url, char *psz_url )
1239 char *psz_server_port;
1241 p_url->psz_private = strdup( psz_url );
1243 psz_parser = p_url->psz_private;
1245 while( *psz_parser == '/' )
1249 p_url->psz_server_addr = psz_parser;
1251 while( *psz_parser &&
1252 *psz_parser != ':' && *psz_parser != '/' && *psz_parser != '@' )
1257 if( *psz_parser == ':' )
1261 psz_server_port = psz_parser;
1263 while( *psz_parser && *psz_parser != '/' )
1270 psz_server_port = "";
1273 if( *psz_parser == '@' )
1275 char *psz_bind_port;
1280 p_url->psz_bind_addr = psz_parser;
1282 while( *psz_parser && *psz_parser != ':' && *psz_parser != '/' )
1287 if( *psz_parser == ':' )
1291 psz_bind_port = psz_parser;
1293 while( *psz_parser && *psz_parser != '/' )
1302 if( *psz_bind_port )
1304 p_url->i_bind_port = strtol( psz_bind_port, &psz_parser, 10 );
1308 p_url->i_bind_port = 0;
1313 p_url->psz_bind_addr = "";
1314 p_url->i_bind_port = 0;
1317 if( *psz_parser == '/' )
1321 p_url->psz_path = psz_parser;
1324 if( *psz_server_port )
1326 p_url->i_server_port = strtol( psz_server_port, &psz_parser, 10 );
1330 p_url->i_server_port = 0;
1334 /****************************************************************************
1336 * MMS specific functions
1338 ****************************************************************************/
1340 static int mms_CommandSend( input_thread_t *p_input,
1342 uint32_t i_prefix1, uint32_t i_prefix2,
1343 uint8_t *p_data, int i_data )
1345 var_buffer_t buffer;
1347 access_t *p_access = (access_t*)p_input->p_access_data;
1350 i_data_by8 = ( i_data + 7 ) / 8;
1352 /* first init uffer */
1353 var_buffer_initwrite( &buffer, 0 );
1355 var_buffer_add32( &buffer, 0x00000001 ); /* start sequence */
1356 var_buffer_add32( &buffer, 0xB00BFACE );
1357 /* size after protocol type */
1358 var_buffer_add32( &buffer, i_data + MMS_CMD_HEADERSIZE - 16 );
1359 var_buffer_add32( &buffer, 0x20534d4d ); /* protocol "MMS " */
1360 var_buffer_add32( &buffer, i_data_by8 + 4 );
1361 var_buffer_add32( &buffer, p_access->i_seq_num ); p_access->i_seq_num++;
1362 var_buffer_add64( &buffer, 0 );
1363 var_buffer_add32( &buffer, i_data_by8 + 2 );
1364 var_buffer_add32( &buffer, 0x00030000 | i_command ); /* dir | command */
1365 var_buffer_add32( &buffer, i_prefix1 ); /* command specific */
1366 var_buffer_add32( &buffer, i_prefix2 ); /* command specific */
1368 /* specific command data */
1369 if( p_data && i_data > 0 )
1371 var_buffer_addmemory( &buffer, p_data, i_data );
1375 if( send( p_access->socket_tcp.i_handle,
1380 msg_Err( p_input, "failed to send command" );
1384 var_buffer_free( &buffer );
1388 static int NetFillBuffer( input_thread_t *p_input )
1393 access_t *p_access = (access_t*)p_input->p_access_data;
1394 struct timeval timeout;
1398 /* FIXME when using udp */
1399 ssize_t i_tcp, i_udp;
1400 ssize_t i_tcp_read, i_udp_read;
1403 /* Initialize file descriptor set */
1406 i_tcp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_tcp;
1408 if( p_access->i_proto == MMS_PROTO_UDP )
1410 i_udp = MMS_BUFFER_SIZE/2 - p_access->i_buffer_udp;
1414 i_udp = 0; /* there isn't udp socket */
1420 FD_SET( p_access->socket_tcp.i_handle, &fds );
1421 i_handle_max = __MAX( i_handle_max, p_access->socket_tcp.i_handle );
1425 FD_SET( p_access->socket_udp.i_handle, &fds );
1426 i_handle_max = __MAX( i_handle_max, p_access->socket_udp.i_handle );
1429 if( i_handle_max == 0 )
1431 msg_Warn( p_input, "nothing to read %d:%d", i_tcp, i_udp );
1436 // msg_Warn( p_input, "ask for tcp:%d udp:%d", i_tcp, i_udp );
1439 /* We'll wait 0.5 second if nothing happens */
1441 timeout.tv_usec = 500000;
1443 /* Find if some data is available */
1444 i_ret = select( i_handle_max + 1,
1446 NULL, NULL, &timeout );
1448 if( i_ret == -1 && errno != EINTR )
1450 msg_Err( p_input, "network select error (%s)", strerror(errno) );
1454 if( i_tcp > 0 && FD_ISSET( p_access->socket_tcp.i_handle, &fds ) )
1457 recv( p_access->socket_tcp.i_handle,
1458 p_access->buffer_tcp + p_access->i_buffer_tcp,
1459 i_tcp + MMS_BUFFER_SIZE/2, 0 );
1466 if( i_udp > 0 && FD_ISSET( p_access->socket_udp.i_handle, &fds ) )
1468 i_udp_read = recv( p_access->socket_udp.i_handle,
1469 p_access->buffer_udp + p_access->i_buffer_udp,
1470 i_udp + MMS_BUFFER_SIZE/2, 0 );
1478 if( p_access->i_proto == MMS_PROTO_UDP )
1481 "filling buffer TCP:%d+%d UDP:%d+%d",
1482 p_access->i_buffer_tcp,
1484 p_access->i_buffer_udp,
1490 "filling buffer TCP:%d+%d",
1491 p_access->i_buffer_tcp,
1495 p_access->i_buffer_tcp += i_tcp_read;
1496 p_access->i_buffer_udp += i_udp_read;
1498 return( i_tcp_read + i_udp_read);
1502 static int mms_ParseCommand( input_thread_t *p_input,
1507 #define GET32( i_pos ) \
1508 ( p_access->p_cmd[i_pos] + ( p_access->p_cmd[i_pos +1] << 8 ) + \
1509 ( p_access->p_cmd[i_pos + 2] << 16 ) + \
1510 ( p_access->p_cmd[i_pos + 3] << 24 ) )
1512 access_t *p_access = (access_t*)p_input->p_access_data;
1516 if( p_access->p_cmd )
1518 free( p_access->p_cmd );
1520 p_access->i_cmd = i_data;
1521 p_access->p_cmd = malloc( i_data );
1522 memcpy( p_access->p_cmd, p_data, i_data );
1524 *pi_used = i_data; /* by default */
1526 if( i_data < MMS_CMD_HEADERSIZE )
1528 msg_Warn( p_input, "truncated command (header incomplete)" );
1529 p_access->i_command = 0;
1532 i_id = GetDWLE( p_data + 4 );
1533 i_length = GetDWLE( p_data + 8 ) + 16;
1535 if( i_id != 0xb00bface )
1538 "incorrect command header (0x%x)", i_id );
1539 p_access->i_command = 0;
1543 if( i_length > p_access->i_cmd )
1546 "truncated command (missing %d bytes)",
1547 i_length - i_data );
1548 p_access->i_command = 0;
1551 else if( i_length < p_access->i_cmd )
1553 p_access->i_cmd = i_length;
1554 *pi_used = i_length;
1558 "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",
1562 /* 12: protocol type "MMS " */
1565 /* 24: unknown (0) */
1566 /* 28: unknown (0) */
1572 p_access->i_command = GET32( 36 ) & 0xffff;
1574 return( MMS_PACKET_CMD );
1577 static int mms_ParsePacket( input_thread_t *p_input,
1578 uint8_t *p_data, size_t i_data,
1581 access_t *p_access = (access_t*)p_input->p_access_data;
1582 int i_packet_seq_num;
1583 size_t i_packet_length;
1584 uint32_t i_packet_id;
1589 // *pi_used = i_data; /* default */
1590 *pi_used = i_data; /* default */
1593 msg_Warn( p_input, "truncated packet (header incomplete)" );
1597 i_packet_id = p_data[4];
1598 i_packet_seq_num = GetDWLE( p_data );
1599 i_packet_length = GetWLE( p_data + 6 );
1602 if( i_packet_length > i_data || i_packet_length <= 8)
1605 "truncated packet (missing %d bytes)",
1606 i_packet_length - i_data );
1610 else if( i_packet_length < i_data )
1612 *pi_used = i_packet_length;
1615 if( i_packet_id == 0xff )
1618 "receive MMS UDP pair timing" );
1619 return( MMS_PACKET_UDP_TIMING );
1622 if( i_packet_id != p_access->i_header_packet_id_type &&
1623 i_packet_id != p_access->i_media_packet_id_type )
1625 msg_Warn( p_input, "incorrect Packet Id Type (0x%x)", i_packet_id );
1629 /* we now have a media or a header packet */
1630 p_packet = malloc( i_packet_length - 8 ); // don't bother with preheader
1631 memcpy( p_packet, p_data + 8, i_packet_length - 8 );
1633 if( i_packet_seq_num != p_access->i_packet_seq_num )
1635 /* FIXME for udp could be just wrong order ? */
1637 "detected packet lost (%d != %d)",
1639 p_access->i_packet_seq_num );
1640 p_access->i_packet_seq_num = i_packet_seq_num;
1642 p_access->i_packet_seq_num++;
1644 if( i_packet_id == p_access->i_header_packet_id_type )
1646 FREE( p_access->p_header );
1647 p_access->p_header = p_packet;
1648 p_access->i_header = i_packet_length - 8;
1649 /* msg_Dbg( p_input,
1650 "receive header packet (%d bytes)",
1651 i_packet_length - 8 ); */
1653 return( MMS_PACKET_HEADER );
1657 FREE( p_access->p_media );
1658 p_access->p_media = p_packet;
1659 p_access->i_media = i_packet_length - 8;
1660 p_access->i_media_used = 0;
1661 /* msg_Dbg( p_input,
1662 "receive media packet (%d bytes)",
1663 i_packet_length - 8 ); */
1665 return( MMS_PACKET_MEDIA );
1669 static int mms_ReceivePacket( input_thread_t *p_input )
1671 access_t *p_access = (access_t*)p_input->p_access_data;
1672 int i_packet_tcp_type;
1673 int i_packet_udp_type;
1677 if( NetFillBuffer( p_input ) < 0 )
1679 msg_Warn( p_input, "cannot fill buffer" );
1684 i_packet_tcp_type = -1;
1685 i_packet_udp_type = -1;
1687 if( p_access->i_buffer_tcp > 0 )
1691 if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
1694 mms_ParseCommand( p_input,
1695 p_access->buffer_tcp,
1696 p_access->i_buffer_tcp,
1703 mms_ParsePacket( p_input,
1704 p_access->buffer_tcp,
1705 p_access->i_buffer_tcp,
1708 if( i_used < MMS_BUFFER_SIZE )
1710 memmove( p_access->buffer_tcp,
1711 p_access->buffer_tcp + i_used,
1712 MMS_BUFFER_SIZE - i_used );
1714 p_access->i_buffer_tcp -= i_used;
1716 else if( p_access->i_buffer_udp > 0 )
1720 if( GetDWLE( p_access->buffer_tcp + 4 ) == 0xb00bface )
1723 mms_ParseCommand( p_input,
1724 p_access->buffer_tcp,
1725 p_access->i_buffer_tcp,
1733 mms_ParsePacket( p_input,
1734 p_access->buffer_udp,
1735 p_access->i_buffer_udp,
1738 if( i_used < MMS_BUFFER_SIZE )
1740 memmove( p_access->buffer_udp,
1741 p_access->buffer_udp + i_used,
1742 MMS_BUFFER_SIZE - i_used );
1744 p_access->i_buffer_udp -= i_used;
1748 i_packet_udp_type = -1;
1751 if( i_packet_tcp_type == MMS_PACKET_CMD &&
1752 p_access->i_command == 0x1b )
1754 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1755 i_packet_tcp_type = -1;
1758 if( i_packet_tcp_type != -1 )
1760 return( i_packet_tcp_type );
1762 else if( i_packet_udp_type != -1 )
1764 return( i_packet_udp_type );
1770 static int mms_ReceiveCommand( input_thread_t *p_input )
1772 access_t *p_access = (access_t*)p_input->p_access_data;
1778 NetFillBuffer( p_input );
1780 i_status = mms_ParseCommand( p_input,
1781 p_access->buffer_tcp,
1782 p_access->i_buffer_tcp,
1784 if( i_used < MMS_BUFFER_SIZE )
1786 memmove( p_access->buffer_tcp,
1787 p_access->buffer_tcp + i_used,
1788 MMS_BUFFER_SIZE - i_used );
1790 p_access->i_buffer_tcp -= i_used;
1797 if( p_access->i_command == 0x1b )
1799 mms_CommandSend( p_input, 0x1b, 0, 0, NULL, 0 );
1810 #define MMS_RETRY_MAX 10
1811 #define MMS_RETRY_SLEEP 50000
1813 static int mms_CommandRead( input_thread_t *p_input, int i_command1, int i_command2 )
1815 access_t *p_access = (access_t*)p_input->p_access_data;
1819 for( i_count = 0; i_count < MMS_RETRY_MAX; )
1822 i_status = mms_ReceiveCommand( p_input );
1823 if( i_status < 0 || p_access->i_command == 0 )
1826 msleep( MMS_RETRY_SLEEP );
1828 else if( i_command1 == 0 && i_command2 == 0)
1832 else if( p_access->i_command == i_command1 || p_access->i_command == i_command2 )
1838 switch( p_access->i_command )
1841 msg_Warn( p_input, "socket closed by server" );
1842 p_access->i_eos = 1;
1845 msg_Warn( p_input, "end of media stream" );
1846 p_access->i_eos = 1;
1853 msg_Warn( p_input, "failed to receive command (abording)" );
1859 static int mms_HeaderMediaRead( input_thread_t *p_input, int i_type )
1861 access_t *p_access = (access_t*)p_input->p_access_data;
1864 for( i_count = 0; i_count < MMS_RETRY_MAX; )
1868 i_status = mms_ReceivePacket( p_input );
1873 "cannot receive header (%d/%d)", i_count, MMS_RETRY_MAX );
1874 msleep( MMS_RETRY_SLEEP );
1876 else if( i_status == i_type || i_type == MMS_PACKET_ANY )
1880 else if( i_status == MMS_PACKET_CMD )
1882 switch( p_access->i_command )
1885 msg_Warn( p_input, "socket closed by server" );
1886 p_access->i_eos = 1;
1889 msg_Warn( p_input, "end of media stream" );
1890 p_access->i_eos = 1;
1893 /* XXX not too dificult to be done EXCEPT that we
1894 * need to restart demuxer... and I don't see how we
1895 * could do that :p */
1897 "reinitialization needed --> unsupported" );
1898 p_access->i_eos = 1;
1906 "cannot receive %s (abording)",
1907 ( i_type == MMS_PACKET_HEADER ) ? "header" : "media data" );