input.c 47.2 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 * Read a stream, demultiplex and parse it before sending it to
Michel Kaempf's avatar
Michel Kaempf committed
4
 * decoders.
5
 *****************************************************************************
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
#include "vlc_playlist.h"
41

42 43
#include "stream_output.h"

44
#include "vlc_interface.h"
45
#include "codecs.h"
46
#include "vlc_meta.h"
47
#include "../../modules/demux/util/sub.h"
48

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

    int64_t          i_stop_time;
59 60
};

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

66 67
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );
68

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

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

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

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

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

110 111 112 113 114
    /* Create a few object variables we'll need later on */
    var_Create( p_input, "video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "audio-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "spu-channel", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
115 116
    var_Create( p_input, "sub-file", VLC_VAR_FILE | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sub-autodetect-file", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
117
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
118 119

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

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

128 129 130 131
    /* start/stop time */
    var_Create( p_input, "start-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );
    var_Create( p_input, "stop-time", VLC_VAR_INTEGER|VLC_VAR_DOINHERIT );

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

135 136 137
    /* play status */

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

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

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

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

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

174 175 176 177
    /* state variable */
    var_Create( p_input, "demuxed-id3", VLC_VAR_BOOL );
    val.b_bool = VLC_FALSE;
    var_Change( p_input, "demuxed-id3", VLC_VAR_SETVALUE, &val, NULL );
178

179
    /* Initialize thread properties */
180
    p_input->b_eof      = 0;
181
    p_input->b_out_pace_control = VLC_FALSE;
182
    p_input->p_sys      = NULL;
183 184

    /* Set target */
185
    p_input->psz_source = strdup( psz_uri );
186

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

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

193
    /* Demux */
194 195 196 197
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
    p_input->pf_demux_control = NULL;
198
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
199 200

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

203 204
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
205
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
206

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

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

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

228 229 230
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

231 232
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
233
    p_input->stream.p_selected_area = NULL;
234
    p_input->stream.p_new_area = NULL;
235

236 237 238 239
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

240
    /* By default there is one area in a stream */
241
    input_AddArea( p_input, 0, 1 );
242
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
243

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

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

252 253 254 255 256
    /* Initialize input info */
    p_input->stream.p_info = NULL;
    p_input->stream.p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_input->stream.p_info, _("Playlist Item"),
                   p_input->psz_source );
257
    vlc_object_attach( p_input, p_parent );
258

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

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

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

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

/*****************************************************************************
 * input_DestroyThread: mark an input thread as zombie
 *****************************************************************************
 * This function should not return until the thread is effectively cancelled.
 *****************************************************************************/
void input_DestroyThread( input_thread_t *p_input )
{
    /* Join the thread */
296
    vlc_thread_join( p_input );
297 298 299

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

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

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

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

322
        ErrorThread( p_input );
323 324 325 326

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

327 328
        input_DelInfo( p_input );

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

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

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

341 342
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
343
        unsigned int i, i_count;
344

345
        p_input->c_loops++;
346

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

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

354 355
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
356 357

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

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

364 365 366 367 368 369 370 371 372 373 374
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

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

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

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

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

388 389 390 391 392 393 394 395 396
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
                    pgrm_descriptor_t * p_pgrm
                                            = p_input->stream.pp_programs[i];

                    /* Reinitialize synchro. */
                    p_pgrm->i_synchro_state = SYNCHRO_REINIT;
                }
            }
397 398 399
            p_input->stream.p_new_area = NULL;
        }

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

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

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

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

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

Laurent Aimar's avatar
Laurent Aimar committed
425
                vlc_mutex_unlock( &p_input->stream.stream_lock );
426 427 428 429 430 431 432 433 434 435 436 437 438 439 440
                if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
                {
                    int i;
                    vlc_value_t val;

                    /* Help in bar display */
                    val.i_time = i_time;
                    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );

                    /* Seek subs */
                    for( i = 0; i < p_input->p_sys->i_sub; i++ )
                    {
                        subtitle_Seek( p_input->p_sys->sub[i], i_time );
                    }
                }
Laurent Aimar's avatar
Laurent Aimar committed
441
                vlc_mutex_lock( &p_input->stream.stream_lock );
442
            }
443
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
444
        }
445

446 447 448 449 450 451 452 453 454 455 456 457
        if( p_input->stream.p_removed_es )
        {
            input_UnselectES( p_input, p_input->stream.p_removed_es );
            p_input->stream.p_removed_es = NULL;
        }

        if( p_input->stream.p_newly_selected_es )
        {
            input_SelectES( p_input, p_input->stream.p_newly_selected_es );
            p_input->stream.p_newly_selected_es = NULL;
        }

