input.c 23.1 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.109 2001/05/25 13:20:10 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>
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
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
78
 * Local prototypes
79
 *****************************************************************************/
80 81 82 83 84
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
85

86
/*****************************************************************************
87
 * input_CreateThread: creates a new input thread
88
 *****************************************************************************
89 90 91 92
 * 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.
93
 *****************************************************************************/
94
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
95
{
96 97 98
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

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

108 109 110
    /* Packets read once */
    p_input->i_read_once = INPUT_READ_ONCE;

111 112 113
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
114 115 116 117 118
    p_input->b_eof              = 0;

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

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

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

130
    /* no stream, no area */
131 132
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
133
    p_input->stream.p_selected_area = NULL;
134
    p_input->stream.p_new_area = NULL;
135 136
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
137
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
138

139 140 141 142 143
    /* 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
144 145

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

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

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

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

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

190 191 192 193 194
    /* 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 );

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

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

215 216 217 218 219 220 221 222 223 224
    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
225

226 227 228 229 230
    /* 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 );

231
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
232
    {
233
        data_packet_t *         pp_packets[p_input->i_read_once];
234

235
#ifdef STATS
236
        p_input->c_loops++;
237 238
#endif

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

241 242 243 244 245 246
        if( p_input->stream.p_new_area )
        {
            p_input->pf_set_area( p_input, p_input->stream.p_new_area );
            p_input->stream.p_new_area = NULL;
        }

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

                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;
                }
            }
266
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
267
        }
268

269 270 271 272 273 274 275 276 277 278 279 280
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

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

281
        vlc_mutex_unlock( &p_input->stream.stream_lock );
282 283

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

285
        /* Demultiplex read packets. */
286
        for( i = 0; i < p_input->i_read_once && pp_packets[i] != NULL; i++ )
287 288 289
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
290

291 292 293
        if( i_error )
        {
            if( i_error == 1 )
294
            {
295 296
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
297
                intf_WarnMsg( 3, "input: EOF reached" );
298
                p_input->b_eof = 1;
299
            }
300
            else
301
            {
302
                p_input->b_error = 1;
303
            }
304 305 306
        }
    }

307
    if( p_input->b_error || p_input->b_eof )
308 309 310
    {
        ErrorThread( p_input );
    }
311

312
    EndThread( p_input );
313 314 315

    DestroyThread( p_input );

316
    intf_DbgMsg("input: Thread end");
317 318
}

319
/*****************************************************************************
320
 * InitThread: init the input Thread
321
 *****************************************************************************/
322
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
323 324 325
{

#ifdef STATS
326 327 328 329 330 331
    /* 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
332
#endif
333

334
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
335
                                           (probedata_t *)p_input );
336 337

    if( p_input->p_input_module == NULL )
338
    {
339 340
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
341
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
342
    }
343

344 345 346 347 348 349
#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;
350
    p_input->pf_set_area      = f.pf_set_area;
351 352 353 354 355 356 357 358 359
    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 );
360

361
    if( p_input->b_error )
362
    {
363 364
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
365
        module_Unneed( p_input->p_input_module );
366
        return( -1 );
367
    }
368 369

    p_input->pf_init( p_input );
370

371 372 373 374
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
375
        module_Unneed( p_input->p_input_module );
376 377 378
        return( -1 );
    }

379
    *p_input->pi_status = THREAD_READY;
380 381

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
382 383
}

384
/*****************************************************************************
385
 * ErrorThread: RunThread() error loop
386
 *****************************************************************************
387
 * This function is called when an error occured during thread main's loop.
388
 *****************************************************************************/
389
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
390
{
391
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
392
    {
393 394
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
395 396 397
    }
}

398
/*****************************************************************************
399
 * EndThread: end the input thread
400
 *****************************************************************************/
401
static void EndThread( input_thread_t * p_input )
402
{
403
    int *       pi_status;                                  /* thread status */
404

405 406 407
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
408

409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424
#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 );

425 426 427
    /* Close stream */
    p_input->pf_close( p_input );

428
    /* Release modules */
429
    module_Unneed( p_input->p_input_module );
430

431 432 433 434 435 436 437 438 439 440 441
}

/*****************************************************************************
 * 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;
442

443 444
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
445
    vlc_mutex_destroy( &p_input->stream.stream_lock );
446
    
447
    /* Free input structure */
448
    free( p_input );
449

450 451
    /* Update status */
    *pi_status = THREAD_OVER;
452
}
453

