input.c 22.5 KB
Newer Older
1
2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3
4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5
6
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
7
 * $Id: input.c,v 1.107 2001/05/07 03:14:09 stef Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10
11
12
13
14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16
17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21
22
23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29
30
#include "defs.h"

31
32
33
34
35
36
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
37
38
39
#ifdef STRNCASECMP_IN_STRINGS_H
#   include <strings.h>
#endif
40
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
41

Henri Fallon's avatar
   
Henri Fallon committed
42
43
/* Network functions */

Sam Hocevar's avatar
   
Sam Hocevar committed
44
45
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
#include <netdb.h>                                            /* hostent ... */
Henri Fallon's avatar
   
Henri Fallon committed
46
47
48
49
50
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
51
#endif
Henri Fallon's avatar
   
Henri Fallon committed
52

53
54
55
56
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
57
#include "config.h"
58
59
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
60
#include "mtime.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
61
#include "netutils.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
62
#include "modules.h"
63

64
#include "intf_msg.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
65
#include "intf_playlist.h"
66

67
68
69
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,    
Michel Lespinasse committed
70

71
#include "input.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
72
73
74
#include "interface.h"

#include "main.h"
Michel Kaempf's avatar
Michel Kaempf committed
75

Henri Fallon's avatar
   
Henri Fallon committed
76
77
78
 /* #include <netutils.h> */


79
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
80
 * Local prototypes
81
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
82
83
84
85
86
static void RunThread       ( input_thread_t *p_input );
static  int InitThread      ( input_thread_t *p_input );
static void ErrorThread     ( input_thread_t *p_input );
static void DestroyThread   ( input_thread_t *p_input );
static void EndThread       ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
87

88
/*****************************************************************************
89
 * input_CreateThread: creates a new input thread
90
 *****************************************************************************
91
92
93
94
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, it will be updated using one of the THREAD_* constants.
95
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
96
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
97
{
98
99
100
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

101
102
103
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
104
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
105
106
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
107
108
        return( NULL );
    }
109

110
111
112
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

113
114
115
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
116
117
118
119
120
    p_input->b_eof              = 0;

    /* Set target */
    p_input->p_source           = p_item->psz_name;

121
    /* I have never understood that stuff --Meuuh */
122
123
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
124

125
    /* Initialize stream description */
126
127
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
128
    p_input->stream.i_pgrm_number = 0;
129
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
130
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
131

132
    /* no stream, no area */
Stéphane Borel's avatar
   
Stéphane Borel committed
133
134
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
135
    p_input->stream.p_selected_area = NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
136
137
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
138
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
139

140
141
142
143
144
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
145
146

    /* Create thread and set locks. */
147
    vlc_mutex_init( &p_input->stream.stream_lock );
148
    vlc_cond_init( &p_input->stream.stream_wait );
149
150
151
    vlc_mutex_init( &p_input->stream.control.control_lock );
    if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
                           (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
152
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
153
154
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
155
156
157
        free( p_input );
        return( NULL );
    }
158

159
160
161
162
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
163
        {
164
            msleep( THREAD_SLEEP );
165
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Sam Hocevar's avatar
   
Sam Hocevar committed
166
                && (i_status != THREAD_FATAL) );
167
168
        if( i_status != THREAD_READY )
        {
169
170
            return( NULL );
        }
171
    }
Michel Kaempf's avatar
Michel Kaempf committed
172
173
174
    return( p_input );
}

175
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
176
 * input_DestroyThread: mark an input thread as zombie
177
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
178
 * This function should not return until the thread is effectively cancelled.
179
 *****************************************************************************/
