input.c 23.1 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-2002 VideoLAN
gbazin's avatar
   
gbazin committed
7
 * $Id: input.c,v 1.234 2003/07/23 01:13:48 gbazin 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
#include <stdlib.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
30

31
#include <vlc/vlc.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
32

33
#include <string.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
34

35
36
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
37
#endif
38

39
#include "vlc_playlist.h"
40

41
42
43
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
44
#include "input_ext-plugins.h"
Michel Lespinasse's avatar
Yop,    
Michel Lespinasse committed
45

46
#include "stream_output.h"
47
#include <vlc/vout.h>
48

49
#include "vlc_interface.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
50

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

gbazin's avatar
   
gbazin committed
59
60
61
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );

62
/*****************************************************************************
63
 * input_CreateThread: creates a new input thread
64
 *****************************************************************************
65
66
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
67
 *****************************************************************************/
68
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
69
                                      playlist_item_t *p_item )
Michel Kaempf's avatar
Michel Kaempf committed
70
{
71
    input_thread_t *    p_input;                        /* thread descriptor */
72
    input_info_category_t * p_info;
gbazin's avatar
   
gbazin committed
73
    int i;
74

75
    /* Allocate descriptor */
76
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
77
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
78
    {
79
        msg_Err( p_parent, "out of memory" );
80
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
81
    }
82

gbazin's avatar
   
gbazin committed
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
    /* Parse input options */
    for( i = 0; i < p_item->i_options; i++ )
    {
        ParseOption( p_input, p_item->ppsz_options[i] );
    }

    /* Create a few object variables we'll need later */
    if( !var_Type( p_input, "sout" ) )
    {
        var_Create( p_input, "sout", VLC_VAR_STRING );
        var_Change( p_input, "sout", VLC_VAR_INHERITVALUE, NULL, NULL );
    }
    if( !var_Type( p_input, "sout-audio" ) )
    {
        var_Create( p_input, "sout-audio", VLC_VAR_BOOL );
        var_Change( p_input, "sout-audio", VLC_VAR_INHERITVALUE, NULL, NULL );
    }
    if( !var_Type( p_input, "sout-video" ) )
    {
        var_Create( p_input, "sout-video", VLC_VAR_BOOL );
        var_Change( p_input, "sout-video", VLC_VAR_INHERITVALUE, NULL, NULL );
    }

106
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
107
    p_input->b_eof      = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
108
109

    /* Set target */
110
    p_input->psz_source = strdup( p_item->psz_uri );
Sam Hocevar's avatar
   
Sam Hocevar committed
111

Stéphane Borel's avatar
   
Stéphane Borel committed
112
    /* Demux */
113
    p_input->p_demux = NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
114
115

    /* Access */
116
    p_input->p_access = NULL;
117

Sam Hocevar's avatar
   
Sam Hocevar committed
118
119
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
120
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
121

122
123
124
125
126
127
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
128
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
129
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
130
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
131

132
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
133
    p_input->stream.b_changed = 0;
134
135
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
136
    p_input->stream.i_pgrm_number = 0;
137
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
138
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
139
    p_input->stream.i_mux_rate = 0;
140
    p_input->stream.b_seekable = 0;
141
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
142

Sam Hocevar's avatar
   
Sam Hocevar committed
143
144
145
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
146
147
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
148
    p_input->stream.p_selected_area = NULL;
149
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
150

Sam Hocevar's avatar
   
Sam Hocevar committed
151
152
153
154
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

Sam Hocevar's avatar
   
Sam Hocevar committed
155
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
156
    input_AddArea( p_input, 0, 1 );
157
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
158

159
160
161
162
    /* 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;
163
164
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" );

165
166
167
168
169
170
171
172
173
174
175
    /* Initialize input info */
    p_input->stream.p_info = malloc( sizeof( input_info_category_t ) );
    if( !p_input->stream.p_info )
    {
        msg_Err( p_input, "No memory!" );
        return NULL;
    }
    p_input->stream.p_info->psz_name = strdup("General") ;
    p_input->stream.p_info->p_info = NULL;
    p_input->stream.p_info->p_next = NULL;

176
    msg_Info( p_input, "playlist item `%s'", p_input->psz_source );
Michel Kaempf's avatar
Michel Kaempf committed
177

178
179
    p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_info, _("Playlist Item"), p_input->psz_source );
180
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
181

Sam Hocevar's avatar
Sam Hocevar committed
182
    /* Create thread and wait for its readiness. */
183
184
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
185
    {
186
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
187
        free( p_input );
188
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
189
    }
190

191
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
192
193
}

194
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
195
 * input_StopThread: mark an input thread as zombie
