input.c 23 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
Michel Kaempf's avatar
Michel Kaempf committed
3 4
 * Read an MPEG2 stream, demultiplex and parse it before sending it to
 * decoders.
5
 *****************************************************************************
6
 * Copyright (C) 1998-2002 VideoLAN
Gildas Bazin's avatar
 
Gildas Bazin committed
7
 * $Id: input.c,v 1.235 2003/07/23 22:01:25 gbazin 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>
Sam Hocevar's avatar
 
Sam Hocevar committed
32

33
#include <string.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
34

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

39
#include "vlc_playlist.h"
40

41 42 43
#include "stream_control.h"
#include "input_ext-intf.h"
#include "input_ext-dec.h"
44
#include "input_ext-plugins.h"
Michel Lespinasse's avatar
Yop,  
Michel Lespinasse committed
45

46
#include "stream_output.h"
47
#include <vlc/vout.h>
48

49
#include "vlc_interface.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
50

51
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
52
 * Local prototypes
53
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
54
static  int RunThread       ( input_thread_t *p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
55 56 57
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
58

Gildas Bazin's avatar
 
Gildas Bazin committed
59 60 61
static void ParseOption     ( input_thread_t *p_input,
                              const char *psz_option );

62
/*****************************************************************************
63
 * input_CreateThread: creates a new input thread
64
 *****************************************************************************
65 66
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
67
 *****************************************************************************/
68
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
69
                                      playlist_item_t *p_item )
