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
 *****************************************************************************
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>
30

31
#include <vlc/vlc.h>
32
#include <vlc/input.h>
33
#include <vlc/decoder.h>
34
#include <vlc/vout.h>
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"
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 );
Gildas Bazin's avatar
Gildas Bazin 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 );
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;

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

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 );
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 );
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 */
Gildas Bazin's avatar
Gildas Bazin 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 );
188

189
    /* Initialize thread properties */
190
    p_input->b_eof      = 0;
191
    p_input->b_out_pace_control = VLC_FALSE;
192
    p_input->p_sys      = NULL;
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 );
198

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

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

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

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

216 217
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
218
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
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 */
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

241 242 243
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

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;
248

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;

253
    /* By default there is one area in a stream */
254
    input_AddArea( p_input, 0, 1 );
255
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
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;
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

Gildas Bazin's avatar
Gildas Bazin 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);
Gildas Bazin's avatar
Gildas Bazin committed
307 308 309
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
310
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
Gildas Bazin's avatar
Gildas Bazin 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 );
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
/*****************************************************************************
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

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 );
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 );
383 384 385

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
386
    vlc_cond_destroy( &p_input->stream.stream_wait );
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
 *****************************************************************************/
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 );

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

408
        ErrorThread( p_input );
409 410 411 412

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

413
        return 0;
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 );

425 426
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
427
        unsigned int i, i_count;
428

429
        p_input->c_loops++;
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 )
            {

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 )
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;
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 );
562

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

566
        if( i_count == 0 )
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
    }

650
    if( p_input->b_error || p_input->b_eof )
651 652 653
    {
        ErrorThread( p_input );
    }
654

655
    EndThread( p_input );
656

657
    return 0;
658 659
}

660
/*****************************************************************************
661
 * InitThread: init the input Thread
662
 *****************************************************************************/
663
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
664
{
665
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
666 667
//    float f_fps;
    double f_fps;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg 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;
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 )
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] ) ;
688
        psz_parser = "";
689 690
    }
#endif
691

Christophe Massiot's avatar
Christophe Massiot committed
692
    if( !*psz_parser )
693
    {
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

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

        p_input->psz_name = psz_parser ;
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;
713

714
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
715 716
        {
            /* No access */
717
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
718 719 720 721
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
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';
            }
        }
739

Christophe Massiot's avatar
Christophe Massiot committed
740 741 742
        if( !*psz_parser )
        {
            /* No demux */
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",
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 );
    }
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",
816
                                         p_input->psz_access, VLC_TRUE );
817
    }
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 );
        }
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

848 849
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
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);
854

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 );
                }
872
                input_EsOutDelete( p_input->p_es_out );
873
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
874 875
            }
        }
876
    }
877

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

Clément Stenac's avatar
Clément Stenac 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 );
        }
897
        input_EsOutDelete( p_input->p_es_out );
898 899 900
        return VLC_EGENERIC;
    }

901
    /* Find and open appropriate demux module */
902 903 904
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
905 906 907
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
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 );
        }
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;

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 );
    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 ) )
987 988 989
    {
        int i;

990 991 992 993
        /* 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 );

994
        msg_Dbg( p_input, "meta informations:" );
995
        if( p_meta->i_meta > 0 )
996
        {
997
            for( i = 0; i < p_meta->i_meta; i++ )
998
            {
999 1000
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
1001 1002 1003 1004
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

1005
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
1006 1007 1008 1009 1010
                    input_Control( p_input, INPUT_ADD_INFO, _("General"),
                                   _("Author"), p_meta->value[i] );

                input_Control( p_input, INPUT_ADD_INFO, _("File"),
                              _(p_meta->name[i]), "%s", p_meta->value[i] );
1011 1012
            }
        }
1013
        for( i = 0; i < p_meta->i_track; i++ )
1014
        {
1015
            vlc_meta_t *tk = p_meta->track[i];
1016 1017 1018 1019 1020 1021 1022 1023 1024 1025
            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 );

                for( j = 0; j < tk->i_meta; j++ )
                {
1026 1027
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
1028 1029 1030

                    input_Control( p_input, INPUT_ADD_INFO, psz_cat,
                                   _(tk->name[j]), "%s", tk->value[j] );