196
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
197
 * This function should not return until the thread is effectively cancelled.
198
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
199
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
200
{
Sam Hocevar's avatar
   
Sam Hocevar committed
201
202
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
203
204
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
205

206
207
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
208
209
210
211
212
213
214
215
216
217
}

/*****************************************************************************
 * input_DestroyThread: mark an input thread as zombie
 *****************************************************************************
 * This function should not return until the thread is effectively cancelled.
 *****************************************************************************/
void input_DestroyThread( input_thread_t *p_input )
{
    /* Join the thread */
218
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
219
220
221

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
222
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
223
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
224
225
}

226
/*****************************************************************************
227
 * RunThread: main thread loop
228
 *****************************************************************************
229
 * Thread in charge of processing the network packets and demultiplexing.
230
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
231
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
232
{
Sam Hocevar's avatar
Sam Hocevar committed
233
234
235
    /* Signal right now, otherwise we'll get stuck in a peek */
    vlc_thread_ready( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
236
237
238
239
240
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
        ErrorThread( p_input );
Sam Hocevar's avatar
Sam Hocevar committed
241
        p_input->b_dead = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
242
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
243
    }
Michel Kaempf's avatar
Michel Kaempf committed
244

245
    /* initialization is complete */
246
247
248
249
    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
250
251
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
252
        unsigned int i, i_count;
253

Sam Hocevar's avatar
   
Sam Hocevar committed
254
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
255

256
        vlc_mutex_lock( &p_input->stream.stream_lock );
257

258
259
260
261
262
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
263
264
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
265
266

                p_input->pf_set_program( p_input,
267
                                         p_input->stream.p_new_program );
268

269
270
271
272
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

273
274
275
276
277
278
279
280
281
282
283
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
            p_input->stream.p_new_program = NULL;
        }
284

285
286
        if( p_input->stream.p_new_area )
        {
287
288
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
289
                input_AccessReinit( p_input );
290
291
292

                p_input->pf_set_area( p_input, p_input->stream.p_new_area );

293
294
295
296
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

297
298
299
300
301
302
303
304
305
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
306
307
308
            p_input->stream.p_new_area = NULL;
        }

309
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
310
        {
311
312
            if( p_input->stream.b_seekable
                 && p_input->pf_seek != NULL )
313
            {
314
315
316
317
318
319
                off_t i_new_pos;

                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );

                i_new_pos = p_input->stream.p_selected_area->i_seek;
Christophe Massiot's avatar
Christophe Massiot committed
320
321
322
                vlc_mutex_unlock( &p_input->stream.stream_lock );
                p_input->pf_seek( p_input, i_new_pos );
                vlc_mutex_lock( &p_input->stream.stream_lock );
323

324
325
326
327
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

328
329
330
331
332
333
334
335
336
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
337
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
338
        }
339

340
341
342
343
344
345
346
347
348
349
350
351
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

        if( p_input->stream.p_newly_selected_es )
        {
            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
            p_input->stream.p_newly_selected_es = NULL;
        }

352
353
354
355
356
357
358
359
360
361
362
363
364
365
        if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
        {
            if( p_input->stream.b_new_mute )
            {
                input_EscapeAudioDiscontinuity( p_input );
            }

            vlc_mutex_lock( &p_input->stream.control.control_lock );
            p_input->stream.control.b_mute = p_input->stream.b_new_mute;
            vlc_mutex_unlock( &p_input->stream.control.control_lock );

            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
        }

366
        vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
367