180
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
181
{
182
    int         i_status;                                   /* thread status */
183
184
185

    /* Set status */
    p_input->pi_status = (pi_status != NULL) ? pi_status : &i_status;
186
187
    *p_input->pi_status = THREAD_DESTROY;

188
189
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
190

191
192
193
194
195
    /* Make the thread exit of an eventual vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

196
197
198
199
200
201
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
202
203
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
204
    }
Michel Kaempf's avatar
Michel Kaempf committed
205
206
}

207
/*****************************************************************************
208
 * RunThread: main thread loop
209
 *****************************************************************************
210
 * Thread in charge of processing the network packets and demultiplexing.
211
 *****************************************************************************/
212
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
213
{
214
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
215

Sam Hocevar's avatar
   
Sam Hocevar committed
216
217
218
219
220
221
222
223
224
225
    if( InitThread( p_input ) )
    {

        /* If we failed, wait before we are killed, and exit */
        *p_input->pi_status = THREAD_ERROR;
        p_input->b_error = 1;
        ErrorThread( p_input );
        DestroyThread( p_input );
        return;
    }
Michel Kaempf's avatar
Michel Kaempf committed
226

227
228
229
230
231
    /* initialization is completed */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_input->stream.b_changed = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

Sam Hocevar's avatar
   
Sam Hocevar committed
232
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
233
    {
234
        data_packet_t *         pp_packets[p_input->i_read_once];
235

Sam Hocevar's avatar
   
Sam Hocevar committed
236
#ifdef STATS
Sam Hocevar's avatar
   
Sam Hocevar committed
237
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
238
239
#endif

240
        vlc_mutex_lock( &p_input->stream.stream_lock );
241

242
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
243
        {
244
245
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
246
247
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
248
249
250
251
252
253
254
255
256
257
258
259
260

                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];
                    /* Escape all decoders for the stream discontinuity they
                     * will encounter. */
                    input_EscapeDiscontinuity( p_input, p_pgrm );

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
261
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
262
        }
263

264
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
265
266

        i_error = p_input->pf_read( p_input, pp_packets );
Sam Hocevar's avatar
   
Sam Hocevar committed
267

Sam Hocevar's avatar
   
Sam Hocevar committed
268
        /* Demultiplex read packets. */
269
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
   
Sam Hocevar committed
270
271
272
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
273

Sam Hocevar's avatar
   
Sam Hocevar committed
274
275
276
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
277
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
278
279
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
280
                intf_WarnMsg( 3, "input: EOF reached" );
Sam Hocevar's avatar
   
Sam Hocevar committed
281
                p_input->b_eof = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
282
            }
Sam Hocevar's avatar
   
Sam Hocevar committed
283
            else
Sam Hocevar's avatar
   
Sam Hocevar committed
284
            {
Sam Hocevar's avatar
   
Sam Hocevar committed
285
                p_input->b_error = 1;
Sam Hocevar's avatar
Sam Hocevar committed
286
            }
287
288
289
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
290
    if( p_input->b_error || p_input->b_eof )
291
292
293
    {
        ErrorThread( p_input );
    }
294

295
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
296
297
298

    DestroyThread( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
299
    intf_DbgMsg("input: Thread end");
300
301
}

302
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
303
 * InitThread: init the input Thread
304
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
305
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
306
307
308
{

#ifdef STATS
309
310
311
312
313
314
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->c_bytes                    = 0;
    p_input->c_payload_bytes            = 0;
    p_input->c_packets_read             = 0;
    p_input->c_packets_trashed          = 0;
Michel Kaempf's avatar
Michel Kaempf committed
315
#endif
Sam Hocevar's avatar
Sam Hocevar committed
316

Sam Hocevar's avatar
   
Sam Hocevar committed
317
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
Sam Hocevar's avatar
   
Sam Hocevar committed
318
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
319
320

    if( p_input->p_input_module == NULL )
321
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
322
323
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
Sam Hocevar's avatar
   
Sam Hocevar committed
324
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
325
    }
326

Sam Hocevar's avatar
   
Sam Hocevar committed
327
328
329
330
331
332
#define f p_input->p_input_module->p_functions->input.functions.input
    p_input->pf_init          = f.pf_init;
    p_input->pf_open          = f.pf_open;
    p_input->pf_close         = f.pf_close;
    p_input->pf_end           = f.pf_end;
    p_input->pf_read          = f.pf_read;
333
    p_input->pf_set_area      = f.pf_set_area;
Sam Hocevar's avatar
   
Sam Hocevar committed
334
335
336
337
338
339
340
341
342
    p_input->pf_demux         = f.pf_demux;
    p_input->pf_new_packet    = f.pf_new_packet;
    p_input->pf_new_pes       = f.pf_new_pes;
    p_input->pf_delete_packet = f.pf_delete_packet;
    p_input->pf_delete_pes    = f.pf_delete_pes;
    p_input->pf_rewind        = f.pf_rewind;
    p_input->pf_seek          = f.pf_seek;
#undef f
    p_input->pf_open( p_input );
343

Sam Hocevar's avatar
   
Sam Hocevar committed
344
    if( p_input->b_error )
345
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
346
347
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
348
        module_Unneed( p_input->p_input_module );
Sam Hocevar's avatar
   
Sam Hocevar committed
349
        return( -1 );
350
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
351
352

    p_input->pf_init( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
353

354
355
356
357
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
358
        module_Unneed( p_input->p_input_module );
359
360
361
        return( -1 );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
362
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
   
Sam Hocevar committed
363
364

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
365
366
}

367
/*****************************************************************************
368
 * ErrorThread: RunThread() error loop
369
 *****************************************************************************
370
 * This function is called when an error occured during thread main's loop.
371
 *****************************************************************************/
372
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
373
{
374
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
375
    {
376
377
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
378
379
380
    }
}

381
/*****************************************************************************
382
 * EndThread: end the input thread
383
 *****************************************************************************/
384
static void EndThread( input_thread_t * p_input )
385
{
386
    int *       pi_status;                                  /* thread status */
387

388
389
390
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
391

Sam Hocevar's avatar
   
Sam Hocevar committed
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("input stats: cpu usage (user: %d, system: %d)",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }
#endif

    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

    /* Free demultiplexer's data */
    p_input->pf_end( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
408
409
410
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
411
    /* Release modules */
Sam Hocevar's avatar
   
Sam Hocevar committed
412
    module_Unneed( p_input->p_input_module );
Sam Hocevar's avatar
   
Sam Hocevar committed
413

Sam Hocevar's avatar
   
Sam Hocevar committed
414
415
416
417
418
419
420
421
422
423
424
}

/*****************************************************************************
 * DestroyThread: destroy the input thread
 *****************************************************************************/
static void DestroyThread( input_thread_t * p_input )
{
    int *       pi_status;                                  /* thread status */

    /* Store status */
    pi_status = p_input->pi_status;
Sam Hocevar's avatar
   
Sam Hocevar committed
425

Henri Fallon's avatar
   
Henri Fallon committed
426
427
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
   
Henri Fallon committed
428
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
   
Henri Fallon committed
429
    
430
    /* Free input structure */
431
    free( p_input );
432

433
434
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
435
}
436

Sam Hocevar's avatar
Sam Hocevar committed
437
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
438
 * input_FileOpen : open a file descriptor
Sam Hocevar's avatar
Sam Hocevar committed
439
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
440
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
441
{
442
    struct stat         stat_info;
Sam Hocevar's avatar
   
Sam Hocevar committed
443
444
445
    int                 i_stat;

    char *psz_name = p_input->p_source;
Michel Kaempf's avatar
Michel Kaempf committed
446

Sam Hocevar's avatar
   
Sam Hocevar committed
447
448
449
    /* FIXME: this code ought to be in the plugin so that code can
     * be shared with the *_Probe function */
    if( ( i_stat = stat( psz_name, &stat_info ) ) == (-1) )
Sam Hocevar's avatar
   
Sam Hocevar committed
450
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
451
452
453
454
455
456
457
458
        int i_size = strlen( psz_name );

        if( ( i_size > 4 )
            && !strncasecmp( psz_name, "dvd:", 4 ) )
        {
            /* get rid of the 'dvd:' stuff and try again */
            psz_name += 4;
            i_stat = stat( psz_name, &stat_info );
Henri Fallon's avatar
   
Henri Fallon committed
459
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
460
        else if( ( i_size > 5 )
Sam Hocevar's avatar
   
Sam Hocevar committed
461
462
463
464
465
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
Henri Fallon's avatar
   
Henri Fallon committed
466
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
467

Sam Hocevar's avatar
   
Sam Hocevar committed
468
        if( i_stat == (-1) )
Sam Hocevar's avatar
   
Sam Hocevar committed
469
470
471
472
473
474
        {
            intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
                         psz_name, strerror(errno));
            p_input->b_error = 1;
            return;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
475
476
477
478
479
480
481
482
483
484
485
    }

    vlc_mutex_lock( &p_input->stream.stream_lock );

    /* If we are here we can control the pace... */
    p_input->stream.b_pace_control = 1;

    if( S_ISREG(stat_info.st_mode) || S_ISCHR(stat_info.st_mode)
         || S_ISBLK(stat_info.st_mode) )
    {
        p_input->stream.b_seekable = 1;
486
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
Sam Hocevar's avatar
   
Sam Hocevar committed
487
    }
Jean-Marc Dressler's avatar
   
Jean-Marc Dressler committed
488
    else if( S_ISFIFO(stat_info.st_mode)
Sam Hocevar's avatar
   
Sam Hocevar committed
489
#if !defined( SYS_BEOS ) && !defined( WIN32 )
Jean-Marc Dressler's avatar
   
Jean-Marc Dressler committed
490
491
492
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
Sam Hocevar's avatar
Sam Hocevar committed
493
    {
494
        p_input->stream.b_seekable = 0;
495
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
   
Benoit Steiner committed
496
497
498
    }
    else
    {
499
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
500
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
   
Sam Hocevar committed
501
                     psz_name );
Sam Hocevar's avatar
   
Sam Hocevar committed
502
503
504
        p_input->b_error = 1;
        return;
    }
505

506
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
507
508
    vlc_mutex_unlock( &p_input->stream.stream_lock );

509
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
Sam Hocevar's avatar
   
Sam Hocevar committed
510
#ifndef WIN32
Sam Hocevar's avatar
   
Sam Hocevar committed
511
    if( (p_input->i_handle = open( psz_name,
Sam Hocevar's avatar
   
Sam Hocevar committed
512
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
Sam Hocevar's avatar
   
Sam Hocevar committed
513
514
515
516
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
517
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
518
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
   
Sam Hocevar committed
519
520
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
521
522
523
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
524
525

/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
526
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
527
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
528
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
529
{
530
    intf_WarnMsg( 1, "input: closing file `%s'", p_input->p_source );
Sam Hocevar's avatar
   
Sam Hocevar committed
531
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
532

Sam Hocevar's avatar
   
Sam Hocevar committed
533
    return;
Stéphane Borel's avatar
Stéphane Borel committed
534
}
Sam Hocevar's avatar
   
Sam Hocevar committed
535

Henri Fallon's avatar
   
Henri Fallon committed
536

Sam Hocevar's avatar
   
Sam Hocevar committed
537
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
Henri Fallon's avatar
   
Henri Fallon committed
538
/*****************************************************************************
Henri Fallon's avatar
   
Henri Fallon committed
539
 * input_NetworkOpen : open a network socket 
Henri Fallon's avatar
   
Henri Fallon committed
540
 *****************************************************************************/
Henri Fallon's avatar
   
Henri Fallon committed
541
void input_NetworkOpen( input_thread_t * p_input )
Henri Fallon's avatar
   
Henri Fallon committed
542
{
Henri Fallon's avatar
   
Henri Fallon committed
543
    char                *psz_server = NULL;
544
    char                *psz_broadcast = NULL;
Henri Fallon's avatar
   
Henri Fallon committed
545
    int                 i_port = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
546
547
    int                 i_opt;
    struct sockaddr_in  sock;
Henri Fallon's avatar
   
Henri Fallon committed
548
549
    
    /* Get the remote server */
Sam Hocevar's avatar
   
Sam Hocevar committed
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
    if( p_input->p_source != NULL )
    {
        psz_server = p_input->p_source;

        /* Skip the protocol name */
        while( *psz_server && *psz_server != ':' )
        {
            psz_server++;
        }

        /* Skip the "://" part */
        while( *psz_server && (*psz_server == ':' || *psz_server == '/') )
        {
            psz_server++;
        }

        /* Found a server name */
        if( *psz_server )
        {
            char *psz_port = psz_server;

            /* Skip the hostname part */
            while( *psz_port && *psz_port != ':' )
            {
                psz_port++;
            }

            /* Found a port name */
            if( *psz_port )
            {
                /* Replace ':' with '\0' */
                *psz_port = '\0';
                psz_port++;

584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
                psz_broadcast = psz_port;
                while( *psz_broadcast && *psz_broadcast != ':' )
                {
                    psz_broadcast++;
                }

                if( *psz_broadcast )
                {
                    *psz_broadcast = '\0';
                    psz_broadcast++;
                    while( *psz_broadcast && *psz_broadcast == ':' )
                    {
                        psz_broadcast++;
                    }
                }
                else
                {
                    psz_broadcast = NULL;
                }

                /* port before broadcast address */
                if( *psz_port != ':' )
                {
                    i_port = atoi( psz_port );
                }
Sam Hocevar's avatar
   
Sam Hocevar committed
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
            }
        }
        else
        {
            psz_server = NULL;
        }
    }

    /* Check that we got a valid server */
    if( psz_server == NULL )
    {
        psz_server = main_GetPszVariable( INPUT_SERVER_VAR, 
                                          INPUT_SERVER_DEFAULT );
    }

    /* Check that we got a valid port */
    if( i_port == 0 )
Henri Fallon's avatar
   
Henri Fallon committed
626
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
627
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
Henri Fallon's avatar
   
Henri Fallon committed
628
    }
629
630
631
632
633
634
635
636
637
638

    if( psz_broadcast == NULL )
    {
        /* Are we broadcasting ? */
        psz_broadcast = main_GetPszVariable( INPUT_BROADCAST_VAR, NULL );
    }

    intf_WarnMsg( 2, "input: server: %s port: %d broadcast: %s",
                     psz_server, i_port, psz_broadcast );

Henri Fallon's avatar
   
Henri Fallon committed
639
640
641
642
643
    /* Open a SOCK_DGRAM (UDP) socket, in the AF_INET domain, automatic (0)
     * protocol */
    p_input->i_handle = socket( AF_INET, SOCK_DGRAM, 0 );
    if( p_input->i_handle == -1 )
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
644
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
Henri Fallon's avatar
   
Henri Fallon committed
645
646
647
648
649
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
Sam Hocevar's avatar
   
Sam Hocevar committed
650
    i_opt = 1;
Henri Fallon's avatar
   
Henri Fallon committed
651
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
Sam Hocevar's avatar
   
Sam Hocevar committed
652
                    &i_opt, sizeof( i_opt ) ) == -1 )
Henri Fallon's avatar
   
Henri Fallon committed
653
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
654
        intf_ErrMsg("input error: can't configure socket (SO_REUSEADDR: %s)",
Henri Fallon's avatar
   
Henri Fallon committed
655
656
657
658
659
660
661
662
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Increase the receive buffer size to 1/2MB (8Mb/s during 1/2s) to avoid
     * packet loss caused by scheduling problems */
Sam Hocevar's avatar
   
Sam Hocevar committed
663
664
665
    i_opt = 0x80000;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
                    &i_opt, sizeof( i_opt ) ) == -1 )
Henri Fallon's avatar
   
Henri Fallon committed
666
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
667
        intf_ErrMsg("input error: can't configure socket (SO_RCVBUF: %s)", 
Henri Fallon's avatar
   
Henri Fallon committed
668
669
670
671
672
673
674
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
Henri Fallon's avatar
   
Henri Fallon committed
675
676
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) 
         == -1 )
Henri Fallon's avatar
   
Henri Fallon committed
677
678
679
680
681
682
683
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
Sam Hocevar's avatar
   
Sam Hocevar committed
684
685
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
Henri Fallon's avatar
   
Henri Fallon committed
686
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
687
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
Henri Fallon's avatar
   
Henri Fallon committed
688
689
690
691
692
693
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
Sam Hocevar's avatar
   
Sam Hocevar committed
694
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
Henri Fallon's avatar
   
Henri Fallon committed
695
696
697
698
699
700
701
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* And connect it ... should we really connect ? */
Sam Hocevar's avatar
   
Sam Hocevar committed
702
703
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
Henri Fallon's avatar
   
Henri Fallon committed
704
    {
Henri Fallon's avatar
   
Henri Fallon committed
705
706
        intf_ErrMsg( "NetworkOpen: can't connect socket : %s", 
                     strerror(errno) );
Henri Fallon's avatar
   
Henri Fallon committed
707
708
709
710
711
712
713
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR
     * with the server. */
Henri Fallon's avatar
   
Henri Fallon committed
714
    p_input->stream.b_pace_control = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
715
    p_input->stream.b_seekable = 0;
Henri Fallon's avatar
   
Henri Fallon committed
716
717
718
719
720
721
722
723
724
725
726
    
    return;
}

/*****************************************************************************
 * input_NetworkClose : close a network socket
 *****************************************************************************/
void input_NetworkClose( input_thread_t * p_input )
{
    close( p_input->i_handle );
}
Sam Hocevar's avatar
   
Sam Hocevar committed
727
#endif