input.c 46.2 KB
Newer Older
1
2
/*****************************************************************************
 * input.c: input thread
3
 * Read a stream, demultiplex and parse it before sending it to
Michel Kaempf's avatar
Michel Kaempf committed
4
 * decoders.
5
 *****************************************************************************
6
 * Copyright (C) 1998-2002 VideoLAN
gbazin's avatar
   
gbazin committed
7
 * $Id: input.c,v 1.260 2003/11/22 13:19:30 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>
32
33
#include <vlc/input.h>
#include <vlc/vout.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
#include "stream_output.h"

43
#include "vlc_interface.h"
44
45
#include "codecs.h"
#include "modules/demux/util/sub.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
46

47
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
48
 * Local prototypes
49
 *****************************************************************************/
50
51
52
53
54
55
56
struct input_thread_sys_t
{
    /* subtitles */
    int              i_sub;
    subtitle_demux_t **sub;
};

Sam Hocevar's avatar
   
Sam Hocevar committed
57
static  int RunThread       ( input_thread_t *p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
58
59
60
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
61

gbazin's avatar
   
gbazin committed
62
63
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );
64
65
66
67

static es_out_t *EsOutCreate ( input_thread_t * );
static void      EsOutRelease( es_out_t * );

68
69
70
71
72
73
74
75
76
77
78
/*****************************************************************************
 * Callbacks
 *****************************************************************************/
static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
gbazin's avatar
   
gbazin committed
79

80
/*****************************************************************************
81
 * input_CreateThread: creates a new input thread
82
 *****************************************************************************
83
84
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
85
 *****************************************************************************/
86
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
87
                                      playlist_item_t *p_item )
Michel Kaempf's avatar
Michel Kaempf committed
88
{
89
    input_thread_t *    p_input;                        /* thread descriptor */
90
    input_info_category_t * p_info;
91
    vlc_value_t val;
gbazin's avatar
   
gbazin committed
92
    int i;
93

94
    /* Allocate descriptor */
95
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
96
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
97
    {
98
        msg_Err( p_parent, "out of memory" );
99
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
100
    }
101

gbazin's avatar
   
gbazin committed
102
103
104
105
106
107
    /* 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
108
109
110
111
112
    /* 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 );
113
114
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
115
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
116
117
118
119

    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 );
120
121
122
123
124
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

    /* play status */

    /* position variable */
125
126
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
127
128
129
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
130
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
131
132
133

    /* time variable */
    var_Create( p_input, "time",  VLC_VAR_TIME );
134
    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
135
136
137
    val.i_time = 0;
    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "time", TimeCallback, NULL );
138
    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    /* length variable */
    var_Create( p_input, "length",  VLC_VAR_TIME );
    val.i_time = 0;
    var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );

    /* rate variable */
    var_Create( p_input, "rate", VLC_VAR_INTEGER );
    var_Create( p_input, "rate-slower", VLC_VAR_VOID );
    var_Create( p_input, "rate-faster", VLC_VAR_VOID );
    val.i_int = DEFAULT_RATE;
    var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "rate", RateCallback, NULL );
    var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
    var_AddCallback( p_input, "rate-faster", RateCallback, NULL );

    /* state variable */
    var_Create( p_input, "state", VLC_VAR_INTEGER );
    val.i_int = INIT_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "state", StateCallback, NULL );

161
162
163
164
    /* state variable */
    var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
    val.b_bool = VLC_FALSE;
    var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
   
gbazin committed
165

166
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
167
    p_input->b_eof      = 0;
168
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
169
170

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

173
174
175
    /* Stream */
    p_input->s = NULL;

176
177
178
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
179
    /* Demux */
180
181
182
183
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
    p_input->pf_demux_control = NULL;
Stéphane Borel's avatar
   
Stéphane Borel committed
184
185

    /* Access */
186
    p_input->p_access = NULL;
187

Sam Hocevar's avatar
   
Sam Hocevar committed
188
189
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
190
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
191

192
193
194
195
196
197
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
198
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
199
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
200
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
201

202
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
203
    p_input->stream.b_changed = 0;
204
205
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
206
    p_input->stream.i_pgrm_number = 0;
207
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
208
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
209
    p_input->stream.i_mux_rate = 0;
210
    p_input->stream.b_seekable = 0;
211
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
212

Sam Hocevar's avatar
   
Sam Hocevar committed
213
214
215
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
216
217
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
218
    p_input->stream.p_selected_area = NULL;
219
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
220

Sam Hocevar's avatar
   
Sam Hocevar committed
221
222
223
224
    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
225
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
226
    input_AddArea( p_input, 0, 1 );
227
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
228

229
    /* Initialize stream control properties. */
230
    p_input->stream.control.i_status = INIT_S;
231
232
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
233
234
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" );

