input.c 41.9 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
gbazin's avatar
   
gbazin committed
7
 * $Id: input.c,v 1.292 2004/03/03 20:39:53 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
#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
#include "vlc_playlist.h"
41

42
43
#include "stream_output.h"

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

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

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
/*****************************************************************************
80
 * input_CreateThread: creates a new input thread
81
 *****************************************************************************
82
83
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
84
 *****************************************************************************/
85
86
87
input_thread_t *__input_CreateThread( vlc_object_t *p_parent, char *psz_uri,
                                      char **ppsz_options, int i_options )

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

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

gbazin's avatar
   
gbazin committed
101
    /* Parse input options */
102
    for( i = 0; i < i_options; i++ )
gbazin's avatar
   
gbazin committed
103
    {
104
105
        msg_Dbg( p_input, "option: %s", ppsz_options[i] );
        ParseOption( p_input, ppsz_options[i] );
gbazin's avatar
   
gbazin committed
106
107
    }

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

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
118
    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
119
120
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
121
122
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

123
124
125
    /* repeat variable */
    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

126
127
128
    /* decoders */
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

129
130
131
    /* play status */

    /* position variable */
132
133
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
134
135
136
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
137
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
138
139
140

    /* time variable */
    var_Create( p_input, "time",  VLC_VAR_TIME );
141
    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
142
143
144
    val.i_time = 0;
    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "time", TimeCallback, NULL );
145
    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167

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

168
169
170
171
    /* 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
172

173
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
174
    p_input->b_eof      = 0;
175
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
176
177

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

180
181
182
    /* Stream */
    p_input->s = NULL;

183
184
185
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
186
    /* Demux */
187
188
189
190
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
    p_input->pf_demux_control = NULL;
191
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
   
Stéphane Borel committed
192
193

    /* Access */
194
    p_input->p_access = NULL;
195

Sam Hocevar's avatar
   
Sam Hocevar committed
196
197
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
198
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
199

200
201
202
203
204
205
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
206
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
207
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
208
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
209

210
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
211
    p_input->stream.b_changed = 0;
212
213
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
214
    p_input->stream.i_pgrm_number = 0;
215
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
216
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
217
    p_input->stream.i_mux_rate = 0;
218
    p_input->stream.b_seekable = 0;
219
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
220

Sam Hocevar's avatar
   
Sam Hocevar committed
221
222
223
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
224
225
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
226
    p_input->stream.p_selected_area = NULL;
227
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
228

Sam Hocevar's avatar
   
Sam Hocevar committed
229
230
231
232
    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
233
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
234
    input_AddArea( p_input, 0, 1 );
235
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
236

237
    /* Initialize stream control properties. */
238
    p_input->stream.control.i_status = INIT_S;
239
240
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
gbazin's avatar
   
gbazin committed
241
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
242

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

gbazin's avatar
   
gbazin committed
245
246
247
248
249
    /* Initialize input info */
    p_input->stream.p_info = NULL;
    p_input->stream.p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_input->stream.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" );
gbazin's avatar
   
gbazin committed
257
        input_DelInfo( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
258
        free( p_input );
259
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
260
    }
261

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

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

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

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

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

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
310
311
312
313
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
314

Sam Hocevar's avatar
   
Sam Hocevar committed
315
        ErrorThread( p_input );
316
317
318
319

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

gbazin's avatar
   
gbazin committed
320
321
        input_DelInfo( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
322
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
323
    }
Michel Kaempf's avatar
Michel Kaempf committed
324

325
    /* initialization is complete */
326
    vlc_mutex_lock( &p_input->stream.stream_lock );
327
328
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
329
330
    vlc_mutex_unlock( &p_input->stream.stream_lock );

331
332
333
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
   
Sam Hocevar committed
334
335
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
336
        unsigned int i, i_count;
337

Sam Hocevar's avatar
   
Sam Hocevar committed
338
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
339

340
        vlc_mutex_lock( &p_input->stream.stream_lock );
