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