input.c 21.9 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.102 2001/04/28 03:36:25 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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
146 147
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout = p_main->p_aout;
Sam Hocevar's avatar
 
Sam Hocevar committed
148
    p_input->p_default_vout = p_main->p_vout;
Sam Hocevar's avatar
 
Sam Hocevar committed
149

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

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

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

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

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

195 196 197 198 199
    /* 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 );

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

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

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

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

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

244
        vlc_mutex_lock( &p_input->stream.stream_lock );
245

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

                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;
                }
            }
265
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
266
        }
267

268
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
269 270

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
294
    if( p_input->b_error || p_input->b_eof )
295 296 297
    {
        ErrorThread( p_input );
    }
298

299
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
300 301 302

    DestroyThread( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
303
    intf_DbgMsg("input: Thread end");
304 305
}

306
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
307
 * InitThread: init the input Thread
308
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
309
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
310 311 312
{

#ifdef STATS
313 314 315 316 317 318
    /* 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
319
#endif
320

Sam Hocevar's avatar
 
Sam Hocevar committed
321
    p_input->p_input_module = module_Need( p_main->p_bank,
Sam Hocevar's avatar
 
Sam Hocevar committed
322 323
                                           MODULE_CAPABILITY_INPUT,
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
324 325

    if( p_input->p_input_module == NULL )
326
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
327 328
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
329
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
330
    }
331

Sam Hocevar's avatar
 
Sam Hocevar committed
332 333 334 335 336 337
#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;
338
    p_input->pf_set_area      = f.pf_set_area;
Sam Hocevar's avatar
 
Sam Hocevar committed
339 340 341 342 343 344 345 346 347
    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 );
348

Sam Hocevar's avatar
 
Sam Hocevar committed
349
    if( p_input->b_error )
350
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
351 352
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
353
        module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
354
        return( -1 );
355
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
356 357

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

359 360 361 362 363 364 365 366
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
        module_Unneed( p_main->p_bank, p_input->p_input_module );
        return( -1 );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
367
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
368 369

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
370 371
}

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

386
/*****************************************************************************
387
 * EndThread: end the input thread
388
 *****************************************************************************/
389
static void EndThread( input_thread_t * p_input )
390
{
391
    int *       pi_status;                                  /* thread status */
392

393 394 395
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
396

Sam Hocevar's avatar
 
Sam Hocevar committed
397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412
#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
413 414 415
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
416
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
417
    module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
418

Sam Hocevar's avatar
 
Sam Hocevar committed
419 420 421 422 423 424 425 426 427 428 429
}

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

Henri Fallon's avatar
 
Henri Fallon committed
431 432
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
433
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
434
    
435
    /* Free input structure */
436
    free( p_input );
437

438 439
    /* Update status */
    *pi_status = THREAD_OVER;
440
}
441

442
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
443
 * input_FileOpen : open a file descriptor
444
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
445
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
446
{
447
    struct stat         stat_info;
Sam Hocevar's avatar
 
Sam Hocevar committed
448 449 450
    int                 i_stat;

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

Sam Hocevar's avatar
 
Sam Hocevar committed
452 453 454
    /* 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
455
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
456 457 458 459 460 461 462 463
        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
464
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
465
        else if( ( i_size > 5 )
Sam Hocevar's avatar
 
Sam Hocevar committed
466 467 468 469 470
                 && !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
471
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
472

Sam Hocevar's avatar
 
Sam Hocevar committed
473
        if( i_stat == (-1) )
Sam Hocevar's avatar
 
Sam Hocevar committed
474 475 476 477 478 479
        {
            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
480 481 482 483 484 485 486 487 488 489 490
    }

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

511
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
512 513
    vlc_mutex_unlock( &p_input->stream.stream_lock );

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

}
Stéphane Borel's avatar
Stéphane Borel committed
529 530

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
531
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
532
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
533
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
534
{
Sam Hocevar's avatar
 
Sam Hocevar committed
535
    intf_Msg( "input: closing file `%s'", p_input->p_source );
Sam Hocevar's avatar
 
Sam Hocevar committed
536
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
537

Sam Hocevar's avatar
 
Sam Hocevar committed
538
    return;
Stéphane Borel's avatar
Stéphane Borel committed
539
}
Sam Hocevar's avatar
 
Sam Hocevar committed
540

Henri Fallon's avatar
 
Henri Fallon committed
541

Sam Hocevar's avatar
 
Sam Hocevar committed
542
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
Henri Fallon's avatar
 
Henri Fallon committed
543
/*****************************************************************************
Henri Fallon's avatar
 
Henri Fallon committed
544
 * input_NetworkOpen : open a network socket 
Henri Fallon's avatar
 
Henri Fallon committed
545
 *****************************************************************************/
Henri Fallon's avatar
 
Henri Fallon committed
546
void input_NetworkOpen( input_thread_t * p_input )
Henri Fallon's avatar
 
Henri Fallon committed
547
{
Henri Fallon's avatar
 
Henri Fallon committed
548 549
    char                *psz_server = NULL;
    int                 i_port = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
550 551
    int                 i_opt;
    struct sockaddr_in  sock;
Henri Fallon's avatar
 
Henri Fallon committed
552 553 554 555
    char *              psz_broadcast;
    
    /* Are we broadcasting ? */
    psz_broadcast = main_GetPszVariable( INPUT_BROADCAST_VAR, NULL );
Henri Fallon's avatar
 
Henri Fallon committed
556 557
    
    /* Get the remote server */
Sam Hocevar's avatar
 
Sam Hocevar committed
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 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 609
    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++;

                i_port = atoi( psz_port );
            }
        }
        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
610
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
611
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
Henri Fallon's avatar
 
Henri Fallon committed
612 613 614 615 616 617 618
    }
    
    /* 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
619
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
620 621 622 623 624
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
625
    i_opt = 1;
Henri Fallon's avatar
 
Henri Fallon committed
626
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
Sam Hocevar's avatar
 
Sam Hocevar committed
627
                    &i_opt, sizeof( i_opt ) ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
628
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
629
        intf_ErrMsg("input error: can't configure socket (SO_REUSEADDR: %s)",
Henri Fallon's avatar
 
Henri Fallon committed
630 631 632 633 634 635 636 637
                    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
638 639 640
    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
641
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
642
        intf_ErrMsg("input error: can't configure socket (SO_RCVBUF: %s)", 
Henri Fallon's avatar
 
Henri Fallon committed
643 644 645 646 647 648 649
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
Henri Fallon's avatar
 
Henri Fallon committed
650 651
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) 
         == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
652 653 654 655 656 657 658
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
Sam Hocevar's avatar
 
Sam Hocevar committed
659 660
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
Henri Fallon's avatar
 
Henri Fallon committed
661
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
662
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
663 664 665 666 667 668
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
Sam Hocevar's avatar
 
Sam Hocevar committed
669
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
670 671 672 673 674 675 676
    {
        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
677 678
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
Henri Fallon's avatar
 
Henri Fallon committed
679
    {
Henri Fallon's avatar
 
Henri Fallon committed
680 681
        intf_ErrMsg( "NetworkOpen: can't connect socket : %s", 
                     strerror(errno) );
Henri Fallon's avatar
 
Henri Fallon committed
682 683 684 685 686 687 688 689
        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. */
    p_input->stream.b_pace_control = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
690
    p_input->stream.b_seekable = 0;
Henri Fallon's avatar
 
Henri Fallon committed
691 692 693 694 695 696 697 698 699 700 701
    
    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
702
#endif