input.c 23.6 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
Sam Hocevar's avatar
 
Sam Hocevar committed
7
 * $Id: input.c,v 1.111 2001/05/28 04:23:52 sam 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

42 43 44 45 46 47 48
/* WinSock Includes */

#ifdef WIN32
#include <winsock2.h>
#endif


Henri Fallon's avatar
 
Henri Fallon committed
49 50
/* Network functions */

Sam Hocevar's avatar
 
Sam Hocevar committed
51 52
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
#include <netdb.h>                                            /* hostent ... */
Henri Fallon's avatar
 
Henri Fallon committed
53 54 55 56 57
#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
58
#endif
Henri Fallon's avatar
 
Henri Fallon committed
59

60 61 62 63
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
64
#include "config.h"
65 66
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
67
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
68
#include "netutils.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
69
#include "modules.h"
70

71
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
72
#include "intf_playlist.h"
73

74 75 76
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
77

78
#include "input.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
79 80 81
#include "interface.h"

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

Henri Fallon's avatar
 
Henri Fallon committed
83

84
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
85
 * Local prototypes
86
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
87 88 89 90 91
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
92

93
/*****************************************************************************
94
 * input_CreateThread: creates a new input thread
95
 *****************************************************************************
96 97 98 99
 * 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.
100
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
101
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
102
{
103 104 105
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

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

115 116 117
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

118 119 120
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
121 122 123 124 125
    p_input->b_eof              = 0;

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

126
    /* I have never understood that stuff --Meuuh */
127 128
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
129

130
    /* Initialize stream description */
131 132
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
133
    p_input->stream.i_pgrm_number = 0;
134
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
135
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
136

137
    /* no stream, no area */
Stéphane Borel's avatar
 
Stéphane Borel committed
138 139
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
140
    p_input->stream.p_selected_area = NULL;
141
    p_input->stream.p_new_area = NULL;
Stéphane Borel's avatar
 
Stéphane Borel committed
142 143
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
144
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
145

146 147 148 149 150
    /* 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
151 152

    /* Create thread and set locks. */
153
    vlc_mutex_init( &p_input->stream.stream_lock );
154
    vlc_cond_init( &p_input->stream.stream_wait );
155 156 157
    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
158
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
159 160
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
161 162 163
        free( p_input );
        return( NULL );
    }
164

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

181
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
182
 * input_DestroyThread: mark an input thread as zombie
183
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
184
 * This function should not return until the thread is effectively cancelled.
185
 *****************************************************************************/
