input.c 24.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.114 2001/05/30 22:16:07 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 44 45 46 47 48
/* WinSock Includes */

#ifdef WIN32
#include <winsock2.h>
#endif


49 50
/* Network functions */

51 52
#if !defined( SYS_BEOS ) && !defined( SYS_NTO ) && !defined( WIN32 )
#include <netdb.h>                                            /* hostent ... */
53 54 55 56 57
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <sys/types.h>
#include <sys/socket.h>
58
#endif
59

60 61 62 63
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
64
#include "config.h"
65 66
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
67
#include "mtime.h"
68
#include "netutils.h"
69
#include "modules.h"
70

71
#include "intf_msg.h"
72
#include "intf_playlist.h"
73

74 75 76
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
77

78
#include "input.h"
79 80 81
#include "interface.h"

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

83

84
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
85
 * Local prototypes
86
 *****************************************************************************/
87 88 89 90 91
static void RunThread       ( input_thread_t *p_input );
static  int InitThread      ( input_thread_t *p_input );
static void ErrorThread     ( input_thread_t *p_input );
static void DestroyThread   ( input_thread_t *p_input );
static void EndThread       ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
92

93 94 95 96 97
static void FileOpen        ( input_thread_t *p_input );
static void FileClose       ( input_thread_t *p_input );
static void NetworkOpen     ( input_thread_t *p_input );
static void NetworkClose    ( input_thread_t *p_input );

98
/*****************************************************************************
99
 * input_CreateThread: creates a new input thread
100
 *****************************************************************************
101 102 103 104
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
 * If pi_status is NULL, then the function will block until the thread is ready.
 * If not, it will be updated using one of the THREAD_* constants.
105
 *****************************************************************************/
106
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
107
{
108 109 110
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

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

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

123 124 125
    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
126 127 128 129 130
    p_input->b_eof              = 0;

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

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

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

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

151 152 153 154 155
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
156

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

Michel Kaempf's avatar
Michel Kaempf committed
165
    /* Create thread and set locks. */
166
    vlc_mutex_init( &p_input->stream.stream_lock );
167
    vlc_cond_init( &p_input->stream.stream_wait );
168 169 170
    vlc_mutex_init( &p_input->stream.control.control_lock );
    if( vlc_thread_create( &p_input->thread_id, "input", (void *) RunThread,
                           (void *) p_input ) )
Michel Kaempf's avatar
Michel Kaempf committed
171
    {
172 173
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
174 175 176
        free( p_input );
        return( NULL );
    }
177

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

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

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

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

210 211 212 213 214
    /* Make the thread exit of an eventual vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );

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

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

235 236 237 238 239 240 241 242 243 244
    if( InitThread( p_input ) )
    {

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

246 247 248 249 250
    /* initialization is completed */
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_input->stream.b_changed = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

251
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
252
    {
253
        data_packet_t *         pp_packets[p_input->i_read_once];
254

255
#ifdef STATS
256
        p_input->c_loops++;
257 258
#endif

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

261 262 263 264 265 266
        if( p_input->stream.p_new_area )
        {
            p_input->pf_set_area( p_input, p_input->stream.p_new_area );
            p_input->stream.p_new_area = NULL;
        }

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

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

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
286
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
287
        }
288

289 290 291 292 293 294 295 296 297 298 299 300
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

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

301
        vlc_mutex_unlock( &p_input->stream.stream_lock );
302 303

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

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

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

327
    if( p_input->b_error || p_input->b_eof )
328 329 330
    {
        ErrorThread( p_input );
    }
331

332
    EndThread( p_input );
333 334 335

    DestroyThread( p_input );

336
    intf_DbgMsg("input: Thread end");
337 338
}

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

#ifdef STATS
346 347 348 349 350 351
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->c_bytes                    = 0;
    p_input->c_payload_bytes            = 0;
    p_input->c_packets_read             = 0;
    p_input->c_packets_trashed          = 0;
Michel Kaempf's avatar
Michel Kaempf committed
352
#endif
353

354 355 356 357
    /* Default, might get overwritten */
    p_input->pf_open = p_input->pf_file_open;
    p_input->pf_close = p_input->pf_file_close;

