input.c 24.3 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.113 2001/05/30 17:03:12 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

Sam Hocevar's avatar
 
Sam Hocevar committed
93 94 95 96 97
static void FileOpen        ( input_thread_t *p_input );
static void FileClose       ( input_thread_t *p_input );
static void NetworkOpen     ( input_thread_t *p_input );
static void NetworkClose    ( input_thread_t *p_input );

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

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

120 121 122
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

123 124 125
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
126 127 128 129 130
    p_input->b_eof              = 0;

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

131
    /* I have never understood that stuff --Meuuh */
132 133
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
134

135
    /* Initialize stream description */
136 137
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
138
    p_input->stream.i_pgrm_number = 0;
139
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
140
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
141

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

151 152 153 154 155
    /* 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
156

Sam Hocevar's avatar
 
Sam Hocevar committed
157 158 159 160 161 162 163 164
    /* Setup callbacks */
    p_input->pf_file_open     = FileOpen;
    p_input->pf_file_close    = FileClose;
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
    p_input->pf_network_open  = NetworkOpen;
    p_input->pf_network_close = NetworkClose;
#endif

Michel Kaempf's avatar
Michel Kaempf committed
165
    /* Create thread and set locks. */
166
    vlc_mutex_init( &p_input->stream.stream_lock );
167
    vlc_cond_init( &p_input->stream.stream_wait );
168 169 170
    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
171
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
172 173
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
174 175 176
        free( p_input );
        return( NULL );
    }
177

178 179 180 181
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
182
        {
183
            msleep( THREAD_SLEEP );
184
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Sam Hocevar's avatar
 
Sam Hocevar committed
185
                && (i_status != THREAD_FATAL) );
186 187
        if( i_status != THREAD_READY )
        {
188 189
            return( NULL );
        }
190
    }
Michel Kaempf's avatar
Michel Kaempf committed
191 192 193
    return( p_input );
}

194
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
195
 * input_DestroyThread: mark an input thread as zombie
196
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
197
 * This function should not return until the thread is effectively cancelled.
198
 *****************************************************************************/
