input.c 60.3 KB
Newer Older
1
2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
zorglub's avatar
zorglub committed
4
 * Copyright (C) 1998-2004 VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
Laurent Aimar's avatar
Laurent Aimar committed
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9
10
11
12
13
 *
 * 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.
14
 *
15
16
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17
18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20
21
22
 * 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.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

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

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

Laurent Aimar's avatar
Laurent Aimar committed
35
#include "input_internal.h"
36

37
38
#include "stream_output.h"

39
#include "vlc_interface.h"
40
#include "vlc_meta.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
41

42
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
43
 * Local prototypes
44
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
45
46
47
48
49
50
51
52
53
static  int Run  ( input_thread_t *p_input );

static  int Init ( input_thread_t *p_input );
static void Error( input_thread_t *p_input );
static void End  ( input_thread_t *p_input );

static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
static void       ControlReduce( input_thread_t * );
static vlc_bool_t Control( input_thread_t *, int, vlc_value_t );
54

55

Laurent Aimar's avatar
Laurent Aimar committed
56
57
static void UpdateFromAccess( input_thread_t * );
static void UpdateFromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
58

59
60
static void UpdateItemLength( input_thread_t *, int64_t i_length );

61
62
63
static void ParseOption( input_thread_t *p_input, const char *psz_option );

static void DecodeUrl  ( char * );
64
static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
65
66

static input_source_t *InputSourceNew( input_thread_t *);
Laurent Aimar's avatar
   
Laurent Aimar committed
67
68
static int  InputSourceInit( input_thread_t *, input_source_t *,
                             char *, char *psz_forced_demux );
69
70
71
72
static void InputSourceClean( input_thread_t *, input_source_t * );

static void SlaveDemux( input_thread_t *p_input );
static void SlaveSeek( input_thread_t *p_input );
73

74
75
static vlc_meta_t *InputMetaUser( input_thread_t *p_input );

76
/*****************************************************************************
77
 * input_CreateThread: creates a new input thread
78
 *****************************************************************************
79
80
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
Laurent Aimar's avatar
Laurent Aimar committed
81
82
83
84
85
86
87
88
89
90
 *
 * Variables for _public_ use:
 * * Get and Set:
 *  - state
 *  - rate,rate-slower, rate-faster
 *  - position, position-offset
 *  - time, time-offset
 *  - title,title-next,title-prev
 *  - chapter,chapter-next, chapter-prev
 *  - program, audio-es, video-es, spu-es
91
 *  - audio-delay, spu-delay
Laurent Aimar's avatar
Laurent Aimar committed
92
93
94
95
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
96
 *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown or not, for that check position != 0.0)
Laurent Aimar's avatar
Laurent Aimar committed
97
98
99
100
 * * For intf callback upon changes
 *  - intf-change
 * TODO explain when Callback is called
 * TODO complete this list (?)
101
 *****************************************************************************/
102
103
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
104

