input.c 49.4 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
124
125
    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
126
127

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

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

136
137
138
139
    /* 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 );

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

143
144
145
    /* play status */

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

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

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

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

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

    /* Set target */
193
194
195
    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
196

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

zorglub's avatar
zorglub committed
847
        msg_Err( p_input, "cannot create stream_t" );
848

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

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

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

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

893
894
895
896
897
    /* 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;

898
899
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
    /* 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 ) )
950
951
952
    {
        int i;

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

957
        msg_Dbg( p_input, "meta informations:" );
gbazin's avatar
gbazin committed
958
        if( p_meta->i_meta > 0 )
959
        {
gbazin's avatar
gbazin committed
960
            for( i = 0; i < p_meta->i_meta; i++ )
961
            {
gbazin's avatar
gbazin committed
962
963
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
964
965
966
967
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );