input.c 36.9 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-2002 VideoLAN
7
 * $Id: input.c,v 1.269 2003/11/30 16:00:24 fenrir Exp $
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 46
#include "codecs.h"
#include "modules/demux/util/sub.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
47

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
63 64
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );
65

66 67 68 69 70 71 72 73 74 75 76
/*****************************************************************************
 * 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
77

78
/*****************************************************************************
79
 * input_CreateThread: creates a new input thread
80
 *****************************************************************************
81 82
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
83
 *****************************************************************************/
84
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
85
                                      playlist_item_t *p_item )
Michel Kaempf's avatar
Michel Kaempf committed
86
{
87
    input_thread_t *    p_input;                        /* thread descriptor */
88
    input_info_category_t * p_info;
89
    vlc_value_t val;
Gildas Bazin's avatar
 
Gildas Bazin committed
90
    int i;
91

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

Gildas Bazin's avatar
 
Gildas Bazin committed
100 101 102 103 104 105
    /* Parse input options */
    for( i = 0; i < p_item->i_options; i++ )
    {
        ParseOption( p_input, p_item->ppsz_options[i] );
    }

Gildas Bazin's avatar
 
Gildas Bazin committed
106 107 108 109 110
    /* 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 );
111 112
    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 );
113
    var_Create( p_input, "sub-autodetect-fuzzy", VLC_VAR_INTEGER | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
114 115

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
116
    var_Create( p_input, "sout-all",   VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
117 118
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
119 120
    var_Create( p_input, "sout-keep",  VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

121 122 123
    /* decoders */
    var_Create( p_input, "minimize-threads", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );

124 125 126
    /* play status */

    /* position variable */
127 128
    var_Create( p_input, "position",  VLC_VAR_FLOAT );  /* position 0.0->1.0 */
    var_Create( p_input, "position-offset",  VLC_VAR_FLOAT );  /* relative */
129 130 131
    val.f_float = 0.0;
    var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "position", PositionCallback, NULL );
132
    var_AddCallback( p_input, "position-offset", PositionCallback, NULL );
133 134 135

    /* time variable */
    var_Create( p_input, "time",  VLC_VAR_TIME );
136
    var_Create( p_input, "time-offset",  VLC_VAR_TIME );    /* relative */
137 138 139
    val.i_time = 0;
    var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    var_AddCallback( p_input, "time", TimeCallback, NULL );
140
    var_AddCallback( p_input, "time-offset", TimeCallback, NULL );
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162

    /* 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 );

163 164 165 166
    /* 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
167

168
    /* Initialize thread properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
169
    p_input->b_eof      = 0;
170
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
171 172

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

175 176 177
    /* Stream */
    p_input->s = NULL;

178 179 180
    /* es out */
    p_input->p_es_out = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
181
    /* Demux */
182 183 184 185
    p_input->p_demux   = NULL;
    p_input->pf_demux  = NULL;
    p_input->pf_rewind = NULL;
    p_input->pf_demux_control = NULL;
186
    p_input->i_cr_average = config_GetInt( p_input, "cr-average" );
Stéphane Borel's avatar
 
Stéphane Borel committed
187 188

    /* Access */
189
    p_input->p_access = NULL;
190

Sam Hocevar's avatar
 
Sam Hocevar committed
191 192
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
193
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
 
Sam Hocevar committed
194

195 196 197 198 199 200
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
201
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
202
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
203
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
204

205
    /* Initialize stream description */
Stéphane Borel's avatar
 
Stéphane Borel committed
206
    p_input->stream.b_changed = 0;
207 208
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
209
    p_input->stream.i_pgrm_number = 0;
210
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
211
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
212
    p_input->stream.i_mux_rate = 0;
213
    p_input->stream.b_seekable = 0;
214
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
215

Sam Hocevar's avatar
 
Sam Hocevar committed
216 217 218
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
219 220
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
221
    p_input->stream.p_selected_area = NULL;
222
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
223

Sam Hocevar's avatar
 
Sam Hocevar committed
224 225 226 227
    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
