input.c 49.7 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
#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
struct input_thread_sys_t
{
    /* subtitles */
    int              i_sub;
    subtitle_demux_t **sub;
57
58

    int64_t          i_stop_time;
59
60
};

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

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

69
70
71
72
73
74
75
76
77
78
79
/*****************************************************************************
 * 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
80
81
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
82

83
/*****************************************************************************
84
 * input_CreateThread: creates a new input thread
85
 *****************************************************************************
86
87
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
88
 *****************************************************************************/
89
90
91
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
92
{
93
94
95
    input_thread_t *p_input;                        /* thread descriptor */
    vlc_value_t     val;
    int             i;
96

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

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

gbazin's avatar
   
gbazin committed
112
113
114
115
116
    /* 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 );
117
118
    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 );
119
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
120
121

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
122
    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
123
124
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
125
126
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

127
128
129
    /* repeat variable */
    var_Create( p_input, "input-repeat", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

130
131
132
133
    /* 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 );

134
    /* decoders */
gbazin's avatar
gbazin committed
135
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL|VLC_VAR_DOINHERIT );
136

137
138
139
    /* play status */

    /* position variable */
140
141
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
142
143
144
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
145
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
146
147
148

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

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

176
177
178
179
    /* 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
180

181
    /* Initialize thread properties */
Sam Hocevar's avatar
   
Sam Hocevar committed
182
    p_input->b_eof      = 0;
183
    p_input->b_out_pace_control = VLC_FALSE;
184
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
185
186

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

189
190
191
    /* Stream */
    p_input->s = NULL;

192
193
194
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
195
    /* Demux */
196
197
198
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
gbazin's avatar
gbazin committed
199
    p_input->pf_demux_control = demux_vaControlDefault;
200
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
   
Stéphane Borel committed
201
202

    /* Access */
203
    p_input->p_access = NULL;
204

Sam Hocevar's avatar
   
Sam Hocevar committed
205
206
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
gbazin's avatar
   
gbazin committed
207
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
   
Sam Hocevar committed
208

209
210
211
212
213
214
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
215
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
216
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
217
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
218

219
    /* Initialize stream description */
Stéphane Borel's avatar
   
Stéphane Borel committed
220
    p_input->stream.b_changed = 0;
221
222
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
223
    p_input->stream.i_pgrm_number = 0;
224
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
225
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
226
    p_input->stream.i_mux_rate = 0;
227
    p_input->stream.b_seekable = 0;
228
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
229

Sam Hocevar's avatar
   
Sam Hocevar committed
230
231
232
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
   
Stéphane Borel committed
233
234
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
235
    p_input->stream.p_selected_area = NULL;
236
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
237

Sam Hocevar's avatar
   
Sam Hocevar committed
238
239
240
241
    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
242
    /* By default there is one area in a stream */
gbazin's avatar
   
gbazin committed
243
    input_AddArea( p_input, 0, 1 );
244
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
   
Stéphane Borel committed
245

246
    /* Initialize stream control properties. */
247
    p_input->stream.control.i_status = INIT_S;
248
249
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
gbazin's avatar
   
gbazin committed
250
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
251

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

gbazin's avatar
gbazin committed
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
    /* 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 ) )
                {
                    seekpoint.i_byte_offset = atol(psz_start + 6);
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
                    seekpoint.i_time_offset = atol(psz_start + 5) * 1000000;
                }
                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 );
    }

gbazin's avatar
   
gbazin committed
312
313
314
315
316
    /* 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 );
317
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
318

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

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

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

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

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

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

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

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

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

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

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

gbazin's avatar
   
gbazin committed
387
388
        input_DelInfo( p_input );

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 );
                    }
                }
Laurent Aimar's avatar
Laurent Aimar committed
501
                vlc_mutex_lock( &p_input->stream.stream_lock );
502
            }
503
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
504
        }
505

506
507
508
509
510
511
512
513
514
515
516
517
        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;
        }

518
519
520
521
522
523
524
525
526
527
528
529
530
531
        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;
        }

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

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

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

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
569
570
571
572
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
573
574

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

591
592
593
594
595
596
597
            /* 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;
            }

598
599
600
601
602
603
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

604
            i_update_next = mdate() + I64C(150000);
605
        }
606
607
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
608
    if( p_input->b_error || p_input->b_eof )
609
610
611
    {
        ErrorThread( p_input );
    }
612

613
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
614

Sam Hocevar's avatar
   
Sam Hocevar committed
615
    return 0;
616
617
}

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

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

634
    subtitle_demux_t *p_sub_toselect = NULL;
635
    char             *psz_sub_file = NULL;
636

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

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

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

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

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

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

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

710
711
    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
712
713

    if( input_AccessInit( p_input ) == -1 )
714
    {
715
716
717
718
719
720
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

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

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

745
    p_input->p_es_out = input_EsOutNew( p_input );
746
747
    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 );
748

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

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

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

        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
785
        input_EsOutDelete( p_input->p_es_out );
786
        return VLC_EGENERIC;
787
    }
Christophe Massiot's avatar
Christophe Massiot committed
788
789
790

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

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

Sam Hocevar's avatar
   
Sam Hocevar committed
806
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
807
    {
Christophe Massiot's avatar
Christophe Massiot committed
808
809
        while( !input_FillBuffer( p_input ) )
        {
810
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
811
            {
812
                module_Unneed( p_input, p_input->p_access );
813
814
815
816
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
817
818
819
820
821
822
                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
823
                input_EsOutDelete( p_input->p_es_out );
824
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
825
826
            }
        }
827
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
828

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

zorglub's avatar
zorglub committed
835
        msg_Err( p_input, "cannot create stream_t" );
836

837
838
839
840
841
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
842
843
844
845
846
847
        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
848
        input_EsOutDelete( p_input->p_es_out );
849
850
851
        return VLC_EGENERIC;
    }

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

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

865
        input_StreamDelete( p_input->s );
866
        module_Unneed( p_input, p_input->p_access );
867
        if ( p_input->stream.p_sout != NULL )
868
        {
869
            sout_DeleteInstance( p_input->stream.p_sout );
870
        }
871
872
873
874
875
876
        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
877
        input_EsOutDelete( p_input->p_es_out );
878
        return VLC_EGENERIC;
879
880
    }

881
882
883
884
885
    /* 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;

886
887
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
    /* 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 ) )
938
939
940
941
942
943
944
    {
        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;

gbazin's avatar
gbazin committed
945
946
947
948
        /* 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 );

949
950
951
952
953
954
955
956
957
958
959
960
        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:" );
gbazin's avatar
gbazin committed
961
        if( p_meta->i_meta > 0 )
962
963
        {
            p_cat = input_InfoCategory( p_input, _("File") );
gbazin's avatar
gbazin committed
964
            for( i = 0; i < p_meta->i_meta; i++ )
965
            {
gbazin's avatar
gbazin committed
966
967
968
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) )
969
                {
gbazin's avatar
gbazin committed
970
                    playlist_ItemSetName( p_item, p_meta->value[i] );
971
                }
gbazin's avatar
gbazin committed
972
                if( !strcmp(