input.c 50.4 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

215 216
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
217
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
218

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

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

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

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

243 244
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
245
    p_input->stream.p_selected_area = NULL;
246
    p_input->stream.p_new_area = NULL;
247

248 249 250 251
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

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

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

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

Gildas Bazin's avatar
Gildas Bazin committed
264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304
    /* 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 ) )
                {
305
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
Gildas Bazin's avatar
Gildas Bazin committed
306 307 308
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
309
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
Gildas Bazin's avatar
Gildas Bazin committed
310 311 312 313 314 315 316 317 318 319 320 321
                }
                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 );
    }

322
    vlc_object_attach( p_input, p_parent );
323

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

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

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

345 346
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
347

348
    /* Request thread destruction */
349 350 351 352 353 354 355 356 357 358

    /* Temporary demux2 hack */
    p_demux = (demux_t *)vlc_object_find( p_input, VLC_OBJECT_DEMUX,
                                          FIND_CHILD );
    if( p_demux )
    {
        p_demux->b_die = 1;
        vlc_object_release( p_demux );
    }

359
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
360

361 362
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
363 364 365 366 367 368 369 370 371 372
}

/*****************************************************************************
 * 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 */
373
    vlc_thread_join( p_input );
374 375 376

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
377
    vlc_cond_destroy( &p_input->stream.stream_wait );
378
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
379 380
}

381
/*****************************************************************************
382
 * RunThread: main thread loop
383
 *****************************************************************************
384
 * Thread in charge of processing the network packets and demultiplexing.
385
 *****************************************************************************/
386
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
387
{
388 389 390
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

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

394 395 396 397
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
398

399
        ErrorThread( p_input );
400 401 402 403

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

404
        return 0;
405
    }
Michel Kaempf's avatar
Michel Kaempf committed
406

407
    /* initialization is complete */
408
    vlc_mutex_lock( &p_input->stream.stream_lock );
409 410
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
411 412
    vlc_mutex_unlock( &p_input->stream.stream_lock );

413 414 415
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

416 417
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
418
        unsigned int i, i_count;
419

420
        p_input->c_loops++;
421

422
        vlc_mutex_lock( &p_input->stream.stream_lock );
423

424 425 426 427 428
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

429 430
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
431 432

                p_input->pf_set_program( p_input,
433
                                         p_input->stream.p_new_program );
434

435 436 437 438
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

439 440 441 442 443 444 445 446 447 448 449
                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;
        }
450

451 452
        if( p_input->stream.p_new_area )
        {
453 454
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
455
                input_AccessReinit( p_input );
456 457 458

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

459 460 461 462
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

463 464 465 466 467 468 469 470 471
                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;
                }
            }
472 473 474
            p_input->stream.p_new_area = NULL;
        }

475
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
476
        {
477
            if( p_input->stream.p_selected_area->i_size > 0 )
478
            {
479
                unsigned int i;
480
                mtime_t      i_time;
481 482
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
483

Christophe Massiot's avatar
Christophe Massiot committed
484
                vlc_mutex_unlock( &p_input->stream.stream_lock );
485
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
486
                vlc_mutex_lock( &p_input->stream.stream_lock );
487

488 489 490 491
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

492 493
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
494
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
495 496 497 498

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

Laurent Aimar's avatar
Laurent Aimar committed
500
                vlc_mutex_unlock( &p_input->stream.stream_lock );
501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
                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 );
                    }
                }
516 517 518 519 520
                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
521
                vlc_mutex_lock( &p_input->stream.stream_lock );
522
            }
523
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
524
        }
525

526 527 528 529 530 531 532 533 534 535 536 537
        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;
        }

538 539 540 541 542 543 544 545 546 547 548 549 550 551
        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;
        }

552
        vlc_mutex_unlock( &p_input->stream.stream_lock );
553

Christophe Massiot's avatar
Christophe Massiot committed
554 555
        /* Read and demultiplex some data. */
        i_count = p_input->pf_demux( p_input );
556

557
        if( i_count == 0 )
558
        {
559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580
            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;
            }
581 582 583 584
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
585
        }
586 587 588

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
589 590 591 592
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
593 594

            /* update input status variables */
595
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
596
            {
597
                val.f_float = (float)d_pos;
598 599
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
600
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
601
            {
602
                val.i_time = i_time;
603 604
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
605
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
606
            {
607 608
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
609
                val.i_time = i_length;
610
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
611 612 613 614 615 616 617 618 619 620 621
                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 ) );
                }
622 623
            }

624 625 626 627 628 629 630
            /* 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;
            }

631 632 633 634 635 636
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

637
            i_update_next = mdate() + I64C(150000);
638
        }
639 640
    }

641
    if( p_input->b_error || p_input->b_eof )
642 643 644
    {
        ErrorThread( p_input );
    }
645

646
    EndThread( p_input );
647

648
    return 0;
649 650
}

651
/*****************************************************************************
652
 * InitThread: init the input Thread
653
 *****************************************************************************/
654
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
655
{
656
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
657 658
//    float f_fps;
    double f_fps;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
659
    mtime_t i_length;
660

Christophe Massiot's avatar
Christophe Massiot committed
661
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
662
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
663
    vlc_value_t val, val1;
664
    int64_t i_microsecondperframe;
665

666
    subtitle_demux_t *p_sub_toselect = NULL;
667
    char             *psz_sub_file = NULL;
668

Christophe Massiot's avatar
Christophe Massiot committed
669 670 671 672 673
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
674
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
675
    if( psz_parser - p_input->psz_dupsource == 1 )
676
    {
677
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
678
                           p_input->psz_dupsource[0] ) ;
679
        psz_parser = "";
680 681
    }