228
    /* By default there is one area in a stream */
Gildas Bazin's avatar
 
Gildas Bazin committed
229
    input_AddArea( p_input, 0, 1 );
230
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
231

232
    /* Initialize stream control properties. */
233
    p_input->stream.control.i_status = INIT_S;
234 235
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
236 237
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" );

238 239 240 241 242 243 244 245 246 247 248
    /* Initialize input info */
    p_input->stream.p_info = malloc( sizeof( input_info_category_t ) );
    if( !p_input->stream.p_info )
    {
        msg_Err( p_input, "No memory!" );
        return NULL;
    }
    p_input->stream.p_info->psz_name = strdup("General") ;
    p_input->stream.p_info->p_info = NULL;
    p_input->stream.p_info->p_next = NULL;

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

251 252
    p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_info, _("Playlist Item"), p_input->psz_source );
253
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
 
Sam Hocevar committed
254

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

264
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
265 266
}

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

279 280
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
281 282 283 284 285 286 287 288 289 290
}

/*****************************************************************************
 * 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 */
291
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
292 293 294

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
295
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
 
Sam Hocevar committed
296
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
297 298
}

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

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

Sam Hocevar's avatar
 
Sam Hocevar committed
312 313 314 315
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
316

Sam Hocevar's avatar
 
Sam Hocevar committed
317
        ErrorThread( p_input );
318 319 320 321

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

Sam Hocevar's avatar
 
Sam Hocevar committed
322
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
323
    }
Michel Kaempf's avatar
Michel Kaempf committed
324

325
    /* initialization is complete */
326
    vlc_mutex_lock( &p_input->stream.stream_lock );
327 328
    p_input->stream.b_changed        = 1;
    p_input->stream.control.i_status = PLAYING_S;
329 330
    vlc_mutex_unlock( &p_input->stream.stream_lock );

331 332 333
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

Sam Hocevar's avatar
 
Sam Hocevar committed
334 335
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
336
        unsigned int i, i_count;
337

Sam Hocevar's avatar
 
Sam Hocevar committed
338
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
339

340
        vlc_mutex_lock( &p_input->stream.stream_lock );
341

342 343 344 345 346
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
 
Johan Bilien committed
347 348
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
349 350

                p_input->pf_set_program( p_input,
351
                                         p_input->stream.p_new_program );
352

353 354 355 356
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

357 358 359 360 361 362 363 364 365 366 367
                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;
        }
368

369 370
        if( p_input->stream.p_new_area )
        {
371 372
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
373
                input_AccessReinit( p_input );
374 375 376

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

377 378 379 380
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

381 382 383 384 385 386 387 388 389
                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;
                }
            }
390 391 392
            p_input->stream.p_new_area = NULL;
        }