454
/*****************************************************************************
455
 * input_FileOpen : open a file descriptor
456
 *****************************************************************************/
457
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
458
{
459
    struct stat         stat_info;
460 461 462
    int                 i_stat;

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

464 465 466
    /* 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) )
467
    {
468 469 470 471 472 473 474 475
        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 );
476
        }
477
        else if( ( i_size > 5 )
478 479 480 481 482
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
483
        }
484

485
        if( i_stat == (-1) )
486 487 488 489 490 491
        {
            intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
                         psz_name, strerror(errno));
            p_input->b_error = 1;
            return;
        }
492 493 494 495 496 497 498 499 500 501 502
    }

    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;
503
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
504
    }
505
    else if( S_ISFIFO(stat_info.st_mode)
506
#if !defined( SYS_BEOS ) && !defined( WIN32 )
507 508 509
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
510
    {
511
        p_input->stream.b_seekable = 0;
512
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
Benoit Steiner committed
513 514 515
    }
    else
    {
516
        vlc_mutex_unlock( &p_input->stream.stream_lock );
517
        intf_ErrMsg( "input error: unknown file type for `%s'",
518
                     psz_name );
519 520 521
        p_input->b_error = 1;
        return;
    }
522

523
    p_input->stream.p_selected_area->i_tell = 0;
524 525
    vlc_mutex_unlock( &p_input->stream.stream_lock );

526
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
527
#ifndef WIN32
528
    if( (p_input->i_handle = open( psz_name,
529
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
530 531 532 533
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
534
    {
535
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
536 537
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
538 539 540
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
541 542

/*****************************************************************************
543
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
544
 *****************************************************************************/
545
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
546
{
547
    intf_WarnMsg( 1, "input: closing file `%s'", p_input->p_source );
548
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
549

550
    return;
Stéphane Borel's avatar
Stéphane Borel committed
551
}
552

553

554
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
555
/*****************************************************************************
556
 * input_NetworkOpen : open a network socket 
557
 *****************************************************************************/
558
void input_NetworkOpen( input_thread_t * p_input )
559
{
560
    char                *psz_server = NULL;
561
    char                *psz_broadcast = NULL;
562
    int                 i_port = 0;
563 564
    int                 i_opt;
    struct sockaddr_in  sock;
565 566
    
    /* Get the remote server */
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
    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++;

601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625
                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 );
                }
626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
            }
        }
        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 )
643
    {
644
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
645
    }
646 647 648 649 650 651 652 653 654 655

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

656 657 658 659 660
    /* 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 )
    {
661
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
662 663 664 665 666
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
667
    i_opt = 1;
668
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
669
                    &i_opt, sizeof( i_opt ) ) == -1 )
670
    {
671
        intf_ErrMsg("input error: can't configure socket (SO_REUSEADDR: %s)",
672 673 674 675 676 677 678 679
                    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 */
680 681 682
    i_opt = 0x80000;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
                    &i_opt, sizeof( i_opt ) ) == -1 )
683
    {
684
        intf_ErrMsg("input error: can't configure socket (SO_RCVBUF: %s)", 
685 686 687 688 689 690 691
                    strerror(errno));
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
692 693
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) 
         == -1 )
694 695 696 697 698 699 700
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
701 702
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
703
    {
704
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
705 706 707 708 709 710
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
711
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
712 713 714 715 716 717 718
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* And connect it ... should we really connect ? */
719 720
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
721
    {
722 723
        intf_ErrMsg( "NetworkOpen: can't connect socket : %s", 
                     strerror(errno) );
724 725 726 727 728 729 730
        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. */
731
    p_input->stream.b_pace_control = 0;
732
    p_input->stream.b_seekable = 0;
733 734 735 736 737 738 739 740 741 742 743
    
    return;
}

/*****************************************************************************
 * input_NetworkClose : close a network socket
 *****************************************************************************/
void input_NetworkClose( input_thread_t * p_input )
{
    close( p_input->i_handle );
}
744
#endif