#endif
682

Christophe Massiot's avatar
Christophe Massiot committed
683
    if( !*psz_parser )
684
    {
685
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
686
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
687
        free( p_input->psz_dupsource );
688
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
689
    }
Christophe Massiot's avatar
Christophe Massiot committed
690 691 692
    else
    {
        *psz_parser++ = '\0';
693

694 695 696 697
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
698
        }
699 700

        p_input->psz_name = psz_parser ;
701

Christophe Massiot's avatar
Christophe Massiot committed
702
        /* Come back to parse the access and demux plug-ins */
Christophe Massiot's avatar
Christophe Massiot committed
703
        psz_parser = p_input->psz_dupsource;
704

705
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
706 707
        {
            /* No access */
708
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
709 710 711 712
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
713
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

            while( *psz_parser && *psz_parser != '/' )
            {
                psz_parser++;
            }

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }
730

Christophe Massiot's avatar
Christophe Massiot committed
731 732 733
        if( !*psz_parser )
        {
            /* No demux */
734
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
735 736 737 738 739
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
Sam Hocevar committed
740
    }
Christophe Massiot's avatar
Christophe Massiot committed
741

742 743
    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
744 745

    if( input_AccessInit( p_input ) == -1 )
746
    {
747 748 749 750 751 752
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

753 754 755 756 757 758 759 760 761 762 763 764
        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 );
765 766 767 768 769 770 771

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
772 773 774
            return VLC_EGENERIC;
        }
        free( val.psz_string );
775
    }
Christophe Massiot's avatar
Christophe Massiot committed
776

777
    p_input->p_es_out = input_EsOutNew( p_input );
778 779
    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 );
780

781
    /* Find and open appropriate access module */
782
    p_input->p_access = module_Need( p_input, "access",
783
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
784

785 786 787 788 789 790 791 792 793
    /* 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 );
    }
794 795 796 797
#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 */
798 799 800 801 802 803 804 805 806
    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",
807
                                         p_input->psz_access, VLC_TRUE );
808
    }
809
#endif
810
    if( p_input->p_access == NULL )
811
    {
812
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
813
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
814 815 816 817
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
818 819 820 821 822 823 824

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
825
        input_EsOutDelete( p_input->p_es_out );
826
        return VLC_EGENERIC;
827
    }
Christophe Massiot's avatar
Christophe Massiot committed
828 829 830

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
831
    {
Christophe Massiot's avatar
Christophe Massiot committed
832
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
833
    }
834 835
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
836
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
837
    }
838

839 840
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
841 842 843 844
    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);
845

846
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
847
    {
Christophe Massiot's avatar
Christophe Massiot committed
848 849
        while( !input_FillBuffer( p_input ) )
        {
850
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
851
            {
852
                module_Unneed( p_input, p_input->p_access );
853 854 855 856
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
857 858 859 860 861 862
                input_AccessEnd( p_input );
                free( p_input->psz_source );
                if( p_input->psz_dupsource != NULL )
                {
                    free( p_input->psz_dupsource );
                }
863
                input_EsOutDelete( p_input->p_es_out );
864
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
865 866
            }
        }
867
    }
868

869
    /* Create the stream_t facilities */
870
    p_input->s = input_StreamNew( p_input );
871 872
    if( p_input->s == NULL )
    {
Clément Stenac's avatar
Clément Stenac committed
873
        /* should never occur yet */
874

Clément Stenac's avatar
Clément Stenac committed
875
        msg_Err( p_input, "cannot create stream_t" );
876

877 878 879 880 881
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
882 883 884 885 886 887
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
888
        input_EsOutDelete( p_input->p_es_out );
889 890 891
        return VLC_EGENERIC;
    }

892
    /* Find and open appropriate demux module */
893 894 895
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
896 897 898
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
899

900
    if( p_input->p_demux == NULL )
901
    {
902
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
903
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
904

905
        input_StreamDelete( p_input->s );
906
        module_Unneed( p_input, p_input->p_access );
907
        if ( p_input->stream.p_sout != NULL )
908
        {
909
            sout_DeleteInstance( p_input->stream.p_sout );
910
        }
911 912 913 914 915 916
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
917
        input_EsOutDelete( p_input->p_es_out );
918
        return VLC_EGENERIC;
919 920
    }

921 922 923 924 925
    /* 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;

926 927
    p_input->p_sys->i_stop_time = 0;

928 929 930 931 932 933 934 935 936 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
    /* 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 ) )
978 979 980
    {
        int i;

981 982 983 984
        /* 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 );

985
        msg_Dbg( p_input, "meta informations:" );
986
        if( p_meta->i_meta > 0 )
987
        {
988
            for( i = 0; i < p_meta->i_meta; i++ )
989
            {
990 991
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
992 993 994 995
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

996
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
997 998 999 1000 1001
                    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] );
1002 1003
            }
        }
1004
        for( i = 0; i < p_meta->i_track; i++ )
1005
        {
1006
            vlc_meta_t *tk = p_meta->track[i];
1007 1008 1009 1010 1011 1012 1013 1014 1015 1016
            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++ )
                {
1017 1018
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
1019 1020 1021

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

1026 1027
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {
1028
            p_input->stream.p_sout->p_meta = p_meta;