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

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

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

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

40
41
#include "stream_output.h"

42
#include "vlc_interface.h"
43
#include "codecs.h"
44
#include "vlc_meta.h"
45
#include "../../modules/demux/util/sub.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
46

47
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
48
 * Local prototypes
49
 *****************************************************************************/
50
51
52
53
54
struct input_thread_sys_t
{
    /* subtitles */
    int              i_sub;
    subtitle_demux_t **sub;
55
56

    int64_t          i_stop_time;
57
58
};

59
60
61
62
static  int RunThread  ( input_thread_t *p_input );
static  int InitThread ( input_thread_t *p_input );
static void ErrorThread( input_thread_t *p_input );
static void EndThread  ( input_thread_t *p_input );
Michel Kaempf's avatar
Michel Kaempf committed
63

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

static void DecodeUrl  ( char * );
67

68
69
70
71
72
73
74
75
76
77
78
/*****************************************************************************
 * Callbacks
 *****************************************************************************/
static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int TimeCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int StateCallback   ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
static int RateCallback    ( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
gbazin's avatar
gbazin committed
79
80
static int BookmarkCallback( vlc_object_t *p_this, char const *psz_cmd,
                             vlc_value_t oldval, vlc_value_t newval, void *p_data );
gbazin's avatar
   
gbazin committed
81

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

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

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

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

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

gbazin's avatar
   
gbazin committed
116
117
118
119
120
    /* Create a few object variables we'll need later on */
    var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
121
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
122
123
    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL |
                VLC_VAR_DOINHERIT );
124
125
    var_Create( p_input, "sub-autodetect-path", VLC_VAR_STRING |
                VLC_VAR_DOINHERIT );
126
127
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER |
                VLC_VAR_DOINHERIT );
gbazin's avatar
   
gbazin committed
128
129

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

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

138
139
140
141
    /* start/stop time */
    var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

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

145
146
147
    /* play status */

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

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

    /* length variable */
    var_Create( p_input, "length",  VLC_VAR_TIME );
    val.i_time = 0;
    var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );

    /* rate variable */
    var_Create( p_input, "rate", VLC_VAR_INTEGER );
    var_Create( p_input, "rate-slower", VLC_VAR_VOID );
    var_Create( p_input, "rate-faster", VLC_VAR_VOID );
    val.i_int = DEFAULT_RATE;
    var_Change( p_input, "rate", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "rate", RateCallback, NULL );
    var_AddCallback( p_input, "rate-slower", RateCallback, NULL );
    var_AddCallback( p_input, "rate-faster", RateCallback, NULL );

    /* state variable */
    var_Create( p_input, "state", VLC_VAR_INTEGER );
    val.i_int = INIT_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "state", StateCallback, NULL );

184
185
186
187
    /* state variable */
    var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
    val.b_bool = VLC_FALSE;
    var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
   
gbazin committed
188

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

    /* Set target */
195
196
197
    vlc_mutex_lock( &p_item->lock );
    p_input->psz_source = strdup( p_item->psz_uri );
    vlc_mutex_unlock( &p_item->lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
198

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

337
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
338
 * input_StopThread: mark an input thread as zombie
339
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
340
 * This function should not return until the thread is effectively cancelled.
341
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
342
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
343
{
344
345
    demux_t  *p_demux;
    access_t *p_access;
346

Sam Hocevar's avatar
   
Sam Hocevar committed
347
348
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
349

350
    /* Request thread destruction */
351
352

    /* Temporary demux2 hack */
353
    p_demux = (demux_t *)vlc_object_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
354
355
356
357
358
359
    if( p_demux )
    {
        p_demux->b_die = 1;
        vlc_object_release( p_demux );
    }

360
361
362
363
364
365
366
367
    /* Temporary access2 hack */
    p_access = (access_t *)vlc_object_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
    if( p_access )
    {
        p_access->b_die = 1;
        vlc_object_release( p_access );
    }

368
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
369

370
371
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
372
373
374
375
376
377
378
379
380
381
}

/*****************************************************************************
 * 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 */
382
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
383
384
385

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
   
Sam Hocevar committed
386
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
   
Sam Hocevar committed
387
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
388
389
}

390
/*****************************************************************************
391
 * RunThread: main thread loop
392
 *****************************************************************************
393
 * Thread in charge of processing the network packets and demultiplexing.
394
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
395
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
396
{
397
398
399
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

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

Sam Hocevar's avatar
   
Sam Hocevar committed
403
404
405
406
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
407

Sam Hocevar's avatar
   
Sam Hocevar committed
408
        ErrorThread( p_input );
409
410
411
412

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

Sam Hocevar's avatar
   
Sam Hocevar committed
413
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
414
    }
Michel Kaempf's avatar
Michel Kaempf committed
415

416
    /* initialization is complete */
417
    vlc_mutex_lock( &p_input->stream.stream_lock );
