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

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

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

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

40
#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"
Sam Hocevar's avatar
 
Sam Hocevar committed
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
};

Sam Hocevar's avatar
 
Sam Hocevar committed
61
static  int RunThread       ( input_thread_t *p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
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

Gildas Bazin's avatar
 
Gildas Bazin committed
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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
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
    input_thread_t *    p_input;                        /* thread descriptor */
92
    vlc_value_t val;
93
    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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
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 );
Gildas Bazin's avatar
 
Gildas Bazin committed
178

179
    /* Initialize thread properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
180
    p_input->b_eof      = 0;
181
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
182 183

    /* Set target */
184
    p_input->psz_source = strdup( psz_uri );
Sam Hocevar's avatar
 
Sam Hocevar committed
185

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
192
    /* Demux */
193 194 195 196
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
    p_input->pf_demux_control = NULL;
197
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
 
Stéphane Borel committed
198 199

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

Sam Hocevar's avatar
 
Sam Hocevar committed
202 203
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
204
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
 
Sam Hocevar committed
205

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
227 228 229
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
230 231
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
232
    p_input->stream.p_selected_area = NULL;
233
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
234

Sam Hocevar's avatar
 
Sam Hocevar committed
235 236 237 238
    p_input->stream.pp_selected_es = NULL;
    p_input->stream.p_removed_es = NULL;
    p_input->stream.p_newly_selected_es = NULL;

Sam Hocevar's avatar
 
Sam Hocevar committed
239
    /* By default there is one area in a stream */
Gildas Bazin's avatar
 
Gildas Bazin committed
240
    input_AddArea( p_input, 0, 1 );
241
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
242

243
    /* Initialize stream control properties. */
244
    p_input->stream.control.i_status = INIT_S;
245 246
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
247
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale");
248

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

Gildas Bazin's avatar
 
Gildas Bazin committed
251 252 253 254 255
    /* 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 );
256
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
 
Sam Hocevar committed
257

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

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

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

283 284
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
285 286 287 288 289 290 291 292 293 294
}

/*****************************************************************************
 * 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 */
295
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
296 297 298

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

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
316 317 318 319
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
320

Sam Hocevar's avatar
 
Sam Hocevar committed
321
        ErrorThread( p_input );
322 323 324 325

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

Gildas Bazin's avatar
 
Gildas Bazin committed
326 327
        input_DelInfo( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
328
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
329
    }
Michel Kaempf's avatar
Michel Kaempf committed
330

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
340 341
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
342
        unsigned int i, i_count;
343

Sam Hocevar's avatar
 
Sam Hocevar committed
344
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
345

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

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

Johan Bilien's avatar
 
Johan Bilien committed
353 354
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
355 356

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

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

363 364 365 366 367 368 369 370 371 372 373
                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;
        }
374

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

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

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

387 388 389 390 391 392 393 394 395
                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;
                }
            }
396 397 398
            p_input->stream.p_new_area = NULL;
        }

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

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

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

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

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

Laurent Aimar's avatar
Laurent Aimar committed
424
                vlc_mutex_unlock( &p_input->stream.stream_lock );
425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
                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
440
                vlc_mutex_lock( &p_input->stream.stream_lock );
441
            }
442
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
443
        }
444

445 446 447 448 449 450 451 452 453 454 455 456
        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;
        }

457 458 459 460 461 462 463 464 465 466 467 468 469 470
        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;
        }

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
476
        if( i_count == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
477
        {
478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499
            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;
            }
500 501 502 503
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
504
        }
505 506 507

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

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

530 531 532 533 534 535 536
            /* 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;
            }

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
547
    if( p_input->b_error || p_input->b_eof )
548 549 550
    {
        ErrorThread( p_input );
    }
551

552
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
553

Sam Hocevar's avatar
 
Sam Hocevar committed
554
    return 0;
555 556
}

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

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

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

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

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

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

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

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

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

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

            if( *psz_parser == '/' )
            {
                *psz_parser++ = '\0';
            }
        }
Gildas Bazin's avatar
 
Gildas Bazin committed
636

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

648 649
    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
650 651

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

659 660 661 662 663 664 665 666 667 668 669 670
        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 );
671 672 673 674 675 676 677

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

683
    p_input->p_es_out = input_EsOutNew( p_input );
684 685
    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 );
686

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

Gildas Bazin's avatar
 
Gildas Bazin committed
691 692 693 694
#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 */
695 696 697 698 699 700 701 702 703
    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",
Gildas Bazin's avatar
 
Gildas Bazin committed
704
                                         p_input->psz_access, VLC_TRUE );
705
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
706
#endif
707

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

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
737 738
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
Gildas Bazin's avatar
 
Gildas Bazin committed
739 740 741 742
    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);
Gildas Bazin's avatar
 
Gildas Bazin committed
743

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

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

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

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

790
    /* Find and open appropriate demux module */
Gildas Bazin's avatar
 
Gildas Bazin committed
791 792 793
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
Gildas Bazin's avatar
 
Gildas Bazin committed
794 795 796
                     p_input->psz_demux : "$demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     VLC_TRUE : VLC_FALSE );
Sam Hocevar's avatar
 
Sam Hocevar committed
797

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

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

819 820 821 822 823
    /* 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;

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

826 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
    /* get meta informations */
    if( !demux_Control( p_input, DEMUX_GET_META, &meta ) )
    {
        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;

        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:" );
        if( meta->i_meta > 0 )
        {
            p_cat = input_InfoCategory( p_input, _("File") );
            for( i = 0; i < meta->i_meta; i++ )
            {
                msg_Dbg( p_input, "  - '%s' = '%s'", _(meta->name[i]), meta->value[i] );
853 854 855 856 857 858 859 860 861
                if( !strcmp( meta->name[i], VLC_META_TITLE ) )
                {
                    playlist_ItemSetName( p_item, meta->value[i] );
                }
                if( !strcmp( meta->name[i], VLC_META_AUTHOR ) )
                {
                    playlist_ItemAddInfo( p_item, _("General"), _("Author"),
                                            meta->value[i] );
                }
862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903
                input_AddInfo( p_cat, _(meta->name[i]), "%s", meta->value[i] );
                if( p_item )
                {
                    playlist_ItemAddInfo( p_item, _("File"),
                                          _(meta->name[i]), "%s", meta->value[i] );
                }
            }
        }
        for( i = 0; i < meta->i_track; i++ )
        {
            vlc_meta_t *tk = meta->track[i];
            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++ )
                {
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]), tk->value[j] );
                    input_AddInfo( p_cat, _(tk->name[j]), "%s", tk->value[j] );
                    if( p_item )
                    {
                        playlist_ItemAddInfo( p_item, psz_cat,
                                              _(tk->name[j]), "%s", tk->value[j] );
                    }
                }
            }
        }

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

        vlc_meta_Delete( meta );
    }

Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
904 905 906
    /* get length */
    if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) && i_length > 0 )
    {
907
        input_info_category_t *p_cat = input_InfoCategory( p_input, _("File") );
Sigmund Augdal Helberg's avatar
Sigmund Augdal Helberg committed
908 909 910 911 912
        p_playlist = (playlist_t*)vlc_object_find( p_input,
                                                   VLC_OBJECT_PLAYLIST,
                                                   FIND_PARENT );
        if( p_playlist )
        {
913
            playlist_SetDuration( p_playlist, -1 , i_length );
914
            val.b_bool = p_playlist->i_index;
Clément Stenac's avatar