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

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
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
345 346
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
347

348 349
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
350 351 352 353 354 355 356 357 358 359
}

/*****************************************************************************
 * 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 */
360
    vlc_thread_join( p_input );
361 362 363

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
364
    vlc_cond_destroy( &p_input->stream.stream_wait );
365
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
366 367
}

368
/*****************************************************************************
369
 * RunThread: main thread loop
370
 *****************************************************************************
371
 * Thread in charge of processing the network packets and demultiplexing.
372
 *****************************************************************************/
373
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
374
{
375 376 377
    vlc_value_t  val;
    mtime_t      i_update_next = -1;

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

381 382 383 384
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
385

386
        ErrorThread( p_input );
387 388 389 390

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

391
        return 0;
392
    }
Michel Kaempf's avatar
Michel Kaempf committed
393

394
    /* initialization is complete */
395
    vlc_mutex_lock( &p_input->stream.stream_lock );
396 397
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
398 399
    vlc_mutex_unlock( &p_input->stream.stream_lock );

400 401 402
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

403 404
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
405
        unsigned int i, i_count;
406

407
        p_input->c_loops++;
408

409
        vlc_mutex_lock( &p_input->stream.stream_lock );
410

411 412 413 414 415
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

416 417
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
418 419

                p_input->pf_set_program( p_input,
420
                                         p_input->stream.p_new_program );
421

422 423 424 425
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

426 427 428 429 430 431 432 433 434 435 436
                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;
        }
437

438 439
        if( p_input->stream.p_new_area )
        {
440 441
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
442
                input_AccessReinit( p_input );
443 444 445

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

446 447 448 449
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

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;
                }
            }
459 460 461
            p_input->stream.p_new_area = NULL;
        }

462
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
463
        {
464
            if( p_input->stream.p_selected_area->i_size > 0 )
465
            {
466
                unsigned int i;
467
                mtime_t      i_time;
468 469
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
470

Christophe Massiot's avatar
Christophe Massiot committed
471
                vlc_mutex_unlock( &p_input->stream.stream_lock );
472
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
473
                vlc_mutex_lock( &p_input->stream.stream_lock );
474

475 476 477 478
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

479 480
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
481
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
482 483 484 485

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

Laurent Aimar's avatar
Laurent Aimar committed
487
                vlc_mutex_unlock( &p_input->stream.stream_lock );
488 489 490 491 492 493 494 495 496 497 498 499 500 501 502
                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 );
                    }
                }
503 504 505 506 507
                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
508
                vlc_mutex_lock( &p_input->stream.stream_lock );
509
            }
510
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
511
        }
512

513 514 515 516 517 518 519 520 521 522 523 524
        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;
        }

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

539
        vlc_mutex_unlock( &p_input->stream.stream_lock );
540

Christophe Massiot's avatar
Christophe Massiot committed
541 542
        /* Read and demultiplex some data. */
        i_count = p_input->pf_demux( p_input );
543

544
        if( i_count == 0 )
545
        {
546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567
            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;
            }
568 569 570 571
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
572
        }
573 574 575

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
576 577 578 579
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
580 581

            /* update input status variables */
582
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
583
            {
584
                val.f_float = (float)d_pos;
585 586
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
587
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
588
            {
589
                val.i_time = i_time;
590 591
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
592
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
593
            {
594
                val.i_time = i_length;
595 596 597
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

598 599 600 601 602 603 604
            /* 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;
            }

605 606 607 608 609 610
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

611
            i_update_next = mdate() + I64C(150000);
612
        }
613 614
    }

615
    if( p_input->b_error || p_input->b_eof )
616 617 618
    {
        ErrorThread( p_input );
    }
619

620
    EndThread( p_input );
621

622
    return 0;
623 624
}

625
/*****************************************************************************
626
 * InitThread: init the input Thread
627
 *****************************************************************************/
628
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
629
{
630
    vlc_meta_t *p_meta = NULL, *p_meta_user = NULL;
631 632
//    float f_fps;
    double f_fps;
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
633
    mtime_t i_length;
634

Christophe Massiot's avatar
Christophe Massiot committed
635
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
636
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
637
    vlc_value_t val, val1;
638
    int64_t i_microsecondperframe;
639

640
    subtitle_demux_t *p_sub_toselect = NULL;
641
    char             *psz_sub_file = NULL;
642

Christophe Massiot's avatar
Christophe Massiot committed
643 644 645 646 647
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
648
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
649
    if( psz_parser - p_input->psz_dupsource == 1 )
650
    {
651
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
652
                           p_input->psz_dupsource[0] ) ;
653
        psz_parser = "";
654 655
    }
#endif
656

Christophe Massiot's avatar
Christophe Massiot committed
657
    if( !*psz_parser )
658
    {
659
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
660
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
661
        free( p_input->psz_dupsource );
662
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
663
    }
Christophe Massiot's avatar
Christophe Massiot committed
664 665 666
    else
    {
        *psz_parser++ = '\0';
667

668 669 670 671
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
672
        }
673 674

        p_input->psz_name = psz_parser ;
675

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

679
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
680 681
        {
            /* No access */
682
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
683 684 685 686
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
687
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703
            psz_parser++;
        }
        else
        {
            p_input->psz_access = psz_parser;

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

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

Christophe Massiot's avatar
Christophe Massiot committed
705 706 707
        if( !*psz_parser )
        {
            /* No demux */
708
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
709 710 711 712 713
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
Sam Hocevar committed
714
    }
Christophe Massiot's avatar
Christophe Massiot committed
715

716 717
    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
718 719

    if( input_AccessInit( p_input ) == -1 )
720
    {
721 722 723 724 725 726
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

727 728 729 730 731 732 733 734 735 736 737 738
        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 );
739 740 741 742 743 744 745

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
746 747 748
            return VLC_EGENERIC;
        }
        free( val.psz_string );
749
    }
Christophe Massiot's avatar
Christophe Massiot committed
750

751
    p_input->p_es_out = input_EsOutNew( p_input );
752 753
    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 );
754

755
    /* Find and open appropriate access module */
756
    p_input->p_access = module_Need( p_input, "access",
757
                                     p_input->psz_access, VLC_TRUE );
Christophe Massiot's avatar
Christophe Massiot committed
758

759 760 761 762 763 764 765 766 767
    /* 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 );
    }
768 769 770 771
#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 */
772 773 774 775 776 777 778 779 780
    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",
781
                                         p_input->psz_access, VLC_TRUE );