418
419
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
420
421
    vlc_mutex_unlock( &p_input->stream.stream_lock );

422
423
424
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
   
Sam Hocevar committed
425
426
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
427
        unsigned int i, i_count;
428

Sam Hocevar's avatar
   
Sam Hocevar committed
429
        p_input->c_loops++;
Sam Hocevar's avatar
   
Sam Hocevar committed
430

431
        vlc_mutex_lock( &p_input->stream.stream_lock );
432

433
434
435
436
437
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
   
Johan Bilien committed
438
439
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
440
441

                p_input->pf_set_program( p_input,
442
                                         p_input->stream.p_new_program );
443

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
457
458
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
            p_input->stream.p_new_program = NULL;
        }
459

460
461
        if( p_input->stream.p_new_area )
        {
462
463
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
464
                input_AccessReinit( p_input );
465
466
467

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

468
469
470
471
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

472
473
474
475
476
477
478
479
480
                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;
                }
            }
481
482
483
            p_input->stream.p_new_area = NULL;
        }

484
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
   
Sam Hocevar committed
485
        {
486
            if( p_input->stream.p_selected_area->i_size > 0 )
487
            {
488
                unsigned int i;
489
                mtime_t      i_time;
490
491
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
492

Christophe Massiot's avatar
Christophe Massiot committed
493
                vlc_mutex_unlock( &p_input->stream.stream_lock );
494
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
495
                vlc_mutex_lock( &p_input->stream.stream_lock );
496

497
498
499
500
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

501
502
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
503
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
504
505
506
507

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

Laurent Aimar's avatar
Laurent Aimar committed
509
                vlc_mutex_unlock( &p_input->stream.stream_lock );
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
                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 );
                    }
                }
525
526
527
528
529
                if( !demux_Control( p_input, DEMUX_GET_POSITION, &f ) )
                {
                    val.f_float = (float)f;
                    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
                }
Laurent Aimar's avatar
Laurent Aimar committed
530
                vlc_mutex_lock( &p_input->stream.stream_lock );
531
            }
532
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
   
Sam Hocevar committed
533
        }
534

535
536
537
538
539
540
541
542
543
544
545
546
        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;
        }

547
548
549
550
551
552
553
554
555
556
557
558
559
560
        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;
        }

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

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

gbazin's avatar
   
gbazin committed
566
        if( i_count == 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
567
        {
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
            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;
            }
590
591
592
593
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
594
        }
595
596
597

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
598
599
600
601
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
602
603

            /* update input status variables */
604
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
605
            {
606
                val.f_float = (float)d_pos;
607
608
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
609
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
610
            {
611
                val.i_time = i_time;
612
613
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
614
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
615
            {
616
617
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
618
                val.i_time = i_length;
619
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
620
621
622
623
624
625
626
627
628
629
630
                if( old_val.i_time != val.i_time )
                {
                    char psz_buffer[MSTRTIME_MAX_SIZE];

                    vlc_mutex_lock( &p_input->p_item->lock );
                    p_input->p_item->i_duration = i_length;
                    vlc_mutex_unlock( &p_input->p_item->lock );

                    input_Control( p_input, INPUT_ADD_INFO, _("General"), _("Duration"),
                       msecstotimestr( psz_buffer, i_length / 1000 ) );
                }
631
632
            }

633
634
635
636
637
638
639
            /* 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;
            }

640
641
642
643
644
645
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

646
            i_update_next = mdate() + I64C(150000);
647
        }
648
649
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
650
    if( p_input->b_error || p_input->b_eof )
651
652
653
    {
        ErrorThread( p_input );
    }
654

655
    EndThread( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
656

Sam Hocevar's avatar
   
Sam Hocevar committed
657
    return 0;
658
659
}

660
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
661
 * InitThread: init the input Thread
662
 *****************************************************************************/
Sam Hocevar's avatar
   
Sam Hocevar committed
663
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
664
{
gbazin's avatar
gbazin committed
665
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
666
667
//    float f_fps;
    double f_fps;
sigmunau's avatar
sigmunau committed
668
    mtime_t i_length;
669

Christophe Massiot's avatar
Christophe Massiot committed
670
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
671
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
672
    vlc_value_t val, val1;
673
    int64_t i_microsecondperframe;
gbazin's avatar
   
gbazin committed
674

675
    subtitle_demux_t *p_sub_toselect = NULL;
676
    char             *psz_sub_file = NULL;
677

Christophe Massiot's avatar
Christophe Massiot committed
678
679
680
681
682
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
683
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
684
    if( psz_parser - p_input->psz_dupsource == 1 )
gbazin's avatar
   
gbazin committed
685
    {
686
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
687
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
   
Stéphane Borel committed
688
        psz_parser = "";
gbazin's avatar
   
gbazin committed
689
690
    }
#endif
Sam Hocevar's avatar
   
Sam Hocevar committed
691

Christophe Massiot's avatar
Christophe Massiot committed
692
    if( !*psz_parser )
693
    {
Sam Hocevar's avatar
   
Sam Hocevar committed
694
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
695
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
696
        free( p_input->psz_dupsource );
697
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
698
    }
Christophe Massiot's avatar
Christophe Massiot committed
699
700
701
    else
    {
        *psz_parser++ = '\0';
702

Xavier Marchesini's avatar
   
Xavier Marchesini committed
703
704
705
706
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
707
        }
Xavier Marchesini's avatar
   
Xavier Marchesini committed
708
709

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

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

Stéphane Borel's avatar
   
Stéphane Borel committed
714
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
715
716
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
717
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
718
719
720
721
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
   
Sam Hocevar committed
722
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
            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
739

Christophe Massiot's avatar
Christophe Massiot committed
740
741
742
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
   
Sam Hocevar committed
743
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
744
745
746
747
748
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
   
Sam Hocevar committed
749
    }
Christophe Massiot's avatar
Christophe Massiot committed
750

751
752
    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
753
754

    if( input_AccessInit( p_input ) == -1 )
755
    {
756
757
758
759
760
761
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

762
763
764
765
766
767
768
769
770
771
772
773
        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 );
774
775
776
777
778
779
780

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
781
782
783
            return VLC_EGENERIC;
        }
        free( val.psz_string );
784
    }
