input.c 16 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.87 2001/02/20 09:10:36 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

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
    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 );
115 116
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
    p_input->stream.p_selected_area->i_seek = NO_SEEK;
Stéphane Borel's avatar
 
Stéphane Borel committed
117

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

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

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

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

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

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

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

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

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

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

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

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

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

217
        vlc_mutex_lock( &p_input->stream.stream_lock );
218
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
219
        {
220 221
            if( p_input->stream.b_seekable && p_input->pf_seek != NULL )
            {
222 223
                p_input->pf_seek( p_input,
                                  p_input->stream.p_selected_area->i_seek );
224 225 226 227 228 229 230 231 232 233 234 235 236

                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;
                }
            }
237
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
238
        }
239
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
240 241

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

Sam Hocevar's avatar
 
Sam Hocevar committed
243 244 245 246 247
        /* 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
248

Sam Hocevar's avatar
 
Sam Hocevar committed
249 250 251
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
252
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
253 254 255 256
                /* 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
257
            }
Sam Hocevar's avatar
 
Sam Hocevar committed
258
            else
Sam Hocevar's avatar
 
Sam Hocevar committed
259
            {
Sam Hocevar's avatar
 
Sam Hocevar committed
260
                p_input->b_error = 1;
Sam Hocevar's avatar
Sam Hocevar committed
261
            }
262 263 264
        }
    }

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

270
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
271 272 273

    DestroyThread( p_input );

274
    intf_DbgMsg("Thread end");
275 276
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
414 415 416
    /* 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
417
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441
        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
442 443 444 445 446 447 448 449 450 451 452
    }

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

473
    p_input->stream.p_selected_area->i_tell = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
474 475
    vlc_mutex_unlock( &p_input->stream.stream_lock );

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

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

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

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