Michel Kaempf's avatar
Michel Kaempf committed
105
{
106
107
    input_thread_t *p_input;                        /* thread descriptor */
    int             i;
108

109
    /* Allocate descriptor */
110
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
111
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
112
    {
113
        msg_Err( p_parent, "out of memory" );
114
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
115
    }
116

Laurent Aimar's avatar
Laurent Aimar committed
117
118
119
120
121
122
123
124
125
126
127
128
129
130
    /* Init Common fields */
    p_input->b_eof = VLC_FALSE;
    p_input->b_can_pace_control = VLC_TRUE;
    p_input->i_start = 0;
    p_input->i_time  = 0;
    p_input->i_stop  = 0;
    p_input->i_title = 0;
    p_input->title   = NULL;
    p_input->i_state = INIT_S;
    p_input->i_rate  = INPUT_RATE_DEFAULT;
    p_input->i_bookmark = 0;
    p_input->bookmark = NULL;
    p_input->p_es_out = NULL;
    p_input->p_sout  = NULL;
131
    p_input->b_out_pace_control = VLC_FALSE;
Laurent Aimar's avatar
Laurent Aimar committed
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
    p_input->i_pts_delay = 0;


    /* Init Input fields */
    p_input->input.p_item = p_item;
    p_input->input.p_access = NULL;
    p_input->input.p_stream = NULL;
    p_input->input.p_demux  = NULL;
    p_input->input.b_title_demux = VLC_FALSE;
    p_input->input.i_title  = 0;
    p_input->input.title    = NULL;
    p_input->input.b_can_pace_control = VLC_TRUE;
    p_input->input.b_eof = VLC_FALSE;
    p_input->input.i_cr_average = 0;

147
148
149
150
    /* No slave */
    p_input->i_slave = 0;
    p_input->slave   = NULL;

Laurent Aimar's avatar
Laurent Aimar committed
151
152
153
    /* Init control buffer */
    vlc_mutex_init( p_input, &p_input->lock_control );
    p_input->i_control = 0;
154

gbazin's avatar
   
gbazin committed
155
    /* Parse input options */
156
157
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
gbazin's avatar
   
gbazin committed
158
    {
159
160
        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
        ParseOption( p_input, p_item->ppsz_options[i] );
gbazin's avatar
   
gbazin committed
161
    }
162
    vlc_mutex_unlock( &p_item->lock );
gbazin's avatar
   
gbazin committed
163

Laurent Aimar's avatar
Laurent Aimar committed
164
165
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
166

Laurent Aimar's avatar
Laurent Aimar committed
167
168
169
    /* Create Objects variables for public Get and Set */
    input_ControlVarInit( p_input );
    p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
gbazin's avatar
gbazin committed
170

Laurent Aimar's avatar
Laurent Aimar committed
171
172
#if 0
    /* TODO */
gbazin's avatar
gbazin committed
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
    var_Get( p_input, "bookmarks", &val );
    if( val.psz_string )
    {
        /* FIXME: have a common cfg parsing routine used by sout and others */
        char *psz_parser, *psz_start, *psz_end;
        psz_parser = val.psz_string;
        while( (psz_start = strchr( psz_parser, '{' ) ) )
        {
            seekpoint_t seekpoint;
            char backup;
            psz_start++;
            psz_end = strchr( psz_start, '}' );
            if( !psz_end ) break;
            psz_parser = psz_end + 1;
            backup = *psz_parser;
            *psz_parser = 0;
            *psz_end = ',';

            seekpoint.psz_name = 0;
            seekpoint.i_byte_offset = 0;
            seekpoint.i_time_offset = 0;
            while( (psz_end = strchr( psz_start, ',' ) ) )
            {
                *psz_end = 0;
                if( !strncmp( psz_start, "name=", 5 ) )
                {
                    seekpoint.psz_name = psz_start + 5;
                }
                else if( !strncmp( psz_start, "bytes=", 6 ) )
                {
203
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
gbazin's avatar
gbazin committed
204
205
206
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
207
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
gbazin's avatar
gbazin committed
208
209
210
211
212
213
214
215
216
217
218
                }
                psz_start = psz_end + 1;
            }
            msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
                     seekpoint.psz_name, seekpoint.i_byte_offset,
                     seekpoint.i_time_offset );
            input_Control( p_input, INPUT_ADD_BOOKMARK, &seekpoint );
            *psz_parser = backup;
        }
        free( val.psz_string );
    }
Laurent Aimar's avatar
Laurent Aimar committed
219
#endif
gbazin's avatar
gbazin committed
220

Laurent Aimar's avatar
Laurent Aimar committed
221
    /* Now we can attach our new input */
222
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
223

Sam Hocevar's avatar
Sam Hocevar committed
224
    /* Create thread and wait for its readiness. */
Laurent Aimar's avatar
Laurent Aimar committed
225
    if( vlc_thread_create( p_input, "input", Run,
226
                           VLC_THREAD_PRIORITY_INPUT, VLC_TRUE ) )
Michel Kaempf's avatar
Michel Kaempf committed
227
    {
228
        msg_Err( p_input, "cannot create input thread" );
Laurent Aimar's avatar
Laurent Aimar committed
229
230
        vlc_object_detach( p_input );
        vlc_object_destroy( p_input );
231
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
232
    }
233

234
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
235
236
}

237
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
238
 * input_StopThread: mark an input thread as zombie
239
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
240
 * This function should not return until the thread is effectively cancelled.
241
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
242
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
243
{
Laurent Aimar's avatar
Laurent Aimar committed
244
245
    vlc_list_t *p_list;
    int i;
246

Laurent Aimar's avatar
Laurent Aimar committed
247
248
    /* Set die for input */
    p_input->b_die = VLC_TRUE;
249

Laurent Aimar's avatar
Laurent Aimar committed
250
251
    /* We cannot touch p_input fields directly (we can from another thread),
     * so use the vlc_object_find way, it's perfectly safe */
252

Laurent Aimar's avatar
Laurent Aimar committed
253
254
255
    /* Set die for all access */
    p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
256
    {
Laurent Aimar's avatar
Laurent Aimar committed
257
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
258
    }
Laurent Aimar's avatar
Laurent Aimar committed
259
    vlc_list_release( p_list );
260

Laurent Aimar's avatar
Laurent Aimar committed
261
262
263
    /* Set die for all stream */
    p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
264
    {
Laurent Aimar's avatar
Laurent Aimar committed
265
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
266
    }
Laurent Aimar's avatar
Laurent Aimar committed
267
    vlc_list_release( p_list );
268

Laurent Aimar's avatar
Laurent Aimar committed
269
270
271
272
273
274
275
    /* Set die for all demux */
    p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
    {
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
    }
    vlc_list_release( p_list );
Michel Kaempf's avatar
Michel Kaempf committed
276

Laurent Aimar's avatar
Laurent Aimar committed
277
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
   
Sam Hocevar committed
278
279
280
281
282
283
284
285
286
287
}

