input.c 49.5 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
};

59
60
61
62
static  int RunThread  ( input_thread_t *p_input );
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

64
65
66
static void ParseOption( input_thread_t *p_input, const char *psz_option );

static void DecodeUrl  ( char * );
67

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
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
81

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

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

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

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

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

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

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

135
136
137
    /* repeat variable */
    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

138
139
140
141
    /* 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 );

142
    /* decoders */
gbazin's avatar
gbazin committed
143
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
144

145
146
147
    /* play status */

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

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

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

184
185
186
187
    /* 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
188

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

    /* Set target */
195
196
197
    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
198

199
200
201
    /* Stream */
    p_input->s = NULL;

202
203
204
    /* es out */
    p_input->p_es_out = NULL;

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

    /* Access */
213
    p_input->p_access = NULL;
214

Sam Hocevar's avatar
   
Sam Hocevar committed
215
216
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
217
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
218

219
220
221
222
223
224
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
240
241
242
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

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

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

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

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

gbazin's avatar
gbazin committed
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
302
303
304
    /* 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 ) )
                {
305
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
gbazin's avatar
gbazin committed
306
307
308
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
309
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
gbazin's avatar
gbazin committed
310
311
312
313
314
315
316
317
318
319
320
321
                }
                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 );
    }

322
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
323

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

333
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
334
335
}

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

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

/*****************************************************************************
 * 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 */
360
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
361
362
363

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

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

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
386
        ErrorThread( p_input );
387
388
389
390

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

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

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

400
401
402
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

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

Sam Hocevar's avatar
   
Sam Hocevar committed
407
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
408

409
        vlc_mutex_lock( &p_input->stream.stream_lock );
410

411
412
413
414
415
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
416
417
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
418
419

                p_input->pf_set_program( p_input,
420
                                         p_input->stream.p_new_program );
421

422
423
424
425
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

426
427
428
429
430
431
432
433
434
435
436
                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;
        }
437

438
439
        if( p_input->stream.p_new_area )
        {
440
441
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
442
                input_AccessReinit( p_input );
443
444
445

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

446
447
448
449
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

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

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

Christophe Massiot's avatar
Christophe Massiot committed
471
                vlc_mutex_unlock( &p_input->stream.stream_lock );
472
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
473
                vlc_mutex_lock( &p_input->stream.stream_lock );
474

475
476
477
478
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

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

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

Laurent Aimar's avatar
Laurent Aimar committed
487
                vlc_mutex_unlock( &p_input->stream.stream_lock );
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
                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 );
                    }
                }
503
504
505
506
507
                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
508
                vlc_mutex_lock( &p_input->stream.stream_lock );
509
            }
510
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
511
        }
512

513
514
515
516
517
518
519
520
521
522
523
524
        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;
        }

525
526
527
528
529
530
531
532
533
534
535
536
537
538
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
544
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
545
        {
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
            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;
            }
568
569
570
571
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
572
        }
573
574
575

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

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

598
599
600
601
602
603
604
            /* 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;
            }

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

611
            i_update_next = mdate() + I64C(150000);
612
        }
613
614
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
615
    if( p_input->b_error || p_input->b_eof )
616
617
618
    {
        ErrorThread( p_input );
    }
619

620
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
621

Sam Hocevar's avatar
   
Sam Hocevar committed
622
    return 0;
623
624
}

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

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

640
    subtitle_demux_t *p_sub_toselect = NULL;
641
    char             *psz_sub_file = NULL;
642

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

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

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

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

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

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

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

716
717
    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
718
719

    if( input_AccessInit( p_input ) == -1 )
720
    {
721
722
723
724
725
726
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

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

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

751
    p_input->p_es_out = input_EsOutNew( p_input );
752
753
    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 );
754

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

759
760
761
762
763
764
765
766
767
    /* Maybe we had an encoded url */
    if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
    {
        DecodeUrl( p_input->psz_name );

        msg_Dbg( p_input, "retying with %s", p_input->psz_name );
        p_input->p_access = module_Need( p_input, "access",
                                         p_input->psz_access, VLC_TRUE );
    }
gbazin's avatar
   
gbazin committed
768
769
770
771
#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 */
772
773
774
775
776
777
778
779
780
    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
781
                                         p_input->psz_access, VLC_TRUE );
782
    }
gbazin's avatar
   
gbazin committed
783
#endif
784
    if( p_input->p_access == NULL )
785
    {
786
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
787
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
788
789
790
791
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
792
793
794
795
796
797
798

        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
799
        input_EsOutDelete( p_input->p_es_out );
800
        return VLC_EGENERIC;
801
    }
Christophe Massiot's avatar
Christophe Massiot committed
802
803
804

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
805
    {
Christophe Massiot's avatar
Christophe Massiot committed
806
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
807
    }
808
809
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
810
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
811
    }
812

gbazin's avatar
   
gbazin committed
813
814
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
815
816
817
818
    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
819

Sam Hocevar's avatar
   
Sam Hocevar committed
820
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
821
    {
Christophe Massiot's avatar
Christophe Massiot committed
822
823
        while( !input_FillBuffer( p_input ) )
        {
824
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
825
            {
826
                module_Unneed( p_input, p_input->p_access );
827
828
829
830
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
831
832
833
834
835
836
                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
837
                input_EsOutDelete( p_input->p_es_out );
838
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
839
840
            }
        }
841
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
842

843
    /* Create the stream_t facilities */
844
    p_input->s = input_StreamNew( p_input );
845
846
    if( p_input->s == NULL )
    {
zorglub's avatar
zorglub committed
847
        /* should never occur yet */
848

zorglub's avatar
zorglub committed
849
        msg_Err( p_input, "cannot create stream_t" );
850

851
852
853
854
855
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
856
857
858
859
860
861
        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
862
        input_EsOutDelete( p_input->p_es_out );
863
864
865
        return VLC_EGENERIC;
    }

866
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
867
868
869
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
gbazin's avatar
   
gbazin committed
870
871
872
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
   
Sam Hocevar committed
873

874
    if( p_input->p_demux == NULL )
875
    {
876
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
877
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
878

879
        input_StreamDelete( p_input->s );
880
        module_Unneed( p_input, p_input->p_access );
881
        if ( p_input->stream.p_sout != NULL )
882
        {
883
            sout_DeleteInstance( p_input->stream.p_sout );
884
        }
885
886
887
888
889
890
        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
891
        input_EsOutDelete( p_input->p_es_out );
892
        return VLC_EGENERIC;
893
894
    }

895
896
897
898
899
    /* 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;

900
901
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
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
951
    /* 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 ) )
952
953
954
    {
        int i;

gbazin's avatar
gbazin committed
955
956
957
958
        /* 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 );

959
        msg_Dbg( p_input, "meta informations:" );
gbazin's avatar
gbazin committed
960
        if( p_meta->i_meta > 0 )
961
        {
gbazin's avatar
gbazin committed
962
            for( i = 0; i < p_meta->i_meta; i++ )
963
            {
gbazin's avatar
gbazin committed
964
965
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->