input.c 43.5 KB
Newer Older
1
2
/*****************************************************************************
 * input.c: input thread
3
 * Read a stream, demultiplex and parse it before sending it to
Michel Kaempf's avatar
Michel Kaempf committed
4
 * decoders.
5
 *****************************************************************************
zorglub's avatar
zorglub committed
6
 * Copyright (C) 1998-2004 VideoLAN
7
 * $Id$
8
 *
9
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
10
11
12
13
14
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
15
 *
16
17
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
20
 *
21
22
23
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA.
24
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
25

26
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
27
 * Preamble
28
 *****************************************************************************/
29
#include <stdlib.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
30

31
#include <vlc/vlc.h>
32
#include <vlc/input.h>
33
#include <vlc/decoder.h>
34
#include <vlc/vout.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
35

36
37
#ifdef HAVE_SYS_TIMES_H
#   include <sys/times.h>
38
#endif
39

40
#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
    input_thread_t *    p_input;                        /* thread descriptor */
92
    vlc_value_t val;
93
    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->p_sys      = NULL;
Sam Hocevar's avatar
   
Sam Hocevar committed
182
183

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

826
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
    /* get meta informations */
    if( !demux_Control( p_input, DEMUX_GET_META, &meta ) )
    {
        playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_input,
                                         VLC_OBJECT_PLAYLIST,  FIND_PARENT);
        playlist_item_t *p_item = NULL;
        input_info_category_t *p_cat;
        int i;

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

        msg_Dbg( p_input, "meta informations:" );
        if( meta->i_meta > 0 )
        {
            p_cat = input_InfoCategory( p_input, _("File") );
            for( i = 0; i < meta->i_meta; i++ )
            {
                msg_Dbg( p_input, "  - '%s' = '%s'", _(meta->name[i]), meta->value[i] );
853
854
855
856
857
858
859
860
861
                if( !strcmp( meta->name[i], VLC_META_TITLE ) )
                {
                    playlist_ItemSetName( p_item, meta->value[i] );
                }
                if( !strcmp( meta->name[i], VLC_META_AUTHOR ) )
                {
                    playlist_ItemAddInfo( p_item, _("General"), _("Author"),
                                            meta->value[i] );
                }
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
                input_AddInfo( p_cat, _(meta->name[i]), "%s", meta->value[i] );
                if( p_item )
                {
                    playlist_ItemAddInfo( p_item, _("File"),
                                          _(meta->name[i]), "%s", meta->value[i] );
                }
            }
        }
        for( i = 0; i < meta->i_track; i++ )
        {
            vlc_meta_t *tk = meta->track[i];
            int j;

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

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

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

        vlc_meta_Delete( meta );
    }

sigmunau's avatar
sigmunau committed
904
905
906
    /* get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) && i_length > 0 )
    {
907
        input_info_category_t *p_cat = input_InfoCategory( p_input, _("File") );
sigmunau's avatar
sigmunau committed
908
909
910
911
912
        p_playlist = (playlist_t*)vlc_object_find( p_input,
                                                   VLC_OBJECT_PLAYLIST,
                                                   FIND_PARENT );
        if( p_playlist )
        {
913
            playlist_SetDuration( p_playlist, -1 , i_length );
914
            val.b_bool = p_playlist->i_index;
915
            var_Set( p_playlist, "item-change", val );
sigmunau's avatar
sigmunau committed
916
917
            vlc_object_release( p_playlist );
        }
918
919
920
921
922
923
        if( p_cat )
        {
            char psz_buffer[MSTRTIME_MAX_SIZE];
            input_AddInfo( p_cat, _("Duration"),
                           msecstotimestr( psz_buffer, i_length / 1000 ) );
        }
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942

        /* Set start time */
        var_Get( p_input, "start-time", &val );
        if(  val.i_int > 0 )
        {
            double f_pos = (double)( (int64_t)val.i_int * I64C(1000000) ) / (double)i_length;

            if( f_pos >= 1.0 )
            {
                msg_Warn( p_input, "invalid start-time, ignored (start-time >= media length)" );
            }
            else
            {
                p_input->stream.p_selected_area->i_seek =
                    (int64_t)( f_pos * (double)p_input->stream.p_selected_area->i_size );

                msg_Dbg( p_input, "start-time %ds (%2.2f)", val.i_int, f_pos );
            }
        }
943
    }
944
945
946
947
948
    /* Set stop-time and check validity */
    var_Get( p_input, "stop-time", &val );
    if( val.i_int > 0 )
    {
        vlc_value_t start;
949

950
951
952
953
954
955
956
957
958
959
960
        var_Get( p_input, "start-time", &start );
        if( start.i_int >= val.i_int )
        {
            msg_Warn( p_input, "invalid stop-time, ignored (stop-time < start-time)" );
        }
        else
        {
            p_input->p_sys->i_stop_time = (int64_t)val.i_int * I64C(1000000);
            msg_Dbg( p_input, "stop-time %ds", val.i_int );
        }
    }
sigmunau's avatar
sigmunau committed
961

962
963
964
965
966
967
968
969
970
971
    /* get fps */
    if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
    {
        i_microsecondperframe = 0;
    }
    else
    {
        i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
    }

972
    /* Look for and add subtitle files */
973
974
975
    var_Get( p_input, "sub-file", &val );