/*****************************************************************************
 * 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 */
288
    vlc_thread_join( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
289

Laurent Aimar's avatar
Laurent Aimar committed
290
291
292
293
294
    /* Delete input lock (only after thread joined) */
    vlc_mutex_destroy( &p_input->lock_control );

    /* TODO: maybe input_DestroyThread should also delete p_input instead
     * of the playlist but I'm not sure if it's possible */
Michel Kaempf's avatar
Michel Kaempf committed
295
296
}

297
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
298
 * Run: main thread loop
299
 *****************************************************************************
300
 * Thread in charge of processing the network packets and demultiplexing.
301
302
303
304
 *
 * TODO:
 *  read subtitle support (XXX take care of spu-delay in the right way).
 *  multi-input support (XXX may be done with subs)
305
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
306
static int Run( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
307
{
Laurent Aimar's avatar
Laurent Aimar committed
308
    int64_t i_intf_update = 0;
309

Laurent Aimar's avatar
Laurent Aimar committed
310
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
311
312
    vlc_thread_ready( p_input );

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

Laurent Aimar's avatar
Laurent Aimar committed
318
        Error( p_input );
319
320

        /* Tell we're dead */
Laurent Aimar's avatar
Laurent Aimar committed
321
        p_input->b_dead = VLC_TRUE;
322

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

Laurent Aimar's avatar
Laurent Aimar committed
326
    /* Main loop */
327
    while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
Sam Hocevar's avatar
   
Sam Hocevar committed
328
    {
Laurent Aimar's avatar
Laurent Aimar committed
329
330
331
332
        vlc_bool_t b_force_update = VLC_FALSE;
        int i_ret;
        int i_type;
        vlc_value_t val;
333

Laurent Aimar's avatar
Laurent Aimar committed
334
335
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
336
        {
Laurent Aimar's avatar
Laurent Aimar committed
337
338
339
340
            if( p_input->i_stop <= 0 || p_input->i_time < p_input->i_stop )
                i_ret=p_input->input.p_demux->pf_demux(p_input->input.p_demux);
            else
                i_ret = 0;  /* EOF */
341

Laurent Aimar's avatar
Laurent Aimar committed
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
            if( i_ret > 0 )
            {
                /* TODO */
                if( p_input->input.b_title_demux &&
                    p_input->input.p_demux->info.i_update )
                {
                    UpdateFromDemux( p_input );
                    b_force_update = VLC_TRUE;
                }
                else if( !p_input->input.b_title_demux &&
                          p_input->input.p_access &&
                          p_input->input.p_access->info.i_update )
                {
                    UpdateFromAccess( p_input );
                    b_force_update = VLC_TRUE;
                }
            }
            else if( i_ret == 0 )    /* EOF */
            {
                vlc_value_t repeat;
362

Laurent Aimar's avatar
Laurent Aimar committed
363
364
365
366
367
368
369
370
371
                var_Get( p_input, "input-repeat", &repeat );
                if( repeat.i_int == 0 )
                {
                    /* End of file - we do not set b_die because only the
                     * playlist is allowed to do so. */
                    msg_Dbg( p_input, "EOF reached" );
                    p_input->input.b_eof = VLC_TRUE;
                }
                else
372
                {
gbazin's avatar
gbazin committed
373
374
                    msg_Dbg( p_input, "repeating the same input (%d)",
                             repeat.i_int );
Laurent Aimar's avatar
Laurent Aimar committed
375
376
377
378
379
                    if( repeat.i_int > 0 )
                    {
                        repeat.i_int--;
                        var_Set( p_input, "input-repeat", repeat );
                    }
380

Laurent Aimar's avatar
Laurent Aimar committed
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
                    /* Seek to title 0 position 0(start) */
                    val.i_int = 0;
                    input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
                    if( p_input->i_start > 0 )
                    {
                        val.i_time = p_input->i_start;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                           &val );
                    }
                    else
                    {
                        val.f_float = 0.0;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                           &val );
                    }
396
397
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
398
399
400
401
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
402
403
404
405
406

            if( i_ret > 0 && p_input->i_slave > 0 )
            {
                SlaveDemux( p_input );
            }
407
        }
Laurent Aimar's avatar
Laurent Aimar committed
408
        else
409
        {
Laurent Aimar's avatar
Laurent Aimar committed
410
411
412
            /* Small wait */
            msleep( 10*1000 );
        }
413

Laurent Aimar's avatar
Laurent Aimar committed
414
415
416
417
418
419
420
421
422
423
        /* Handle control */
        vlc_mutex_lock( &p_input->lock_control );
        ControlReduce( p_input );
        while( !ControlPopNoLock( p_input, &i_type, &val ) )
        {
            msg_Dbg( p_input, "control type=%d", i_type );
            if( Control( p_input, i_type, val ) )
                b_force_update = VLC_TRUE;
        }
        vlc_mutex_unlock( &p_input->lock_control );
424

Laurent Aimar's avatar
Laurent Aimar committed
425
426
427
428
429
430
431
        if( b_force_update ||
            i_intf_update < mdate() )
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
gbazin's avatar
gbazin committed
432
433
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_POSITION, &f_pos ) )
Laurent Aimar's avatar
Laurent Aimar committed
434
435
436
437
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
gbazin's avatar
gbazin committed
438
439
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_TIME, &i_time ) )
Laurent Aimar's avatar
Laurent Aimar committed
440
441
442
443
444
            {
                p_input->i_time = i_time;
                val.i_time = i_time;
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
gbazin's avatar
gbazin committed
445
446
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_LENGTH, &i_length ) )
Laurent Aimar's avatar
Laurent Aimar committed
447
448
449
450
451
            {
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
                val.i_time = i_length;
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
452

Laurent Aimar's avatar
Laurent Aimar committed
453
                if( old_val.i_time != val.i_time )
454
                {
455
                    UpdateItemLength( p_input, i_length );
456
457
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
458
459
460

            var_SetBool( p_input, "intf-change", VLC_TRUE );
            i_intf_update = mdate() + I64C(150000);
461
        }
Laurent Aimar's avatar
Laurent Aimar committed
462
463
    }