235
236
237
238
239
240
241
242
243
244
245
    /* 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;

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

248
249
    p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_info, _("Playlist Item"), p_input->psz_source );
250
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
251

Sam Hocevar's avatar
Sam Hocevar committed
252
    /* Create thread and wait for its readiness. */
253
254
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
255
    {
256
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
257
        free( p_input );
258
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
259
    }
260

261
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
262
263
}

264
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
265
 * input_StopThread: mark an input thread as zombie
266
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
267
 * This function should not return until the thread is effectively cancelled.
268
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
269
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
270
{
Sam Hocevar's avatar
   
Sam Hocevar committed
271
272
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
273
274
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
275

276
277
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
278
279
280
281
282
283
284
285
286
287
}

/*****************************************************************************
 * 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 */
288
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
289
290
291

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
292
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
293
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
294
295
}

296
/*****************************************************************************
297
 * RunThread: main thread loop
298
 *****************************************************************************
299
 * Thread in charge of processing the network packets and demultiplexing.
300
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
301
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
302
{
303
304
305
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

Sam Hocevar's avatar
Sam Hocevar committed
306
307
308
    /* Signal right now, otherwise we'll get stuck in a peek */
    vlc_thread_ready( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
309
310
311
312
313
    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
314
        p_input->b_dead = 1;
Sam Hocevar's avatar
   
Sam Hocevar committed
315
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
316
    }
Michel Kaempf's avatar
Michel Kaempf committed
317

318
    /* initialization is complete */
319
    vlc_mutex_lock( &p_input->stream.stream_lock );
320
321
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
322
323
    vlc_mutex_unlock( &p_input->stream.stream_lock );

324
325
326
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
   
Sam Hocevar committed
327
328
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
329
        unsigned int i, i_count;
330

Sam Hocevar's avatar
   
Sam Hocevar committed
331
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
332

333
        vlc_mutex_lock( &p_input->stream.stream_lock );
334

335
336
337
338
339
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
340
341
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
342
343

                p_input->pf_set_program( p_input,
344
                                         p_input->stream.p_new_program );
345

346
347
348
349
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

350
351
352
353
354
355
356
357
358
359
360
                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;
        }
361

362
363
        if( p_input->stream.p_new_area )
        {
364
365
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
366
                input_AccessReinit( p_input );
367
368
369

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

370
371
372
373
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

374
375
376
377
378
379
380
381
382
                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;
                }
            }
383
384
385
            p_input->stream.p_new_area = NULL;
        }

386
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
387
        {
388
            if( p_input->stream.p_selected_area->i_size > 0 )
389
            {
390
                unsigned int i;
391
                mtime_t      i_time;
392
393
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
394

Christophe Massiot's avatar
Christophe Massiot committed
395
                vlc_mutex_unlock( &p_input->stream.stream_lock );
396
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
397
                vlc_mutex_lock( &p_input->stream.stream_lock );
398

399
400
401
402
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

403
404
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
405
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
406
407
408
409

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
410

Laurent Aimar's avatar
Laurent Aimar committed
411
                vlc_mutex_unlock( &p_input->stream.stream_lock );
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
                if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
                {
                    int i;
                    vlc_value_t val;

                    /* Help in bar display */
                    val.i_time = i_time;
                    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );

                    /* Seek subs */
                    for( i = 0; i < p_input->p_sys->i_sub; i++ )
                    {
                        subtitle_Seek( p_input->p_sys->sub[i], i_time );
                    }
                }
Laurent Aimar's avatar
Laurent Aimar committed
427
                vlc_mutex_lock( &p_input->stream.stream_lock );
428
            }
429
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
430
        }
431

432
433
434
435
436
437
438
439
440
441
442
443
        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;
        }

444
445
446
447
448
449
450
451
452
453
454
455
456
457
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
463
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
464
        {
465
            /* End of file - we do not set b_die because only the
466
             * playlist is allowed to do so. */
467
            msg_Info( p_input, "EOF reached" );
468
469
470
471
472
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
473
        }
474
475
476

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
477
478
479
480
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
481
482

            /* update input status variables */
483
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
484
            {
485
                val.f_float = (float)d_pos;
486
487
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
488
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
489
            {
490
                val.i_time = i_time;
491
492
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
493
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
494
            {
495
                val.i_time = i_length;
496
497
498
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

499
500
501
502
503
504
505
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

            i_update_next = mdate() + 150000LL;
506
        }
507
508
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
509
    if( p_input->b_error || p_input->b_eof )
510
511
512
    {
        ErrorThread( p_input );
    }
513

514
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
515

Sam Hocevar's avatar
   
Sam Hocevar committed
516
    return 0;
517
518
}

519
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
520
 * InitThread: init the input Thread
521
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
522
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
523
{
524
    float f_fps;
Christophe Massiot's avatar
Christophe Massiot committed
525
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
526
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
527
    vlc_value_t val;
528
529
    subtitle_demux_t *p_sub;
    int64_t i_microsecondperframe;
gbazin's avatar
   
gbazin committed
530

Christophe Massiot's avatar
Christophe Massiot committed
531
532
533
534
535
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
536
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
537
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
538
    {
539
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
540
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
541
        psz_parser = "";
gbazin's avatar
   
gbazin committed
542
543
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
544

Christophe Massiot's avatar
Christophe Massiot committed
545
    if( !*psz_parser )
546
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
547
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
548
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
549
        free( p_input->psz_dupsource );
550
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
551
    }
Christophe Massiot's avatar
Christophe Massiot committed
552
553
554
    else
    {
        *psz_parser++ = '\0';
555

Xavier Marchesini's avatar
   
Xavier Marchesini committed
556
557
558
559
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
560
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
561
562

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
567
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
568
569
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
570
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
571
572
573
574
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
575
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
            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
592

Christophe Massiot's avatar
Christophe Massiot committed
593
594
595
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
596
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
597
598
599
600
601
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
602
    }
Christophe Massiot's avatar
Christophe Massiot committed
603

604
605
    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
606
607

    if( input_AccessInit( p_input ) == -1 )
608
    {
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
        return VLC_EGENERIC;
    }

    /* Initialize optional stream output. (before demuxer)*/
    var_Get( p_input, "sout", &val );
    if( val.psz_string != NULL )
    {
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
            free( val.psz_string );
            return VLC_EGENERIC;
        }
        free( val.psz_string );
624
    }
Christophe Massiot's avatar
Christophe Massiot committed
625

626
627
    p_input->p_es_out = EsOutCreate( p_input );

628
    /* Find and open appropriate access module */
629
630
    p_input->p_access = module_Need( p_input, "access",
                                     p_input->psz_access );
Christophe Massiot's avatar
Christophe Massiot committed
631

gbazin's avatar
   
gbazin committed
632
633
634
635
#ifndef WIN32      /* Remove this gross hack from the win32 build as colons
                    * are forbidden in filenames on Win32. */

    /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
636
637
638
639
640
641
642
643
644
645
646
    if ( p_input->p_access == NULL
          && (*p_input->psz_demux || *p_input->psz_access) )
    {
        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 );
    }
gbazin's avatar
   
gbazin committed
647
#endif
648

649
    if( p_input->p_access == NULL )
650
    {
651
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
652
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
653
654
655
656
657
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
        return VLC_EGENERIC;
658
    }
Christophe Massiot's avatar
Christophe Massiot committed
659
660
661

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
662
    {
Christophe Massiot's avatar
Christophe Massiot committed
663
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
664
    }
665
666
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
667
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
668
    }
669

gbazin's avatar
   
gbazin committed
670
671
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
672
673
674
675
    var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
gbazin's avatar
   
gbazin committed
676

Sam Hocevar's avatar
   
Sam Hocevar committed
677
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
678
    {
Christophe Massiot's avatar
Christophe Massiot committed
679
680
        while( !input_FillBuffer( p_input ) )
        {
681
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
682
            {
683
                module_Unneed( p_input, p_input->p_access );
684
685
686
687
688
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
689
690
            }
        }
691
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
692

693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
    /* Create the stream_t facilities */
    p_input->s = stream_OpenInput( p_input );
    if( p_input->s == NULL )
    {
        /* should nver occur yet */

        msg_Err( p_input, "cannot create stream_t !" );
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
        return VLC_EGENERIC;
    }

708
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
709
710
711
712
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     p_input->psz_demux : "$demux" );
Sam Hocevar's avatar
   
Sam Hocevar committed
713

714
    if( p_input->p_demux == NULL )
715
    {
716
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
717
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
718
        stream_Release( p_input->s );
719
        module_Unneed( p_input, p_input->p_access );
720
        if ( p_input->stream.p_sout != NULL )
721
        {
722
            sout_DeleteInstance( p_input->stream.p_sout );
723
        }
724
        return VLC_EGENERIC;
725
726
    }

727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
    /* Init input_thread_sys_t */
    p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
    p_input->p_sys->i_sub = 0;
    p_input->p_sys->sub   = NULL;

    /* get fps */
    if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
    {
        i_microsecondperframe = 0;
    }
    else
    {
        i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
    }

742
    /* Look for and add subtitle files */
743
744
745
    var_Get( p_input, "sub-file", &val );
    if( val.psz_string && *val.psz_string )
    {
746
        if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string), i_microsecondperframe, 0 ) ) )
747
        {
748
749
750
            /* Select this ES by default */
            es_out_Control( p_input->p_es_out, ES_OUT_SET_SELECT, p_sub->p_es, VLC_TRUE );

751
752
753
754
            TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
        }
    }
    if( val.psz_string ) free( val.psz_string );
