input.c 15.9 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
Stéphane Borel's avatar
 
Stéphane Borel committed
7
 * $Id: input.c,v 1.85 2001/02/20 02:53:13 stef Exp $
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10 11 12 13 14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 * 
16 17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21 22 23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

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

31 32 33 34 35 36 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

39 40 41 42
#ifdef STATS
#   include <sys/times.h>
#endif

Michel Kaempf's avatar
Michel Kaempf committed
43
#include "config.h"
44 45
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
46
#include "mtime.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
47
#include "modules.h"
48

49
#include "intf_msg.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
50
#include "intf_plst.h"
51

52 53 54
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
55

56
#include "input.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
57 58 59
#include "interface.h"

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

61
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
62
 * Local prototypes
63
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
64 65 66 67 68
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
69

70
/*****************************************************************************
71
 * input_CreateThread: creates a new input thread
72
 *****************************************************************************
73 74 75 76
 * 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.
77
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
78
input_thread_t *input_CreateThread ( playlist_item_t *p_item, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
79
{
80 81 82
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

83 84 85
    /* Allocate descriptor */
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
86
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
87 88
        intf_ErrMsg( "input error: can't allocate input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
89 90
        return( NULL );
    }
91 92 93 94

    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
95 96 97 98 99
    p_input->b_eof              = 0;

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

100
    /* I have never understood that stuff --Meuuh */
101 102
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
Michel Kaempf's avatar
Michel Kaempf committed
103

104
    /* Initialize stream description */
105 106
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
107
    p_input->stream.i_pgrm_number = 0;
108
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
Christophe Massiot's avatar
Christophe Massiot committed
109
    p_input->stream.i_mux_rate = 0;
Michel Kaempf's avatar
Michel Kaempf committed
110

Stéphane Borel's avatar
 
Stéphane Borel committed
111 112 113 114 115 116
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
    /* By default there is one areas in a stream */
    input_AddArea( p_input );
    p_input->stream.pp_areas[0]->i_seek = NO_SEEK;

117 118 119 120 121
    /* 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
122

Sam Hocevar's avatar
 
Sam Hocevar committed
123 124
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout = p_main->p_aout;
Sam Hocevar's avatar
 
Sam Hocevar committed
125
    p_input->p_default_vout = p_main->p_vout;
Sam Hocevar's avatar
 
Sam Hocevar committed
126

Michel Kaempf's avatar
Michel Kaempf committed
127
    /* Create thread and set locks. */
128
    vlc_mutex_init( &p_input->stream.stream_lock );
129
    vlc_cond_init( &p_input->stream.stream_wait );
130 131 132
    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
133
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
134 135
        intf_ErrMsg( "input error: can't create input thread (%s)",
                     strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
136 137 138
        free( p_input );
        return( NULL );
    }
139

140 141 142 143
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
144
        {
145
            msleep( THREAD_SLEEP );
146
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
Sam Hocevar's avatar
 
Sam Hocevar committed
147
                && (i_status != THREAD_FATAL) );
148 149
        if( i_status != THREAD_READY )
        {
150 151
            return( NULL );
        }
152
    }
Michel Kaempf's avatar
Michel Kaempf committed
153 154 155
    return( p_input );
}

156
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
157
 * input_DestroyThread: mark an input thread as zombie
158
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
159
 * This function should not return until the thread is effectively cancelled.
160
 *****************************************************************************/