464
    if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
Laurent Aimar's avatar
Laurent Aimar committed
465
    {
466
467
        /* We have finish to demux data but not to play them */
        while( !p_input->b_die )
Sam Hocevar's avatar
   
Sam Hocevar committed
468
        {
469
470
            if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
                break;
471

472
            msg_Dbg( p_input, "waiting decoder fifos to empty" );
473

474
            msleep( INPUT_IDLE_SLEEP );
Sam Hocevar's avatar
   
Sam Hocevar committed
475
        }
476

477
478
        /* We have finished */
        p_input->b_eof = VLC_TRUE;
479
480
    }

481
482
    /* Wait we are asked to die */
    if( !p_input->b_die )
483
    {
484
        Error( p_input );
485
    }
486

487
488
    /* Clean up */
    End( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
489

Sam Hocevar's avatar
   
Sam Hocevar committed
490
    return 0;
491
492
}

493
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
494
 * Init: init the input Thread
495
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
496
static int Init( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
497
{
Laurent Aimar's avatar
Laurent Aimar committed
498
    char *psz;
Laurent Aimar's avatar
   
Laurent Aimar committed
499
    char *psz_subtitle;
Laurent Aimar's avatar
Laurent Aimar committed
500
    vlc_value_t val;
Laurent Aimar's avatar
   
Laurent Aimar committed
501
    double f_fps;
502
503
    vlc_meta_t *p_meta, *p_meta_user;
    int i;
504

Laurent Aimar's avatar
Laurent Aimar committed
505
506
507
    /* Initialize optional stream output. (before access/demuxer) */
    psz = var_GetString( p_input, "sout" );
    if( *psz )
508
    {
Laurent Aimar's avatar
Laurent Aimar committed
509
510
        p_input->p_sout = sout_NewInstance( p_input, psz );
        if( p_input->p_sout == NULL )
511
512
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
Laurent Aimar's avatar
Laurent Aimar committed
513
            free( psz );
514
515
            return VLC_EGENERIC;
        }
516
    }
Laurent Aimar's avatar
Laurent Aimar committed
517
    free( psz );
Christophe Massiot's avatar
Christophe Massiot committed
518

Laurent Aimar's avatar
Laurent Aimar committed
519
    /* Create es out */
520
    p_input->p_es_out = input_EsOutNew( p_input );
521
522
    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 );
523

524
    if( InputSourceInit( p_input, &p_input->input,
Laurent Aimar's avatar
   
Laurent Aimar committed
525
                         p_input->input.p_item->psz_uri, NULL ) )
526
    {
527
        goto error;
Laurent Aimar's avatar
Laurent Aimar committed
528
    }
529

530
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
531
    p_input->i_title = p_input->input.i_title;
532
    p_input->title   = p_input->input.title;
Laurent Aimar's avatar
Laurent Aimar committed
533
    if( p_input->i_title > 0 )
534
    {
Laurent Aimar's avatar
Laurent Aimar committed
535
536
537
        /* Setup variables */
        input_ControlVarNavigation( p_input );
        input_ControlVarTitle( p_input, 0 );
538
    }
539

