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

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

31 32 33 34 35 36
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
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
/* Network functions */

44 45
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
#include <netdb.h>                                            /* hostent ... */
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>
51
#endif
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"
61
#include "netutils.h"
62
#include "modules.h"
63

64
#include "intf_msg.h"
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"
72 73 74
#include "interface.h"

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

76 77 78
 /* #include <netutils.h> */


79
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
80
 * Local prototypes
81
 *****************************************************************************/
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
 *****************************************************************************/
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
    {
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;
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 */
133 134
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
135
    p_input->stream.p_selected_area = NULL;
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];
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
    {
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)
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

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 );

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

236
#ifdef STATS
237
        p_input->c_loops++;
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 )
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;
262
        }
263

264
        vlc_mutex_unlock( &p_input->stream.stream_lock );
265 266

        i_error = p_input->pf_read( p_input, pp_packets );
267

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

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

290
    if( p_input->b_error || p_input->b_eof )
291 292 293
    {
        ErrorThread( p_input );
    }
294

295
    EndThread( p_input );
296 297 298

    DestroyThread( p_input );

299
    intf_DbgMsg("input: Thread end");
300 301
}

302
/*****************************************************************************
303
 * InitThread: init the input Thread
304
 *****************************************************************************/
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

317
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
318
                                           (probedata_t *)p_input );
319 320

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

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;
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

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

    p_input->pf_init( p_input );
353

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

362
    *p_input->pi_status = THREAD_READY;
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

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 );

408 409 410
    /* Close stream */
    p_input->pf_close( p_input );

411
    /* Release modules */
412
    module_Unneed( p_input->p_input_module );
413

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;
425

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

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

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

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

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) )
450
    {
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 );
459
        }
460
        else if( ( i_size > 5 )
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 );
466
        }
467

468
        if( i_stat == (-1) )
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;
        }
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;
487
    }
488
    else if( S_ISFIFO(stat_info.st_mode)
489
#if !defined( SYS_BEOS ) && !defined( WIN32 )
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 );
500
        intf_ErrMsg( "input error: unknown file type for `%s'",
501
                     psz_name );
502 503 504
        p_input->b_error = 1;
        return;
    }
505

506
    p_input->stream.p_selected_area->i_tell = 0;
507 508
    vlc_mutex_unlock( &p_input->stream.stream_lock );

509
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
510
#ifndef WIN32
511
    if( (p_input->i_handle = open( psz_name,
512
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
513 514 515 516
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
517
    {
518
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
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

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

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

536

537
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
538
/*****************************************************************************
539
 * input_NetworkOpen : open a network socket 
540
 *****************************************************************************/
541
void input_NetworkOpen( input_thread_t * p_input )
542
{
543
    char                *psz_server = NULL;
544
    char                *psz_broadcast = NULL;
545
    int                 i_port = 0;
546 547
    int                 i_opt;
    struct sockaddr_in  sock;
548 549
    
    /* Get the remote server */
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 );
                }
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 )
626
    {
627
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
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 );

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 )
    {
644
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
645 646 647 648 649
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
650
    i_opt = 1;
651
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
652
                    &i_opt, sizeof( i_opt ) ) == -1 )
653
    {
654
        intf_ErrMsg("input error: can't configure socket (SO_REUSEADDR: %s)",
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 */
663 664 665
    i_opt = 0x80000;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
                    &i_opt, sizeof( i_opt ) ) == -1 )
666
    {
667
        intf_ErrMsg("input error: can't configure socket (SO_RCVBUF: %s)", 
668 669 670 671 672 673 674
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

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

    /* Build socket for remote connection */
694
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
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 ? */
702 703
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
704
    {
705 706
        intf_ErrMsg( "NetworkOpen: can't connect socket : %s", 
                     strerror(errno) );
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. */
714
    p_input->stream.b_pace_control = 0;
715
    p_input->stream.b_seekable = 0;
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 );
}
727
#endif