393
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
394
        {
395
            if( p_input->stream.p_selected_area->i_size > 0 )
396
            {
397
                unsigned int i;
398
                mtime_t      i_time;
399 400
                double f = (double)p_input->stream.p_selected_area->i_seek /
                           (double)p_input->stream.p_selected_area->i_size;
401

Christophe Massiot's avatar
Christophe Massiot committed
402
                vlc_mutex_unlock( &p_input->stream.stream_lock );
403
                demux_Control( p_input, DEMUX_SET_POSITION, f );
Christophe Massiot's avatar
Christophe Massiot committed
404
                vlc_mutex_lock( &p_input->stream.stream_lock );
405

406 407 408 409
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

410 411
                for( i = 0; i < p_input->stream.i_pgrm_number; i++ )
                {
412
                    pgrm_descriptor_t * p_pgrm=p_input->stream.pp_programs[i];
413 414 415 416

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

Laurent Aimar's avatar
Laurent Aimar committed
418
                vlc_mutex_unlock( &p_input->stream.stream_lock );
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433
                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
434
                vlc_mutex_lock( &p_input->stream.stream_lock );
435
            }
436
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
437
        }
438

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

451 452 453 454 455 456 457 458 459 460 461 462 463 464
        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;
        }

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
470
        if( i_count == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
471
        {
472
            /* End of file - we do not set b_die because only the
473
             * playlist is allowed to do so. */
474
            msg_Info( p_input, "EOF reached" );
475 476 477 478 479
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
480
        }
481 482 483

        if( !p_input->b_error && !p_input->b_eof && i_update_next < mdate() )
        {
484 485 486 487
            int i;
            mtime_t i_time;
            mtime_t i_length;
            double  d_pos;
488 489

            /* update input status variables */
490
            if( !demux_Control( p_input, DEMUX_GET_POSITION, &d_pos ) )
491
            {
492
                val.f_float = (float)d_pos;
493 494
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
495
            if( !demux_Control( p_input, DEMUX_GET_TIME, &i_time ) )
496
            {
497
                val.i_time = i_time;
498 499
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
500
            if( !demux_Control( p_input, DEMUX_GET_LENGTH, &i_length ) )
501
            {
502
                val.i_time = i_length;
503 504 505
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
            }

506 507 508 509 510 511 512
            /* update subs */
            for( i = 0; i < p_input->p_sys->i_sub; i++ )
            {
                subtitle_Demux( p_input->p_sys->sub[i], i_time );
            }

            i_update_next = mdate() + 150000LL;
513
        }
514 515
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
516
    if( p_input->b_error || p_input->b_eof )
517 518 519
    {
        ErrorThread( p_input );
    }
520

521
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
522

Sam Hocevar's avatar
 
Sam Hocevar committed
523
    return 0;
524 525
}

526
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
527
 * InitThread: init the input Thread
528
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
529
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
530
{
531
    float f_fps;
Christophe Massiot's avatar
Christophe Massiot committed
532
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
533
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
Gildas Bazin's avatar
 
Gildas Bazin committed
534
    vlc_value_t val;
535 536
    subtitle_demux_t *p_sub;
    int64_t i_microsecondperframe;
Gildas Bazin's avatar
 
Gildas Bazin committed
537

Christophe Massiot's avatar
Christophe Massiot committed
538 539 540 541 542
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
543
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
544
    if( psz_parser - p_input->psz_dupsource == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
545
    {
546
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
547
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
 
Stéphane Borel committed
548
        psz_parser = "";
Gildas Bazin's avatar
 
Gildas Bazin committed
549 550
    }
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
551

Christophe Massiot's avatar
Christophe Massiot committed
552
    if( !*psz_parser )
553
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
554
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
555
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
556
        free( p_input->psz_dupsource );
557
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
558
    }
Christophe Massiot's avatar
Christophe Massiot committed
559 560 561
    else
    {
        *psz_parser++ = '\0';
562

Xavier Marchesini's avatar
 
Xavier Marchesini committed
563 564 565 566
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
567
        }
Xavier Marchesini's avatar
 
Xavier Marchesini committed
568 569

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
574
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
575 576
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
577
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
578 579 580 581
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
582
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
            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
599

Christophe Massiot's avatar
Christophe Massiot committed
600 601 602
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
 
Sam Hocevar committed
603
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
604 605 606 607 608
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
609
    }
Christophe Massiot's avatar
Christophe Massiot committed
610

611 612
    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
613 614

    if( input_AccessInit( p_input ) == -1 )
615
    {
616 617 618 619 620 621
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }

622 623 624 625 626 627 628 629 630 631 632 633
        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 );
634 635 636 637 638 639 640

            input_AccessEnd( p_input );
            free( p_input->psz_source );
            if( p_input->psz_dupsource != NULL )
            {
                free( p_input->psz_dupsource );
            }
641 642 643
            return VLC_EGENERIC;
        }
        free( val.psz_string );
644
    }
Christophe Massiot's avatar
Christophe Massiot committed
645

646
    p_input->p_es_out = input_EsOutNew( p_input );
647 648
    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 );
649

650
    /* Find and open appropriate access module */
651 652
    p_input->p_access = module_Need( p_input, "access",
                                     p_input->psz_access );
Christophe Massiot's avatar
Christophe Massiot committed
653

Gildas Bazin's avatar
 