Laurent Aimar's avatar
Laurent Aimar committed
540
541
542
543
544
545
546
    /* Global flag */
    p_input->b_can_pace_control = p_input->input.b_can_pace_control;
    p_input->b_can_pause        = p_input->input.b_can_pause;

    /* Fix pts delay */
    if( p_input->i_pts_delay <= 0 )
        p_input->i_pts_delay = DEFAULT_PTS_DELAY;
547

gbazin's avatar
   
gbazin committed
548
549
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
550
551
552
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
gbazin's avatar
   
gbazin committed
553

554
    /* Load master infos */
Laurent Aimar's avatar
Laurent Aimar committed
555
    /* Init length */
gbazin's avatar
gbazin committed
556
557
    if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_LENGTH,
                         &val.i_time ) && val.i_time > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
558
559
    {
        var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
560
561

        UpdateItemLength( p_input, val.i_time );
Laurent Aimar's avatar
Laurent Aimar committed
562
563
564
565
566
567
568
569
570
571
572
    }
    /* Start time*/
    /* Set start time */
    p_input->i_start = (int64_t)var_GetInteger( p_input, "start-time" ) *
                       I64C(1000000);
    p_input->i_stop  = (int64_t)var_GetInteger( p_input, "stop-time" ) *
                       I64C(1000000);

    if( p_input->i_start > 0 )
    {
        if( p_input->i_start >= val.i_time )
573
        {
Laurent Aimar's avatar
Laurent Aimar committed
574
            msg_Warn( p_input, "invalid start-time ignored" );
575
        }
Laurent Aimar's avatar
Laurent Aimar committed
576
        else
577
        {
Laurent Aimar's avatar
Laurent Aimar committed
578
579
580
581
582
583
584
            vlc_value_t s;

            msg_Dbg( p_input, "start-time: %ds",
                     (int)( p_input->i_start / I64C(1000000) ) );

            s.i_time = p_input->i_start;
            input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
585
        }
Laurent Aimar's avatar
Laurent Aimar committed
586
587
588
589
590
    }
    if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
    {
        msg_Warn( p_input, "invalid stop-time ignored" );
        p_input->i_stop = 0;
591
592
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
593

Laurent Aimar's avatar
   
Laurent Aimar committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
    /* Load subtitles */
    /* Get fps and set it if not already set */
    if( !demux2_Control( p_input->input.p_demux, DEMUX_GET_FPS, &f_fps ) &&
        f_fps > 1.0 )
    {
        vlc_value_t fps;

        if( var_Get( p_input, "sub-fps", &fps ) )
        {
            var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| VLC_VAR_DOINHERIT );
            var_SetFloat( p_input, "sub-fps", f_fps );
        }
    }

    /* Look for and add subtitle files */
    psz_subtitle = var_GetString( p_input, "sub-file" );
    if( *psz_subtitle )
    {
        input_source_t *sub;
        vlc_value_t count;
        vlc_value_t list;

        msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );

        var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );

        /* */
        sub = InputSourceNew( p_input );
        if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle" ) )
        {
            TAB_APPEND( p_input->i_slave, p_input->slave, sub );

            /* Select the ES */
            if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list, NULL ) )
            {
                if( count.i_int == 0 )
                    count.i_int++;  /* if it was first one, there is disable too */

                if( count.i_int < list.p_list->i_count )
                {
gbazin's avatar
gbazin committed
634
635
                    input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
                                       &list.p_list->p_values[count.i_int] );
Laurent Aimar's avatar
   
Laurent Aimar committed
636
637
638
639
640
641
642
643
644
645
646
647
648
                }
                var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list, NULL );
            }
        }
    }

    var_Get( p_input, "sub-autodetect-file", &val );
    if( val.b_bool )
    {
        char *psz_autopath = var_GetString( p_input, "sub-autodetect-path" );
        char **subs = subtitles_Detect( p_input, psz_autopath,
                                        p_input->input.p_item->psz_uri );
        input_source_t *sub;
649

Laurent Aimar's avatar
   
Laurent Aimar committed
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
        for( i = 0; subs[i] != NULL; i++ )
        {
            if( strcmp( psz_subtitle, subs[i] ) )
            {
                sub = InputSourceNew( p_input );
                if( !InputSourceInit( p_input, sub, subs[i], "subtitle" ) )
                {
                    TAB_APPEND( p_input->i_slave, p_input->slave, sub );
                }
            }
            free( subs[i] );
        }
        free( subs );
        free( psz_autopath );
    }
    free( psz_subtitle );
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

    /* Look for slave */
    psz = var_GetString( p_input, "input-slave" );
    if( *psz )
    {
        char *psz_delim = strchr( psz, '#' );

        for( ;; )
        {
            input_source_t *slave;

            if( psz_delim )
            {
                *psz_delim++ = '\0';
            }

            if( *psz == '\0' )
            {
                if( psz_delim )
                    continue;
                else
                    break;
            }

            msg_Dbg( p_input, "adding slave '%s'", psz );
            slave = InputSourceNew( p_input );
            if( !InputSourceInit( p_input, slave, psz, NULL ) )
            {
                TAB_APPEND( p_input->i_slave, p_input->slave, slave );
            }
            if( !psz_delim )
                break;
        }
    }
    free( psz );