755

756
757
    var_Get( p_input, "sub-autodetect-file", &val );
    if( val.b_bool )
758
    {
759
        int i;
760
761
        char **tmp = subtitles_Detect( p_input, "", p_input->psz_source );
        char **tmp2 = tmp;
762
        for( i = 0; *tmp2 != NULL; i++ )
763
        {
764
            if( ( p_sub = subtitle_New( p_input, strdup(*tmp2++), i_microsecondperframe, i ) ) )
765
766
767
            {
                TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
            }
768
        }
769
        free(tmp);
770
771
    }

772
    return VLC_SUCCESS;
Michel Kaempf's avatar
Michel Kaempf committed
773
774
}

775
/*****************************************************************************
776
 * ErrorThread: RunThread() error loop
777
 *****************************************************************************
778
 * This function is called when an error occured during thread main's loop.
779
 *****************************************************************************/
780
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
781
{
782
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
783
    {
784
785
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
786
787
788
    }
}

789
/*****************************************************************************
790
 * EndThread: end the input thread
791
 *****************************************************************************/
792
static void EndThread( input_thread_t * p_input )
793
{
794
    int i;
795
#ifdef HAVE_SYS_TIMES_H
796
797
798
    /* Display statistics */
    struct tms  cpu_usage;
    times( &cpu_usage );
Sam Hocevar's avatar
   
Sam Hocevar committed
799

800
    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
801
             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
802
#else
803
    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
804
#endif
805

806
807
    input_DumpStream( p_input );

gbazin's avatar
   
gbazin committed
808
809
810
811
812
813
    /* Free demultiplexer's data */
    module_Unneed( p_input, p_input->p_demux );

    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

814
815
816
    /* Close optional stream output instance */
    if ( p_input->stream.p_sout != NULL )
    {
817
818
        vlc_object_t *p_pl =
            vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
        vlc_value_t keep;

        if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
        {
            /* attach sout to the playlist */
            msg_Warn( p_input, "keeping sout" );
            vlc_object_detach( p_input->stream.p_sout );
            vlc_object_attach( p_input->stream.p_sout, p_pl );
        }
        else
        {
            msg_Warn( p_input, "destroying sout" );
            sout_DeleteInstance( p_input->stream.p_sout );
        }
        if( p_pl )
        {
            vlc_object_release( p_pl );
        }
837
838
    }

839
840
841
842
843
844
845
846
847
848
849
850
851
    /* Destroy subtitles demuxers */
    for( i = 0; i < p_input->p_sys->i_sub; i++ )
    {
        subtitle_Close( p_input->p_sys->sub[i] );
    }
    if( p_input->p_sys->i_sub > 0 )
    {
        free( p_input->p_sys->sub );
    }

    /* Free input_thread_sys_t */
    free( p_input->p_sys );

852
853
854
    /* Destroy the stream_t facilities */
    stream_Release( p_input->s );

855
856
857
    /* Destroy es out */
    EsOutRelease( p_input->p_es_out );

858
    /* Close the access plug-in */
859
    module_Unneed( p_input, p_input->p_access );
Sam Hocevar's avatar
   
Sam Hocevar committed
860

Christophe Massiot's avatar
Christophe Massiot committed
861
862
    input_AccessEnd( p_input );

863
864
865
866
    /* Free info structures XXX destroy es before 'cause vorbis */
    msg_Dbg( p_input, "freeing info structures...");
    input_DelInfo( p_input );

Christophe Massiot's avatar
Christophe Massiot committed
867
    free( p_input->psz_source );
868
    if ( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
869
870
871

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

gbazin's avatar
   
gbazin committed
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
/*****************************************************************************
 * 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:
gbazin's avatar
   
gbazin committed
951
    case VLC_VAR_MODULE:
gbazin's avatar
   
gbazin committed
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
    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;
}
970

971
972
973
974
975
976
977
978
979
/*****************************************************************************
 * es_out_t input handler
 *****************************************************************************/
struct es_out_sys_t
{
    input_thread_t *p_input;

    int         i_id;
    es_out_id_t **id;
980
981
982

    vlc_bool_t  i_audio;
    vlc_bool_t  i_video;
983
};
gbazin's avatar
   
gbazin committed
984

985
986
987
988
989
990
struct es_out_id_t
{
    es_descriptor_t *p_es;
};

static es_out_id_t *EsOutAdd    ( es_out_t *, es_format_t * );
gbazin's avatar
   
gbazin committed
991
992
static int          EsOutSend   ( es_out_t *, es_out_id_t *, block_t * );
static int          EsOutSendPES( es_out_t *, es_out_id_t *, pes_packet_t * );
993
994
995
996
997
998