Gildas Bazin committed
654 655 656 657
#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 */
658 659 660 661 662 663 664 665 666 667 668
    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",
                                         p_input->psz_access );
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
669
#endif
670

671
    if( p_input->p_access == NULL )
672
    {
673
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
674
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
675 676 677 678
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
679 680 681 682 683 684 685

        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
686
        return VLC_EGENERIC;
687
    }
Christophe Massiot's avatar
Christophe Massiot committed
688 689 690

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
691
    {
Christophe Massiot's avatar
Christophe Massiot committed
692
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
693
    }
694 695
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
696
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
697
    }
698

Gildas Bazin's avatar
 
Gildas Bazin committed
699 700
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
Gildas Bazin's avatar
 
Gildas Bazin committed
701 702 703 704
    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
705

Sam Hocevar's avatar
 
Sam Hocevar committed
706
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
707
    {
Christophe Massiot's avatar
Christophe Massiot committed
708 709
        while( !input_FillBuffer( p_input ) )
        {
710
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
711
            {
712
                module_Unneed( p_input, p_input->p_access );
713 714 715 716
                if ( p_input->stream.p_sout != NULL )
                {
                    sout_DeleteInstance( p_input->stream.p_sout );
                }
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 );
                }
723
                return VLC_EGENERIC;
Christophe Massiot's avatar
Christophe Massiot committed
724 725
            }
        }
726
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
727

728 729 730 731 732 733 734
    /* Create the stream_t facilities */
    p_input->s = stream_OpenInput( p_input );
    if( p_input->s == NULL )
    {
        /* should nver occur yet */

        msg_Err( p_input, "cannot create stream_t !" );
735

736 737 738 739 740
        module_Unneed( p_input, p_input->p_access );
        if ( p_input->stream.p_sout != NULL )
        {
            sout_DeleteInstance( p_input->stream.p_sout );
        }
741 742 743 744 745 746
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
747 748 749
        return VLC_EGENERIC;
    }

750
    /* Find and open appropriate demux module */
Gildas Bazin's avatar
 
Gildas Bazin committed
751 752 753 754
    p_input->p_demux =
        module_Need( p_input, "demux",
                     (p_input->psz_demux && *p_input->psz_demux) ?
                     p_input->psz_demux : "$demux" );
Sam Hocevar's avatar
 
Sam Hocevar committed
755

756
    if( p_input->p_demux == NULL )
757
    {
758
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
759
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
760

761
        stream_Release( p_input->s );
762
        module_Unneed( p_input, p_input->p_access );
763
        if ( p_input->stream.p_sout != NULL )
764
        {
765
            sout_DeleteInstance( p_input->stream.p_sout );
766
        }
767 768 769 770 771 772
        input_AccessEnd( p_input );
        free( p_input->psz_source );
        if( p_input->psz_dupsource != NULL )
        {
            free( p_input->psz_dupsource );
        }
773
        return VLC_EGENERIC;
774 775
    }

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790
    /* 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;

    /* get fps */
    if( demux_Control( p_input, DEMUX_GET_FPS, &f_fps ) || f_fps < 0.1 )
    {
        i_microsecondperframe = 0;
    }
    else
    {
        i_microsecondperframe = (int64_t)( (double)1000000.0 / (double)f_fps );
    }

791
    /* Look for and add subtitle files */
792 793 794
    var_Get( p_input, "sub-file", &val );
    if( val.psz_string && *val.psz_string )
    {
795
        if( ( p_sub = subtitle_New( p_input, strdup(val.psz_string), i_microsecondperframe, 0 ) ) )
796
        {
797
            /* Select this ES by default */
798
            es_out_Control( p_input->p_es_out, ES_OUT_SET_ES_STATE, p_sub->p_es, VLC_TRUE );
799

800 801 802 803
            TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
        }
    }
    if( val.psz_string ) free( val.psz_string );
804

805 806
    var_Get( p_input, "sub-autodetect-file", &val );
    if( val.b_bool )