782
    }
783
#endif
784
    if( p_input->p_access == NULL )
785
    {
786
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
787
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
788 789 790 791
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
792 793 794 795 796 797 798

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
799
        input_EsOutDelete( p_input->p_es_out );
800
        return VLC_EGENERIC;
801
    }
Christophe Massiot's avatar
Christophe Massiot committed
802 803 804

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
805
    {
Christophe Massiot's avatar
Christophe Massiot committed
806
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
807
    }
808 809
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
810
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
811
    }
812

813 814
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
815 816 817 818
    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);
819

820
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
821
    {
Christophe Massiot's avatar
Christophe Massiot committed
822 823
        while( !input_FillBuffer( p_input ) )
        {
824
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
825
            {
826
                module_Unneed( p_input, p_input->p_access );
827 828 829 830
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
831 832 833 834 835 836
                input_AccessEnd( p_input );
                free( p_input->psz_source );
                if( p_input->psz_dupsource != NULL )
                {
                    free( p_input->psz_dupsource );
                }
837
                input_EsOutDelete( p_input->p_es_out );
838
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
839 840
            }
        }
841
    }
842

843
    /* Create the stream_t facilities */
844
    p_input->s = input_StreamNew( p_input );
845 846
    if( p_input->s == NULL )
    {
Clément Stenac's avatar
Clément Stenac committed
847
        /* should never occur yet */
848

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

851 852 853 854 855
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
856 857 858 859 860 861
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
862
        input_EsOutDelete( p_input->p_es_out );
863 864 865
        return VLC_EGENERIC;
    }

866
    /* Find and open appropriate demux module */
867 868 869
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
870 871 872
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
873

874
    if( p_input->p_demux == NULL )
875
    {
876
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
877
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
878

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

895 896 897 898 899
    /* 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;

900 901
    p_input->p_sys->i_stop_time = 0;

902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951
    /* 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 ) )
952 953 954
    {
        int i;

955 956 957 958
        /* 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 );

959
        msg_Dbg( p_input, "meta informations:" );
960
        if( p_meta->i_meta > 0 )
961
        {
962
            for( i = 0; i < p_meta->i_meta; i++ )
963
            {
964 965
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
966 967 968 969
                if( !strcmp( p_meta->name[i], VLC_META_TITLE ) &&
                    p_meta->value[i] )
                    input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

970
                if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
971 972 973 974 975
                    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] );
976 977
            }
        }
978
        for( i = 0; i < p_meta->i_track; i++ )
979
        {
980
            vlc_meta_t *tk = p_meta->track[i];
981 982 983 984 985 986 987 988 989 990
            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++ )
                {
991 992
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
993 994 995

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

1000 1001
        if( p_input->stream.p_sout && p_input->stream.p_sout->p_meta == NULL )
        {
1002
            p_input->stream.p_sout->p_meta = p_meta;
1003 1004 1005
        }
        else
        {
1006
            vlc_meta_Delete( p_meta );
1007
        }
1008
    }
1009
    if( p_meta_user ) vlc_meta_Delete( p_meta_user );
1010

1011 1012 1013
    /* Get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) &&
        i_length > 0 )
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
1014
    {
1015 1016 1017 1018 1019 1020 1021 1022
        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 ) );
Laurent Aimar's avatar