161
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
162
{
163
    int         i_status;                                   /* thread status */
164 165 166

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

169 170
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
171

172 173 174 175 176
    /* 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 );

177 178 179 180 181 182
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
183 184
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
185
    }
Michel Kaempf's avatar
Michel Kaempf committed
186 187
}

188
/*****************************************************************************
189
 * RunThread: main thread loop
190
 *****************************************************************************
191
 * Thread in charge of processing the network packets and demultiplexing.
192
 *****************************************************************************/
193
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
194
{
195 196
    data_packet_t *         pp_packets[INPUT_READ_ONCE];
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
197

Sam Hocevar's avatar
 
Sam Hocevar committed
198 199 200 201 202 203 204 205 206 207
    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
208

Sam Hocevar's avatar
 
Sam Hocevar committed
209
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
210 211
    {

Sam Hocevar's avatar
 
Sam Hocevar committed
212
#ifdef STATS
Sam Hocevar's avatar
 
Sam Hocevar committed
213
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
214 215
#endif

216
        vlc_mutex_lock( &p_input->stream.stream_lock );
Stéphane Borel's avatar
 
Stéphane Borel committed
217
        if( p_input->stream.pp_areas[0]->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
218
        {
219 220
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
Stéphane Borel's avatar
 
Stéphane Borel committed
221
                p_input->pf_seek( p_input, p_input->stream.pp_areas[0]->i_seek );
222 223 224 225 226 227 228 229 230 231 232 233 234

                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;
                }
            }
Stéphane Borel's avatar
 
Stéphane Borel committed
235
            p_input->stream.pp_areas[0]->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
236
        }
237
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
238 239

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

Sam Hocevar's avatar
 
Sam Hocevar committed
241 242 243 244 245
        /* Demultiplex read packets. */
        for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
        {
            p_input->pf_demux( p_input, pp_packets[i] );
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
246

Sam Hocevar's avatar
 
Sam Hocevar committed
247 248 249
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
250
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
251 252 253 254
                /* End of file - we do not set b_die because only the
                 * interface is allowed to do so. */
                intf_WarnMsg( 1, "End of file reached" );
                p_input->b_eof = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
255
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
256
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
257
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
258
                p_input->b_error = 1;
Sam Hocevar's avatar
Sam Hocevar committed
259
            }
260 261 262
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
263
    if( p_input->b_error || p_input->b_eof )
264 265 266
    {
        ErrorThread( p_input );
    }
267

268
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
269 270 271

    DestroyThread( p_input );

272
    intf_DbgMsg("Thread end");
273 274
}

275
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
276
 * InitThread: init the input Thread
277
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
278
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
279 280 281
{

#ifdef STATS
282 283 284 285 286 287
    /* 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
288
#endif
Sam Hocevar's avatar
Sam Hocevar committed
289

Sam Hocevar's avatar
 
Sam Hocevar committed
290
    p_input->p_input_module = module_Need( p_main->p_bank,
Sam Hocevar's avatar
 
Sam Hocevar committed
291 292
                                           MODULE_CAPABILITY_INPUT,
                                           (probedata_t *)p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
293 294

    if( p_input->p_input_module == NULL )
295
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
296
        intf_ErrMsg( "input error: no suitable input module" );
Sam Hocevar's avatar
 
Sam Hocevar committed
297 298
        module_Unneed( p_main->p_bank, p_input->p_input_module );
        return( -1 );
Michel Kaempf's avatar
Michel Kaempf committed
299
    }
300

Sam Hocevar's avatar
 
Sam Hocevar committed
301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316
#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;
    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 );
317

Sam Hocevar's avatar
 
Sam Hocevar committed
318
    if( p_input->b_error )
319
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
320 321
        /* We barfed -- exit nicely */
        p_input->pf_close( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
322
        module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
323
        return( -1 );
324
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
325 326

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

Sam Hocevar's avatar
 
Sam Hocevar committed
328
    *p_input->pi_status = THREAD_READY;
Sam Hocevar's avatar
 
Sam Hocevar committed
329 330

    return( 0 );
Michel Kaempf's avatar
Michel Kaempf committed
331 332
}

333
/*****************************************************************************
334
 * ErrorThread: RunThread() error loop
335
 *****************************************************************************
336
 * This function is called when an error occured during thread main's loop.
337
 *****************************************************************************/
338
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
339
{
340
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
341
    {
342 343
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
344 345 346
    }
}

347
/*****************************************************************************
348
 * EndThread: end the input thread
349
 *****************************************************************************/
350
static void EndThread( input_thread_t * p_input )
351
{
352
    int *       pi_status;                                  /* thread status */
353

354 355 356
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
357

Sam Hocevar's avatar
 
Sam Hocevar committed
358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373
#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
374 375 376
    /* Close stream */
    p_input->pf_close( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
377
    /* Release modules */
Sam Hocevar's avatar
 
Sam Hocevar committed
378
    module_Unneed( p_main->p_bank, p_input->p_input_module );
Sam Hocevar's avatar
 
Sam Hocevar committed
379

Sam Hocevar's avatar
 
Sam Hocevar committed
380 381 382 383 384 385 386 387 388 389 390
}

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

Henri Fallon's avatar
 
Henri Fallon committed
392 393
    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Henri Fallon's avatar
 
Henri Fallon committed
394
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Henri Fallon's avatar
 
Henri Fallon committed
395
    
396
    /* Free input structure */
397
    free( p_input );
398

399 400
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
401
}
402

Sam Hocevar's avatar
Sam Hocevar committed
403
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
404
 * input_FileOpen : open a file descriptor
Sam Hocevar's avatar
Sam Hocevar committed
405
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
406
void input_FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
407
{
408
    struct stat         stat_info;
Sam Hocevar's avatar
 
Sam Hocevar committed
409 410 411
    int                 i_stat;

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

Sam Hocevar's avatar
 
Sam Hocevar committed
413 414 415
    /* 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
416
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
        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 );
	}
	else if( ( i_size > 5 )
                 && !strncasecmp( psz_name, "file:", 5 ) )
        {
            /* get rid of the 'file:' stuff and try again */
            psz_name += 5;
            i_stat = stat( psz_name, &stat_info );
	}

	if( i_stat == (-1) )
        {
            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
441 442 443 444 445 446 447 448 449 450 451
    }

    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;
Stéphane Borel's avatar
 
Stéphane Borel committed
452
        p_input->stream.pp_areas[0]->i_size = stat_info.st_size;
Sam Hocevar's avatar
 
Sam Hocevar committed
453
    }
Jean-Marc Dressler's avatar
 
Jean-Marc Dressler committed
454 455 456 457 458
    else if( S_ISFIFO(stat_info.st_mode)
#ifndef SYS_BEOS
             || S_ISSOCK(stat_info.st_mode)
#endif
             )
Sam Hocevar's avatar
Sam Hocevar committed
459
    {
460
        p_input->stream.b_seekable = 0;
Stéphane Borel's avatar
 
Stéphane Borel committed
461
        p_input->stream.pp_areas[0]->i_size = 0;
Benoit Steiner's avatar
 
Benoit Steiner committed
462 463 464
    }
    else
    {
465
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
466
        intf_ErrMsg( "input error: unknown file type for `%s'",
Sam Hocevar's avatar
 
Sam Hocevar committed
467
                     psz_name );
Sam Hocevar's avatar
 
Sam Hocevar committed
468 469 470
        p_input->b_error = 1;
        return;
    }
471

Stéphane Borel's avatar
 
Stéphane Borel committed
472
    p_input->stream.pp_areas[0]->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
473 474
    vlc_mutex_unlock( &p_input->stream.stream_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
475 476
    intf_Msg( "input: opening %s", p_input->p_source );
    if( (p_input->i_handle = open( psz_name,
Sam Hocevar's avatar
 
Sam Hocevar committed
477 478
                                   /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
479
        intf_ErrMsg( "input error: cannot open file (%s)", strerror(errno) );
Sam Hocevar's avatar
 
Sam Hocevar committed
480 481
        p_input->b_error = 1;
        return;
Michel Kaempf's avatar
Michel Kaempf committed
482 483 484
    }

}
Stéphane Borel's avatar
Stéphane Borel committed
485 486

/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
487
 * input_FileClose : close a file descriptor
Stéphane Borel's avatar
Stéphane Borel committed
488
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
489
void input_FileClose( input_thread_t * p_input )
Stéphane Borel's avatar
Stéphane Borel committed
490
{
Sam Hocevar's avatar
 
Sam Hocevar committed
491
    close( p_input->i_handle );
Stéphane Borel's avatar
Stéphane Borel committed
492

Sam Hocevar's avatar
 
Sam Hocevar committed
493
    return;
Stéphane Borel's avatar
Stéphane Borel committed
494
}
Sam Hocevar's avatar
 
Sam Hocevar committed
495