Laurent Aimar's avatar
Laurent Aimar committed
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716

    /* Set up es_out */
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
    val.b_bool =  VLC_FALSE;
    if( p_input->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 );

    if( p_input->p_sout )
    {
        if( p_input->p_sout->i_out_pace_nocontrol > 0 )
        {
            p_input->b_out_pace_control = VLC_FALSE;
717
        }
Laurent Aimar's avatar
Laurent Aimar committed
718
719
720
721
722
723
        else
        {
            p_input->b_out_pace_control = VLC_TRUE;
        }
        msg_Dbg( p_input, "starting in %s mode",
                 p_input->b_out_pace_control ? "asynch" : "synch" );
724
725
    }

726
727
    /* Get meta data from users */
    p_meta_user = InputMetaUser( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
728

729
730
731
    /* Get meta data from master input */
    if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
        p_meta = NULL;
732

733
734
    /* Merge them */
    if( p_meta == NULL )
gbazin's avatar
gbazin committed
735
    {
736
        p_meta = p_meta_user;
gbazin's avatar
gbazin committed
737
    }
738
    else if( p_meta_user )
739
    {
740
741
742
        vlc_meta_Merge( p_meta, p_meta_user );
        vlc_meta_Delete( p_meta_user );
    }
743

744
745
746
747
    /* Get meta data from slave input */
    for( i = 0; i < p_input->i_slave; i++ )
    {
        vlc_meta_t *p_meta_slave;
gbazin's avatar
gbazin committed
748

749
        if( !demux2_Control( p_input->slave[i]->p_demux, DEMUX_GET_META, &p_meta_slave ) )
750
        {
751
            if( p_meta == NULL )
752
            {
753
                p_meta = p_meta_slave;
754
            }
755
756
757
758
759
760
761
762
763
764
            else if( p_meta_slave )
            {
                vlc_meta_Merge( p_meta, p_meta_slave );
                vlc_meta_Delete( p_meta_slave );
            }
        }
    }

    if( p_meta && p_meta->i_meta > 0 )
    {
765
        msg_Dbg( p_input, "meta information:" );
766
767
768
769
770
771
772
773
774
775
776
777
        for( i = 0; i < p_meta->i_meta; i++ )
        {
            msg_Dbg( p_input, "  - '%s' = '%s'",
                    _(p_meta->name[i]), p_meta->value[i] );

            if( !strcmp(p_meta->name[i], VLC_META_TITLE) && p_meta->value[i] )
                input_Control( p_input, INPUT_SET_NAME, p_meta->value[i] );

            if( !strcmp( p_meta->name[i], VLC_META_AUTHOR ) )
                input_Control( p_input, INPUT_ADD_INFO, _("General"),
                               _("Author"), p_meta->value[i] );

778
            input_Control( p_input, INPUT_ADD_INFO, _("Meta-information"),
779
                          _(p_meta->name[i]), "%s", p_meta->value[i] );
780
        }
781

gbazin's avatar
gbazin committed
782
        for( i = 0; i < p_meta->i_track; i++ )
783
        {
gbazin's avatar
gbazin committed
784
            vlc_meta_t *tk = p_meta->track[i];
785
786
787
788
789
790
            int j;

            if( tk->i_meta > 0 )
            {
                char *psz_cat = malloc( strlen(_("Stream")) + 10 );

791
792
793
                msg_Dbg( p_input, "  - track[%d]:", i );

                sprintf( psz_cat, "%s %d", _("Stream"), i );
794
795
                for( j = 0; j < tk->i_meta; j++ )
                {
gbazin's avatar
gbazin committed
796
797
                    msg_Dbg( p_input, "     - '%s' = '%s'", _(tk->name[j]),
                             tk->value[j] );
798
799
800

                    input_Control( p_input, INPUT_ADD_INFO, psz_cat,
                                   _(tk->name[j]), "%s", tk->value[j] );
801
802
803
804
                }
            }
        }

805
        if( p_input->p_sout && p_input->p_sout->p_meta == NULL )
806
        {
807
            p_input->p_sout->p_meta = p_meta;
808
809
810
        }
        else
        {
gbazin's avatar
gbazin committed
811
            vlc_meta_Delete( p_meta );
812
        }
813
814
    }

815
816
    msg_Dbg( p_input, "`%s' sucessfully opened",
             p_input->input.p_item->psz_uri );
817

818
819
    /* initialization is complete */
    p_input->i_state = PLAYING_S;
820

821
822
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
gbazin committed
823

824
    return VLC_SUCCESS;
825

826
827
828
error:
    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );
