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

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

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

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

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

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

128
129
130
131
    /* 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 );

132
133
134
    /* decoders */
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

135
136
137
    /* play status */

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

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

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

174
175
176
177
    /* 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
178

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

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

187
188
189
    /* Stream */
    p_input->s = NULL;

190
191
192
    /* es out */
    p_input->p_es_out = NULL;

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

    /* Access */
201
    p_input->p_access = NULL;
202

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

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

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

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

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

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

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

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

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

gbazin's avatar
   
gbazin committed
252
253
254
255
256
    /* 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 );
257
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
258

Sam Hocevar's avatar
Sam Hocevar committed
259
    /* Create thread and wait for its readiness. */
260
261
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
262
    {
263
        msg_Err( p_input, "cannot create input thread" );
gbazin's avatar
   
gbazin committed
264
        input_DelInfo( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
265
        free( p_input );
266
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
267
    }
268

269
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
270
271
}

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

284
285
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
286
287
288
289
290
291
292
293
294
295
}

/*****************************************************************************
 * 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 */
296
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
297
298
299

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
300
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
301
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
302
303
}

304
/*****************************************************************************
305
 * RunThread: main thread loop
306
 *****************************************************************************
307
 * Thread in charge of processing the network packets and demultiplexing.
308
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
309
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
310
{
311
312
313
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

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

Sam Hocevar's avatar
   
Sam Hocevar committed
317
318
319
320
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
321

Sam Hocevar's avatar
   
Sam Hocevar committed
322
        ErrorThread( p_input );
323
324
325
326

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

gbazin's avatar
   
gbazin committed
327
328
        input_DelInfo( p_input );

Sam Hocevar's avatar
   
Sam Hocevar committed
329
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
330
    }
Michel Kaempf's avatar
Michel Kaempf committed
331

332
    /* initialization is complete */
333
    vlc_mutex_lock( &p_input->stream.stream_lock );
334
335
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
336
337
    vlc_mutex_unlock( &p_input->stream.stream_lock );

338
339
340
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
   
Sam Hocevar committed
341
342
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
343
        unsigned int i, i_count;
344

Sam Hocevar's avatar
   
Sam Hocevar committed
345
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
346

347
        vlc_mutex_lock( &p_input->stream.stream_lock );
348

349
350
351
352
353
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
354
355
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
356
357

                p_input->pf_set_program( p_input,
358
                                         p_input->stream.p_new_program );
359

360
361
362
363
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

364
365
366
367
368
369
370
371
372
373
374
                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;
        }
375

376
377
        if( p_input->stream.p_new_area )
        {
378
379
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
380
                input_AccessReinit( p_input );
381
382
383

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

384
385
386
387
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

388
389
390
391
392
393
394
395
396
                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;
                }
            }
397
398
399
            p_input->stream.p_new_area = NULL;
        }

400
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
401
        {
402
            if( p_input->stream.p_selected_area->i_size > 0 )
403
            {
404
                unsigned int i;
405
                mtime_t      i_time;
406
407
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
408

Christophe Massiot's avatar
Christophe Massiot committed
409
                vlc_mutex_unlock( &p_input->stream.stream_lock );
410
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
411
                vlc_mutex_lock( &p_input->stream.stream_lock );
412

413
414
415
416
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

417
418
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
419
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
420
421
422
423

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

Laurent Aimar's avatar
Laurent Aimar committed
425
                vlc_mutex_unlock( &p_input->stream.stream_lock );
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
                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
441
                vlc_mutex_lock( &p_input->stream.stream_lock );
442
            }
443
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
444
        }
445

446
447
448
449
450
451
452
453
454
455
456
457
        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;
        }

458
459
460
461
462
463
464
465
466
467
468
469
470
471
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
477
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
478
        {
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
            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;
            }
501
502
503
504
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
505
        }
506
507
508

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
509
510
511
512
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
513
514

            /* update input status variables */
