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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    DestroyThread( p_input );

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

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

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

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

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

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

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

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

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

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

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

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

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

388 389 390
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
391

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

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

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

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

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

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

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

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

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

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

433 434
    /* Update status */
    *pi_status = THREAD_OVER;
435
}
436

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

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

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

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

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

    vlc_mutex_lock( &p_input->stream.stream_lock );

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

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

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

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

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

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

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

Henri Fallon's avatar
 
Henri Fallon committed
536

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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