Laurent Aimar's avatar
Laurent Aimar committed
829

830
831
    if( p_input->p_sout )
        sout_DeleteInstance( p_input->p_sout );
832

833
834
835
836
837
838
    /* Mark them deleted */
    p_input->input.p_demux = NULL;
    p_input->input.p_stream = NULL;
    p_input->input.p_access = NULL;
    p_input->p_es_out = NULL;
    p_input->p_sout = NULL;
839

840
    return VLC_EGENERIC;
Michel Kaempf's avatar
Michel Kaempf committed
841
842
}

843
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
844
 * Error: RunThread() error loop
845
 *****************************************************************************
846
 * This function is called when an error occured during thread main's loop.
847
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
848
static void Error( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
849
{
850
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
851
    {
852
853
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
854
855
856
    }
}

857
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
858
 * End: end the input thread
859
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
860
static void End( input_thread_t * p_input )
861
{
Laurent Aimar's avatar
Laurent Aimar committed
862
    vlc_value_t val;
863
    int i;
864

Laurent Aimar's avatar
Laurent Aimar committed
865
866
    msg_Dbg( p_input, "closing `%s'",
             p_input->input.p_item->psz_uri );
867

Laurent Aimar's avatar
Laurent Aimar committed
868
869
870
871
872
873
874
875
    /* We are at the end */
    p_input->i_state = END_S;

    val.i_int = END_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );

    /* Clean control variables */
    input_ControlVarClean( p_input );
876

877
878
    /* Clean up master */
    InputSourceClean( p_input, &p_input->input );
Laurent Aimar's avatar
Laurent Aimar committed
879

880
881
882
883
884
885
886
    /* Delete slave */
    for( i = 0; i < p_input->i_slave; i++ )
    {
        InputSourceClean( p_input, p_input->slave[i] );
        free( p_input->slave[i] );
    }
    if( p_input->slave ) free( p_input->slave );
Laurent Aimar's avatar
Laurent Aimar committed
887

888
    /* Unload all modules */
Laurent Aimar's avatar
Laurent Aimar committed
889
890
    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );
gbazin's avatar
   
gbazin committed
891

892
    /* Close optional stream output instance */
Laurent Aimar's avatar
Laurent Aimar committed
893
    if( p_input->p_sout )
894
    {
895
896
        vlc_object_t *p_pl =
            vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
897
898
899
900
901
902
        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" );
Laurent Aimar's avatar
Laurent Aimar committed
903
904
            vlc_object_detach( p_input->p_sout );
            vlc_object_attach( p_input->p_sout, p_pl );
905
906
907
908
        }
        else
        {
            msg_Warn( p_input, "destroying sout" );
Laurent Aimar's avatar
Laurent Aimar committed
909
            sout_DeleteInstance( p_input->p_sout );
910
911
912
        }
        if( p_pl )
            vlc_object_release( p_pl );
913
914
    }

Laurent Aimar's avatar
Laurent Aimar committed
915
916
917
    /* Tell we're dead */
    p_input->b_dead = VLC_TRUE;
}
918

Laurent Aimar's avatar
Laurent Aimar committed
919
920
921
922
923
924
925
926
927
928
/*****************************************************************************
 * Control
 *****************************************************************************/
static inline int ControlPopNoLock( input_thread_t *p_input,
                                    int *pi_type, vlc_value_t *p_val )
{
    if( p_input->i_control <= 0 )
    {
        return VLC_EGENERIC;
    }
929

Laurent Aimar's avatar
Laurent Aimar committed
930
931
    *pi_type = p_input->control[0].i_type;
    *p_val   = p_input->control[0].val;
Sam Hocevar's avatar
   
Sam Hocevar committed
932

Laurent Aimar's avatar
Laurent Aimar committed
933
934
935
936
    p_input->i_control--;
    if( p_input->i_control > 0 )
    {
        int i;
Christophe Massiot's avatar
Christophe Massiot committed
937

Laurent Aimar's avatar
Laurent Aimar committed
938
939
940
941
942
943
        for( i = 0; i < p_input->i_control; i++ )
        {
            p_input->control[i].i_type = p_input->control[i+1].i_type;
            p_input->control[i].val    = p_input->control[i+1].val;
        }
    }
944

Laurent Aimar's avatar
Laurent Aimar committed
945
946
    return VLC_SUCCESS;
}
947

Laurent Aimar's avatar
Laurent Aimar committed
948
949
950
951
952
953
954
955
956
static void ControlReduce( input_thread_t *p_input )
{
    int i;
    for( i = 1; i < p_input->i_control; i++ )
    {
        const int i_lt = p_input->control[i-1].i_type;
        const int i_ct = p_input->control[i].i_type;

        /* XXX We can't merge INPUT_CONTROL_SET_ES */
gbazin's avatar
gbazin committed
957
958
        msg_Dbg( p_input, "[%d/%d] l=%d c=%d", i, p_input->i_control,
                 i_lt, i_ct );
Laurent Aimar's avatar
Laurent Aimar committed
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
        if( i_lt == i_ct &&
            ( i_ct == INPUT_CONTROL_SET_STATE ||
              i_ct == INPUT_CONTROL_SET_RATE ||
              i_ct == INPUT_CONTROL_SET_POSITION ||
              i_ct == INPUT_CONTROL_SET_TIME ||
              i_ct == INPUT_CONTROL_SET_PROGRAM ||
              i_ct == INPUT_CONTROL_SET_TITLE ||
              i_ct == INPUT_CONTROL_SET_SEEKPOINT ||
              i_ct == INPUT_CONTROL_SET_BOOKMARK ) )
        {
            int j;
            msg_Dbg( p_input, "merged at %d", i );
            /* Remove the i-1 */
            for( j = i; j <  p_input->i_control; j++ )
                p_input->control[j-1] = p_input->control[j];
            p_input->i_control--;
        }
        else
        {
            /* TODO but that's not that important
                - merge SET_X with SET_X_CMD
                - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before a SET_TITLE
                - remove SET_SEEKPOINT/SET_POSITION/SET_TIME before another among them
                - ?
                */
        }
    }
Sam Hocevar's avatar
   
Sam Hocevar committed
986
}
Laurent Aimar's avatar
Laurent Aimar committed
987

gbazin's avatar
gbazin committed
988
989
static vlc_bool_t Control( input_thread_t *p_input, int i_type,
                           vlc_value_t val )
Laurent Aimar's avatar
Laurent Aimar committed
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
{
    vlc_bool_t b_force_update = VLC_FALSE;

    switch( i_type )
    {
        case INPUT_CONTROL_SET_DIE:
            msg_Dbg( p_input, "control: INPUT_CONTROL_SET_DIE proceed" );
            /* Mark all submodules to die */
            if( p_input->input.p_access )
                p_input->input.p_access->b_die = VLC_TRUE;
            if( p_input->input.p_stream )
                p_input->input.p_stream->b_die = VLC_TRUE;
            p_input->input.p_demux->b_die = VLC_TRUE;

            p_input->b_die = VLC_TRUE;
            break;

        case INPUT_CONTROL_SET_POSITION:
        case INPUT_CONTROL_SET_POSITION_OFFSET:
        {
            double f_pos;
            if( i_type == INPUT_CONTROL_SET_POSITION )
            {
                f_pos = val.f_float;
            }
            else
            {
                /* Should not fail */
gbazin's avatar
gbazin committed
1018
1019
                demux2_Control( p_input->input.p_demux,
                                DEMUX_GET_POSITION, &f_pos );
Laurent Aimar's avatar
Laurent Aimar committed
1020
1021
1022
1023
                f_pos += val.f_float;
            }
            if( f_pos < 0.0 ) f_pos = 0.0;
            if( f_pos > 1.0 ) f_pos = 1.0;
gbazin's avatar
gbazin committed
1024
1025
            if( demux2_Control( p_input->input.p_demux, DEMUX_SET_POSITION,
                                f_pos ) )
Laurent Aimar's avatar
Laurent Aimar committed
1026
            {
gbazin's avatar
gbazin committed
1027
1028
                msg_Err( p_input, "INPUT_CONTROL_SET_POSITION(_OFFSET) "
                         "%2.1f%% failed", f_pos * 100 );
Laurent Aimar's avatar
Laurent Aimar committed
1029
1030
1031
            }
            else
            {
1032
1033
1034
                if( p_input->i_slave > 0 )
                    SlaveSeek( p_input );

Laurent Aimar's avatar
Laurent Aimar committed
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
                input_EsOutDiscontinuity( p_input->p_es_out, VLC_FALSE );
                es_out_Control( p_input->p_es_out, ES_OUT_RESET_PCR );
                b_force_update = VLC_TRUE;
            }
            break;
        }

        case INPUT_CONTROL_SET_TIME:
        case INPUT_CONTROL_SET_TIME_OFFSET:
        {
            int64_t i_time;
            int i_ret;

            if( i_type == INPUT_CONTROL_SET_TIME )
            {
                i_time = val.i_time;
            }
            else
            {
                /* Should not fail */
                demux2_Control( p_input->input.p_demux,
                                DEMUX_GET_TIME, &i_time );
                i_time += val.i_time;
            }
            if( i_time < 0 ) i_time = 0;
            i_ret = demux2_Control( p_input->input.p_demux,
                                    DEMUX_SET_TIME, i_time );
            if( i_ret )
            {
                int64_t i_length;
                /* Emulate it with a SET_POS */

                demux2_Control( p_input->input.p_demux,
                                DEMUX_GET_LENGTH, &i_length );
                if( i_length > 0 )
                {
                    double