341

342
343
344
345
346
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
347
348
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
349
350

                p_input->pf_set_program( p_input,
351
                                         p_input->stream.p_new_program );
352

353
354
355
356
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

357
358
359
360
361
362
363
364
365
366
367
                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;
        }
368

369
370
        if( p_input->stream.p_new_area )
        {
371
372
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
373
                input_AccessReinit( p_input );
374
375
376

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

377
378
379
380
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

381
382
383
384
385
386
387
388
389
                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;
                }
            }
390
391
392
            p_input->stream.p_new_area = NULL;
        }

393
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
394
        {
395
            if( p_input->stream.p_selected_area->i_size > 0 )
396
            {
397
                unsigned int i;
398
                mtime_t      i_time;
399
400
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
401

Christophe Massiot's avatar
Christophe Massiot committed
402
                vlc_mutex_unlock( &p_input->stream.stream_lock );
403
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
404
                vlc_mutex_lock( &p_input->stream.stream_lock );
405

406
407
408
409
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

410
411
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
412
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
413
414
415
416

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

Laurent Aimar's avatar
Laurent Aimar committed
418
                vlc_mutex_unlock( &p_input->stream.stream_lock );
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
                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
434
                vlc_mutex_lock( &p_input->stream.stream_lock );
435
            }
436
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
437
        }
438

439
440
441
442
443
444
445
446
447
448
449
450
        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;
        }

451
452
453
454
455
456
457
458
459
460
461
462
463
464
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
470
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
471
        {
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
            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;
            }
494
495
496
497
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
498
        }
499
500
501

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
502
503
504
505
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
506
507

            /* update input status variables */
508
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
509
            {
510
                val.f_float = (float)d_pos;
511
512
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
513
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
514
            {
515
                val.i_time = i_time;
516
517
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
518
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
519
            {
520
                val.i_time = i_length;
521
522
523
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

524
525
526
527
528
529
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

530
            i_update_next = mdate() + I64C(150000);
531
        }
532
533
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
534
    if( p_input->b_error || p_input->b_eof )
535
536
537
    {
        ErrorThread( p_input );
    }
538

539
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
540

Sam Hocevar's avatar
   
Sam Hocevar committed
541
    return 0;
542
543
}

544
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
545
 * InitThread: init the input Thread
546
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
547
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
548
{
549
    vlc_meta_t *meta;
550
    float f_fps;
sigmunau's avatar
sigmunau committed
551
552
    playlist_t *p_playlist;
    mtime_t i_length;
553

Christophe Massiot's avatar
Christophe Massiot committed
554
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
555
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
556
    vlc_value_t val;
557
    int64_t i_microsecondperframe;
gbazin's avatar
   
gbazin committed
558

559
    subtitle_demux_t *p_sub_toselect = NULL;
560
    char             *psz_sub_file = NULL;
561

Christophe Massiot's avatar
Christophe Massiot committed
562
563
564
565
566
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
567
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
568
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
569
    {
570
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
571
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
572
        psz_parser = "";
gbazin's avatar
   
gbazin committed
573
574
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
575

Christophe Massiot's avatar
Christophe Massiot committed
576
    if( !*psz_parser )
577
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
578
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
579
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
580
        free( p_input->psz_dupsource );
581
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
582
    }
Christophe Massiot's avatar
Christophe Massiot committed
583
584
585
    else
    {
        *psz_parser++ = '\0';
586

Xavier Marchesini's avatar
   
Xavier Marchesini committed
587
588
589
590
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
591
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
592
593

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
598
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
599
600
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
601
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
602
603
604
605
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
606
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
            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
623

Christophe Massiot's avatar
Christophe Massiot committed
624
625
626
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
627
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
628
629
630
631
632
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
633
    }
Christophe Massiot's avatar
Christophe Massiot committed
634

635
636
    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
637
638

    if( input_AccessInit( p_input ) == -1 )
639
    {
640
641
642
643
644
645
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

646
647
648
649
650
651
652
653
654
655
656
657
        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 );
658
659
660
661
662
663
664

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
665
666
667
            return VLC_EGENERIC;
        }
        free( val.psz_string );
668
    }
