]> git.sesse.net Git - vlc/blob - src/input/input.c
* Fixed a warning in input_es.c ;
[vlc] / src / input / input.c
1 /*****************************************************************************
2  * input.c: input thread
3  * Read an MPEG2 stream, demultiplex and parse it before sending it to
4  * decoders.
5  *****************************************************************************
6  * Copyright (C) 1998, 1999, 2000 VideoLAN
7  * $Id: input.c,v 1.134 2001/10/02 17:04:43 massiot Exp $
8  *
9  * Authors: Christophe Massiot <massiot@via.ecp.fr>
10  *
11  * This program is free software; you can redistribute it and/or modify
12  * it under the terms of the GNU General Public License as published by
13  * the Free Software Foundation; either version 2 of the License, or
14  * (at your option) any later version.
15  * 
16  * This program is distributed in the hope that it will be useful,
17  * but WITHOUT ANY WARRANTY; without even the implied warranty of
18  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
19  * GNU General Public License for more details.
20  *
21  * You should have received a copy of the GNU General Public License
22  * along with this program; if not, write to the Free Software
23  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24  *****************************************************************************/
25
26 /*****************************************************************************
27  * Preamble
28  *****************************************************************************/
29 #include "defs.h"
30
31 #include <stdlib.h>
32 #include <sys/types.h>
33 #include <sys/stat.h>
34 #include <fcntl.h>
35
36 #ifdef HAVE_UNISTD_H
37 #   include <unistd.h>
38 #elif defined( _MSC_VER ) && defined( _WIN32 )
39 #   include <io.h>
40 #endif
41
42 #include <string.h>
43 #include <errno.h>
44
45 #ifdef STRNCASECMP_IN_STRINGS_H
46 #   include <strings.h>
47 #endif
48
49 #ifdef WIN32
50 #   include <winsock2.h>
51 #elif !defined( SYS_BEOS ) && !defined( SYS_NTO )
52 #   include <netdb.h>                                         /* hostent ... */
53 #   include <sys/socket.h>
54 #   include <netinet/in.h>
55 #   include <arpa/inet.h>
56 #   include <sys/types.h>
57 #   include <sys/socket.h>
58 #endif
59
60 #include <sys/times.h>
61
62 #include "config.h"
63 #include "common.h"
64 #include "threads.h"
65 #include "mtime.h"
66 #include "netutils.h"
67 #include "modules.h"
68
69 #include "intf_msg.h"
70 #include "intf_playlist.h"
71
72 #include "stream_control.h"
73 #include "input_ext-intf.h"
74 #include "input_ext-dec.h"
75 #include "input_ext-plugins.h"
76
77 #include "interface.h"
78
79 #include "main.h"
80
81 /*****************************************************************************
82  * Local prototypes
83  *****************************************************************************/
84 static void RunThread       ( input_thread_t *p_input );
85 static  int InitThread      ( input_thread_t *p_input );
86 static void ErrorThread     ( input_thread_t *p_input );
87 static void DestroyThread   ( input_thread_t *p_input );
88 static void EndThread       ( input_thread_t *p_input );
89
90 static void FileOpen        ( input_thread_t *p_input );
91 static void FileClose       ( input_thread_t *p_input );
92 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
93 static void NetworkOpen     ( input_thread_t *p_input );
94 static void HTTPOpen        ( input_thread_t *p_input );
95 static void NetworkClose    ( input_thread_t *p_input );
96 #endif
97
98 /*****************************************************************************
99  * input_CreateThread: creates a new input thread
100  *****************************************************************************
101  * This function creates a new input, and returns a pointer
102  * to its description. On error, it returns NULL.
103  * If pi_status is NULL, then the function will block until the thread is ready.
104  * If not, it will be updated using one of the THREAD_* constants.
105  *****************************************************************************/
106 input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
107 {
108     input_thread_t *    p_input;                        /* thread descriptor */
109     int                 i_status;                           /* thread status */
110
111     /* Allocate descriptor */
112     p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
113     if( p_input == NULL )
114     {
115         intf_ErrMsg( "input error: can't allocate input thread (%s)",
116                      strerror(errno) );
117         return( NULL );
118     }
119
120     /* Packets read once */
121     p_input->i_read_once = INPUT_READ_ONCE;
122
123     /* Initialize thread properties */
124     p_input->b_die              = 0;
125     p_input->b_error            = 0;
126     p_input->b_eof              = 0;
127
128     /* Set target */
129     p_input->p_source           = p_item->psz_name;
130
131     /* I have never understood that stuff --Meuuh */
132     p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
133     *p_input->pi_status         = THREAD_CREATE;
134
135     /* Initialize stream description */
136     p_input->stream.i_es_number = 0;
137     p_input->stream.i_selected_es_number = 0;
138     p_input->stream.i_pgrm_number = 0;
139     p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
140     p_input->stream.b_new_mute = MUTE_NO_CHANGE;
141     p_input->stream.i_mux_rate = 0;
142
143     /* no stream, no area */
144     p_input->stream.i_area_nb = 0;
145     p_input->stream.pp_areas = NULL;
146     p_input->stream.p_selected_area = NULL;
147     p_input->stream.p_new_area = NULL;
148
149     /* By default there is one area in a stream */
150     input_AddArea( p_input );
151     p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
152
153     /* Initialize stream control properties. */
154     p_input->stream.control.i_status = PLAYING_S;
155     p_input->stream.control.i_rate = DEFAULT_RATE;
156     p_input->stream.control.b_mute = 0;
157     p_input->stream.control.b_grayscale = main_GetIntVariable(
158                             VOUT_GRAYSCALE_VAR, VOUT_GRAYSCALE_DEFAULT );
159     p_input->stream.control.i_smp = main_GetIntVariable(
160                             VDEC_SMP_VAR, VDEC_SMP_DEFAULT );
161
162     intf_WarnMsg( 1, "input: playlist item `%s'", p_input->p_source );
163
164     /* Create thread. */
165     if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
166                            (void *) p_input ) )
167     {
168         intf_ErrMsg( "input error: can't create input thread (%s)",
169                      strerror(errno) );
170         free( p_input );
171         return( NULL );
172     }
173
174     /* If status is NULL, wait until the thread is created */
175     if( pi_status == NULL )
176     {
177         do
178         {
179             msleep( THREAD_SLEEP );
180         } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
181                 && (i_status != THREAD_FATAL) );
182         if( i_status != THREAD_READY )
183         {
184             return( NULL );
185         }
186     }
187     return( p_input );
188 }
189
190 /*****************************************************************************
191  * input_DestroyThread: mark an input thread as zombie
192  *****************************************************************************
193  * This function should not return until the thread is effectively cancelled.
194  *****************************************************************************/
195 void input_DestroyThread( input_thread_t *p_input, int *pi_status )
196 {
197     int         i_status;                                   /* thread status */
198
199     /* Set status */
200     p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
201     *p_input->pi_status = THREAD_DESTROY;
202
203     /* Request thread destruction */
204     p_input->b_die = 1;
205
206     /* Make the thread exit of an eventual vlc_cond_wait() */
207     vlc_mutex_lock( &p_input->stream.stream_lock );
208     vlc_cond_signal( &p_input->stream.stream_wait );
209     vlc_mutex_unlock( &p_input->stream.stream_lock );
210
211     /* If status is NULL, wait until thread has been destroyed */
212     if( pi_status == NULL )
213     {
214         do
215         {
216             msleep( THREAD_SLEEP );
217         } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
218                   && (i_status != THREAD_FATAL) );
219     }
220 }
221
222 /*****************************************************************************
223  * RunThread: main thread loop
224  *****************************************************************************
225  * Thread in charge of processing the network packets and demultiplexing.
226  *****************************************************************************/
227 static void RunThread( input_thread_t *p_input )
228 {
229     int                     i_error, i;
230     data_packet_t **        pp_packets;
231
232     if( InitThread( p_input ) )
233     {
234         /* If we failed, wait before we are killed, and exit */
235         *p_input->pi_status = THREAD_ERROR;
236         p_input->b_error = 1;
237         ErrorThread( p_input );
238         DestroyThread( p_input );
239         return;
240     }
241
242     /* initialization is completed */
243     vlc_mutex_lock( &p_input->stream.stream_lock );
244     p_input->stream.b_changed = 1;
245     vlc_mutex_unlock( &p_input->stream.stream_lock );
246
247     pp_packets = (data_packet_t **) malloc( p_input->i_read_once *
248                                         sizeof( data_packet_t * ) );
249     if( pp_packets == NULL )
250     {
251         intf_ErrMsg( "input error: out of memory" );
252         free( pp_packets );
253         p_input->b_error = 1;
254     }
255
256     while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
257     {
258         p_input->c_loops++;
259
260         vlc_mutex_lock( &p_input->stream.stream_lock );
261
262         if( p_input->stream.p_new_area )
263         {
264             if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
265             {
266
267                 p_input->pf_set_area( p_input, p_input->stream.p_new_area );
268
269                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
270                 {
271                     pgrm_descriptor_t * p_pgrm
272                                             = p_input->stream.pp_programs[i];
273                     /* Escape all decoders for the stream discontinuity they
274                      * will encounter. */
275                     input_EscapeDiscontinuity( p_input, p_pgrm );
276
277                     /* Reinitialize synchro. */
278                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
279                 }
280             }
281             p_input->stream.p_new_area = NULL;
282         }
283
284         if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
285         {
286             if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
287             {
288                 p_input->pf_seek( p_input,
289                                   p_input->stream.p_selected_area->i_seek );
290
291                 for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
292                 {
293                     pgrm_descriptor_t * p_pgrm
294                                             = p_input->stream.pp_programs[i];
295                     /* Escape all decoders for the stream discontinuity they
296                      * will encounter. */
297                     input_EscapeDiscontinuity( p_input, p_pgrm );
298
299                     /* Reinitialize synchro. */
300                     p_pgrm->i_synchro_state = SYNCHRO_REINIT;
301                 }
302             }
303             p_input->stream.p_selected_area->i_seek = NO_SEEK;
304         }
305
306         if( p_input->stream.p_removed_es )
307         {
308             input_UnselectES( p_input, p_input->stream.p_removed_es );
309             p_input->stream.p_removed_es = NULL;
310         }
311
312         if( p_input->stream.p_newly_selected_es )
313         {
314             input_SelectES( p_input, p_input->stream.p_newly_selected_es );
315             p_input->stream.p_newly_selected_es = NULL;
316         }
317
318         if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
319         {
320             if( p_input->stream.b_new_mute )
321             {
322                 input_EscapeAudioDiscontinuity( p_input );
323             }
324
325             vlc_mutex_lock( &p_input->stream.control.control_lock );
326             p_input->stream.control.b_mute = p_input->stream.b_new_mute;
327             vlc_mutex_unlock( &p_input->stream.control.control_lock );
328
329             p_input->stream.b_new_mute = MUTE_NO_CHANGE;
330         }
331
332         vlc_mutex_unlock( &p_input->stream.stream_lock );
333
334         i_error = p_input->pf_read( p_input, pp_packets );
335
336         /* Demultiplex read packets. */
337         for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
338         {
339             p_input->stream.c_packets_read++;
340             p_input->pf_demux( p_input, pp_packets[i] );
341         }
342
343         if( i_error )
344         {
345             if( i_error == 1 )
346             {
347                 /* End of file - we do not set b_die because only the
348                  * interface is allowed to do so. */
349                 intf_WarnMsg( 3, "input: EOF reached" );
350                 p_input->b_eof = 1;
351             }
352             else
353             {
354                 p_input->b_error = 1;
355             }
356         }
357     }
358
359     free( pp_packets );
360
361     if( p_input->b_error || p_input->b_eof )
362     {
363         ErrorThread( p_input );
364     }
365
366     EndThread( p_input );
367
368     DestroyThread( p_input );
369
370     intf_DbgMsg("input: Thread end");
371 }
372
373 /*****************************************************************************
374  * InitThread: init the input Thread
375  *****************************************************************************/
376 static int InitThread( input_thread_t * p_input )
377 {
378
379     /* Initialize statistics */
380     p_input->c_loops                    = 0;
381     p_input->stream.c_packets_read      = 0;
382     p_input->stream.c_packets_trashed   = 0;
383     p_input->p_stream                   = NULL;
384
385     /* Set locks. */
386     vlc_mutex_init( &p_input->stream.stream_lock );
387     vlc_cond_init( &p_input->stream.stream_wait );
388     vlc_mutex_init( &p_input->stream.control.control_lock );
389
390     /* Find appropriate module. */
391     p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
392                                            (probedata_t *)p_input );
393
394     if( p_input->p_input_module == NULL )
395     {
396         intf_ErrMsg( "input error: no suitable input module for `%s'",
397                      p_input->p_source );
398         return( -1 );
399     }
400
401 #define f p_input->p_input_module->p_functions->input.functions.input
402     p_input->pf_init          = f.pf_init;
403     p_input->pf_end           = f.pf_end;
404     p_input->pf_init_bit_stream= f.pf_init_bit_stream;
405     p_input->pf_read          = f.pf_read;
406     p_input->pf_set_area      = f.pf_set_area;
407     p_input->pf_demux         = f.pf_demux;
408     p_input->pf_new_packet    = f.pf_new_packet;
409     p_input->pf_new_pes       = f.pf_new_pes;
410     p_input->pf_delete_packet = f.pf_delete_packet;
411     p_input->pf_delete_pes    = f.pf_delete_pes;
412     p_input->pf_rewind        = f.pf_rewind;
413     p_input->pf_seek          = f.pf_seek;
414 #undef f
415
416     /* FIXME : this is waaaay too kludgy */
417     if( (strlen( p_input->p_source ) > 3) && !strncasecmp( p_input->p_source, "ts:", 3 ) )
418     {
419         /* Network stream */
420         NetworkOpen( p_input );
421         p_input->stream.i_method = INPUT_METHOD_NETWORK;
422     }
423     else if( ( strlen( p_input->p_source ) > 5 ) && !strncasecmp( p_input->p_source, "http:", 5 ) )
424     {
425         /* HTTP stream */
426         HTTPOpen( p_input );
427         p_input->stream.i_method = INPUT_METHOD_NETWORK;
428     }
429     else if( ( strlen( p_input->p_source ) > 4 ) && !strncasecmp( p_input->p_source, "dvd:", 4 ) )
430     {
431         /* DVD - this is THE kludge */
432         p_input->p_input_module->p_functions->input.functions.input.pf_open( p_input );
433         p_input->stream.i_method = INPUT_METHOD_DVD;
434     }
435     else
436     {
437         /* File input */
438         FileOpen( p_input );
439         p_input->stream.i_method = INPUT_METHOD_FILE;
440     }
441
442     if( p_input->b_error )
443     {
444         /* We barfed -- exit nicely */
445         module_Unneed( p_input->p_input_module );
446         return( -1 );
447     }
448
449     p_input->pf_init( p_input );
450
451     if( p_input->b_error )
452     {
453         /* We barfed -- exit nicely */
454         p_input->pf_close( p_input );
455         module_Unneed( p_input->p_input_module );
456         return( -1 );
457     }
458
459     *p_input->pi_status = THREAD_READY;
460
461     return( 0 );
462 }
463
464 /*****************************************************************************
465  * ErrorThread: RunThread() error loop
466  *****************************************************************************
467  * This function is called when an error occured during thread main's loop.
468  *****************************************************************************/
469 static void ErrorThread( input_thread_t *p_input )
470 {
471     while( !p_input->b_die )
472     {
473         /* Sleep a while */
474         msleep( INPUT_IDLE_SLEEP );
475     }
476 }
477
478 /*****************************************************************************
479  * EndThread: end the input thread
480  *****************************************************************************/
481 static void EndThread( input_thread_t * p_input )
482 {
483     int *       pi_status;                                  /* thread status */
484
485     /* Store status */
486     pi_status = p_input->pi_status;
487     *pi_status = THREAD_END;
488
489     if( p_main->b_stats )
490     {
491         /* Display statistics */
492         struct tms  cpu_usage;
493         times( &cpu_usage );
494
495         intf_StatMsg( "input stats: %d loops consuming user: %d, system: %d",
496                       p_input->c_loops,
497                       cpu_usage.tms_utime, cpu_usage.tms_stime );
498
499         input_DumpStream( p_input );
500     }
501
502     /* Free all ES and destroy all decoder threads */
503     input_EndStream( p_input );
504
505     /* Free demultiplexer's data */
506     p_input->pf_end( p_input );
507
508     /* Close stream */
509     if( (strlen( p_input->p_source ) > 3) && !strncasecmp( p_input->p_source, "ts:", 3 ) )
510     {
511         NetworkClose( p_input );
512     }
513     else if( ( strlen( p_input->p_source ) > 5 ) && !strncasecmp( p_input->p_source, "http:", 5 ) )
514     {
515         NetworkClose( p_input );
516     }
517     else if( ( strlen( p_input->p_source ) > 4 ) && !strncasecmp( p_input->p_source, "dvd:", 4 ) )
518     {
519         p_input->p_input_module->p_functions->input.functions.input.pf_close( p_input );
520     }
521     else
522     {
523         FileClose( p_input );
524     }
525
526     /* Release modules */
527     module_Unneed( p_input->p_input_module );
528
529 }
530
531 /*****************************************************************************
532  * DestroyThread: destroy the input thread
533  *****************************************************************************/
534 static void DestroyThread( input_thread_t * p_input )
535 {
536     int *       pi_status;                                  /* thread status */
537
538     /* Store status */
539     pi_status = p_input->pi_status;
540
541     /* Destroy Mutex locks */
542     vlc_mutex_destroy( &p_input->stream.control.control_lock );
543     vlc_mutex_destroy( &p_input->stream.stream_lock );
544     
545     /* Free input structure */
546     free( p_input );
547
548     /* Update status */
549     *pi_status = THREAD_OVER;
550 }
551
552 /*****************************************************************************
553  * FileOpen : open a file descriptor
554  *****************************************************************************/
555 static void FileOpen( input_thread_t * p_input )
556 {
557     struct stat         stat_info;
558     int                 i_stat;
559
560     char *psz_name = p_input->p_source;
561
562     if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
563     {
564         int i_size = strlen( psz_name );
565
566         if( ( i_size > 4 )
567             && !strncasecmp( psz_name, "dvd:", 4 ) )
568         {
569             /* get rid of the 'dvd:' stuff and try again */
570             psz_name += 4;
571             i_stat = stat( psz_name, &stat_info );
572         }
573         else if( ( i_size > 5 )
574                  && !strncasecmp( psz_name, "file:", 5 ) )
575         {
576             /* get rid of the 'file:' stuff and try again */
577             psz_name += 5;
578             i_stat = stat( psz_name, &stat_info );
579         }
580
581         if( i_stat == (-1) )
582         {
583             intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
584                          psz_name, strerror(errno));
585             p_input->b_error = 1;
586             return;
587         }
588     }
589
590     vlc_mutex_lock( &p_input->stream.stream_lock );
591
592     /* If we are here we can control the pace... */
593     p_input->stream.b_pace_control = 1;
594
595     if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
596          || S_ISBLK(stat_info.st_mode) )
597     {
598         p_input->stream.b_seekable = 1;
599         p_input->stream.p_selected_area->i_size = stat_info.st_size;
600     }
601     else if( S_ISFIFO(stat_info.st_mode)
602 #if !defined( SYS_BEOS ) && !defined( WIN32 )
603              || S_ISSOCK(stat_info.st_mode)
604 #endif
605              )
606     {
607         p_input->stream.b_seekable = 0;
608         p_input->stream.p_selected_area->i_size = 0;
609     }
610     else
611     {
612         vlc_mutex_unlock( &p_input->stream.stream_lock );
613         intf_ErrMsg( "input error: unknown file type for `%s'",
614                      psz_name );
615         p_input->b_error = 1;
616         return;
617     }
618
619     p_input->stream.p_selected_area->i_tell = 0;
620     vlc_mutex_unlock( &p_input->stream.stream_lock );
621
622     intf_WarnMsg( 2, "input: opening file `%s'", p_input->p_source );
623     if( (p_input->i_handle = open( psz_name,
624                                    /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
625     {
626         intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
627         p_input->b_error = 1;
628         return;
629     }
630
631 }
632
633 /*****************************************************************************
634  * FileClose : close a file descriptor
635  *****************************************************************************/
636 static void FileClose( input_thread_t * p_input )
637 {
638     intf_WarnMsg( 2, "input: closing file `%s'", p_input->p_source );
639
640     close( p_input->i_handle );
641
642     return;
643 }
644
645 #if !defined( SYS_BEOS ) && !defined( SYS_NTO )
646 /*****************************************************************************
647  * NetworkOpen : open a network socket 
648  *****************************************************************************/
649 static void NetworkOpen( input_thread_t * p_input )
650 {
651     char                *psz_server = NULL;
652     char                *psz_broadcast = NULL;
653     int                 i_port = 0;
654     int                 i_opt;
655     int                 i_opt_size;
656     struct sockaddr_in  sock;
657     unsigned int        i_mc_group;
658
659 #ifdef WIN32
660     WSADATA Data;
661     int i_err;
662 #endif
663     
664 #ifdef WIN32
665     /* WinSock Library Init. */
666     i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );
667
668     if( i_err )
669     {
670         intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
671         return ;
672     }
673 #endif
674     
675     /* Get the remote server */
676     if( p_input->p_source != NULL )
677     {
678         psz_server = p_input->p_source;
679
680         /* Skip the protocol name */
681         while( *psz_server && *psz_server != ':' )
682         {
683             psz_server++;
684         }
685
686         /* Skip the "://" part */
687         while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
688         {
689             psz_server++;
690         }
691
692         /* Found a server name */
693         if( *psz_server )
694         {
695             char *psz_port = psz_server;
696
697             /* Skip the hostname part */
698             while( *psz_port && *psz_port != ':' )
699             {
700                 psz_port++;
701             }
702
703             /* Found a port name */
704             if( *psz_port )
705             {
706                 /* Replace ':' with '\0' */
707                 *psz_port = '\0';
708                 psz_port++;
709
710                 psz_broadcast = psz_port;
711                 while( *psz_broadcast && *psz_broadcast != ':' )
712                 {
713                     psz_broadcast++;
714                 }
715
716                 if( *psz_broadcast )
717                 {
718                     *psz_broadcast = '\0';
719                     psz_broadcast++;
720                     while( *psz_broadcast && *psz_broadcast == ':' )
721                     {
722                         psz_broadcast++;
723                     }
724                 }
725                 else
726                 {
727                     psz_broadcast = NULL;
728                 }
729
730                 /* port before broadcast address */
731                 if( *psz_port != '\0' )
732                 {
733                     i_port = atoi( psz_port );
734                 }
735             }
736         }
737         else
738         {
739             psz_server = NULL;
740         }
741     }
742
743     /* Check that we got a valid server */
744     if( psz_server == NULL )
745     {
746         psz_server = main_GetPszVariable( INPUT_SERVER_VAR, 
747                                           INPUT_SERVER_DEFAULT );
748     }
749
750     /* Check that we got a valid port */
751     if( i_port == 0 )
752     {
753         i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
754     }
755
756     if( psz_broadcast == NULL )
757     {
758         /* Are we broadcasting ? */
759         if( main_GetIntVariable( INPUT_BROADCAST_VAR,
760                                  INPUT_BROADCAST_DEFAULT ) )
761         {
762             psz_broadcast = main_GetPszVariable( INPUT_BCAST_ADDR_VAR,
763                                                  INPUT_BCAST_ADDR_DEFAULT );
764         }
765         else
766         {
767            psz_broadcast = NULL; 
768         }
769     }
770
771     intf_WarnMsg( 2, "input: server=%s port=%d broadcast=%s",
772                      psz_server, i_port, psz_broadcast );
773
774     /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
775      * protocol */
776     p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
777     if( p_input->i_handle == -1 )
778     {
779         intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );
780         p_input->b_error = 1;
781         return;
782     }
783
784     /* We may want to reuse an already used socket */
785     i_opt = 1;
786     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
787                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
788     {
789         intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
790                      strerror(errno));
791         close( p_input->i_handle );
792         p_input->b_error = 1;
793         return;
794     }
795
796     /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
797      * packet loss caused by scheduling problems */
798     i_opt = 0x80000;
799     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
800                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
801     {
802         intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
803                      strerror(errno));
804         close( p_input->i_handle );
805         p_input->b_error = 1;
806         return;
807     }
808
809     /* Check if we really got what we have asked for, because Linux, etc.
810      * will silently limit the max buffer size to net.core.rmem_max which
811      * is typically only 65535 bytes */
812     i_opt = 0;
813     i_opt_size = sizeof( i_opt );
814     if( getsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
815                     (void*) &i_opt, &i_opt_size ) == -1 )
816     {
817         intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
818                      strerror(errno));
819         close( p_input->i_handle );
820         p_input->b_error = 1;
821         return;
822     }
823     
824     if( i_opt < 0x80000 )
825     {
826         intf_WarnMsg( 1, "input warning: socket receive buffer size just %d instead of %d bytes.",
827                      i_opt, 0x80000 );
828     }
829
830     /* Build the local socket */
831     if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -1 )
832     {
833         intf_ErrMsg( "input error: can't build local address" );
834         close( p_input->i_handle );
835         p_input->b_error = 1;
836         return;
837     }
838
839     /* Required for IP_ADD_MEMBERSHIP */
840     i_mc_group = sock.sin_addr.s_addr;
841
842 #if defined( WIN32 )
843     if ( psz_broadcast != NULL )
844     {
845         sock.sin_addr.s_addr = INADDR_ANY;
846     }
847 #define IN_MULTICAST(a)         IN_CLASSD(a)
848 #endif
849     
850     /* Bind it */
851     if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
852               sizeof( sock ) ) < 0 )
853     {
854         intf_ErrMsg( "input error: can't bind socket (%s)", strerror(errno) );
855         close( p_input->i_handle );
856         p_input->b_error = 1;
857         return;
858     }
859
860     /* Join the multicast group if the socket is a multicast address */
861     if( IN_MULTICAST( ntohl(i_mc_group) ) )
862     {
863         struct ip_mreq imr;
864
865         imr.imr_interface.s_addr = htonl(INADDR_ANY);
866         imr.imr_multiaddr.s_addr = i_mc_group;
867         if( setsockopt( p_input->i_handle, IPPROTO_IP, IP_ADD_MEMBERSHIP,
868                         (char*)&imr, sizeof(struct ip_mreq) ) == -1 )
869         {
870             intf_ErrMsg( "input error: failed to join IP multicast group (%s)",
871                          strerror(errno) );
872             close( p_input->i_handle);
873             p_input->b_error = 1;
874             return;
875         }
876     }
877
878     /* Build socket for remote connection */
879     if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
880     {
881         intf_ErrMsg( "input error: can't build remote address" );
882         close( p_input->i_handle );
883         p_input->b_error = 1;
884         return;
885     }
886
887     /* Only connect if the user has passed a valid host */
888     if( sock.sin_addr.s_addr != INADDR_ANY )
889     {
890         /* Connect the socket */
891         if( connect( p_input->i_handle, (struct sockaddr *) &sock,
892                      sizeof( sock ) ) == (-1) )
893         {
894             intf_ErrMsg( "input error: can't connect socket (%s)", 
895                          strerror(errno) );
896             close( p_input->i_handle );
897             p_input->b_error = 1;
898             return;
899         }
900     }
901
902     p_input->stream.b_pace_control = 0;
903     p_input->stream.b_seekable = 0;
904
905     intf_WarnMsg( 3, "input: successfully opened network mode" );
906     
907     return;
908 }
909
910 /*****************************************************************************
911  * NetworkClose : close a network socket
912  *****************************************************************************/
913 static void NetworkClose( input_thread_t * p_input )
914 {
915     close( p_input->i_handle );
916
917 #ifdef WIN32 
918     WSACleanup();
919 #endif
920 }
921
922 /*****************************************************************************
923  * HTTPOpen : make an HTTP request
924  *****************************************************************************/
925 static void HTTPOpen( input_thread_t * p_input )
926 {
927     char                *psz_server = NULL;
928     char                *psz_path = NULL;
929     char                *psz_proxy;
930     int                 i_port = 0;
931     int                 i_opt;
932     struct sockaddr_in  sock;
933     char                psz_buffer[256];
934
935 #ifdef WIN32
936     WSADATA Data;
937     int i_err;
938 #endif
939     
940 #ifdef WIN32
941     /* WinSock Library Init. */
942     i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );
943
944     if( i_err )
945     {
946         intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
947         return ;
948     }
949 #endif
950     
951     /* Get the remote server */
952     if( p_input->p_source != NULL )
953     {
954         psz_server = p_input->p_source;
955
956         /* Skip the protocol name */
957         while( *psz_server && *psz_server != ':' )
958         {
959             psz_server++;
960         }
961
962         /* Skip the "://" part */
963         while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
964         {
965             psz_server++;
966         }
967
968         /* Found a server name */
969         if( *psz_server )
970         {
971             char *psz_port = psz_server;
972
973             /* Skip the hostname part */
974             while( *psz_port && *psz_port != ':' && *psz_port != '/' )
975             {
976                 psz_port++;
977             }
978
979             /* Found a port name */
980             if( *psz_port )
981             {
982                 if( *psz_port == ':' )
983                 {
984                     /* Replace ':' with '\0' */
985                     *psz_port = '\0';
986                     psz_port++;
987                 }
988
989                 psz_path = psz_port;
990                 while( *psz_path && *psz_path != '/' )
991                 {
992                     psz_path++;
993                 }
994
995                 if( *psz_path )
996                 {
997                     *psz_path = '\0';
998                     psz_path++;
999                 }
1000                 else
1001                 {
1002                     psz_path = NULL;
1003                 }
1004
1005                 if( *psz_port != '\0' )
1006                 {
1007                     i_port = atoi( psz_port );
1008                 }
1009             }
1010         }
1011         else
1012         {
1013             psz_server = NULL;
1014         }
1015     }
1016
1017     /* Check that we got a valid server */
1018     if( psz_server == NULL )
1019     {
1020         intf_ErrMsg( "input error: No server given" );
1021         p_input->b_error = 1;
1022         return;
1023     }
1024
1025     /* Check that we got a valid port */
1026     if( i_port == 0 )
1027     {
1028         i_port = 80; /* FIXME */
1029     }
1030
1031     intf_WarnMsg( 2, "input: server=%s port=%d path=%s", psz_server,
1032                   i_port, psz_path );
1033
1034     /* Open a SOCK_STREAM (TCP) socket, in the AF_INET domain, automatic (0)
1035      *      * protocol */
1036     p_input->i_handle = socket( AF_INET, SOCK_STREAM, 0 );
1037     if( p_input->i_handle == -1 )
1038     {
1039         intf_ErrMsg( "input error: can't create socket (%s)", strerror(errno) );        p_input->b_error = 1;
1040         return;
1041     }
1042
1043     /* We may want to reuse an already used socket */
1044     i_opt = 1;
1045     if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
1046                     (void *) &i_opt, sizeof( i_opt ) ) == -1 )
1047     {
1048         intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
1049                      strerror(errno));
1050         close( p_input->i_handle );
1051         p_input->b_error = 1;
1052         return;
1053     }
1054
1055     /* Check proxy */
1056     if( (psz_proxy = main_GetPszVariable( "http_proxy", NULL )) != NULL )
1057     {
1058         /* http://myproxy.mydomain:myport/ */
1059         int                 i_proxy_port = 0;
1060
1061         /* Skip the protocol name */
1062         while( *psz_proxy && *psz_proxy != ':' )
1063         {
1064             psz_proxy++;
1065         }
1066
1067         /* Skip the "://" part */
1068         while( *psz_proxy && (*psz_proxy == ':' || *psz_proxy == '/') )
1069         {
1070             psz_proxy++;
1071         }
1072
1073         /* Found a proxy name */
1074         if( *psz_proxy )
1075         {
1076             char *psz_port = psz_proxy;
1077
1078             /* Skip the hostname part */
1079             while( *psz_port && *psz_port != ':' && *psz_port != '/' )
1080             {
1081                 psz_port++;
1082             }
1083
1084             /* Found a port name */
1085             if( *psz_port )
1086             {
1087                 char * psz_junk;
1088
1089                 /* Replace ':' with '\0' */
1090                 *psz_port = '\0';
1091                 psz_port++;
1092
1093                 psz_junk = psz_port;
1094                 while( *psz_junk && *psz_junk != '/' )
1095                 {
1096                     psz_junk++;
1097                 }
1098
1099                 if( *psz_junk )
1100                 {
1101                     *psz_junk = '\0';
1102                 }
1103
1104                 if( *psz_port != '\0' )
1105                 {
1106                     i_proxy_port = atoi( psz_port );
1107                 }
1108             }
1109         }
1110         else
1111         {
1112             intf_ErrMsg( "input error: http_proxy environment variable is invalid !" );
1113             close( p_input->i_handle );
1114             p_input->b_error = 1;
1115             return;
1116         }
1117
1118         /* Build socket for proxy connection */
1119         if ( network_BuildRemoteAddr( &sock, psz_proxy ) == -1 )
1120         {
1121             intf_ErrMsg( "input error: can't build remote address" );
1122             close( p_input->i_handle );
1123             p_input->b_error = 1;
1124             return;
1125         }
1126         sock.sin_port = htons( i_proxy_port );
1127     }
1128     else
1129     {
1130         /* No proxy, direct connection */
1131         if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
1132         {
1133             intf_ErrMsg( "input error: can't build remote address" );
1134             close( p_input->i_handle );
1135             p_input->b_error = 1;
1136             return;
1137         }
1138         sock.sin_port = htons( i_port );
1139     }
1140
1141     /* Connect the socket */
1142     if( connect( p_input->i_handle, (struct sockaddr *) &sock,
1143                  sizeof( sock ) ) == (-1) )
1144     {
1145         intf_ErrMsg( "input error: can't connect socket (%s)",
1146                      strerror(errno) );
1147         close( p_input->i_handle );
1148         p_input->b_error = 1;
1149         return;
1150     }
1151
1152     p_input->stream.b_seekable = 0;
1153     p_input->stream.b_pace_control = 1; /* TCP/IP... */
1154
1155     /* Prepare GET ... */
1156     if( psz_proxy != NULL )
1157     {
1158         snprintf( psz_buffer, sizeof(psz_buffer),
1159                   "GET http://%s:%d/%s HTTP/1.0\r\n\r\n", psz_server,
1160                   i_port, psz_path );
1161     }
1162     else
1163     {
1164         snprintf( psz_buffer, sizeof(psz_buffer), "GET /%s HTTP/1.0\r\n\r\n",
1165                   psz_path );
1166     }
1167     psz_buffer[sizeof(psz_buffer) - 1] = '\0';
1168
1169     /* Send GET ... */
1170     if( write( p_input->i_handle, psz_buffer, strlen( psz_buffer ) ) == (-1) )
1171     {
1172         intf_ErrMsg( "input error: can't send request (%s)", strerror(errno) );
1173         close( p_input->i_handle );
1174         p_input->b_error = 1;
1175         return;
1176     }
1177
1178     /* Read HTTP header - this is gonna be fun with plug-ins which do not
1179      * use p_input->p_stream :-( */
1180     if( (p_input->p_stream = fdopen( p_input->i_handle, "r+" )) == NULL )
1181     {
1182         intf_ErrMsg( "input error: can't reopen socket (%s)", strerror(errno) );
1183         close( p_input->i_handle );
1184         p_input->b_error = 1;
1185         return;
1186     }
1187
1188     while( !feof( p_input->p_stream ) && !ferror( p_input->p_stream ) )
1189     {
1190         if( fgets( psz_buffer, sizeof(psz_buffer), p_input->p_stream ) == NULL
1191              || *psz_buffer == '\r' || *psz_buffer == '\0' )
1192         {
1193             break;
1194         }
1195         /* FIXME : check Content-Type one day */
1196     }
1197
1198     intf_WarnMsg( 3, "input: successfully opened HTTP mode" );
1199 }
1200
1201 #endif /* !defined( SYS_BEOS ) && !defined( SYS_NTO ) */
1202