186
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
187
{
188
    int         i_status;                                   /* thread status */
189 190 191

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

194 195
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
196

197 198 199 200 201
    /* 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 );

202 203 204 205 206 207
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
208 209
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
210
    }
Michel Kaempf's avatar
Michel Kaempf committed
211 212
}

213
/*****************************************************************************
214
 * RunThread: main thread loop
215
 *****************************************************************************
216
 * Thread in charge of processing the network packets and demultiplexing.
217
 *****************************************************************************/
218
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
219
{
220
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
221

Sam Hocevar's avatar
 
Sam Hocevar committed
222 223 224 225 226 227 228 229 230 231
    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
232

233 234 235 236 237
    /* 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
238
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
239
    {
240
        data_packet_t *         pp_packets[p_input->i_read_once];
241

Sam Hocevar's avatar
 
Sam Hocevar committed
242
#ifdef STATS
Sam Hocevar's avatar
 
Sam Hocevar committed
243
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
244 245
#endif

246
        vlc_mutex_lock( &p_input->stream.stream_lock );
247

248 249 250 251 252 253
        if( p_input->stream.p_new_area )
        {
            p_input->pf_set_area( p_input, p_input->stream.p_new_area );
            p_input->stream.p_new_area = NULL;
        }

254
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
255
        {
256 257
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
258 259
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
260 261 262 263 264 265 266 267 268 269 270 271 272

                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;
                }
            }
273
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
274
        }
275

276 277 278 279 280 281 282 283 284 285 286 287
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

        if( p_input->stream.p_newly_selected_es )
        {
            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
            p_input->stream.p_newly_selected_es = NULL;
        }

288
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
289 290

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

Sam Hocevar's avatar
 
Sam Hocevar committed
292
        /* Demultiplex read packets. */
293
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
294 295 296
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
297

Sam Hocevar's avatar
 
Sam Hocevar committed
298 299 300
        if( i_error )
        {
            if( i_error == 1 )
301
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
302 303
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
304
                intf_WarnMsg( 3, "input: EOF reached" );
Sam Hocevar's avatar
 
Sam Hocevar committed
305
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
306
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
307
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
308
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
309
                p_input->b_error = 1;
310
            }
311 312 313
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
314
    if( p_input->b_error || p_input->b_eof )
315 316 317
    {
        ErrorThread( p_input );
    }
318

319
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
320 321 322

    DestroyThread( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
323
    intf_DbgMsg("input: Thread end");
324 325
}

326
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
327
 * InitThread: init the input Thread
328
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
329
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
330 331 332
{

#ifdef STATS
333 334 335 336 337 338
    /* 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
339
#endif
340

Sam Hocevar's avatar
 
Sam Hocevar committed
341
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
Sam Hocevar's avatar
 
Sam Hocevar committed
342
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
343 344

    if( p_input->p_input_module == NULL )
345
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
346 347
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
348
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
349
    }
350

Sam Hocevar's avatar
 
Sam Hocevar committed
351 352 353 354 355 356
#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;
357
    p_input->pf_set_area      = f.pf_set_area;
Sam Hocevar's avatar
 
Sam Hocevar committed
358 359 360 361 362 363 364 365 366
    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 );
367

Sam Hocevar's avatar
 
Sam Hocevar committed
368
    if( p_input->b_error )
369
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
370 371
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
372
        module_Unneed( p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
373
        return( -1 );
374
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
375 376

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

378 379 380 381
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
382
        module_Unneed( p_input->p_input_module );
383 384 385
        return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
386
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
387 388

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
389 390
}

391
/*****************************************************************************
392
 * ErrorThread: RunThread() error loop
393
 *****************************************************************************
394
 * This function is called when an error occured during thread main's loop.
395
 *****************************************************************************/
396
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
397
{
398
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
399
    {
400 401
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
402 403 404
    }
}

405
/*****************************************************************************
406
 * EndThread: end the input thread
407
 *****************************************************************************/
408
static void EndThread( input_thread_t * p_input )
409
{
410
    int *       pi_status;                                  /* thread status */
411

412 413 414
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
415

Sam Hocevar's avatar
 
Sam Hocevar committed
416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431
#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
432 433 434
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
435
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
436
    module_Unneed( p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
437

Sam Hocevar's avatar
 
Sam Hocevar committed
438 439 440 441 442 443 444 445 446 447 448
}

/*****************************************************************************
 * 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
449

Henri Fallon's avatar
 
Henri Fallon committed
450 451
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
452
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
453
    
454
    /* Free input structure */
455
    free( p_input );
456

457 458
    /* Update status */
    *pi_status = THREAD_OVER;
459
}
460

461
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
462
 * input_FileOpen : open a file descriptor
463
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
464
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
465
{
466
    struct stat         stat_info;
Sam Hocevar's avatar
 
Sam Hocevar committed
467 468 469
    int                 i_stat;

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

Sam Hocevar's avatar
 
Sam Hocevar committed
471 472 473
    /* 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
474
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
475 476 477 478 479 480 481 482
        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
483
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
484
        else if( ( i_size > 5 )
Sam Hocevar's avatar
 
Sam Hocevar committed
485 486 487 488 489
                 && !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
490
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
491

Sam Hocevar's avatar
 
Sam Hocevar committed
492
        if( i_stat == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
493 494 495 496 497 498
        {
            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
499 500 501 502 503 504 505 506 507 508 509
    }

    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;
510
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
Sam Hocevar's avatar
 
Sam Hocevar committed
511
    }
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
512
    else if( S_ISFIFO(stat_info.st_mode)
Sam Hocevar's avatar
 
Sam Hocevar committed
513
#if !defined( SYS_BEOS ) && !defined( WIN32 )
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
514 515 516
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
517
    {
518
        p_input->stream.b_seekable = 0;
519
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
 
Benoit Steiner committed
520 521 522
    }
    else
    {
523
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
524
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
 
Sam Hocevar committed
525
                     psz_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
526 527 528
        p_input->b_error = 1;
        return;
    }
529

530
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
531 532
    vlc_mutex_unlock( &p_input->stream.stream_lock );

533
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
534
#ifndef WIN32
Sam Hocevar's avatar
 
Sam Hocevar committed
535
    if( (p_input->i_handle = open( psz_name,
Sam Hocevar's avatar
 
Sam Hocevar committed
536
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
537 538 539 540
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
541
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
542
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
 
Sam Hocevar committed
543 544
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
545 546 547
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
548 549

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
550
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
551
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
552
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
553
{
554
    intf_WarnMsg( 1, "input: closing file `%s'", p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
555
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
556

Sam Hocevar's avatar
 
Sam Hocevar committed
557
    return;
Stéphane Borel's avatar
Stéphane Borel committed
558
}
Sam Hocevar's avatar
 
Sam Hocevar committed
559

Henri Fallon's avatar
 
Henri Fallon committed
560

561
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
Henri Fallon's avatar
 
Henri Fallon committed
562
/*****************************************************************************
Henri Fallon's avatar
 
Henri Fallon committed
563
 * input_NetworkOpen : open a network socket 
Henri Fallon's avatar
 
Henri Fallon committed
564
 *****************************************************************************/
Henri Fallon's avatar
 
Henri Fallon committed
565
void input_NetworkOpen( input_thread_t * p_input )
Henri Fallon's avatar
 
Henri Fallon committed
566
{
Henri Fallon's avatar
 
Henri Fallon committed
567
    char                *psz_server = NULL;
568
    char                *psz_broadcast = NULL;
Henri Fallon's avatar
 
Henri Fallon committed
569
    int                 i_port = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
570 571
    int                 i_opt;
    struct sockaddr_in  sock;
572

Sam Hocevar's avatar
 
Sam Hocevar committed
573 574 575 576 577 578 579 580 581 582 583
#ifdef WIN32
    /* WinSock Library Init. */
    WSADATA Data;
    int i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );

    if( i_err )
    {
        intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
        return ;
    }
#endif
Henri Fallon's avatar
 
Henri Fallon committed
584 585
    
    /* Get the remote server */
Sam Hocevar's avatar
 
Sam Hocevar committed
586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619
    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++;

620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644
                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
645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661
            }
        }
        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
662
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
663
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
Henri Fallon's avatar
 
Henri Fallon committed
664
    }
665 666 667 668 669 670 671 672 673 674

    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
675 676 677 678 679
    /* 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
680
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
681 682 683 684 685
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
686
    i_opt = 1;
Henri Fallon's avatar
 
Henri Fallon committed
687
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
Sam Hocevar's avatar
 
Sam Hocevar committed
688
                    &i_opt, sizeof( i_opt ) ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
689
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
690 691
        intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
                     strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
692 693 694 695 696 697 698
        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
699 700 701
    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
702
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
703 704
        intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
                     strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
705 706 707 708 709 710
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
711
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
712
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
713
        intf_ErrMsg( "input error: can't build local address" );
Henri Fallon's avatar
 
Henri Fallon committed
714 715 716 717 718 719
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
Sam Hocevar's avatar
 
Sam Hocevar committed
720 721
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
Henri Fallon's avatar
 
Henri Fallon committed
722
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
723
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
724 725 726 727 728 729
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
Sam Hocevar's avatar
 
Sam Hocevar committed
730
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
731
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
732
        intf_ErrMsg( "input error: can't build remote address" );
Henri Fallon's avatar
 
Henri Fallon committed
733 734 735 736 737 738
        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
739 740
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
Henri Fallon's avatar
 
Henri Fallon committed
741
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
742
        intf_ErrMsg( "input error: can't connect socket, %s", 
Henri Fallon's avatar
 
Henri Fallon committed
743
                     strerror(errno) );
Henri Fallon's avatar
 
Henri Fallon committed
744 745 746 747 748 749 750
        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
751
    p_input->stream.b_pace_control = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
752
    p_input->stream.b_seekable = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
753 754

    intf_WarnMsg( 3, "input: successfully opened network mode" );
Henri Fallon's avatar
 
Henri Fallon committed
755 756 757 758 759 760 761 762 763 764
    
    return;
}

/*****************************************************************************
 * input_NetworkClose : close a network socket
 *****************************************************************************/
void input_NetworkClose( input_thread_t * p_input )
{
    close( p_input->i_handle );
765

Sam Hocevar's avatar
 
Sam Hocevar committed
766 767 768
#ifdef WIN32 
    WSACleanup();
#endif
769

Henri Fallon's avatar
 
Henri Fallon committed
770
}
Sam Hocevar's avatar
 
Sam Hocevar committed
771
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
772