input.c 47.2 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 * Read a stream, demultiplex and parse it before sending it to
Michel Kaempf's avatar
Michel Kaempf committed
4
 * decoders.
5
 *****************************************************************************
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 92 93
    input_thread_t *p_input;                        /* thread descriptor */
    vlc_value_t     val;
    int             i;
94

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

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->b_out_pace_control = VLC_FALSE;
182
    p_input->p_sys      = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
183 184

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            p_input->stream.b_new_mute = MUTE_NO_CHANGE;
        }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        p_input->p_access = module_Need( p_input, "access",
Gildas Bazin's avatar
 
Gildas Bazin committed
705
                                         p_input->psz_access, VLC_TRUE );
706
    }
Gildas Bazin's avatar
 
Gildas Bazin committed
707
#endif
708

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        msg_Dbg( p_input, "meta informations:" );
900
        if( p_meta->i_meta > 0 )
901 902
        {
            p_cat = input_InfoCategory( p_input, _("File") );
903
            for( i = 0; i < p_meta->i_meta; i++ )
904
            {
905 906 907
                msg_Dbg( p_input, "  - '%s' = '%s'", _(p_meta->name[i]),
                         p_meta->value[i] );
                i