input.c 14.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.62 2000/12/21 14:18:15 massiot Exp $
8
 *
9
 * Authors: 
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"
47

48
#include "intf_msg.h"
49

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

54
#include "input.h"
Michel Kaempf's avatar
Michel Kaempf committed
55

56
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
57
 * Local prototypes
58
 *****************************************************************************/
59
static void RunThread   ( input_thread_t *p_input );
60
static void InitThread  ( input_thread_t *p_input );
61
62
static void ErrorThread ( input_thread_t *p_input );
static void EndThread   ( input_thread_t *p_input );
63
64
static void NetworkOpen ( input_thread_t *p_input );
static void FileOpen    ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
65

66
/*****************************************************************************
67
 * input_CreateThread: creates a new input thread
68
 *****************************************************************************
69
70
71
72
 * 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.
73
 *****************************************************************************/
74
input_thread_t *input_CreateThread ( input_config_t * p_config, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
75
{
76
77
78
    input_thread_t *    p_input;                        /* thread descriptor */
    int                 i_status;                           /* thread status */

79
80
81
82
    /* Allocate descriptor */
    intf_DbgMsg("\n");
    p_input = (input_thread_t *)malloc( sizeof(input_thread_t) );
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
83
    {
84
85
        intf_ErrMsg("error: %s\n", strerror(errno));
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
86
87
        return( NULL );
    }
88
89
90
91

    /* Initialize thread properties */
    p_input->b_die              = 0;
    p_input->b_error            = 0;
92
    /* I have never understood that stuff --Meuuh */
93
94
    p_input->pi_status          = (pi_status != NULL) ? pi_status : &i_status;
    *p_input->pi_status         = THREAD_CREATE;
95
    p_input->p_config = p_config;
Michel Kaempf's avatar
Michel Kaempf committed
96

97
    /* Initialize stream description */
98
99
100
101
    p_input->pp_es = NULL;
    p_input->pp_selected_es = NULL;
    p_input->i_es_number = 0;
    p_input->i_selected_es_number = 0;
102
    p_input->stream.i_pgrm_number = 0;
Michel Kaempf's avatar
Michel Kaempf committed
103

104
105
106
107
108
109
110
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.i_ref_sysdate = 0;
    p_input->stream.control.i_ref_clock = 0;
    p_input->stream.control.b_mute = 0;
    p_input->stream.control.b_bw = 0;
Michel Kaempf's avatar
Michel Kaempf committed
111
112

    /* Create thread and set locks. */
113
114
115
116
    vlc_mutex_init( &p_input->stream.stream_lock );
    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
117
    {
118
        intf_ErrMsg("error: %s\n", strerror(errno) );
Michel Kaempf's avatar
Michel Kaempf committed
119
        free( p_input );
120
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
121
122
        return( NULL );
    }
123

124
125
126
127
    /* If status is NULL, wait until the thread is created */
    if( pi_status == NULL )
    {
        do
128
        {
129
            msleep( THREAD_SLEEP );
130
        } while( (i_status != THREAD_READY) && (i_status != THREAD_ERROR)
131
132
133
                && (i_status != THREAD_FATAL) );
        if( i_status != THREAD_READY )
        {
134
135
            return( NULL );
        }
136
    }
Michel Kaempf's avatar
Michel Kaempf committed
137
138
139
    return( p_input );
}

140
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
141
 * input_DestroyThread: mark an input thread as zombie
142
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
143
 * This function should not return until the thread is effectively cancelled.
144
 *****************************************************************************/
145
void input_DestroyThread( input_thread_t *p_input, int *pi_status )
Michel Kaempf's avatar
Michel Kaempf committed
146
{
147
    int         i_status;                                   /* thread status */
148
149
150

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

153
154
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
155

156
157
158
159
160
161
    /* If status is NULL, wait until thread has been destroyed */
    if( pi_status == NULL )
    {
        do
        {
            msleep( THREAD_SLEEP );
162
163
        } while ( (i_status != THREAD_OVER) && (i_status != THREAD_ERROR)
                  && (i_status != THREAD_FATAL) );
164
    }
Michel Kaempf's avatar
Michel Kaempf committed
165
166
}

167
/*****************************************************************************
168
 * RunThread: main thread loop
169
 *****************************************************************************
170
 * Thread in charge of processing the network packets and demultiplexing.
171
 *****************************************************************************/
172
static void RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
173
{
174
175
    data_packet_t *         pp_packets[INPUT_READ_ONCE];
    int                     i_error, i;
Michel Kaempf's avatar
Michel Kaempf committed
176

177
    InitThread( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
178

179
180
181
182
    while( !p_input->b_die && !p_input->b_error )
    {
#ifdef STATS
        p_input->c_loops++;
Michel Kaempf's avatar
Michel Kaempf committed
183
184
#endif

185
186
187
        vlc_mutex_lock( &p_input->stream.control.control_lock );
        if( p_input->stream.control.i_status == BACKWARD_S
             && p_input->p_plugin->pf_rewind != NULL )
Sam Hocevar's avatar
Sam Hocevar committed
188
        {
189
190
            p_input->p_plugin->pf_rewind( p_input );
            /* FIXME: probably don't do it every loop, but when ? */
Michel Kaempf's avatar
Michel Kaempf committed
191
        }
192
        vlc_mutex_unlock( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
Sam Hocevar committed
193

194
195
196
197
        i_error = p_input->p_plugin->pf_read( p_input, pp_packets );

        /* Demultiplex read packets. */
        for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
Sam Hocevar committed
198
        {
199
200
            p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
        }
201

202
203
204
        if( i_error )
        {
            if( i_error == 1 )
Sam Hocevar's avatar
Sam Hocevar committed
205
            {
206
207
208
                /* End of file */
                intf_WarnMsg( 1, "End of file reached" );
                /* FIXME: don't treat that as an error */
Sam Hocevar's avatar
Sam Hocevar committed
209
            }
210
            p_input->b_error = 1;
211
212
213
        }
    }

214
215
216
217
    if( p_input->b_error )
    {
        ErrorThread( p_input );
    }
218

219
220
    EndThread( p_input );
    intf_DbgMsg("Thread end");
221
222
}

223
/*****************************************************************************
224
 * InitThread: init the input thread
225
 *****************************************************************************/
226
227
input_capabilities_t * PSKludge( void );
static void InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
228
{
229
230
231
    /* Initialize default settings for spawned decoders */
    p_input->p_default_aout     = p_input->p_config->p_default_aout;
    p_input->p_default_vout     = p_input->p_config->p_default_vout;
Michel Kaempf's avatar
Michel Kaempf committed
232
233

#ifdef STATS
234
235
236
237
238
239
    /* 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
240
#endif
Sam Hocevar's avatar
Sam Hocevar committed
241

242
243
244
245
246
247
248
249
    /* Use the appropriate input method */
    switch( p_input->p_config->i_method )
    {
    case INPUT_METHOD_FILE:                                  /* file methods */
        FileOpen( p_input );
        break;
    case INPUT_METHOD_VLAN_BCAST:                     /* vlan network method */
/*        if( !p_main->b_vlans )
Michel Kaempf's avatar
Michel Kaempf committed
250
        {
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
            intf_ErrMsg("error: vlans are not activated\n");
            free( p_input );
            return( NULL );
        } */ /* la-lala */
        /* ... pass through */
    case INPUT_METHOD_UCAST:                              /* network methods */
    case INPUT_METHOD_MCAST:
    case INPUT_METHOD_BCAST:
        NetworkOpen( p_input );
        break;
#ifdef DEBUG
    default:
        intf_ErrMsg("Unknow input method");
        free( p_input->p_config );
        p_input->b_error = 1;
        break;
Sam Hocevar's avatar
Sam Hocevar committed
267
#endif
Michel Kaempf's avatar
Michel Kaempf committed
268
    }
269
270
271
272
273
274
275
276

    free( p_input->p_config );

    /* Probe plugin (FIXME: load plugins before & write this) */
    p_input->p_plugin = PSKludge();
    p_input->p_plugin->pf_init( p_input );

    *p_input->pi_status = THREAD_READY;
Michel Kaempf's avatar
Michel Kaempf committed
277
278
}

279
/*****************************************************************************
280
 * ErrorThread: RunThread() error loop
281
 *****************************************************************************
282
 * This function is called when an error occured during thread main's loop.
283
 *****************************************************************************/
284
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
285
{
286
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
287
    {
288
289
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
290
291
292
    }
}

293
/*****************************************************************************
294
 * EndThread: end the input thread
295
 *****************************************************************************/
296
static void EndThread( input_thread_t * p_input )
297
{
298
299
    int *       pi_status;                                  /* thread status */
    int         i_es_loop;                                       /* es index */
300

301
302
303
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
304

305
306
307
308
309
310
311
312
313
314
#ifdef STATS
    {
        struct tms cpu_usage;
        times( &cpu_usage );

        intf_Msg("input stats: cpu usage (user: %d, system: %d)\n",
                 cpu_usage.tms_utime, cpu_usage.tms_stime);
    }
#endif

315
    /* Destroy all decoder threads */
316
    for( i_es_loop = 0; i_es_loop < p_input->i_selected_es_number;
317
         i_es_loop++ )
318
    {
319
320
321
322
323
324
325
326
327
        decoder_fifo_t *    p_decoder_fifo;

        p_decoder_fifo = p_input->pp_selected_es[i_es_loop]->p_decoder_fifo;
        p_decoder_fifo->b_die = 1;

        /* Make sure the thread leaves the NextDataPacket() function */
        vlc_mutex_lock( &p_decoder_fifo->data_lock);
        vlc_cond_signal( &p_decoder_fifo->data_wait );
        vlc_mutex_unlock( &p_decoder_fifo->data_lock );
328

329
330
        /* Waiting for the thread to exit */
        vlc_thread_join( p_input->pp_selected_es[i_es_loop]->thread_id );
331
332
333
334
335
336
337
338

        /* Freeing all packets still in the decoder fifo. */
        while( !DECODER_FIFO_ISEMPTY( *p_decoder_fifo ) )
        {
            p_decoder_fifo->pf_delete_pes( p_decoder_fifo->p_packets_mgt,
                                     DECODER_FIFO_START( *p_decoder_fifo ) );
            DECODER_FIFO_INCSTART( *p_decoder_fifo );
        }
339
        free( p_input->pp_selected_es[i_es_loop]->p_decoder_fifo );
Sam Hocevar's avatar
Sam Hocevar committed
340
341
    }

342
    /* Free demultiplexer's data */
343
344
345
346
347
348
349
350
    p_input->p_plugin->pf_end( p_input );
    free( p_input->p_plugin );

    /* Free input structures */
    input_EndStream( p_input );
    free( p_input->pp_es );
    free( p_input->pp_selected_es );
    free( p_input );
351

352
353
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
354
}
355

Sam Hocevar's avatar
Sam Hocevar committed
356
/*****************************************************************************
357
 * NetworkOpen : open a network socket descriptor
Sam Hocevar's avatar
Sam Hocevar committed
358
 *****************************************************************************/
359
static void NetworkOpen( input_thread_t * p_input )
Sam Hocevar's avatar
Sam Hocevar committed
360
{
361
    /* straight copy & paste of input_network.c of input-I */
362

363
364
365
366
    /* We cannot rewind nor lseek() */
    p_input->stream.b_seekable = 0;
    /* We cannot control the pace */
    p_input->stream.b_pace_control = 0;
367
368
}

369
/*****************************************************************************
370
 * FileOpen : open a file descriptor
371
 *****************************************************************************/
372
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
373
{
374
    struct stat         stat_info;
Michel Kaempf's avatar
Michel Kaempf committed
375

376
#define p_config    p_input->p_config
Michel Kaempf's avatar
Michel Kaempf committed
377

378
    if( !strncmp( p_config->p_source, "-", 1 ) )
Sam Hocevar's avatar
Sam Hocevar committed
379
    {
380
381
382
383
384
        /* stdin */
        p_input->i_handle = 0;
        
        vlc_mutex_lock( &p_input->stream.stream_lock );
        p_input->stream.b_pace_control = 1;
385
386
        p_input->stream.b_seekable = 0;
        p_input->stream.i_size = 0;
387
388
        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Benoit Steiner's avatar
   
Benoit Steiner committed
389
390
391
    }
    else
    {
392
393
394
395
396
397
398
        if( stat( p_config->p_source, &stat_info ) == (-1) )
        {
            intf_ErrMsg("Cannot stat() file %s (%s)", p_config->p_source,
                        strerror(errno));
            p_input->b_error = 1;
            return;
        }
Michel Kaempf's avatar
Michel Kaempf committed
399

400
        vlc_mutex_lock( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
401

402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
        /* 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;
            p_input->stream.i_size = stat_info.st_size;
        }
        else if( S_ISFIFO(stat_info.st_mode) || S_ISSOCK(stat_info.st_mode) )
        {
            p_input->stream.b_seekable = 0;
            p_input->stream.i_size = 0;
        }
        else
        {
            vlc_mutex_unlock( &p_input->stream.stream_lock );
            intf_ErrMsg("Unknown file type");
            p_input->b_error = 1;
            return;
        }

        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );

        intf_Msg( "Opening file %s", p_config->p_source );
        if( (p_input->i_handle = open( p_config->p_source,
                                       /*O_NONBLOCK | O_LARGEFILE*/0 )) == (-1) )
        {
            intf_ErrMsg("Cannot open file (%s)", strerror(errno));
            p_input->b_error = 1;
            return;
        }
Michel Kaempf's avatar
Michel Kaempf committed
435
436
    }

437
#undef p_config
Michel Kaempf's avatar
Michel Kaempf committed
438
}