Christophe Massiot's avatar
Christophe Massiot committed
368
369
        /* Read and demultiplex some data. */
        i_count = p_input->pf_demux( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
370

gbazin's avatar
   
gbazin committed
371
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
372
        {
373
            /* End of file - we do not set b_die because only the
374
             * playlist is allowed to do so. */
375
            msg_Info( p_input, "EOF reached" );
376
377
378
379
380
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
381
382
383
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
384
    if( p_input->b_error || p_input->b_eof )
385
386
387
    {
        ErrorThread( p_input );
    }
388

389
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
390

Sam Hocevar's avatar
   
Sam Hocevar committed
391
    return 0;
392
393
}

394
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
395
 * InitThread: init the input Thread
396
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
397
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
398
{
Christophe Massiot's avatar
Christophe Massiot committed
399
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
400
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
401
    vlc_value_t val;
gbazin's avatar
   
gbazin committed
402

Christophe Massiot's avatar
Christophe Massiot committed
403
404
405
406
407
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
408
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
409
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
410
    {
411
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
412
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
413
        psz_parser = "";
gbazin's avatar
   
gbazin committed
414
415
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
416

Christophe Massiot's avatar
Christophe Massiot committed
417
    if( !*psz_parser )
418
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
419
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
420
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
421
        free( p_input->psz_dupsource );
422
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
423
    }
Christophe Massiot's avatar
Christophe Massiot committed
424
425
426
    else
    {
        *psz_parser++ = '\0';
427

Xavier Marchesini's avatar
   
Xavier Marchesini committed
428
429
430
431
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
432
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
433
434

        p_input->psz_name = psz_parser ;
Sam Hocevar's avatar
   
Sam Hocevar committed
435

Christophe Massiot's avatar
Christophe Massiot committed
436
        /* Come back to parse the access and demux plug-ins */
Christophe Massiot's avatar
Christophe Massiot committed
437
        psz_parser = p_input->psz_dupsource;
gbazin's avatar
   
gbazin committed
438

Stéphane Borel's avatar
   
Stéphane Borel committed
439
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
440
441
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
442
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
443
444
445
446
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
447
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

            while( *psz_parser && *psz_parser != '/' )
            {
                psz_parser++;
            }

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }
gbazin's avatar
   
gbazin committed
464

Christophe Massiot's avatar
Christophe Massiot committed
465
466
467
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
468
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
469
470
471
472
473
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
474
    }
Christophe Massiot's avatar
Christophe Massiot committed
475

476
477
    msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
             p_input->psz_access, p_input->psz_demux, p_input->psz_name );
Christophe Massiot's avatar
Christophe Massiot committed
478
479

    if( input_AccessInit( p_input ) == -1 )
480
    {
481
        return -1;
482
    }
Christophe Massiot's avatar
Christophe Massiot committed
483

484
    /* Find and open appropriate access module */
485
486
    p_input->p_access = module_Need( p_input, "access",
                                     p_input->psz_access );
Christophe Massiot's avatar
Christophe Massiot committed
487

488
489
490
491
492
493
494
495
496
497
498
499
500
501
    if ( p_input->p_access == NULL
          && (*p_input->psz_demux || *p_input->psz_access) )
    {
        /* Maybe we got something like :
         * /Volumes/toto:titi/gabu.mpg */
        p_input->psz_access = p_input->psz_demux = "";
        p_input->psz_name = p_input->psz_source;
        free( p_input->psz_dupsource);
        p_input->psz_dupsource = NULL;

        p_input->p_access = module_Need( p_input, "access",
                                         p_input->psz_access );
    }

502
    if( p_input->p_access == NULL )
503
    {
504
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
505
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
506
        return -1;
507
    }
Christophe Massiot's avatar
Christophe Massiot committed
508
509
510

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
511
    {
Christophe Massiot's avatar
Christophe Massiot committed
512
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
513
    }
514
515
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
516
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
517
    }
518

gbazin's avatar
   
gbazin committed
519
520
521
522
523
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
    if( p_input->p_vlc->i_desync < 0 )
        p_input->i_pts_delay -= p_input->p_vlc->i_desync;

Sam Hocevar's avatar
   
Sam Hocevar committed
524
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
525
    {
Christophe Massiot's avatar
Christophe Massiot committed
526
527
        while( !input_FillBuffer( p_input ) )
        {
528
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
529
            {
530
                module_Unneed( p_input, p_input->p_access );
531
                return -1;
Christophe Massiot's avatar
Christophe Massiot committed
532
533
            }
        }
534
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
535

536
    /* Find and open appropriate demux module */
537
538
    p_input->p_demux = module_Need( p_input, "demux",
                                    p_input->psz_demux );
Sam Hocevar's avatar
   
Sam Hocevar committed
539

540
    if( p_input->p_demux == NULL )
541
    {
542
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
543
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
544
        module_Unneed( p_input, p_input->p_access );
545
        return -1;
546
547
    }

548
    /* Initialize optional stream output. */
gbazin's avatar
   
gbazin committed
549
550
    var_Get( p_input, "sout", &val );
    if ( val.psz_string != NULL )
551
    {
gbazin's avatar
   
gbazin committed
552
553
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
554
555
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
gbazin's avatar
   
gbazin committed
556
            free( val.psz_string );
557
558
559
560
561
            module_Unneed( p_input, p_input->p_access );
            module_Unneed( p_input, p_input->p_demux );
            return -1;
        }

gbazin's avatar
   
gbazin committed
562
        free( val.psz_string );
563
564
    }

565
    return 0;
Michel Kaempf's avatar
Michel Kaempf committed
566
567
}

568
/*****************************************************************************
569
 * ErrorThread: RunThread() error loop
570
 *****************************************************************************
571
 * This function is called when an error occured during thread main's loop.
572
 *****************************************************************************/
573
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
574
{
575
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
576
    {
577
578
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
579
580
581
    }
}