515
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
516
            {
517
                val.f_float = (float)d_pos;
518
519
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
520
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
521
            {
522
                val.i_time = i_time;
523
524
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
525
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
526
            {
527
                val.i_time = i_length;
528
529
530
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

531
532
533
534
535
536
537
            /* 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;
            }

538
539
540
541
542
543
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

544
            i_update_next = mdate() + I64C(150000);
545
        }
546
547
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
548
    if( p_input->b_error || p_input->b_eof )
549
550
551
    {
        ErrorThread( p_input );
    }
552

553
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
554

Sam Hocevar's avatar
   
Sam Hocevar committed
555
    return 0;
556
557
}

558
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
559
 * InitThread: init the input Thread
560
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
561
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
562
{
gbazin's avatar
gbazin committed
563
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
564
    float f_fps;
sigmunau's avatar
sigmunau committed
565
566
    playlist_t *p_playlist;
    mtime_t i_length;
567

Christophe Massiot's avatar
Christophe Massiot committed
568
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
569
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
gbazin's avatar
   
gbazin committed
570
    vlc_value_t val;
571
    int64_t i_microsecondperframe;
gbazin's avatar
   
gbazin committed
572

573
    subtitle_demux_t *p_sub_toselect = NULL;
574
    char             *psz_sub_file = NULL;
575

Christophe Massiot's avatar
Christophe Massiot committed
576
577
578
579
580
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
581
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
582
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
583
    {
584
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
585
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
586
        psz_parser = "";
gbazin's avatar
   
gbazin committed
587
588
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
589

Christophe Massiot's avatar
Christophe Massiot committed
590
    if( !*psz_parser )
591
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
592
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
593
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
594
        free( p_input->psz_dupsource );
595
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
596
    }
Christophe Massiot's avatar
Christophe Massiot committed
597
598
599
    else
    {
        *psz_parser++ = '\0';
600

Xavier Marchesini's avatar
   
Xavier Marchesini committed
601
602
603
604
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
605
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
606
607

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
612
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
613
614
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
615
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
616
617
618
619
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
620
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
            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
637

Christophe Massiot's avatar
Christophe Massiot committed
638
639
640
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
641
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
642
643
644
645
646
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
647
    }
Christophe Massiot's avatar
Christophe Massiot committed
648

649
650
    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
651
652

    if( input_AccessInit( p_input ) == -1 )
653
    {
654
655
656
657
658
659
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

660
661
662
663
664
665
666
667
668
669
670
671
        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 );
672
673
674
675
676
677
678

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
679
680
681
            return VLC_EGENERIC;
        }
        free( val.psz_string );
682
    }
Christophe Massiot's avatar
Christophe Massiot committed
683

684
    p_input->p_es_out = input_EsOutNew( p_input );
685
686
    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 );
687

688
    /* Find and open appropriate access module */
689
    p_input->p_access = module_Need( p_input, "access",
gbazin's avatar
   
gbazin committed
690
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
691

gbazin's avatar
   
gbazin committed
692
693
694
695
#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 */
696
697
698
699
700
701
702
703
704
    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
705
                                         p_input->psz_access, VLC_TRUE );
706
    }
gbazin's avatar
   
gbazin committed
707
#endif
708

709
    if( p_input->p_access == NULL )
710
    {
711
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
712
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
713
714
715
716
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
717
718
719
720
721
722
723

        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
724
        input_EsOutDelete( p_input->p_es_out );
725
        return VLC_EGENERIC;
726
    }
Christophe Massiot's avatar
Christophe Massiot committed
727
728
729

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
730
    {
Christophe Massiot's avatar
Christophe Massiot committed
731
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
732
    }
733
734
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
735
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
736
    }
737

gbazin's avatar
   
gbazin committed
738
739
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
740
741
742
743
    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
744

Sam Hocevar's avatar
   
Sam Hocevar committed
745
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
746
    {
Christophe Massiot's avatar
Christophe Massiot committed
747
748
        while( !input_FillBuffer( p_input ) )
        {
749
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
750
            {
751
                module_Unneed( p_input, p_input->p_access );
752
753
754
755
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
756
757
758
759
760
761
                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
762
                input_EsOutDelete( p_input->p_es_out );
763
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
764
765
            }
        }
766
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
767

768
    /* Create the stream_t facilities */
769
    p_input->s = input_StreamNew( p_input );
770
771
    if( p_input->s == NULL )
    {
zorglub's avatar
zorglub committed
772
        /* should never occur yet */
773

zorglub's avatar
zorglub committed
774
        msg_Err( p_input, "cannot create stream_t" );
775

776
777
778
779
780
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
781
782
783
784
785
786
        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
787
        input_EsOutDelete( p_input->p_es_out );
788
789
790
        return VLC_EGENERIC;
    }

791
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
792
793
794
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
gbazin's avatar
   
gbazin committed
795
796
797
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
   
Sam Hocevar committed
798

799
    if( p_input->p_demux == NULL )
800
    {
801
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
802
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
803

804
        input_StreamDelete( p_input->s );
805
        module_Unneed( p_input, p_input->p_access );
806
        if ( p_input->stream.p_sout != NULL )
807
        {
808
            sout_DeleteInstance( p_input->stream.p_sout );
809
        }
810
811
812
813
814
815
        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
816
        input_EsOutDelete( p_input->p_es_out );
817
        return VLC_EGENERIC;
818
819
    }

820
821
822
823
824
    /* 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;

825
826
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
    /* 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 ) )
877
878
879
880
881
882
883
    {
        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
884
885
886
887
        /* 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 );

888
889
890
891
892
893
894
895
896
897
898
899
        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
900
        if( p_meta->i_meta > 0 )
901
902
        {
            p_cat = input_InfoCategory( p_input, _("File") );
gbazin's avatar
gbazin committed
903
            for( i = 0; i < p_meta->i_meta; i++ )
904
            {
gbazin's avatar
gbazin committed
905
906
907
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) )
908
                {
gbazin's avatar
gbazin committed
909
                    playlist_ItemSetName( p_item, p_meta->value[i] );
910
                }
gbazin's avatar
gbazin committed
911
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
912
913
                {
                    playlist_ItemAddInfo( p_item, _("General"), _("Author"),
gbazin's avatar
gbazin committed
914
                                          p_meta->value[i] );
915
                }
gbazin's avatar
gbazin committed
916
917
                input_AddInfo( p_cat, _(p_meta->name[i]), "%s",
                               p_meta->value[i] );
918
919
920
                if( p_item )
                {
                    playlist_ItemAddInfo( p_item, _("File"),
gbazin's avatar
gbazin committed
921
922
                                          _(p_meta->name[i]), "%s",
                                          p_meta->value[i] );
923
924
925
                }
            }
        }
gbazin's avatar
gbazin committed
926
        for( i = 0; i < p_meta->i_track; i++ )
927
        {
gbazin's avatar
gbazin committed
928
            vlc_meta_t *tk = p_meta->track[i];
929
930
931
932
933
934
935
936
937
938
939
            int j;

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

                for( j = 0; j < tk->i_meta; j++ )
                {
gbazin's avatar
gbazin committed
940
941
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );