input.c 48.3 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
 *****************************************************************************
zorglub's avatar
zorglub committed
6
 * Copyright (C) 1998-2004 VideoLAN
7
 * $Id$
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
#include <vlc/input.h>
33
#include <vlc/decoder.h>
34
#include <vlc/vout.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
35

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

40
41
#include "stream_output.h"

42
#include "vlc_interface.h"
43
#include "codecs.h"
44
#include "vlc_meta.h"
45
#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
struct input_thread_sys_t
{
    /* subtitles */
    int              i_sub;
    subtitle_demux_t **sub;
55
56

    int64_t          i_stop_time;
57
58
};

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

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

67
68
69
70
71
72
73
74
75
76
77
/*****************************************************************************
 * 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
78
79
static int BookmarkCallback( 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
80

81
/*****************************************************************************
82
 * input_CreateThread: creates a new input thread
83
 *****************************************************************************
84
85
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
86
 *****************************************************************************/
87
88
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
89

Michel Kaempf's avatar
Michel Kaempf committed
90
{
91
92
93
    input_thread_t *p_input;                        /* thread descriptor */
    vlc_value_t     val;
    int             i;
94

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

103
104
105
    /* Store pointer to input item descriptor */
    p_input->p_item = p_item;

gbazin's avatar
   
gbazin committed
106
    /* Parse input options */
107
108
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
gbazin's avatar
   
gbazin committed
109
    {
110
111
        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
        ParseOption( p_input, p_item->ppsz_options[i] );
gbazin's avatar
   
gbazin committed
112
    }
113
    vlc_mutex_unlock( &p_item->lock );
gbazin's avatar
   
gbazin committed
114

gbazin's avatar
   
gbazin committed
115
116
117
118
119
    /* 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 );
120
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
121
122
123
124
    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
                VLC_VAR_DOINHERIT );
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
                VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
125
126

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
127
    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
128
129
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
130
131
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

132
133
134
    /* repeat variable */
    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

135
136
137
138
    /* start/stop time */
    var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

139
    /* decoders */
gbazin's avatar
gbazin committed
140
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
141

142
143
144
    /* play status */

    /* position variable */
145
146
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
147
148
149
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
150
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
151
152
153

    /* time variable */
    var_Create( p_input, "time",  VLC_VAR_TIME );
154
    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
155
156
157
    val.i_time = 0;
    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "time", TimeCallback, NULL );
158
    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180

    /* 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 );

181
182
183
184
    /* 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
185

186
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
187
    p_input->b_eof      = 0;
188
    p_input->b_out_pace_control = VLC_FALSE;
189
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
190
191

    /* Set target */
192
193
194
    vlc_mutex_lock( &p_item->lock );
    p_input->psz_source = strdup( p_item->psz_uri );
    vlc_mutex_unlock( &p_item->lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
195

196
197
198
    /* Stream */
    p_input->s = NULL;

199
200
201
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
202
    /* Demux */
203
204
205
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
gbazin's avatar
gbazin committed
206
    p_input->pf_demux_control = demux_vaControlDefault;
207
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
   
Stéphane Borel committed
208
209

    /* Access */
210
    p_input->p_access = NULL;
211

Sam Hocevar's avatar
   
Sam Hocevar committed
212
213
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
214
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
215

216
217
218
219
220
221
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
222
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
223
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
224
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
225

226
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
227
    p_input->stream.b_changed = 0;
228
229
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
230
    p_input->stream.i_pgrm_number = 0;
231
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
232
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
233
    p_input->stream.i_mux_rate = 0;
234
    p_input->stream.b_seekable = 0;
235
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
236

Sam Hocevar's avatar
   
Sam Hocevar committed
237
238
239
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
240
241
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
242
    p_input->stream.p_selected_area = NULL;
243
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
244

Sam Hocevar's avatar
   
Sam Hocevar committed
245
246
247
248
    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
249
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
250
    input_AddArea( p_input, 0, 1 );
251
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
252

253
    /* Initialize stream control properties. */
254
    p_input->stream.control.i_status = INIT_S;
255
256
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
gbazin's avatar
   
gbazin committed
257
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
258

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

gbazin's avatar
gbazin committed
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
    /* Bookmarks */
    var_Create( p_input, "bookmarks", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "bookmark", VLC_VAR_INTEGER | VLC_VAR_HASCHOICE |
                VLC_VAR_ISCOMMAND );
    val.psz_string = _("Bookmark");
    var_Change( p_input, "bookmark", VLC_VAR_SETTEXT, &val, NULL );
    var_AddCallback( p_input, "bookmark", BookmarkCallback, NULL );

    p_input->i_bookmarks = 0;
    p_input->pp_bookmarks = NULL;

    var_Get( p_input, "bookmarks", &val );
    if( val.psz_string )
    {
        /* FIXME: have a common cfg parsing routine used by sout and others */
        char *psz_parser, *psz_start, *psz_end;
        psz_parser = val.psz_string;
        while( (psz_start = strchr( psz_parser, '{' ) ) )
        {
            seekpoint_t seekpoint;
            char backup;
            psz_start++;
            psz_end = strchr( psz_start, '}' );
            if( !psz_end ) break;
            psz_parser = psz_end + 1;
            backup = *psz_parser;
            *psz_parser = 0;
            *psz_end = ',';

            seekpoint.psz_name = 0;
            seekpoint.i_byte_offset = 0;
            seekpoint.i_time_offset = 0;
            while( (psz_end = strchr( psz_start, ',' ) ) )
            {
                *psz_end = 0;
                if( !strncmp( psz_start, "name=", 5 ) )
                {
                    seekpoint.psz_name = psz_start + 5;
                }
                else if( !strncmp( psz_start, "bytes=", 6 ) )
                {
302
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
gbazin's avatar
gbazin committed
303
304
305
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
306
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
gbazin's avatar
gbazin committed
307
308
309
310
311
312
313
314
315
316
317
318
                }
                psz_start = psz_end + 1;
            }
            msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
                     seekpoint.psz_name, seekpoint.i_byte_offset,
                     seekpoint.i_time_offset );
            input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
            *psz_parser = backup;
        }
        free( val.psz_string );
    }

319
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
320

Sam Hocevar's avatar
Sam Hocevar committed
321
    /* Create thread and wait for its readiness. */
322
323
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
324
    {
325
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
326
        free( p_input );
327
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
328
    }
329

330
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
331
332
}

333
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
334
 * input_StopThread: mark an input thread as zombie
335
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
336
 * This function should not return until the thread is effectively cancelled.
337
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
338
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
339
{
Sam Hocevar's avatar
   
Sam Hocevar committed
340
341
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
342
343
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
344

345
346
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
347
348
349
350
351
352
353
354
355
356
}

/*****************************************************************************
 * 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 */
357
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
358
359
360

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
361
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
362
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
363
364
}

365
/*****************************************************************************
366
 * RunThread: main thread loop
367
 *****************************************************************************
368
 * Thread in charge of processing the network packets and demultiplexing.
369
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
370
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
371
{
372
373
374
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

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

Sam Hocevar's avatar
   
Sam Hocevar committed
378
379
380
381
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
382

Sam Hocevar's avatar
   
Sam Hocevar committed
383
        ErrorThread( p_input );
384
385
386
387

        /* Tell we're dead */
        p_input->b_dead = 1;

Sam Hocevar's avatar
   
Sam Hocevar committed
388
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
389
    }
Michel Kaempf's avatar
Michel Kaempf committed
390

391
    /* initialization is complete */
392
    vlc_mutex_lock( &p_input->stream.stream_lock );
393
394
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
395
396
    vlc_mutex_unlock( &p_input->stream.stream_lock );

397
398
399
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
   
Sam Hocevar committed
400
401
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
402
        unsigned int i, i_count;
403

Sam Hocevar's avatar
   
Sam Hocevar committed
404
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
405

406
        vlc_mutex_lock( &p_input->stream.stream_lock );
407

408
409
410
411
412
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
413
414
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
415
416

                p_input->pf_set_program( p_input,
417
                                         p_input->stream.p_new_program );
418

419
420
421
422
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

423
424
425
426
427
428
429
430
431
432
433
                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;
        }
434

435
436
        if( p_input->stream.p_new_area )
        {
437
438
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
439
                input_AccessReinit( p_input );
440
441
442

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

443
444
445
446
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

447
448
449
450
451
452
453
454
455
                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;
                }
            }
456
457
458
            p_input->stream.p_new_area = NULL;
        }