Christophe Massiot's avatar
Christophe Massiot committed
785

786
    p_input->p_es_out = input_EsOutNew( p_input );
787
788
    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 );
789

790
    /* Find and open appropriate access module */
791
    p_input->p_access = module_Need( p_input, "access",
gbazin's avatar
   
gbazin committed
792
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
793

794
795
796
797
798
799
800
801
802
    /* Maybe we had an encoded url */
    if( !p_input->p_access && strchr( p_input->psz_name, '%' ) )
    {
        DecodeUrl( p_input->psz_name );

        msg_Dbg( p_input, "retying with %s", p_input->psz_name );
        p_input->p_access = module_Need( p_input, "access",
                                         p_input->psz_access, VLC_TRUE );
    }
gbazin's avatar
   
gbazin committed
803
804
805
806
#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 */
807
808
809
810
811
812
813
814
815
    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
816
                                         p_input->psz_access, VLC_TRUE );
817
    }
gbazin's avatar
   
gbazin committed
818
#endif
819
    if( p_input->p_access == NULL )
820
    {
821
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
822
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
823
824
825
826
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
827
828
829
830
831
832
833

        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
834
        input_EsOutDelete( p_input->p_es_out );
835
        return VLC_EGENERIC;
836
    }
Christophe Massiot's avatar
Christophe Massiot committed
837
838
839

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
840
    {
Christophe Massiot's avatar
Christophe Massiot committed
841
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
842
    }
843
844
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
845
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
846
    }
847

gbazin's avatar
   
gbazin committed
848
849
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
850
851
852
853
    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
854

Sam Hocevar's avatar
   
Sam Hocevar committed
855
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
856
    {
Christophe Massiot's avatar
Christophe Massiot committed
857
858
        while( !input_FillBuffer( p_input ) )
        {
859
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
860
            {
861
                module_Unneed( p_input, p_input->p_access );
862
863
864
865
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
866
867
868
869
870
871
                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
872
                input_EsOutDelete( p_input->p_es_out );
873
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
874
875
            }
        }
876
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
877

878
    /* Create the stream_t facilities */
879
    p_input->s = input_StreamNew( p_input );
880
881
    if( p_input->s == NULL )
    {
zorglub's avatar
zorglub committed
882
        /* should never occur yet */
883

zorglub's avatar
zorglub committed
884
        msg_Err( p_input, "cannot create stream_t" );
885

886
887
888
889
890
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
891
892
893
894
895
896
        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
897
        input_EsOutDelete( p_input->p_es_out );
898
899
900
        return VLC_EGENERIC;
    }

901
    /* Find and open appropriate demux module */
gbazin's avatar
   
gbazin committed
902
903
904
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
gbazin's avatar
   
gbazin committed
905
906
907
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
   
Sam Hocevar committed
908

909
    if( p_input->p_demux == NULL )
910
    {
911
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
912
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
913

914
        input_StreamDelete( p_input->s );
915
        module_Unneed( p_input, p_input->p_access );
916
        if ( p_input->stream.p_sout != NULL )
917
        {
918
            sout_DeleteInstance( p_input->stream.p_sout );
919
        }
920
921
922
923
924
925
        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
926
        input_EsOutDelete( p_input->p_es_out );
927
        return VLC_EGENERIC;
928
929
    }

930
931
932
933
934
    /* 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;

935
936
    p_input->p_sys->i_stop_time = 0;

gbazin's avatar
gbazin committed
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
    /* 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 );