Christophe Massiot's avatar
Christophe Massiot committed
669

670
    p_input->p_es_out = input_EsOutNew( p_input );
671
672
    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 );
673

674
    /* Find and open appropriate access module */
675
    p_input->p_access = module_Need( p_input, "access",
gbazin's avatar
   
gbazin committed
676
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
677

gbazin's avatar
   
gbazin committed
678
679
680
681
#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 */
682
683
684
685
686
687
688
689
690
    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
691
                                         p_input->psz_access, VLC_TRUE );
692
    }
gbazin's avatar
   
gbazin committed
693
#endif
694

695
    if( p_input->p_access == NULL )
696
    {
697
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
698
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
699
700
701
702
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
703
704
705
706
707
708
709

        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
710
        input_EsOutDelete( p_input->p_es_out );
711
        return VLC_EGENERIC;
712
    }
Christophe Massiot's avatar
Christophe Massiot committed
713
714
715

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
716
    {
Christophe Massiot's avatar
Christophe Massiot committed
717
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
718
    }
719
720
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
721
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
722
    }
723

gbazin's avatar
   
gbazin committed
724
725
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
726
727
728
729
    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
730

Sam Hocevar's avatar
   
Sam Hocevar committed
731
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
732
    {
Christophe Massiot's avatar
Christophe Massiot committed
733
734
        while( !input_FillBuffer( p_input ) )
        {
735
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
736
            {
737
                module_Unneed( p_input, p_input->p_access );
738
739
740
741
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
742
743
744
745
746
747
                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
748
                input_EsOutDelete( p_input->p_es_out );
749
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
750
751
            }
        }
752
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
753

754
    /* Create the stream_t facilities */
755
    p_input->s = input_StreamNew( p_input );
756
757
    if( p_input->s == NULL )
    {
zorglub's avatar
zorglub committed
758
        /* should never occur yet */
759

zorglub's avatar
zorglub committed
760
        msg_Err( p_input, "cannot create stream_t" );
761

762
763
764
765
766
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
767
768
769
770
771
772
        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
773
        input_EsOutDelete( p_input->p_es_out );
774
775
776
        return VLC_EGENERIC;
    }

777
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
778
779
780
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
gbazin's avatar
   
gbazin committed
781
782
783
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
   
Sam Hocevar committed
784

785
    if( p_input->p_demux == NULL )
786
    {
787
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
788
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
789

790
        input_StreamDelete( p_input->s );
791
        module_Unneed( p_input, p_input->p_access );
792
        if ( p_input->stream.p_sout != NULL )
793
        {
794
            sout_DeleteInstance( p_input->stream.p_sout );
795
        }
796
797
798
799
800
801
        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
802
        input_EsOutDelete( p_input->p_es_out );
803
        return VLC_EGENERIC;
804
805
    }

806
807
808
809
810
    /* 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;

811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
    /* get meta informations */
    if( !demux_Control( p_input, DEMUX_GET_META, &meta ) )
    {
        playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_input,
                                         VLC_OBJECT_PLAYLIST,  FIND_PARENT);
        playlist_item_t *p_item = NULL;
        input_info_category_t *p_cat;
        int i;

        if( p_playlist )
        {
            vlc_mutex_lock( &p_playlist->object_lock );
            p_item = playlist_ItemGetByPos( p_playlist, -1 );
            if( p_item )
            {
                vlc_mutex_lock( &p_item->lock );
            }
            vlc_mutex_unlock( &p_playlist->object_lock );
        }

        msg_Dbg( p_input, "meta informations:" );
        if( meta->i_meta > 0 )
        {
            p_cat = input_InfoCategory( p_input, _("File") );
            for( i = 0; i < meta->i_meta; i++ )
            {
                msg_Dbg( p_input, "  - '%s' = '%s'", _(meta->name[i]), meta->value[i] );
838
839
840
841
842
843
844
845
846
                if( !strcmp( meta->name[i], VLC_META_TITLE ) )
                {
                    playlist_ItemSetName( p_item, meta->value[i] );
                }
                if( !strcmp( meta->name[i], VLC_META_AUTHOR ) )
                {
                    playlist_ItemAddInfo( p_item, _("General"), _("Author"),
                                            meta->value[i] );
                }
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
                input_AddInfo( p_cat, _(meta->name[i]), "%s", meta->value[i] );
                if( p_item )
                {
                    playlist_ItemAddInfo( p_item, _("File"),
                                          _(meta->name[i]), "%s", meta->value[i] );
                }
            }
        }
        for( i = 0; i < meta->i_track; i++ )
        {
            vlc_meta_t *tk = meta->track[i];
            int j;

            msg_Dbg( p_input, "  - track[%d]:", i );
            if( tk->i_meta > 0 )
            {
                char *psz_cat = malloc( strlen(_("Stream")) + 10 );
                sprintf( psz_cat, "%s %d", _("Stream"), i );
                p_cat = input_InfoCategory( p_input, psz_cat );

                for( j = 0; j < tk->i_meta; j++ )
                {
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]), tk->value[j] );
                    input_AddInfo( p_cat, _(tk->name[j]), "%s", tk->value[j] );
                    if( p_item )
                    {
                        playlist_ItemAddInfo( p_item, psz_cat,
                                              _(tk->name[j]), "%s", tk->value[j] );
                    }
                }
            }
        }

        if( p_item )
        {
            vlc_mutex_unlock( &p_item->lock );
        }
        if( p_playlist ) vlc_object_release( p_playlist );

        vlc_meta_Delete( meta );
    }