582
/*****************************************************************************
583
 * EndThread: end the input thread
584
 *****************************************************************************/
585
static void EndThread( input_thread_t * p_input )
586
{
gbazin's avatar
   
gbazin committed
587
588
    vlc_object_t *p_object;

589
#ifdef HAVE_SYS_TIMES_H
590
591
592
    /* Display statistics */
    struct tms  cpu_usage;
    times( &cpu_usage );
Sam Hocevar's avatar
   
Sam Hocevar committed
593

594
    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
595
             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
596
#else
597
    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
598
#endif
599

600
601
    input_DumpStream( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
602
603
604
    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

605
606
607
608
609
610
    /* Close optional stream output instance */
    if ( p_input->stream.p_sout != NULL )
    {
        sout_DeleteInstance( p_input->stream.p_sout );
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
611
    /* Free demultiplexer's data */
612
    module_Unneed( p_input, p_input->p_demux );
Sam Hocevar's avatar
   
Sam Hocevar committed
613

614
    /* Close the access plug-in */
615
    module_Unneed( p_input, p_input->p_access );
Sam Hocevar's avatar
   
Sam Hocevar committed
616

Christophe Massiot's avatar
Christophe Massiot committed
617
618
    input_AccessEnd( p_input );

619
620
621
622
    /* Free info structures XXX destroy es before 'cause vorbis */
    msg_Dbg( p_input, "freeing info structures...");
    input_DelInfo( p_input );

gbazin's avatar
   
gbazin committed
623
624
    /* Close the video output that should have been re-attached
     * to our object */
625
    while( ( p_object = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD ) ) != NULL )
gbazin's avatar
   
gbazin committed
626
627
628
    {
        vlc_object_detach( p_object );
        vlc_object_release( p_object );
629
        vout_Destroy( (vout_thread_t *)p_object );
gbazin's avatar
   
gbazin committed
630
631
    }

Christophe Massiot's avatar
Christophe Massiot committed
632
    free( p_input->psz_source );
633
    if ( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
634
635
636

    /* Tell we're dead */
    p_input->b_dead = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
637
638
}

gbazin's avatar
   
gbazin committed
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
/*****************************************************************************
 * ParseOption: parses the options for the input
 *****************************************************************************
 * This function parses the input (config) options and creates their associated
 * object variables.
 * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
 * bar is the value of the option.
 *****************************************************************************/
static void ParseOption( input_thread_t *p_input, const char *psz_option )
{
    char *psz_name = (char *)psz_option;
    char *psz_value = strchr( psz_option, '=' );
    int  i_name_len, i_type;
    vlc_bool_t b_isno = VLC_FALSE;
    vlc_value_t val;

    if( psz_value ) i_name_len = psz_value - psz_option;
    else i_name_len = strlen( psz_option );

    /* It's too much of an hassle to remove the ':' when we parse
     * the cmd line :) */
    if( i_name_len && *psz_name == ':' )
    {
        psz_name++;
        i_name_len--;
    }

    if( i_name_len == 0 ) return;

    psz_name = strndup( psz_name, i_name_len );
    if( psz_value ) psz_value++;

    i_type = config_GetType( p_input, psz_name );

    if( !i_type && !psz_value )
    {
        /* check for "no-foo" or "nofoo" */
        if( !strncmp( psz_name, "no-", 3 ) )
        {
            memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
        }
        else if( !strncmp( psz_name, "no", 2 ) )
        {
            memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
        }
        else goto cleanup;           /* Option doesn't exist */

        b_isno = VLC_TRUE;
        i_type = config_GetType( p_input, psz_name );

        if( !i_type ) goto cleanup;  /* Option doesn't exist */
    }
    else if( !i_type ) goto cleanup; /* Option doesn't exist */

    if( ( i_type != VLC_VAR_BOOL ) &&
        ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */

    /* Create the variable in the input object.
     * Children of the input object will be able to retreive this value
     * thanks to the inheritance property of the object variables. */
    var_Create( p_input, psz_name, i_type );

    switch( i_type )
    {
    case VLC_VAR_BOOL:
        val.b_bool = !b_isno;
        break;

    case VLC_VAR_INTEGER:
        val.i_int = atoi( psz_value );
        break;

    case VLC_VAR_FLOAT:
        val.f_float = atof( psz_value );
        break;

    case VLC_VAR_STRING:
    case VLC_VAR_FILE:
    case VLC_VAR_DIRECTORY:
        val.psz_string = psz_value;
        break;

    default:
        goto cleanup;
        break;
    }

    var_Set( p_input, psz_name, val );

    msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );

  cleanup:
    if( psz_name ) free( psz_name );
    return;
}