199
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
200
{
201
    int         i_status;                                   /* thread status */
202 203 204

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

207 208
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
209

210 211 212 213 214
    /* 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 );

215 216 217 218 219 220
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
221 222
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
223
    }
Michel Kaempf's avatar
Michel Kaempf committed
224 225
}

226
/*****************************************************************************
227
 * RunThread: main thread loop
228
 *****************************************************************************
229
 * Thread in charge of processing the network packets and demultiplexing.
230
 *****************************************************************************/
231
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
232
{
233
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
234

Sam Hocevar's avatar
 
Sam Hocevar committed
235 236 237 238 239 240 241 242 243 244
    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
245

246 247 248 249 250
    /* 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
251
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
252
    {
253
        data_packet_t *         pp_packets[p_input->i_read_once];
254

Sam Hocevar's avatar
 
Sam Hocevar committed
255
#ifdef STATS
Sam Hocevar's avatar
 
Sam Hocevar committed
256
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
257 258
#endif

259
        vlc_mutex_lock( &p_input->stream.stream_lock );
260

261 262 263 264 265 266
        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;
        }

267
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
268
        {
269 270
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
271 272
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
273 274 275 276 277 278 279 280 281 282 283 284 285

                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;
                }
            }
286
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
287
        }
288

289 290 291 292 293 294 295 296 297 298 299 300
        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;
        }

301
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
302 303

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

Sam Hocevar's avatar
 
Sam Hocevar committed
305
        /* Demultiplex read packets. */
306
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
 
Sam Hocevar committed
307 308 309
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
310

Sam Hocevar's avatar
 
Sam Hocevar committed
311 312 313
        if( i_error )
        {
            if( i_error == 1 )
314
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
315 316
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
317
                intf_WarnMsg( 3, "input: EOF reached" );
Sam Hocevar's avatar
 
Sam Hocevar committed
318
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
319
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
320
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
321
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
322
                p_input->b_error = 1;
323
            }
324 325 326
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
327
    if( p_input->b_error || p_input->b_eof )
328 329 330
    {
        ErrorThread( p_input );
    }
331

332
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
333 334 335

    DestroyThread( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
336
    intf_DbgMsg("input: Thread end");
337 338
}

339
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
340
 * InitThread: init the input Thread
341
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
342
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
343 344 345
{

#ifdef STATS
346 347 348 349 350 351
    /* 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
352
#endif
353

Sam Hocevar's avatar
 
Sam Hocevar committed
354
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
Sam Hocevar's avatar
 
Sam Hocevar committed
355
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
356 357

    if( p_input->p_input_module == NULL )
358
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
359 360
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
361
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
362
    }
363

Sam Hocevar's avatar
 
Sam Hocevar committed
364 365 366 367 368 369
#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;
370
    p_input->pf_set_area      = f.pf_set_area;
Sam Hocevar's avatar
 
Sam Hocevar committed
371 372 373 374 375 376 377 378 379
    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 );
380

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

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

391 392 393 394
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
395
        module_Unneed( p_input->p_input_module );
396 397 398
        return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
399
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
400 401

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
402 403
}

404
/*****************************************************************************
405
 * ErrorThread: RunThread() error loop
406
 *****************************************************************************
407
 * This function is called when an error occured during thread main's loop.
408
 *****************************************************************************/
409
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
410
{
411
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
412
    {
413 414
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
415 416 417
    }
}

418
/*****************************************************************************
419
 * EndThread: end the input thread
420
 *****************************************************************************/
421
static void EndThread( input_thread_t * p_input )
422
{
423
    int *       pi_status;                                  /* thread status */
424

425 426 427
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
428

Sam Hocevar's avatar
 
Sam Hocevar committed
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444
#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
445 446 447
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
448
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
449
    module_Unneed( p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
450

Sam Hocevar's avatar
 
Sam Hocevar committed
451 452 453 454 455 456 457 458 459 460 461
}

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

Henri Fallon's avatar
 
Henri Fallon committed
463 464
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
465
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
466
    
467
    /* Free input structure */
468
    free( p_input );
469

470 471
    /* Update status */
    *pi_status = THREAD_OVER;
472
}
473

474
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
475
 * FileOpen : open a file descriptor
476
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
477
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
478
{
479
    struct stat         stat_info;
Sam Hocevar's avatar
 
Sam Hocevar committed
480 481 482
    int                 i_stat;

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

Sam Hocevar's avatar
 
Sam Hocevar committed
484 485 486
    /* 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
487
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
488 489 490 491 492 493 494 495
        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
496
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
497
        else if( ( i_size > 5 )
Sam Hocevar's avatar
 
Sam Hocevar committed
498 499 500 501 502
                 && !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
503
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
504

Sam Hocevar's avatar
 
Sam Hocevar committed
505
        if( i_stat == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
506 507 508 509 510 511
        {
            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
512 513 514 515 516 517 518 519 520 521 522
    }

    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;
523
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
Sam Hocevar's avatar
 
Sam Hocevar committed
524
    }
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
525
    else if( S_ISFIFO(stat_info.st_mode)
Sam Hocevar's avatar
 
Sam Hocevar committed
526
#if !defined( SYS_BEOS ) && !defined( WIN32 )
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
527 528 529
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
530
    {
531
        p_input->stream.b_seekable = 0;
532
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
 
Benoit Steiner committed
533 534 535
    }
    else
    {
536
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
537
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
 
Sam Hocevar committed
538
                     psz_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
539 540 541
        p_input->b_error = 1;
        return;
    }
542

543
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
544 545
    vlc_mutex_unlock( &p_input->stream.stream_lock );

546
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
547
#ifndef WIN32
Sam Hocevar's avatar
 
Sam Hocevar committed
548
    if( (p_input->i_handle = open( psz_name,
Sam Hocevar's avatar
 
Sam Hocevar committed
549
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
550 551 552 553
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
554
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
555
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
 
Sam Hocevar committed
556 557
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
558 559 560
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
561 562

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
563
 * FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
564
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
565
static void FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
566
{
567
    intf_WarnMsg( 1, "input: closing file `%s'", p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
568
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
569

Sam Hocevar's avatar
 
Sam Hocevar committed
570
    return;
Stéphane Borel's avatar
Stéphane Borel committed
571
}
Sam Hocevar's avatar
 
Sam Hocevar committed
572

Henri Fallon's avatar
 
Henri Fallon committed
573

574
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
Henri Fallon's avatar
 
Henri Fallon committed
575
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
576
 * NetworkOpen : open a network socket 
Henri Fallon's avatar
 
Henri Fallon committed
577
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
578
static void NetworkOpen( input_thread_t * p_input )
Henri Fallon's avatar
 
Henri Fallon committed
579
{
Henri Fallon's avatar
 
Henri Fallon committed
580
    char                *psz_server = NULL;
581
    char                *psz_broadcast = NULL;
Henri Fallon's avatar
 
Henri Fallon committed
582
    int                 i_port = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
583 584
    int                 i_opt;
    struct sockaddr_in  sock;
585

Sam Hocevar's avatar
 
Sam Hocevar committed
586 587 588 589 590 591 592 593 594 595 596
#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
597 598
    
    /* Get the remote server */
Sam Hocevar's avatar
 
Sam Hocevar committed
599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632
    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++;

633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657
                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
658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674
            }
        }
        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
675
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
676
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
Henri Fallon's avatar
 
Henri Fallon committed
677
    }
678 679 680 681

    if( psz_broadcast == NULL )
    {
        /* Are we broadcasting ? */
682 683 684 685 686 687 688 689 690 691
        if( main_GetIntVariable( INPUT_BROADCAST_VAR,
                                 INPUT_BROADCAST_DEFAULT ) )
        {
            psz_broadcast = main_GetPszVariable( INPUT_BCAST_ADDR_VAR,
                                                 INPUT_BCAST_ADDR_DEFAULT );
        }
        else
        {
           psz_broadcast = NULL; 
        }
692 693 694 695 696
    }

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

Henri Fallon's avatar
 
Henri Fallon committed
697 698 699 700 701
    /* 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
702
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
703 704 705 706 707
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
708
    i_opt = 1;
Henri Fallon's avatar
 
Henri Fallon committed
709
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
Sam Hocevar's avatar
 
Sam Hocevar committed
710
                    &i_opt, sizeof( i_opt ) ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
711
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
712 713
        intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
                     strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
714 715 716 717 718 719 720
        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
721 722 723
    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
724
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
725 726
        intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
                     strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
727 728 729 730 731 732
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
733
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
734
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
735
        intf_ErrMsg( "input error: can't build local address" );
Henri Fallon's avatar
 
Henri Fallon committed
736 737 738 739 740 741
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
Sam Hocevar's avatar
 
Sam Hocevar committed
742 743
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
Henri Fallon's avatar
 
Henri Fallon committed
744
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
745
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
746 747 748 749 750 751
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
Sam Hocevar's avatar
 
Sam Hocevar committed
752
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
753
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
754
        intf_ErrMsg( "input error: can't build remote address" );
Henri Fallon's avatar
 
Henri Fallon committed
755 756 757 758 759 760
        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
761 762
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
Henri Fallon's avatar
 
Henri Fallon committed
763
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
764
        intf_ErrMsg( "input error: can't connect socket, %s", 
Henri Fallon's avatar
 
Henri Fallon committed
765
                     strerror(errno) );
Henri Fallon's avatar
 
Henri Fallon committed
766 767 768 769 770 771 772
        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
773
    p_input->stream.b_pace_control = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
774
    p_input->stream.b_seekable = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
775 776

    intf_WarnMsg( 3, "input: successfully opened network mode" );
Henri Fallon's avatar
 
Henri Fallon committed
777 778 779 780 781
    
    return;
}

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
782
 * NetworkClose : close a network socket
Henri Fallon's avatar
 
Henri Fallon committed
783
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
784
static void NetworkClose( input_thread_t * p_input )
Henri Fallon's avatar
 
Henri Fallon committed
785 786
{
    close( p_input->i_handle );
787

Sam Hocevar's avatar
 
Sam Hocevar committed
788 789 790
#ifdef WIN32 
    WSACleanup();
#endif
791

Henri Fallon's avatar
 
Henri Fallon committed
792
}
Sam Hocevar's avatar
 
Sam Hocevar committed
793
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
794