input.c 13.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
7
 *****************************************************************************
 * Copyright (C) 1998, 1999, 2000 VideoLAN
 *
8
 * Authors: 
9
10
11
12
13
 *
 * 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.
14
 * 
15
16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20
21
22
 * 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.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

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

30
31
32
33
34
35
36
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
Michel Kaempf's avatar
Michel Kaempf committed
37
38

#include "config.h"
39
40
#include "common.h"
#include "threads.h"
Michel Kaempf's avatar
Michel Kaempf committed
41
#include "mtime.h"
42

43
#include "intf_msg.h"
44

45
46
47
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
Michel Lespinasse's avatar
Yop,    
Michel Lespinasse committed
48

49
#include "input.h"
Michel Kaempf's avatar
Michel Kaempf committed
50

51
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
52
 * Local prototypes
53
 *****************************************************************************/
54
static void RunThread   ( input_thread_t *p_input );
55
static void InitThread  ( input_thread_t *p_input );
56
57
static void ErrorThread ( input_thread_t *p_input );
static void EndThread   ( input_thread_t *p_input );
58
59
static void NetworkOpen ( input_thread_t *p_input );
static void FileOpen    ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
60

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

75
76
77
78
    /* 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
79
    {
80
81
        intf_ErrMsg("error: %s\n", strerror(errno));
        free( p_config );
Michel Kaempf's avatar
Michel Kaempf committed
82
83
        return( NULL );
    }
84
85
86
87

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

93
    /* Initialize stream description */
94
    for( i = 0; i < INPUT_MAX_SELECTED_ES; i++ )
Michel Kaempf's avatar
Michel Kaempf committed
95
    {
96
        p_input->pp_selected_es[i] = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
97
    }
98
    for( i= 0; i < INPUT_MAX_ES; i++ )
Michel Kaempf's avatar
Michel Kaempf committed
99
    {
100
        p_input->p_es[i].i_id = EMPTY_ID;
Michel Kaempf's avatar
Michel Kaempf committed
101
    }
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
    data_packet_t *      pp_packets[INPUT_READ_ONCE];
Michel Kaempf's avatar
Michel Kaempf committed
175

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

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

184
185
186
        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
187
        {
188
189
            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
190
        }
191
        vlc_mutex_unlock( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
Sam Hocevar committed
192

193
194
        p_input->p_plugin->pf_read( p_input, pp_packets );
        if( !p_input->b_error )
Sam Hocevar's avatar
Sam Hocevar committed
195
        {
196
197
198
            int     i;

            for( i = 0; i < INPUT_READ_ONCE && pp_packets[i] != NULL; i++ )
Sam Hocevar's avatar
Sam Hocevar committed
199
            {
200
                p_input->p_plugin->pf_demux( p_input, pp_packets[i] );
Sam Hocevar's avatar
Sam Hocevar committed
201
            }
202
203
204
        }
    }

205
206
207
208
    if( p_input->b_error )
    {
        ErrorThread( p_input );
    }
209

210
211
    EndThread( p_input );
    intf_DbgMsg("Thread end");
212
213
}

214
/*****************************************************************************
215
 * InitThread: init the input thread
216
 *****************************************************************************/
217
218
input_capabilities_t * PSKludge( void );
static void InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
219
{
220
221
222
    /* 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
223
224

#ifdef STATS
225
226
227
228
229
230
    /* 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
231
#endif
Sam Hocevar's avatar
Sam Hocevar committed
232

233
234
235
236
237
238
239
240
    /* 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
241
        {
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
            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
258
#endif
Michel Kaempf's avatar
Michel Kaempf committed
259
    }
260
261
262
263
264
265
266
267

    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
268
269
}

270
/*****************************************************************************
271
 * ErrorThread: RunThread() error loop
272
 *****************************************************************************
273
 * This function is called when an error occured during thread main's loop.
274
 *****************************************************************************/
275
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
276
{
277
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
278
    {
279
280
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
281
282
283
    }
}

284
/*****************************************************************************
285
 * EndThread: end the input thread
286
 *****************************************************************************/
287
static void EndThread( input_thread_t * p_input )
288
{
289
290
    int *       pi_status;                                  /* thread status */
    int         i_es_loop;                                       /* es index */
291

292
293
294
    /* Store status */
    pi_status = p_input->pi_status;
    *pi_status = THREAD_END;
Sam Hocevar's avatar
Sam Hocevar committed
295

296
297
298
299
300
    /* Destroy all decoder threads */
    for( i_es_loop = 0;
         (i_es_loop < INPUT_MAX_ES)
            && (p_input->pp_selected_es[i_es_loop] != NULL) ;
         i_es_loop++ )
301
    {
302
303
304
305
306
        p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->b_die = 1;
        /* Make sure the thread leaves the GetByte() function */
        vlc_mutex_lock( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_lock);
        vlc_cond_signal( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_wait );
        vlc_mutex_unlock( &p_input->pp_selected_es[i_es_loop]->p_decoder_fifo->data_lock );
307

308
309
310
        /* Waiting for the thread to exit */
        vlc_thread_join( p_input->pp_selected_es[i_es_loop]->thread_id );
        free( p_input->pp_selected_es[i_es_loop]->p_decoder_fifo );
Sam Hocevar's avatar
Sam Hocevar committed
311
312
    }

313
    /* Free demultiplexer's data */
314

315
316
    /* Update status */
    *pi_status = THREAD_OVER;
Sam Hocevar's avatar
Sam Hocevar committed
317
}
318

Sam Hocevar's avatar
Sam Hocevar committed
319
/*****************************************************************************
320
 * NetworkOpen : open a network socket descriptor
Sam Hocevar's avatar
Sam Hocevar committed
321
 *****************************************************************************/
322
static void NetworkOpen( input_thread_t * p_input )
Sam Hocevar's avatar
Sam Hocevar committed
323
{
324
    /* straight copy & paste of input_network.c of input-I */
325

326
327
328
329
    /* We cannot rewind nor lseek() */
    p_input->stream.b_seekable = 0;
    /* We cannot control the pace */
    p_input->stream.b_pace_control = 0;
330
331
}

332
/*****************************************************************************
333
 * FileOpen : open a file descriptor
334
 *****************************************************************************/
335
static void FileOpen( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
336
{
337
    struct stat         stat_info;
Michel Kaempf's avatar
Michel Kaempf committed
338

339
#define p_config    p_input->p_config
Michel Kaempf's avatar
Michel Kaempf committed
340

341
    if( !strncmp( p_config->p_source, "-", 1 ) )
Sam Hocevar's avatar
Sam Hocevar committed
342
    {
343
344
345
346
347
        /* stdin */
        p_input->i_handle = 0;
        
        vlc_mutex_lock( &p_input->stream.stream_lock );
        p_input->stream.b_pace_control = 1;
348
349
        p_input->stream.b_seekable = 0;
        p_input->stream.i_size = 0;
350
351
        p_input->stream.i_tell = 0;
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Benoit Steiner's avatar
   
Benoit Steiner committed
352
353
354
    }
    else
    {
355
356
357
358
359
360
361
        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
362

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

365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
        /* 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
398
399
    }

400
#undef p_config
Michel Kaempf's avatar
Michel Kaempf committed
401
}