458 459 460 461 462 463 464 465 466 467 468 469 470 471
        if( p_input->stream.b_new_mute != MUTE_NO_CHANGE )
        {
            if( p_input->stream.b_new_mute )
            {
                input_EscapeAudioDiscontinuity( p_input );
            }

            vlc_mutex_lock( &p_input->stream.control.control_lock );
            p_input->stream.control.b_mute = p_input->stream.b_new_mute;
            vlc_mutex_unlock( &p_input->stream.control.control_lock );

            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
        }

472
        vlc_mutex_unlock( &p_input->stream.stream_lock );
473

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

477
        if( i_count == 0 )
478
        {
479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
            vlc_value_t repeat;

            var_Get( p_input, "input-repeat", &repeat );
            if( repeat.i_int == 0 || p_input->stream.i_area_nb <= 0 )
            {
                /* End of file - we do not set b_die because only the
                 * playlist is allowed to do so. */
                msg_Info( p_input, "EOF reached" );
                p_input->b_eof = 1;
            }
            else
            {
                msg_Dbg( p_input, "repeating the same input (%d)", repeat.i_int );
                if( repeat.i_int > 0 )
                {
                    repeat.i_int--;
                    var_Set( p_input, "input-repeat", repeat );
                }

                p_input->stream.p_new_area = p_input->stream.pp_areas[0];
                p_input->stream.p_new_area->i_seek = 0;
            }
501 502 503 504
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
505
        }
506 507 508

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

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

531 532 533 534 535 536 537
            /* Check stop-time */
            if( p_input->p_sys->i_stop_time > 0 && p_input->p_sys->i_stop_time < i_time )
            {
                msg_Warn( p_input, "EOF reached because of stop-time" );
                p_input->b_eof = 1;
            }

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

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

548
    if( p_input->b_error || p_input->b_eof )
549 550 551
    {
        ErrorThread( p_input );
    }
552

553
    EndThread( p_input );
554

555
    return 0;
556 557
}

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

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

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

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

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

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

        p_input->psz_name = psz_parser ;
608

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

612
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
613 614
        {
            /* No access */
615
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
616 617 618 619
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
620
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

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

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

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

649 650
    msg_Dbg( p_input, "access `%s', demux `%s', name `%s'",
             p_input->psz_access, p_input->psz_demux, p_input->psz_name );
Christophe Massiot's avatar
Christophe Massiot committed
651 652

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

660 661 662 663 664 665 666 667 668 669 670 671
        return VLC_EGENERIC;
    }

    /* Initialize optional stream output. (before demuxer)*/
    var_Get( p_input, "sout", &val );
    if( val.psz_string != NULL )
    {
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
            free( val.psz_string );
672 673 674 675 676 677 678

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

684
    p_input->p_es_out = input_EsOutNew( p_input );
685 686
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_FALSE );
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, ES_OUT_MODE_NONE );
687

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

692 693 694 695
#ifndef WIN32      /* Remove this gross hack from the win32 build as colons
                    * are forbidden in filenames on Win32. */

    /* Maybe we got something like: /Volumes/toto:titi/gabu.mpg */
696 697 698 699 700 701 702 703 704
    if ( p_input->p_access == NULL
          && (*p_input->psz_demux || *p_input->psz_access) )
    {
        p_input->psz_access = p_input->psz_demux = "";
        p_input->psz_name = p_input->psz_source;
        free( p_input->psz_dupsource);
        p_input->psz_dupsource = NULL;

        p_input->p_access = module_Need( p_input, "access",
705
                                         p_input->psz_access, VLC_TRUE );
706
    }
707
#endif
708

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

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
724
        input_EsOutDelete( p_input->p_es_out );
725
        return VLC_EGENERIC;
726
    }
Christophe Massiot's avatar
Christophe Massiot committed
727 728 729

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

738 739
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
740 741 742 743
    var_Create( p_input, "audio-desync", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
744

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

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

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

776 777 778 779 780
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
781 782 783 784 785 786
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
787
        input_EsOutDelete( p_input->p_es_out );
788 789 790
        return VLC_EGENERIC;
    }

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

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

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

820 821 822 823 824
    /* Init input_thread_sys_t */
    p_input->p_sys = malloc( sizeof( input_thread_sys_t ) );
    p_input->p_sys->i_sub = 0;
    p_input->p_sys->sub   = NULL;

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

827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876
    /* Get meta information from user */
    var_Create( p_input, "meta-title", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-author", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-artist", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-genre", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-copyright", VLC_VAR_STRING | VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-description", VLC_VAR_STRING|VLC_VAR_DOINHERIT);
    var_Create( p_input, "meta-date", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "meta-url", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    if( (p_meta_user = vlc_meta_New()) )
    {
        vlc_value_t val;

        var_Get( p_input, "meta-title", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_TITLE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-author", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_AUTHOR, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-artist", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_ARTIST, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-genre", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_GENRE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-copyright", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_COPYRIGHT, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-description", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DESCRIPTION, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-date", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_DATE, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
        var_Get( p_input, "meta-url", &val );
        if( val.psz_string && *val.psz_string )
            vlc_meta_Add( p_meta_user, VLC_META_URL, val.psz_string );
        if( val.psz_string ) free( val.psz_string );
    }

    /* Get meta informations from demuxer */
    if( !demux_Control( p_input, DEMUX_GET_META, &p_meta ) ||
        ( p_meta_user && p_meta_user->i_meta ) )
877 878 879 880 881 882 883
    {
        playlist_t *p_playlist = (playlist_t *)vlc_object_find( p_input,
                                         VLC_OBJECT_PLAYLIST,  FIND_PARENT);
        playlist_item_t *p_item = NULL;
        input_info_category_t *p_cat;
        int i;

884 885 886 887
        /* Merge demux and user metadata */
        if( !p_meta ){ p_meta = p_meta_user; p_meta_user = NULL; }
        else if( p_meta && p_meta_user ) vlc_meta_Merge( p_meta, p_meta_user );

888 889 890 891 892 893 894 895 896 897 898 899
        if( p_playlist )
        {
            vlc_mutex_lock( &p_playlist->object_lock );
            p_item = playlist_ItemGetByPos( p_playlist, -1 );
            if( p_item )
            {
                vlc_mutex_lock( &p_item->lock );
            }
            vlc_mutex_unlock( &p_playlist->object_lock );
        }

        msg_Dbg( p_input, "meta informations:" );
900
        if( p_meta->i_meta > 0 )
901 902
        {
            p_cat = input_InfoCategory( p_input, _("File") );
903
            for( i = 0; i < p_meta->i_meta; i++ )
904
            {
905 906 907
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) )
908
                {
909
                    playlist_ItemSetName( p_item, p_meta->value[i] );
910
                }
911
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
912 913
                {
                    playlist_ItemAddInfo( p_item, _("General"), _("Author"),
914
                                          p_meta->value[i] );
915
                }
916 917
                input_AddInfo( p_cat, _(p_meta->name[i]), "%s",
                               p_meta->value[i] );
918 919 920
                if( p_item )
                {
                    playlist_ItemAddInfo( p_item, _("File"),
921 922
                                          _(p_meta->name[i]), "%s",
                                          p_meta->value[i] );
923 924 925
                }
            }
        }
926
        for( i = 0; i < p_meta->i_track; i++ )
927
        {
928
            vlc_meta_t *tk = p_meta->track[i];
929 930 931 932 933 934 935 936 937 938 939
            int j;

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

                for( j = 0; j < tk->i_meta; j++ )
                {
940 941
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
942 943 944
                    input_AddInfo( p_cat, _(tk->name[j]), "%s", tk->value[j] );
                    if( p_item )
                    {
945 946
                        playlist_ItemAddInfo( p_item, psz_cat, _(tk->name[j]),
                                              "%s", tk->value[j] );
947 948 949 950 951 952 953 954 955 956 957
                    }
                }
            }
        }

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

958 959
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {
960
            p_input->stream.p_sout->p_meta = p_meta;
961 962 963
        }
        else
        {
964
            vlc_meta_Delete( p_meta );
965
        }
966
    }
967
    if( p_meta_user ) vlc_meta_Delete( p_meta_user );
968

969 970 971
    /* Get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
        i_length > 0 )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
972
    {
973 974 975 976 977
        input_info_category_t *p_cat =
            input_InfoCategory( p_input, _("File") );
        p_playlist =
            (playlist_t*)vlc_object_find( p_input, VLC_OBJECT_PLAYLIST,
                                          FIND_PARENT );
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
978 979
        if( p_playlist )
        {
980
            playlist_SetDuration( p_playlist, -1 , i_length );
981
            val.b_bool = p_playlist->i_index;
982
            var_Set( p_playlist, "item-change", val );
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
983 984
            vlc_object_release( p_playlist );
        }
985 986 987 988 989 990
        if( p_cat )
        {
            char psz_buffer[MSTRTIME_MAX_SIZE];
            input_AddInfo( p_cat, _("Duration"),
                           msecstotimestr( psz_buffer, i_length / 1000 ) );
        }
991 992 993 994 995

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

            if( f_pos >= 1.0 )
            {
1000 1001
                msg_Warn( p_input, "invalid start-time, ignored (start-time "
                          ">= media length)" );