input.c 21.6 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3 4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5 6
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
Sam Hocevar's avatar
 
Sam Hocevar committed
7
 * $Id: input.c,v 1.100 2001/04/27 16:08:26 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 37
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
38

Henri Fallon's avatar
 
Henri Fallon committed
39 40
/* Network functions */

Sam Hocevar's avatar
 
Sam Hocevar committed
41
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
Henri Fallon's avatar
 
Henri Fallon committed
42 43 44 45 46 47
#include <netdb.h>                                             /* hostent ... */
#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
48
#endif
Henri Fallon's avatar
 
Henri Fallon committed
49

50 51 52 53
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
54
#include "config.h"
55 56
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
57
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
58
#include "netutils.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
59
#include "modules.h"
60

61
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
62
#include "intf_playlist.h"
63

64 65 66
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
67

68
#include "input.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
69 70 71
#include "interface.h"

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

Henri Fallon's avatar
 
Henri Fallon committed
73 74 75
 /* #include <netutils.h> */


76
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
77
 * Local prototypes
78
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
79 80 81 82 83
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
84

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

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

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

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

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

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

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

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

137 138 139 140 141
    /* 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
142

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

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

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

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

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

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

192 193 194 195 196
    /* 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 );

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
217 218 219 220 221 222 223 224 225 226
    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
227

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

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

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

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

                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;
                }
            }
262
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
263
        }
264

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
275 276 277
        if( i_error )
        {
            if( i_error == 1 )
278
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
279 280
                /* 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
281
                intf_WarnMsg( 1, "input: EOF reached" );
Sam Hocevar's avatar
 
Sam Hocevar committed
282
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
283
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
284
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
285
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
286
                p_input->b_error = 1;
287
            }
288 289 290
        }
    }

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

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

    DestroyThread( p_input );

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

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

#ifdef STATS
310 311 312 313 314 315
    /* 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
316
#endif
317

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

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

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
364
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
365 366

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
367 368
}

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

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

390 391 392
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
393

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

Sam Hocevar's avatar
 
Sam Hocevar committed
413
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
414
    module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
415

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

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

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

435 436
    /* Update status */
    *pi_status = THREAD_OVER;
437
}
438

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

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

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

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

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

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

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

}
Stéphane Borel's avatar
Stéphane Borel committed
521 522

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

Sam Hocevar's avatar
 
Sam Hocevar committed
530
    return;
Stéphane Borel's avatar
Stéphane Borel committed
531
}
Sam Hocevar's avatar
 
Sam Hocevar committed
532

Henri Fallon's avatar
 
Henri Fallon committed
533

Sam Hocevar's avatar
 
Sam Hocevar committed
534
#if !defined( SYS_BEOS ) && !defined( SYS_NTO )
Henri Fallon's avatar
 
Henri Fallon committed
535
/*****************************************************************************
Henri Fallon's avatar
 
Henri Fallon committed
536
 * input_NetworkOpen : open a network socket 
Henri Fallon's avatar
 
Henri Fallon committed
537
 *****************************************************************************/
Henri Fallon's avatar
 
Henri Fallon committed
538
void input_NetworkOpen( input_thread_t * p_input )
Henri Fallon's avatar
 
Henri Fallon committed
539
{
Sam Hocevar's avatar
 
Sam Hocevar committed
540 541 542 543 544
    char *psz_server = NULL;
    int   i_port = 0;

    int                 i_opt;
    struct sockaddr_in  sock;
Henri Fallon's avatar
 
Henri Fallon committed
545
    boolean_t           b_broadcast;
Henri Fallon's avatar
 
Henri Fallon committed
546 547
    
    /* Get the remote server */
Sam Hocevar's avatar
 
Sam Hocevar committed
548 549 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 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599
    if( p_input->p_source != NULL )
    {
        psz_server = p_input->p_source;

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

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

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

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

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

                i_port = atoi( psz_port );
            }
        }
        else
        {
            psz_server = NULL;
        }
    }

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

    /* Check that we got a valid port */
    if( i_port == 0 )
Henri Fallon's avatar
 
Henri Fallon committed
600
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
601
        i_port = main_GetIntVariable( INPUT_PORT_VAR, INPUT_PORT_DEFAULT );
Henri Fallon's avatar
 
Henri Fallon committed
602 603 604 605 606 607 608
    }
    
    /* 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
609
        intf_ErrMsg("input error: can't create socket : %s", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
610 611 612 613 614
        p_input->b_error = 1;
        return;
    }

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

    /* Get details about what we are supposed to do */
    b_broadcast = (boolean_t)main_GetIntVariable( INPUT_BROADCAST_VAR, 0 );

Sam Hocevar's avatar
 
Sam Hocevar committed
642
    /* TODO : here deal with channel stuff */
Henri Fallon's avatar
 
Henri Fallon committed
643
    
Henri Fallon's avatar
 
Henri Fallon committed
644
    /* Build the local socket */
Sam Hocevar's avatar
 
Sam Hocevar committed
645
    if ( network_BuildLocalAddr( &sock, i_port, b_broadcast ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
646 647 648 649 650 651 652
    {
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }
    
    /* Bind it */
Sam Hocevar's avatar
 
Sam Hocevar committed
653 654
    if( bind( p_input->i_handle, (struct sockaddr *)&sock, 
              sizeof( sock ) ) < 0 )
Henri Fallon's avatar
 
Henri Fallon committed
655
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
656
        intf_ErrMsg("input error: can't bind socket (%s)", strerror(errno));
Henri Fallon's avatar
 
Henri Fallon committed
657 658 659 660 661 662
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* Build socket for remote connection */
Sam Hocevar's avatar
 
Sam Hocevar committed
663
    if ( network_BuildRemoteAddr( &sock, psz_server ) == -1 )
Henri Fallon's avatar
 
Henri Fallon committed
664 665 666 667 668 669 670
    {
        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
671 672
    if( connect( p_input->i_handle, (struct sockaddr *) &sock,
                 sizeof( sock ) ) == (-1) )
Henri Fallon's avatar
 
Henri Fallon committed
673
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
674
        intf_ErrMsg("input error: can't connect socket" );
Henri Fallon's avatar
 
Henri Fallon committed
675 676 677 678 679 680 681 682
        close( p_input->i_handle );
        p_input->b_error = 1;
        return;
    }

    /* We can't pace control, but FIXME : bug in meuuh's code to sync PCR
     * with the server. */
    p_input->stream.b_pace_control = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
683
    p_input->stream.b_seekable = 0;
Henri Fallon's avatar
 
Henri Fallon committed
684 685 686 687 688 689 690 691 692 693 694 695
    
    return;
}

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