Michel Kaempf's avatar
Michel Kaempf committed
70
{
71
    input_thread_t *    p_input;                        /* thread descriptor */
72
    input_info_category_t * p_info;
Gildas Bazin's avatar
 
Gildas Bazin committed
73
    int i;
74

75
    /* Allocate descriptor */
76
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
77
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
78
    {
79
        msg_Err( p_parent, "out of memory" );
80
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
81
    }
82

Gildas Bazin's avatar
 
Gildas Bazin committed
83 84 85 86 87 88
    /* 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
89 90 91 92 93 94 95 96 97
    /* 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 );

    var_Create( p_input, "sout", VLC_VAR_STRING | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-audio", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
    var_Create( p_input, "sout-video", VLC_VAR_BOOL | VLC_VAR_DOINHERIT );
Gildas Bazin's avatar
 
Gildas Bazin committed
98

99
    /* Initialize thread properties */
Sam Hocevar's avatar
 
Sam Hocevar committed
100
    p_input->b_eof      = 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
101 102

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

Stéphane Borel's avatar
 
Stéphane Borel committed
105
    /* Demux */
106
    p_input->p_demux = NULL;
Stéphane Borel's avatar
 
Stéphane Borel committed
107 108

    /* Access */
109
    p_input->p_access = NULL;
110

Sam Hocevar's avatar
 
Sam Hocevar committed
111 112
    p_input->i_bufsize = 0;
    p_input->i_mtu = 0;
Gildas Bazin's avatar
 
Gildas Bazin committed
113
    p_input->i_pts_delay = DEFAULT_PTS_DELAY;
Sam Hocevar's avatar
 
Sam Hocevar committed
114

115 116 117 118 119 120
    /* Initialize statistics */
    p_input->c_loops                    = 0;
    p_input->stream.c_packets_read      = 0;
    p_input->stream.c_packets_trashed   = 0;

    /* Set locks. */
121
    vlc_mutex_init( p_input, &p_input->stream.stream_lock );
122
    vlc_cond_init( p_input, &p_input->stream.stream_wait );
123
    vlc_mutex_init( p_input, &p_input->stream.control.control_lock );
Michel Kaempf's avatar
Michel Kaempf committed
124

125
    /* Initialize stream description */
Stéphane Borel's avatar
 
Stéphane Borel committed
126
    p_input->stream.b_changed = 0;
127 128
    p_input->stream.i_es_number = 0;
    p_input->stream.i_selected_es_number = 0;
129
    p_input->stream.i_pgrm_number = 0;
130
    p_input->stream.i_new_status = p_input->stream.i_new_rate = 0;
131
    p_input->stream.b_new_mute = MUTE_NO_CHANGE;
Christophe Massiot's avatar
Christophe Massiot committed
132
    p_input->stream.i_mux_rate = 0;
133
    p_input->stream.b_seekable = 0;
134
    p_input->stream.p_sout = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
135

Sam Hocevar's avatar
 
Sam Hocevar committed
136 137 138
    /* no stream, no program, no area, no es */
    p_input->stream.p_new_program = NULL;

Stéphane Borel's avatar
 
Stéphane Borel committed
139 140
    p_input->stream.i_area_nb = 0;
    p_input->stream.pp_areas = NULL;
141
    p_input->stream.p_selected_area = NULL;
142
    p_input->stream.p_new_area = NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
143

Sam Hocevar's avatar
 
Sam Hocevar committed
144 145 146 147
    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
148
    /* By default there is one area in a stream */
Gildas Bazin's avatar
 
Gildas Bazin committed
149
    input_AddArea( p_input, 0, 1 );
150
    p_input->stream.p_selected_area = p_input->stream.pp_areas[0];
Stéphane Borel's avatar
 
Stéphane Borel committed
151

152 153 154 155
    /* Initialize stream control properties. */
    p_input->stream.control.i_status = PLAYING_S;
    p_input->stream.control.i_rate = DEFAULT_RATE;
    p_input->stream.control.b_mute = 0;
156 157
    p_input->stream.control.b_grayscale = config_GetInt( p_input, "grayscale" );

158 159 160 161 162 163 164 165 166 167 168
    /* 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;

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

171 172
    p_info = input_InfoCategory( p_input, _("General") );
    input_AddInfo( p_info, _("Playlist Item"), p_input->psz_source );
173
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
 
Sam Hocevar committed
174

Sam Hocevar's avatar
Sam Hocevar committed
175
    /* Create thread and wait for its readiness. */
176 177
    if( vlc_thread_create( p_input, "input", RunThread,
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
178
    {
179
        msg_Err( p_input, "cannot create input thread" );
Michel Kaempf's avatar
Michel Kaempf committed
180
        free( p_input );
181
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
182
    }
183

184
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
185 186
}

187
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
188
 * input_StopThread: mark an input thread as zombie
189
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
190
 * This function should not return until the thread is effectively cancelled.
191
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
192
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
193
{
Sam Hocevar's avatar
 
Sam Hocevar committed
194 195
    /* Make the thread exit from a possible vlc_cond_wait() */
    vlc_mutex_lock( &p_input->stream.stream_lock );
196 197
    /* Request thread destruction */
    p_input->b_die = 1;
Michel Kaempf's avatar
Michel Kaempf committed
198

199 200
    vlc_cond_signal( &p_input->stream.stream_wait );
    vlc_mutex_unlock( &p_input->stream.stream_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
201 202 203 204 205 206 207 208 209 210
}

/*****************************************************************************
 * 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 */
211
    vlc_thread_join( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
212 213 214

    /* Destroy Mutex locks */
    vlc_mutex_destroy( &p_input->stream.control.control_lock );
Sam Hocevar's avatar
 
Sam Hocevar committed
215
    vlc_cond_destroy( &p_input->stream.stream_wait );
Sam Hocevar's avatar
 
Sam Hocevar committed
216
    vlc_mutex_destroy( &p_input->stream.stream_lock );
Michel Kaempf's avatar
Michel Kaempf committed
217 218
}

219
/*****************************************************************************
220
 * RunThread: main thread loop
221
 *****************************************************************************
222
 * Thread in charge of processing the network packets and demultiplexing.
223
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
224
static int RunThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
225
{
Sam Hocevar's avatar
Sam Hocevar committed
226 227 228
    /* Signal right now, otherwise we'll get stuck in a peek */
    vlc_thread_ready( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
229 230 231 232 233
    if( InitThread( p_input ) )
    {
        /* If we failed, wait before we are killed, and exit */
        p_input->b_error = 1;
        ErrorThread( p_input );
Sam Hocevar's avatar
Sam Hocevar committed
234
        p_input->b_dead = 1;
Sam Hocevar's avatar
 
Sam Hocevar committed
235
        return 0;
Sam Hocevar's avatar
 
Sam Hocevar committed
236
    }
Michel Kaempf's avatar
Michel Kaempf committed
237

238
    /* initialization is complete */
239 240 241 242
    vlc_mutex_lock( &p_input->stream.stream_lock );
    p_input->stream.b_changed = 1;
    vlc_mutex_unlock( &p_input->stream.stream_lock );

Sam Hocevar's avatar
 
Sam Hocevar committed
243 244
    while( !p_input->b_die && !p_input->b_error && !p_input->b_eof )
    {
245
        unsigned int i, i_count;
246

Sam Hocevar's avatar
 
Sam Hocevar committed
247
        p_input->c_loops++;
Sam Hocevar's avatar
 
Sam Hocevar committed
248

249
        vlc_mutex_lock( &p_input->stream.stream_lock );
250

251 252 253 254 255
        if( p_input->stream.p_new_program )
        {
            if( p_input->pf_set_program != NULL )
            {

Johan Bilien's avatar
 
Johan Bilien committed
256 257
                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );
258 259

                p_input->pf_set_program( p_input,
260
                                         p_input->stream.p_new_program );
261

262 263 264 265
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

266 267 268 269 270 271 272 273 274 275 276
                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;
        }
277

278 279
        if( p_input->stream.p_new_area )
        {
280 281
            if( p_input->stream.b_seekable && p_input->pf_set_area != NULL )
            {
282
                input_AccessReinit( p_input );
283 284 285

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

286 287 288 289
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

290 291 292 293 294 295 296 297 298
                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;
                }
            }
299 300 301
            p_input->stream.p_new_area = NULL;
        }

302
        if( p_input->stream.p_selected_area->i_seek != NO_SEEK )
Sam Hocevar's avatar
 
Sam Hocevar committed
303
        {
304 305
            if( p_input->stream.b_seekable
                 && p_input->pf_seek != NULL )
306
            {
307 308 309 310 311 312
                off_t i_new_pos;

                /* Reinitialize buffer manager. */
                input_AccessReinit( p_input );

                i_new_pos = p_input->stream.p_selected_area->i_seek;
Christophe Massiot's avatar
Christophe Massiot committed
313 314 315
                vlc_mutex_unlock( &p_input->stream.stream_lock );
                p_input->pf_seek( p_input, i_new_pos );
                vlc_mutex_lock( &p_input->stream.stream_lock );
316

317 318 319 320
                /* Escape all decoders for the stream discontinuity they
                 * will encounter. */
                input_EscapeDiscontinuity( p_input );

321 322 323 324 325 326 327 328 329
                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;
                }
            }
330
            p_input->stream.p_selected_area->i_seek = NO_SEEK;
Sam Hocevar's avatar
 
Sam Hocevar committed
331
        }
332

333 334 335 336 337 338 339 340 341 342 343 344
        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;
        }

345 346 347 348 349 350 351 352 353 354 355 356 357 358
        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;
        }

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

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

Gildas Bazin's avatar
 
Gildas Bazin committed
364
        if( i_count == 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
365
        {
366
            /* End of file - we do not set b_die because only the
367
             * playlist is allowed to do so. */
368
            msg_Info( p_input, "EOF reached" );
369 370 371 372 373
            p_input->b_eof = 1;
        }
        else if( i_count < 0 )
        {
            p_input->b_error = 1;
374 375 376
        }
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
377
    if( p_input->b_error || p_input->b_eof )
378 379 380
    {
        ErrorThread( p_input );
    }
381

382
    EndThread( p_input );
Sam Hocevar's avatar
 
Sam Hocevar committed
383

Sam Hocevar's avatar
 
Sam Hocevar committed
384
    return 0;
385 386
}

387
/*****************************************************************************
Sam Hocevar's avatar
 
Sam Hocevar committed
388
 * InitThread: init the input Thread
389
 *****************************************************************************/
Sam Hocevar's avatar
 
Sam Hocevar committed
390
static int InitThread( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
391
{
Christophe Massiot's avatar
Christophe Massiot committed
392
    /* Parse source string. Syntax : [[<access>][/<demux>]:][<source>] */
393
    char * psz_parser = p_input->psz_dupsource = strdup(p_input->psz_source);
Gildas Bazin's avatar
 
Gildas Bazin committed
394
    vlc_value_t val;
Gildas Bazin's avatar
 
Gildas Bazin committed
395

Christophe Massiot's avatar
Christophe Massiot committed
396 397 398 399 400
    /* Skip the plug-in names */
    while( *psz_parser && *psz_parser != ':' )
    {
        psz_parser++;
    }
401
#if defined( WIN32 ) || defined( UNDER_CE )
Christophe Massiot's avatar
Christophe Massiot committed
402
    if( psz_parser - p_input->psz_dupsource == 1 )
Gildas Bazin's avatar
 
Gildas Bazin committed
403
    {
404
        msg_Warn( p_input, "drive letter %c: found in source string",
Christophe Massiot's avatar
Christophe Massiot committed
405
                           p_input->psz_dupsource[0] ) ;
Stéphane Borel's avatar
 
Stéphane Borel committed
406
        psz_parser = "";
Gildas Bazin's avatar
 
Gildas Bazin committed
407 408
    }
#endif
Sam Hocevar's avatar
 
Sam Hocevar committed
409

Christophe Massiot's avatar
Christophe Massiot committed
410
    if( !*psz_parser )
411
    {
Sam Hocevar's avatar
 
Sam Hocevar committed
412
        p_input->psz_access = p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
413
        p_input->psz_name = p_input->psz_source;
Christophe Massiot's avatar
Christophe Massiot committed
414
        free( p_input->psz_dupsource );
415
        p_input->psz_dupsource = NULL;
Michel Kaempf's avatar
Michel Kaempf committed
416
    }
Christophe Massiot's avatar
Christophe Massiot committed
417 418 419
    else
    {
        *psz_parser++ = '\0';
420

Xavier Marchesini's avatar
 
Xavier Marchesini committed
421 422 423 424
        /* let's skip '//' */
        if( psz_parser[0] == '/' && psz_parser[1] == '/' )
        {
            psz_parser += 2 ;
425
        }
Xavier Marchesini's avatar
 
Xavier Marchesini committed
426 427

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

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

Stéphane Borel's avatar
 
Stéphane Borel committed
432
        if( !*psz_parser )
Christophe Massiot's avatar
Christophe Massiot committed
433 434
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
435
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
436 437 438 439
        }
        else if( *psz_parser == '/' )
        {
            /* No access */
Sam Hocevar's avatar
 
Sam Hocevar committed
440
            p_input->psz_access = "";
Christophe Massiot's avatar
Christophe Massiot committed
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456
            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
457

Christophe Massiot's avatar
Christophe Massiot committed
458 459 460
        if( !*psz_parser )
        {
            /* No demux */
Sam Hocevar's avatar
 
Sam Hocevar committed
461
            p_input->psz_demux = "";
Christophe Massiot's avatar
Christophe Massiot committed
462 463 464 465 466
        }
        else
        {
            p_input->psz_demux = psz_parser;
        }
Sam Hocevar's avatar
 
Sam Hocevar committed
467
    }
Christophe Massiot's avatar
Christophe Massiot committed
468

469 470
    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
471 472

    if( input_AccessInit( p_input ) == -1 )
473
    {
474
        return -1;
475
    }
Christophe Massiot's avatar
Christophe Massiot committed
476

477
    /* Find and open appropriate access module */
478 479
    p_input->p_access = module_Need( p_input, "access",
                                     p_input->psz_access );
Christophe Massiot's avatar
Christophe Massiot committed
480

481 482 483 484 485 486 487 488 489 490 491 492 493 494
    if ( p_input->p_access == NULL
          && (*p_input->psz_demux || *p_input->psz_access) )
    {
        /* Maybe we got something like :
         * /Volumes/toto:titi/gabu.mpg */
        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 );
    }

495
    if( p_input->p_access == NULL )
496
    {
497
        msg_Err( p_input, "no suitable access module for `%s/%s://%s'",
498
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
499
        return -1;
500
    }
Christophe Massiot's avatar
Christophe Massiot committed
501 502 503

    /* Waiting for stream. */
    if( p_input->i_mtu )
Christophe Massiot's avatar
Christophe Massiot committed
504
    {
Christophe Massiot's avatar
Christophe Massiot committed
505
        p_input->i_bufsize = p_input->i_mtu;
Christophe Massiot's avatar
Christophe Massiot committed
506
    }
507 508
    else
    {
Christophe Massiot's avatar
Christophe Massiot committed
509
        p_input->i_bufsize = INPUT_DEFAULT_BUFSIZE;
510
    }
511

Gildas Bazin's avatar
 
Gildas Bazin committed
512 513 514 515 516
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
    if( p_input->p_vlc->i_desync < 0 )
        p_input->i_pts_delay -= p_input->p_vlc->i_desync;

Sam Hocevar's avatar
 
Sam Hocevar committed
517
    if( p_input->p_current_data == NULL && p_input->pf_read != NULL )
518
    {
Christophe Massiot's avatar
Christophe Massiot committed
519 520
        while( !input_FillBuffer( p_input ) )
        {
521
            if( p_input->b_die || p_input->b_error || p_input->b_eof )
Christophe Massiot's avatar
Christophe Massiot committed
522
            {
523
                module_Unneed( p_input, p_input->p_access );
524
                return -1;
Christophe Massiot's avatar
Christophe Massiot committed
525 526
            }
        }
527
    }
Sam Hocevar's avatar
 
Sam Hocevar committed
528

529
    /* Find and open appropriate demux module */
530 531
    p_input->p_demux = module_Need( p_input, "demux",
                                    p_input->psz_demux );
Sam Hocevar's avatar
 
Sam Hocevar committed
532

533
    if( p_input->p_demux == NULL )
534
    {
535
        msg_Err( p_input, "no suitable demux module for `%s/%s://%s'",
536
                 p_input->psz_access, p_input->psz_demux, p_input->psz_name );
537
        module_Unneed( p_input, p_input->p_access );
538
        return -1;
539 540
    }

541
    /* Initialize optional stream output. */
Gildas Bazin's avatar
 
Gildas Bazin committed
542
    var_Get( p_input, "sout", &val );
Gildas Bazin's avatar
 
Gildas Bazin committed
543
    if( val.psz_string != NULL )
544
    {
Gildas Bazin's avatar
 
Gildas Bazin committed
545 546
        if ( *val.psz_string && (p_input->stream.p_sout =
             sout_NewInstance( p_input, val.psz_string )) == NULL )
547 548
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
Gildas Bazin's avatar
 
Gildas Bazin committed
549
            free( val.psz_string );
550 551 552 553 554
            module_Unneed( p_input, p_input->p_access );
            module_Unneed( p_input, p_input->p_demux );
            return -1;
        }

Gildas Bazin's avatar
 
Gildas Bazin committed
555
        free( val.psz_string );
556 557
    }

558
    return 0;
Michel Kaempf's avatar
Michel Kaempf committed
559 560
}

561
/*****************************************************************************
562
 * ErrorThread: RunThread() error loop
563
 *****************************************************************************
564
 * This function is called when an error occured during thread main's loop.
565
 *****************************************************************************/
566
static void ErrorThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
567
{
568
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
569
    {
570 571
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
572 573 574
    }
}

575
/*****************************************************************************
576
 * EndThread: end the input thread
577
 *****************************************************************************/
578
static void EndThread( input_thread_t * p_input )
579
{
Gildas Bazin's avatar
 
Gildas Bazin committed
580 581
    vlc_object_t *p_object;

582
#ifdef HAVE_SYS_TIMES_H
583 584 585
    /* Display statistics */
    struct tms  cpu_usage;
    times( &cpu_usage );
Sam Hocevar's avatar
 
Sam Hocevar committed
586

587
    msg_Dbg( p_input, "%ld loops consuming user: %ld, system: %ld",
588
             p_input->c_loops, cpu_usage.tms_utime, cpu_usage.tms_stime );
589
#else
590
    msg_Dbg( p_input, "%ld loops", p_input->c_loops );
591
#endif
592

593 594
    input_DumpStream( p_input );

Sam Hocevar's avatar
 
Sam Hocevar committed
595 596 597
    /* Free all ES and destroy all decoder threads */
    input_EndStream( p_input );

598 599 600 601 602 603
    /* Close optional stream output instance */
    if ( p_input->stream.p_sout != NULL )
    {
        sout_DeleteInstance( p_input->stream.p_sout );
    }

Sam Hocevar's avatar
 
Sam Hocevar committed
604
    /* Free demultiplexer's data */
605
    module_Unneed( p_input, p_input->p_demux );
Sam Hocevar's avatar
 
Sam Hocevar committed
606

607
    /* Close the access plug-in */
608
    module_Unneed( p_input, p_input->p_access );
Sam Hocevar's avatar
 
Sam Hocevar committed
609

Christophe Massiot's avatar
Christophe Massiot committed
610 611
    input_AccessEnd( p_input );

612 613 614 615
    /* Free info structures XXX destroy es before 'cause vorbis */
    msg_Dbg( p_input, "freeing info structures...");
    input_DelInfo( p_input );

Gildas Bazin's avatar
 
Gildas Bazin committed
616 617
    /* Close the video output that should have been re-attached
     * to our object */
618
    while( ( p_object = vlc_object_find( p_input, VLC_OBJECT_VOUT, FIND_CHILD ) ) != NULL )
Gildas Bazin's avatar
 
Gildas Bazin committed
619 620 621
    {
        vlc_object_detach( p_object );
        vlc_object_release( p_object );
622
        vout_Destroy( (vout_thread_t *)p_object );
Gildas Bazin's avatar
 
Gildas Bazin committed
623 624
    }

Christophe Massiot's avatar
Christophe Massiot committed
625
    free( p_input->psz_source );
626
    if ( p_input->psz_dupsource != NULL ) free( p_input->psz_dupsource );
627 628 629

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

Gildas Bazin's avatar
 
Gildas Bazin committed
632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726
/*****************************************************************************
 * 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:
    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;
}