807
    {
808
        int i;
809 810
        char **tmp = subtitles_Detect( p_input, "", p_input->psz_source );
        char **tmp2 = tmp;
811
        for( i = 0; *tmp2 != NULL; i++ )
812
        {
813
            if( ( p_sub = subtitle_New( p_input, strdup(*tmp2++), i_microsecondperframe, i ) ) )
814 815 816
            {
                TAB_APPEND( p_input->p_sys->i_sub, p_input->p_sys->sub, p_sub );
            }
817
        }
818
        free(tmp);
819 820
    }

821
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
822 823 824 825 826 827 828
    val.b_bool =  VLC_FALSE;
    if( p_input->stream.p_sout )
    {
        var_Get( p_input, "sout-all", &val );
    }
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE,
                    val.b_bool ? ES_OUT_MODE_ALL : ES_OUT_MODE_AUTO );
829

830
    return VLC_SUCCESS;
Michel Kaempf's avatar
Michel Kaempf committed
831 832
}

833
/*****************************************************************************
834
 * ErrorThread: RunThread() error loop
835
 *****************************************************************************
836
 * This function is called when an error occured during thread main's loop.
837
 *****************************************************************************/
838
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
839
{
840
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
841
    {
842 843
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
844 845 846
    }
}

847
/*****************************************************************************
848
 * EndThread: end the input thread
849
 *****************************************************************************/
850
static void EndThread( input_thread_t * p_input )
851
{
852
    int i;
853
#ifdef HAVE_SYS_TIMES_H
854 855 856
    /* Display statistics */
    struct tms  cpu_usage;
    times( &cpu_usage );
Sam Hocevar's avatar
 
Sam Hocevar committed
857

858
    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
859
             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
860
#else
861
    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
862
#endif
863

864 865
    input_DumpStream( p_input );

Gildas Bazin's avatar
 
Gildas Bazin committed
866
    /* Free demultiplexer's data */
Gildas Bazin's avatar
 
Gildas Bazin committed
867
    if( p_input->p_demux ) module_Unneed( p_input, p_input->p_demux );
Gildas Bazin's avatar
 
Gildas Bazin committed
868 869 870 871

    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

872
    /* Close optional stream output instance */
Gildas Bazin's avatar
 
Gildas Bazin committed
873
    if( p_input->stream.p_sout )
874
    {
875 876
        vlc_object_t *p_pl =
            vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894
        vlc_value_t keep;

        if( var_Get( p_input, "sout-keep", &keep ) >= 0 && keep.b_bool && p_pl )
        {
            /* attach sout to the playlist */
            msg_Warn( p_input, "keeping sout" );
            vlc_object_detach( p_input->stream.p_sout );
            vlc_object_attach( p_input->stream.p_sout, p_pl );
        }
        else
        {
            msg_Warn( p_input, "destroying sout" );
            sout_DeleteInstance( p_input->stream.p_sout );
        }
        if( p_pl )
        {
            vlc_object_release( p_pl );
        }
895 896
    }

897
    /* Destroy subtitles demuxers */
Gildas Bazin's avatar
 
Gildas Bazin committed
898
    if( p_input->p_sys )
899
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
900 901 902 903 904 905 906 907
        for( i = 0; i < p_input->p_sys->i_sub; i++ )
        {
            subtitle_Close( p_input->p_sys->sub[i] );
        }
        if( p_input->p_sys->i_sub > 0 )
        {
            free( p_input->p_sys->sub );
        }
908

Gildas Bazin's avatar
 
Gildas Bazin committed
909 910 911
        /* Free input_thread_sys_t */
        free( p_input->p_sys );
    }
912

913
    /* Destroy the stream_t facilities */
Gildas Bazin's avatar
 
Gildas Bazin committed
914
    if( p_input->s ) stream_Release( p_input->s );
915

916
    /* Destroy es out */
Gildas Bazin's avatar
 
Gildas Bazin committed
917
    if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );
918

919
    /* Close the access plug-in */
Gildas Bazin's avatar
 
Gildas Bazin committed
920
    if( p_input->p_access ) module_Unneed( p_input, p_input->p_access );