358
    p_input->p_input_module = module_Need( MODULE_CAPABILITY_INPUT,
359
                                           (probedata_t *)p_input );
360 361

    if( p_input->p_input_module == NULL )
362
    {
363 364
        intf_ErrMsg( "input error: no suitable input module for `%s'",
                     p_input->p_source );
365
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
366
    }
367

368 369
#define f p_input->p_input_module->p_functions->input.functions.input
    p_input->pf_init          = f.pf_init;
370 371 372 373 374 375 376 377
    if( f.pf_open != NULL )
    {
        p_input->pf_open          = f.pf_open;
    }
    if( f.pf_close != NULL )
    {
        p_input->pf_close         = f.pf_close;
    }
378 379
    p_input->pf_end           = f.pf_end;
    p_input->pf_read          = f.pf_read;
380
    p_input->pf_set_area      = f.pf_set_area;
381 382 383 384 385 386 387 388 389
    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 );
390

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

    p_input->pf_init( p_input );
400

401 402 403 404
    if( p_input->b_error )
    {
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
405
        module_Unneed( p_input->p_input_module );
406 407 408
        return( -1 );
    }

409
    *p_input->pi_status = THREAD_READY;
410 411

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
412 413
}

414
/*****************************************************************************
415
 * ErrorThread: RunThread() error loop
416
 *****************************************************************************
417
 * This function is called when an error occured during thread main's loop.
418
 *****************************************************************************/
419
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
420
{
421
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
422
    {
423 424
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
425 426 427
    }
}

428
/*****************************************************************************
429
 * EndThread: end the input thread
430
 *****************************************************************************/
431
static void EndThread( input_thread_t * p_input )
432
{
433
    int *       pi_status;                                  /* thread status */
434

435 436 437
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
438

439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454
#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 );

455 456 457
    /* Close stream */
    p_input->pf_close( p_input );

458
    /* Release modules */
459
    module_Unneed( p_input->p_input_module );
460

461 462 463 464 465 466 467 468 469 470 471
}

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

473 474
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
475
    vlc_mutex_destroy( &p_input->stream.stream_lock );
476
    
477
    /* Free input structure */
478
    free( p_input );
479

480 481
    /* Update status */
    *pi_status = THREAD_OVER;
482
}
483

484
/*****************************************************************************
485
 * FileOpen : open a file descriptor
486
 *****************************************************************************/
487
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
488
{
489
    struct stat         stat_info;
490 491 492
    int                 i_stat;

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

494 495 496
    /* 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) )
497
    {
498 499 500 501 502 503 504 505
        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 );
506
        }
507
        else if( ( i_size > 5 )
508 509 510 511 512
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
513
        }
514

515
        if( i_stat == (-1) )
516 517 518 519 520 521
        {
            intf_ErrMsg( "input error: cannot stat() file `%s' (%s)",
                         psz_name, strerror(errno));
            p_input->b_error = 1;
            return;
        }
522 523 524 525 526 527 528 529 530 531 532
    }

    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;
533
        p_input->stream.p_selected_area->i_size = stat_info.st_size;
534
    }
535
    else if( S_ISFIFO(stat_info.st_mode)
536
#if !defined( SYS_BEOS ) && !defined( WIN32 )
537 538 539
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
540
    {
541
        p_input->stream.b_seekable = 0;
542
        p_input->stream.p_selected_area->i_size = 0;
Benoit Steiner's avatar
Benoit Steiner committed
543 544 545
    }
    else
    {
546
        vlc_mutex_unlock( &p_input->stream.stream_lock );
547
        intf_ErrMsg( "input error: unknown file type for `%s'",
548
                     psz_name );
549 550 551
        p_input->b_error = 1;
        return;
    }
552

553
    p_input->stream.p_selected_area->i_tell = 0;
554 555
    vlc_mutex_unlock( &p_input->stream.stream_lock );

556
    intf_WarnMsg( 1, "input: opening file `%s'", p_input->p_source );
557
#ifndef WIN32
558
    if( (p_input->i_handle = open( psz_name,
559
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
560 561 562 563
#else
    if( (p_input->i_handle = open( psz_name, O_BINARY
                                   /*O_NONBLOCK | O_LARGEFILE*/ )) == (-1) )
#endif
564
    {
565
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
566 567
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
568 569 570
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
571 572

/*****************************************************************************
573
 * FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
574
 *****************************************************************************/
575
static void FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
576
{
577
    intf_WarnMsg( 1, "input: closing file `%s'", p_input->p_source );
578
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
579

580
    return;
Stéphane Borel's avatar
Stéphane Borel committed
581
}
582

583

584
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
585
/*****************************************************************************
586
 * NetworkOpen : open a network socket 
587
 *****************************************************************************/
588
static void NetworkOpen( input_thread_t * p_input )
589
{
590
    char                *psz_server = NULL;
591
    char                *psz_broadcast = NULL;
592
    int                 i_port = 0;
593 594
    int                 i_opt;
    struct sockaddr_in  sock;
595

596 597 598 599 600 601 602 603 604 605 606
#ifdef WIN32
    /* WinSock Library Init. */
    WSADATA Data;
    int i_err = WSAStartup( MAKEWORD( 1, 1 ), &Data );

    if( i_err )
    {
        intf_ErrMsg( "input: can't initiate WinSocks, error %i", i_err );
        return ;
    }
#endif
607 608
    
    /* Get the remote server */
609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642
    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++;

643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667
                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 );
                }
668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684
            }
        }
        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 )
685
    {
686
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
687
    }
688 689 690 691

    if( psz_broadcast == NULL )
    {
        /* Are we broadcasting ? */
692 693 694 695 696 697 698 699 700 701
        if( main_GetIntVariable( INPUT_BROADCAST_VAR,
                                 INPUT_BROADCAST_DEFAULT ) )
        {
            psz_broadcast = main_GetPszVariable( INPUT_BCAST_ADDR_VAR,
                                                 INPUT_BCAST_ADDR_DEFAULT );
        }
        else
        {
           psz_broadcast = NULL; 
        }
702 703 704 705 706
    }

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

707 708 709 710 711
    /* 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 )
    {
712
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
713 714 715 716 717
        p_input->b_error = 1;
        return;
    }

    /* We may want to reuse an already used socket */
718
    i_opt = 1;
719
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_REUSEADDR,
720
                    &i_opt, sizeof( i_opt ) ) == -1 )
721
    {
722 723
        intf_ErrMsg( "input error: can't configure socket (SO_REUSEADDR: %s)",
                     strerror(errno));
724 725 726 727 728 729 730
        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 */
731 732 733
    i_opt = 0x80000;
    if( setsockopt( p_input->i_handle, SOL_SOCKET, SO_RCVBUF,
                    &i_opt, sizeof( i_opt ) ) == -1 )
734
    {
735 736
        intf_ErrMsg( "input error: can't configure socket (SO_RCVBUF: %s)", 
                     strerror(errno));
737 738 739 740 741 742
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build the local socket */
743
    if ( network_BuildLocalAddr( &sock, i_port, psz_broadcast ) == -1 )
744
    {
745
        intf_ErrMsg( "input error: can't build local address" );
746 747 748 749 750 751
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
752 753
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
754
    {
755
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
756 757 758 759 760 761
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
762
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
763
    {
764
        intf_ErrMsg( "input error: can't build remote address" );
765 766 767 768 769 770
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* And connect it ... should we really connect ? */
771 772
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
773
    {
774
        intf_ErrMsg( "input error: can't connect socket, %s", 
775
                     strerror(errno) );
776 777 778 779 780 781 782
        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. */
783
    p_input->stream.b_pace_control = 0;
784
    p_input->stream.b_seekable = 0;
785 786

    intf_WarnMsg( 3, "input: successfully opened network mode" );
787 788 789 790 791
    
    return;
}

/*****************************************************************************
792
 * NetworkClose : close a network socket
793
 *****************************************************************************/
794
static void NetworkClose( input_thread_t * p_input )
795 796
{
    close( p_input->i_handle );
797

798 799 800
#ifdef WIN32 
    WSACleanup();
#endif
801

802
}
803
#endif
804