459
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
460
        {
461
            if( p_input->stream.p_selected_area->i_size > 0 )
462
            {
463
                unsigned int i;
464
                mtime_t      i_time;
465
466
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
467

Christophe Massiot's avatar
Christophe Massiot committed
468
                vlc_mutex_unlock( &p_input->stream.stream_lock );
469
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
470
                vlc_mutex_lock( &p_input->stream.stream_lock );
471

472
473
474
475
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

476
477
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
478
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
479
480
481
482

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

Laurent Aimar's avatar
Laurent Aimar committed
484
                vlc_mutex_unlock( &p_input->stream.stream_lock );
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
                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 );
                    }
                }
500
501
502
503
504
                if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
                {
                    val.f_float = (float)f;
                    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
                }
Laurent Aimar's avatar
Laurent Aimar committed
505
                vlc_mutex_lock( &p_input->stream.stream_lock );
506
            }
507
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
508
        }
509

510
511
512
513
514
515
516
517
518
519
520
521
        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;
        }

522
523
524
525
526
527
528
529
530
531
532
533
534
535
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
541
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
542
        {
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
            vlc_value_t repeat;

            var_Get( p_input, "input-repeat", &repeat );
            if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
            {
                /* End of file - we do not set b_die because only the
                 * playlist is allowed to do so. */
                msg_Info( p_input, "EOF reached" );
                p_input->b_eof = 1;
            }
            else
            {
                msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
                if( repeat.i_int > 0 )
                {
                    repeat.i_int--;
                    var_Set( p_input, "input-repeat", repeat );
                }

                p_input->stream.p_new_area = p_input->stream.pp_areas[0];
                p_input->stream.p_new_area->i_seek = 0;
            }
565
566
567
568
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
569
        }
570
571
572

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
573
574
575
576
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
577
578

            /* update input status variables */
579
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
580
            {
581
                val.f_float = (float)d_pos;
582
583
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
584
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
585
            {
586
                val.i_time = i_time;
587
588
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
589
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
590
            {
591
                val.i_time = i_length;
592
593
594
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

595
596
597
598
599
600
601
            /* Check stop-time */
            if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
            {
                msg_Warn( p_input, "EOF reached because of stop-time" );
                p_input->b_eof = 1;
            }

602
603
604
605
606
607
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

608
            i_update_next = mdate() + I64C(150000);
609
        }
610
611
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
612
    if( p_input->b_error || p_input->b_eof )
613
614
615
    {
        ErrorThread( p_input );
    }
616

617
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
618

Sam Hocevar's avatar
   
Sam Hocevar committed
619
    return 0;
620
621
}

622
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
623
 * InitThread: init the input Thread
624
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
625
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
626
{
gbazin's avatar
gbazin committed
627
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
628
629
//    float f_fps;
    double f_fps;
sigmunau's avatar
sigmunau committed
630
    mtime_t i_length;
631

Christophe Massiot's avatar
Christophe Massiot committed
632
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
633
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
634
    vlc_value_t val;
635
    int64_t i_microsecondperframe;
gbazin's avatar
   
gbazin committed
636

637
    subtitle_demux_t *p_sub_toselect = NULL;
638
    char             *psz_sub_file = NULL;
639

Christophe Massiot's avatar
Christophe Massiot committed
640
641
642
643
644
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
645
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
646
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
647
    {
648
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
649
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
650
        psz_parser = "";
gbazin's avatar
   
gbazin committed
651
652
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
653

Christophe Massiot's avatar
Christophe Massiot committed
654
    if( !*psz_parser )
655
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
656
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
657
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
658
        free( p_input->psz_dupsource );
659
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
660
    }
Christophe Massiot's avatar
Christophe Massiot committed
661
662
663
    else
    {
        *psz_parser++ = '\0';
664

Xavier Marchesini's avatar
   
Xavier Marchesini committed
665
666
667
668
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
669
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
670
671

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
676
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
677
678
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
679
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
680
681
682
683
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
684
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
            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
701

Christophe Massiot's avatar
Christophe Massiot committed
702
703
704
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
705
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
706
707
708
709
710
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
711
    }
Christophe Massiot's avatar
Christophe Massiot committed
712

713
714
    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
715
716

    if( input_AccessInit( p_input ) == -1 )
717
    {
718
719
720
721
722
723
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

724
725
726
727
728
729
730
731
732
733
734
735
        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 );
736
737
738
739
740
741
742

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
743
744
745
            return VLC_EGENERIC;
        }
        free( val.psz_string );
746
    }
Christophe Massiot's avatar
Christophe Massiot committed
747

748
    p_input->p_es_out = input_EsOutNew( p_input );
749
750
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
751

752
    /* Find and open appropriate access module */
753
    p_input->p_access = module_Need( p_input, "access",
gbazin's avatar
   
gbazin committed
754
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
755

gbazin's avatar
   
gbazin committed
756
757
758
759
#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 */
760
761
762
763
764
765
766
767
768
    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",
gbazin's avatar
   
gbazin committed
769
                                         p_input->psz_access, VLC_TRUE );
770
    }
gbazin's avatar
   
gbazin committed
771
#endif
772

773
    if( p_input->p_access == NULL )
774
    {
775
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
776
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
777
778
779
780
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
781
782
783
784
785
786
787

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
gbazin's avatar
   
gbazin committed
788
        input_EsOutDelete( p_input->p_es_out );
789
        return VLC_EGENERIC;
790
    }
Christophe Massiot's avatar
Christophe Massiot committed
791
792
793

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
794
    {
Christophe Massiot's avatar
Christophe Massiot committed
795
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
796
    }
797
798
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
799
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
800
    }
801

gbazin's avatar
   
gbazin committed
802
803
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
804
805
806
807
    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
808

Sam Hocevar's avatar
   
Sam Hocevar committed
809
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
810
    {
Christophe Massiot's avatar
Christophe Massiot committed
811
812
        while( !input_FillBuffer( p_input ) )
        {
813
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
814
            {
815
                module_Unneed( p_input, p_input->p_access );
816
817
818
819
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
820
821
822
823
824
825
                input_AccessEnd( p_input );
                free( p_input->psz_source );
                if( p_input->psz_dupsource != NULL )
                {
                    free( p_input->psz_dupsource );
                }
gbazin's avatar
   
gbazin committed
826
                input_EsOutDelete( p_input->p_es_out );
827
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
828
829
            }
        }
830
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
831

832
    /* Create the stream_t facilities */
833
    p_input->s = input_StreamNew( p_input );
834
835
    if( p_input->s == NULL )
    {
zorglub's avatar
zorglub committed
836
        /* should never occur yet */
837

zorglub's avatar
zorglub committed
838
        msg_Err( p_input, "cannot create stream_t" );
839

840
841
842
843
844
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
845
846
847
848
849
850
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
gbazin's avatar
   
gbazin committed
851
        input_EsOutDelete( p_input->p_es_out );
852
853
854
        return VLC_EGENERIC;
    }

855
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
856
857
858
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
gbazin's avatar
   
gbazin committed
859
860
861
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
   
Sam Hocevar committed
862

863
    if( p_input->p_demux == NULL )
864
    {
865
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
866
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
867

868
        input_StreamDelete( p_input->s );
869
        module_Unneed( p_input, p_input->p_access );
870
        if ( p_input->stream.p_sout != NULL )
871
        {
872
            sout_DeleteInstance( p_input->stream.p_sout );
873
        }
874
875
876
877
878
879
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
gbazin's avatar
   
gbazin committed
880
        input_EsOutDelete( p_input->p_es_out );
881
        return VLC_EGENERIC;
882
883
    }

884
885
886
887
888
    /* 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;

889
890
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
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
    /* Get meta information from user */
    var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    if( (p_meta_user = vlc_meta_New()) )
    {
        vlc_value_t val;

        var_Get( p_input, "meta-title", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-author", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-artist", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-genre", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-copyright", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-description", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-date", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-url", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
    }

    /* Get meta informations from demuxer */
    if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
        ( p_meta_user && p_meta_user->i_meta ) )
941
942
943
    {
        int i;

gbazin's avatar
gbazin committed
944
945
946
947
        /* Merge demux and user metadata */
        if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
        else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );

948
        msg_Dbg( p_input, "meta informations:" );
gbazin's avatar
gbazin committed
949
        if( p_meta->i_meta > 0 )
950
        {
gbazin's avatar
gbazin committed
951
            for( i = 0; i < p_meta->i_meta; i++ )
952
            {
gbazin's avatar
gbazin committed
953
954
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
955
956
957
958
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )