input.c 23 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.235 2003/07/23 22:01:25 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
    /* Parse input options */
    for( i = 0; i < p_item->i_options; i++ )
    {
        ParseOption( p_input, p_item->ppsz_options[i] );
    }

gbazin's avatar
   
gbazin committed
89
90
91
92
93
94
95
96
97
    /* Create a few object variables we'll need later on */
    var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
98

99
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
100
    p_input->b_eof      = 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
101
102

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

Stéphane Borel's avatar
   
Stéphane Borel committed
105
    /* Demux */
106
    p_input->p_demux = NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
107
108

    /* Access */
109
    p_input->p_access = NULL;
110

Sam Hocevar's avatar
   
Sam Hocevar committed
111
112
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
113
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
114

115
116
117
118
119
120
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
121
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
122
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
123
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
124

125
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
126
    p_input->stream.b_changed = 0;
127
128
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
129
    p_input->stream.i_pgrm_number = 0;
130
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
131
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
132
    p_input->stream.i_mux_rate = 0;
133
    p_input->stream.b_seekable = 0;
134
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
135

Sam Hocevar's avatar
   
Sam Hocevar committed
136
137
138
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
139
140
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
141
    p_input->stream.p_selected_area = NULL;
142
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
143

Sam Hocevar's avatar
   
Sam Hocevar committed
144
145
146
147
    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
148
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
149
    input_AddArea( p_input, 0, 1 );
150
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
151

152
153
154
155
    /* 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;
156
157
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" );

158
159
160
161
162
163
164
165
166
167
168
    /* 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;

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

171
172
    p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_info, _("Playlist Item"), p_input->psz_source );
173
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
174

Sam Hocevar's avatar
Sam Hocevar committed
175
    /* Create thread and wait for its readiness. */
176
177
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
178
    {
179
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
180
        free( p_input );
181
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
182
    }
183

184
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
185
186
}

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

199
200
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
201
202
203
204
205
206
207
208
209
210
}

/*****************************************************************************
 * 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 */
211
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
212
213
214

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
215
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
216
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
217
218
}

219
/*****************************************************************************
220
 * RunThread: main thread loop
221
 *****************************************************************************
222
 * Thread in charge of processing the network packets and demultiplexing.
223
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
224
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
225
{
Sam Hocevar's avatar
Sam Hocevar committed
226
227
228
    /* Signal right now, otherwise we'll get stuck in a peek */
    vlc_thread_ready( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
229
230
231
232
233
    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
234
        p_input->b_dead = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
235
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
236
    }
Michel Kaempf's avatar
Michel Kaempf committed
237

238
    /* initialization is complete */
239
240
241
242
    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
243
244
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
245
        unsigned int i, i_count;
246

Sam Hocevar's avatar
   
Sam Hocevar committed
247
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
248

249
        vlc_mutex_lock( &p_input->stream.stream_lock );
250

251
252
253
254
255
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
256
257
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
258
259

                p_input->pf_set_program( p_input,
260
                                         p_input->stream.p_new_program );
261

262
263
264
265
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

266
267
268
269
270
271
272
273
274
275
276
                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;
        }
277

278
279
        if( p_input->stream.p_new_area )
        {
280
281
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
282
                input_AccessReinit( p_input );
283
284
285

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

286
287
288
289
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

290
291
292
293
294
295
296
297
298
                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;
                }
            }
299
300
301
            p_input->stream.p_new_area = NULL;
        }

302
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
303
        {
304
305
            if( p_input->stream.b_seekable
                 && p_input->pf_seek != NULL )
306
            {
307
308
309
310
311
312
                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
313
314
315
                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 );
316

317
318
319
320
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

321
322
323
324
325
326
327
328
329
                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;
                }
            }
330
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
331
        }
332

333
334
335
336
337
338
339
340
341
342
343
344
        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;
        }

345
346
347
348
349
350
351
352
353
354
355
356
357
358
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
364
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
365
        {
366
            /* End of file - we do not set b_die because only the
367
             * playlist is allowed to do so. */
368
            msg_Info( p_input, "EOF reached" );
369
370
371
372
373
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
374
375
376
        }
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
377
    if( p_input->b_error || p_input->b_eof )
378
379
380
    {
        ErrorThread( p_input );
    }
381

382
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
383

Sam Hocevar's avatar
   
Sam Hocevar committed
384
    return 0;
385
386
}

387
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
388
 * InitThread: init the input Thread
389
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
390
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
391
{
Christophe Massiot's avatar
Christophe Massiot committed
392
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
393
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
394
    vlc_value_t val;
gbazin's avatar
   
gbazin committed
395

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

Christophe Massiot's avatar
Christophe Massiot committed
410
    if( !*psz_parser )
411
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
412
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
413
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
414
        free( p_input->psz_dupsource );
415
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
416
    }
Christophe Massiot's avatar
Christophe Massiot committed
417
418
419
    else
    {
        *psz_parser++ = '\0';
420

Xavier Marchesini's avatar
   
Xavier Marchesini committed
421
422
423
424
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
425
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
426
427

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
432
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
433
434
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
435
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
436
437
438
439
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
440
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
            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
457

Christophe Massiot's avatar
Christophe Massiot committed
458
459
460
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
461
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
462
463
464
465
466
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
467
    }
Christophe Massiot's avatar
Christophe Massiot committed
468

469
470
    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
471
472

    if( input_AccessInit( p_input ) == -1 )
473
    {
474
        return -1;
475
    }
Christophe Massiot's avatar
Christophe Massiot committed
476

477
    /* Find and open appropriate access module */
478
479
    p_input->p_access = module_Need( p_input, "access",
                                     p_input->psz_access );
Christophe Massiot's avatar
Christophe Massiot committed
480

481
482
483
484
485
486
487
488
489
490
491
492
493
494
    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 );
    }

495
    if( p_input->p_access == NULL )
496
    {
497
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
498
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
499
        return -1;
500
    }
Christophe Massiot's avatar
Christophe Massiot committed
501
502
503

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
504
    {
Christophe Massiot's avatar
Christophe Massiot committed
505
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
506
    }
507
508
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
509
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
510
    }
511

gbazin's avatar
   
gbazin committed
512
513
514
515
516
    /* 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
517
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
518
    {
Christophe Massiot's avatar
Christophe Massiot committed
519
520
        while( !input_FillBuffer( p_input ) )
        {
521
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
522
            {
523
                module_Unneed( p_input, p_input->p_access );
524
                return -1;
Christophe Massiot's avatar
Christophe Massiot committed
525
526
            }
        }
527
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
528

529
    /* Find and open appropriate demux module */
530
531
    p_input->p_demux = module_Need( p_input, "demux",
                                    p_input->psz_demux );
Sam Hocevar's avatar
   
Sam Hocevar committed
532

533
    if( p_input->p_demux == NULL )
534
    {
535
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
536
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
537
        module_Unneed( p_input, p_input->p_access );
538
        return -1;
539
540
    }

541
    /* Initialize optional stream output. */
gbazin's avatar
   
gbazin committed
542
    var_Get( p_input, "sout", &val );
gbazin's avatar
   
gbazin committed
543
    if( val.psz_string != NULL )
544
    {
gbazin's avatar
   
gbazin committed
545
546
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
547
548
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
gbazin's avatar
   
gbazin committed
549
            free( val.psz_string );
550
551
552
553
554
            module_Unneed( p_input, p_input->p_access );
            module_Unneed( p_input, p_input->p_demux );
            return -1;
        }

gbazin's avatar
   
gbazin committed
555
        free( val.psz_string );
556
557
    }

558
    return 0;
Michel Kaempf's avatar
Michel Kaempf committed
559
560
}

561
/*****************************************************************************
562
 * ErrorThread: RunThread() error loop
563
 *****************************************************************************
564
 * This function is called when an error occured during thread main's loop.
565
 *****************************************************************************/
566
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
567
{
568
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
569
    {
570
571
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
572
573
574
    }
}

575
/*****************************************************************************
576
 * EndThread: end the input thread
577
 *****************************************************************************/
578
static void EndThread( input_thread_t * p_input )
579
{
gbazin's avatar
   
gbazin committed
580
581
    vlc_object_t *p_object;

582
#ifdef HAVE_SYS_TIMES_H
583
584
585
    /* Display statistics */
    struct tms  cpu_usage;
    times( &cpu_usage );
Sam Hocevar's avatar
   
Sam Hocevar committed
586

587
    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
588
             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
589
#else
590
    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
591
#endif
592

593
594
    input_DumpStream( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
595
596
597
    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

598
599
600
601
602
603
    /* 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
604
    /* Free demultiplexer's data */
605
    module_Unneed( p_input, p_input->p_demux );
Sam Hocevar's avatar
   
Sam Hocevar committed
606

607
    /* Close the access plug-in */
608
    module_Unneed( p_input, p_input->p_access );
Sam Hocevar's avatar
   
Sam Hocevar committed
609

Christophe Massiot's avatar
Christophe Massiot committed
610
611
    input_AccessEnd( p_input );

612
613
614
615
    /* 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
616
617
    /* Close the video output that should have been re-attached
     * to our object */
618
    while( ( p_object = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD ) ) != NULL )
gbazin's avatar
   
gbazin committed
619
620
621
    {
        vlc_object_detach( p_object );
        vlc_object_release( p_object );
622
        vout_Destroy( (vout_thread_t *)p_object );
gbazin's avatar
   
gbazin committed
623
624
    }

Christophe Massiot's avatar
Christophe Massiot committed
625
    free( p_input->psz_source );
626
    if ( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
627
628
629

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

gbazin's avatar
   
gbazin committed
632
633
634
635
636
637
638
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
/*****************************************************************************
 * 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;
}