sigmunau's avatar
sigmunau committed
889
890
891
    /* get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) && i_length > 0 )
    {
892
        input_info_category_t *p_cat = input_InfoCategory( p_input, _("File") );
sigmunau's avatar
sigmunau committed
893
894
895
896
897
        p_playlist = (playlist_t*)vlc_object_find( p_input,
                                                   VLC_OBJECT_PLAYLIST,
                                                   FIND_PARENT );
        if( p_playlist )
        {
898
            playlist_SetDuration( p_playlist, -1 , i_length );
899
            val.b_bool = p_playlist->i_index;
900
            var_Set( p_playlist, "item-change", val );
sigmunau's avatar
sigmunau committed
901
902
            vlc_object_release( p_playlist );
        }
903
904
905
906
907
908
        if( p_cat )
        {
            char psz_buffer[MSTRTIME_MAX_SIZE];
            input_AddInfo( p_cat, _("Duration"),
                           msecstotimestr( psz_buffer, i_length / 1000 ) );
        }
909
910
    }

sigmunau's avatar
sigmunau committed
911

912
913
914
915
916
917
918
919
920
921
    /* 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 );
    }

922
    /* Look for and add subtitle files */
923
924
925
    var_Get( p_input, "sub-file", &val );
    if( val.psz_string && *val.psz_string )
    {
926
        subtitle_demux_t *p_sub;
Laurent Aimar's avatar
Laurent Aimar committed
927
928

        msg_Dbg( p_input, "force subtitle: %s", val.psz_string );
zorglub's avatar
zorglub committed
929
        if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string),
hartman's avatar
hartman committed
930
                                    i_microsecondperframe ) ) )
931
        {
932
            p_sub_toselect = p_sub;
933
934
935
            TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
        }
    }
936
    psz_sub_file = val.psz_string;
937

938
939
    var_Get( p_input, "sub-autodetect-file", &val );
    if( val.b_bool )
940
    {
941
        subtitle_demux_t *p_sub;
942
        int i;
943
        char **tmp = subtitles_Detect( p_input, "", p_input->psz_name );
944
        char **tmp2 = tmp;
945
        for( i = 0; *tmp2 != NULL; i