Sam Hocevar's avatar
 
Sam Hocevar committed
921

Christophe Massiot's avatar
Christophe Massiot committed
922 923
    input_AccessEnd( p_input );

924 925 926 927
    /* Free info structures XXX destroy es before 'cause vorbis */
    msg_Dbg( p_input, "freeing info structures...");
    input_DelInfo( p_input );

Christophe Massiot's avatar
Christophe Massiot committed
928
    free( p_input->psz_source );
Gildas Bazin's avatar
 
Gildas Bazin committed
929
    if( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
930 931 932

    /* Tell we're dead */
    p_input->b_dead = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
933 934
}

Gildas Bazin's avatar
 
Gildas Bazin committed
935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011
/*****************************************************************************
 * ParseOption: parses the options for the input
 *****************************************************************************
 * This function parses the input (config) options and creates their associated
 * object variables.
 * Options are of the form "[no[-]]foo[=bar]" where foo is the option name and
 * bar is the value of the option.
 *****************************************************************************/
static void ParseOption( input_thread_t *p_input, const char *psz_option )
{
    char *psz_name = (char *)psz_option;
    char *psz_value = strchr( psz_option, '=' );
    int  i_name_len, i_type;
    vlc_bool_t b_isno = VLC_FALSE;
    vlc_value_t val;

    if( psz_value ) i_name_len = psz_value - psz_option;
    else i_name_len = strlen( psz_option );

    /* It's too much of an hassle to remove the ':' when we parse
     * the cmd line :) */
    if( i_name_len && *psz_name == ':' )
    {
        psz_name++;
        i_name_len--;
    }

    if( i_name_len == 0 ) return;

    psz_name = strndup( psz_name, i_name_len );
    if( psz_value ) psz_value++;

    i_type = config_GetType( p_input, psz_name );

    if( !i_type && !psz_value )
    {
        /* check for "no-foo" or "nofoo" */
        if( !strncmp( psz_name, "no-", 3 ) )
        {
            memmove( psz_name, psz_name + 3, strlen(psz_name) + 1 - 3 );
        }
        else if( !strncmp( psz_name, "no", 2 ) )
        {
            memmove( psz_name, psz_name + 2, strlen(psz_name) + 1 - 2 );
        }
        else goto cleanup;           /* Option doesn't exist */

        b_isno = VLC_TRUE;
        i_type = config_GetType( p_input, psz_name );

        if( !i_type ) goto cleanup;  /* Option doesn't exist */
    }
    else if( !i_type ) goto cleanup; /* Option doesn't exist */

    if( ( i_type != VLC_VAR_BOOL ) &&
        ( !psz_value || !*psz_value ) ) goto cleanup; /* Invalid value */

    /* Create the variable in the input object.
     * Children of the input object will be able to retreive this value
     * thanks to the inheritance property of the object variables. */
    var_Create( p_input, psz_name, i_type );

    switch( i_type )
    {
    case VLC_VAR_BOOL:
        val.b_bool = !b_isno;
        break;

    case VLC_VAR_INTEGER:
        val.i_int = atoi( psz_value );
        break;

    case VLC_VAR_FLOAT:
        val.f_float = atof( psz_value );
        break;

    case VLC_VAR_STRING:
Gildas Bazin's avatar
 
Gildas Bazin committed
1012
    case VLC_VAR_MODULE:
Gildas Bazin's avatar
 
Gildas Bazin committed
1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030
    case VLC_VAR_FILE:
    case VLC_VAR_DIRECTORY:
        val.psz_string = psz_value;
        break;

    default:
        goto cleanup;
        break;
    }

    var_Set( p_input, psz_name, val );

    msg_Dbg( p_input, "set input option: %s to %s", psz_name, psz_value );

  cleanup:
    if( psz_name ) free( psz_name );
    return;
}
1031 1032 1033 1034 1035

/*****************************************************************************
 * Callbacks  (position, time, state, rate )
 *****************************************************************************/
static int PositionCallback( vlc_object_t *p_this, char const *psz_cmd,
Gildas Bazin's avatar