input.c 84 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>
29
#include <ctype.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

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

38
#include "stream_output.h"
39
#include "vlc_playlist.h"
40
#include "vlc_interface.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
static  int Run  ( input_thread_t *p_input );

47
static  int Init ( input_thread_t *p_input, vlc_bool_t b_quick );
Laurent Aimar's avatar
Laurent Aimar committed
48
49
50
51
52
53
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

56
57
static int  UpdateFromAccess( input_thread_t * );
static int  UpdateFromDemux( input_thread_t * );
58
static int  UpdateMeta( input_thread_t *, vlc_bool_t );
Michel Kaempf's avatar
Michel Kaempf committed
59

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

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

64
static void DecodeUrl( char * );
65
static void MRLSplit( input_thread_t *, char *, char **, char **, char ** );
66
static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
67
68

static input_source_t *InputSourceNew( input_thread_t *);
Laurent Aimar's avatar
   
Laurent Aimar committed
69
static int  InputSourceInit( input_thread_t *, input_source_t *,
70
71
                             char *, char *psz_forced_demux,
                             vlc_bool_t b_quick );
72
73
74
75
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 );
76

77
78
static vlc_meta_t *InputMetaUser( input_thread_t *p_input );

79
/*****************************************************************************
80
 * input_CreateThread: creates a new input thread
81
 *****************************************************************************
82
83
 * 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
84
85
86
87
88
89
90
91
92
93
 *
 * 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
94
 *  - audio-delay, spu-delay
Laurent Aimar's avatar
Laurent Aimar committed
95
96
97
98
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
99
 *  - 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
100
101
102
103
 * * For intf callback upon changes
 *  - intf-change
 * TODO explain when Callback is called
 * TODO complete this list (?)
104
 *****************************************************************************/
105
106
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
107

Michel Kaempf's avatar
Michel Kaempf committed
108
{
109
    input_thread_t *p_input;                        /* thread descriptor */
110
111
    vlc_value_t val;
    int i;
112

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

Laurent Aimar's avatar
Laurent Aimar committed
121
122
123
124
125
126
127
128
    /* 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;
129
    p_input->i_title_offset = p_input->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
130
131
132
133
    p_input->i_state = INIT_S;
    p_input->i_rate  = INPUT_RATE_DEFAULT;
    p_input->i_bookmark = 0;
    p_input->bookmark = NULL;
134
    p_input->p_meta  = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
135
136
    p_input->p_es_out = NULL;
    p_input->p_sout  = NULL;
137
    p_input->b_out_pace_control = VLC_FALSE;
Laurent Aimar's avatar
Laurent Aimar committed
138
139
140
141
142
143
144
145
146
147
    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;
148
    p_input->input.i_title_offset = p_input->input.i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
149
150
151
152
    p_input->input.b_can_pace_control = VLC_TRUE;
    p_input->input.b_eof = VLC_FALSE;
    p_input->input.i_cr_average = 0;

153
154
155
156
    /* No slave */
    p_input->i_slave = 0;
    p_input->slave   = NULL;

Laurent Aimar's avatar
Laurent Aimar committed
157
158
159
    /* Init control buffer */
    vlc_mutex_init( p_input, &p_input->lock_control );
    p_input->i_control = 0;
160

gbazin's avatar
   
gbazin committed
161
    /* Parse input options */
162
163
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
gbazin's avatar
   
gbazin committed
164
    {
165
        ParseOption( p_input, p_item->ppsz_options[i] );
gbazin's avatar
   
gbazin committed
166
    }
167
    vlc_mutex_unlock( &p_item->lock );
gbazin's avatar
   
gbazin committed
168

Laurent Aimar's avatar
Laurent Aimar committed
169
170
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
171

Laurent Aimar's avatar
Laurent Aimar committed
172
173
174
    /* 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
175

Laurent Aimar's avatar
Laurent Aimar committed
176
    /* TODO */
gbazin's avatar
gbazin committed
177
178
179
180
181
182
183
184
    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, '{' ) ) )
        {
185
            seekpoint_t *p_seekpoint = vlc_seekpoint_New();
gbazin's avatar
gbazin committed
186
187
188
189
190
191
192
193
194
195
196
197
198
199
            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 = ',';

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

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

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

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

238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
/*****************************************************************************
 * input_PreParse: Lightweight input for playlist item preparsing
 *****************************************************************************/
int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
{
    input_thread_t *p_input;                        /* thread descriptor */
    int i;

    /* Allocate descriptor */
    p_input = vlc_object_create( p_parent, VLC_OBJECT_INPUT );
    if( p_input == NULL )
    {
        msg_Err( p_parent, "out of memory" );
        return VLC_EGENERIC;
    }

    /* 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_title_offset = p_input->i_seekpoint_offset = 0;
    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_meta  = NULL;
    p_input->p_es_out = NULL;
    p_input->p_sout  = NULL;
    p_input->b_out_pace_control = VLC_FALSE;
    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.i_title_offset = p_input->input.i_seekpoint_offset = 0;
    p_input->input.b_can_pace_control = VLC_TRUE;
    p_input->input.b_eof = VLC_FALSE;
    p_input->input.i_cr_average = 0;

    /* No slave */
    p_input->i_slave = 0;
    p_input->slave   = NULL;

    /* Init control buffer */
    vlc_mutex_init( p_input, &p_input->lock_control );
    p_input->i_control = 0;

    /* Parse input options */
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
    {
        ParseOption( p_input, p_item->ppsz_options[i] );
    }
    vlc_mutex_unlock( &p_item->lock );

    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
304
    input_ControlVarInit( p_input );
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331

    p_input->input.i_cr_average = var_GetInteger( p_input, "cr-average" );

    /* Now we can attach our new input */
    vlc_object_attach( p_input, p_parent );

    Init( p_input, VLC_TRUE );

    /* Clean up master */
    InputSourceClean( p_input, &p_input->input );

    /* Kill access and demux */
    if( p_input->input.p_access ) p_input->input.p_access->b_die = VLC_TRUE;
    if( p_input->input.p_demux ) p_input->input.p_access->b_die = VLC_TRUE;

    /* Unload all modules */
    if( p_input->p_es_out ) input_EsOutDelete( p_input->p_es_out );

    /* Delete meta */
    if( p_input->p_meta ) vlc_meta_Delete( p_input->p_meta );

    vlc_object_detach( p_input );
    vlc_object_destroy( p_input );

    return VLC_SUCCESS;
}

332
/*****************************************************************************
Sam Hocevar's avatar
   
Sam Hocevar committed
333
 * input_StopThread: mark an input thread as zombie
334
 *****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
335
 * This function should not return until the thread is effectively cancelled.
336
 *****************************************************************************/
Sam Hocevar's avatar
Sam Hocevar committed
337
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
338
{
Laurent Aimar's avatar
Laurent Aimar committed
339
340
    vlc_list_t *p_list;
    int i;
341

Laurent Aimar's avatar
Laurent Aimar committed
342
343
    /* Set die for input */
    p_input->b_die = VLC_TRUE;
344

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

Laurent Aimar's avatar
Laurent Aimar committed
348
349
350
    /* 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++ )
351
    {
Laurent Aimar's avatar
Laurent Aimar committed
352
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
353
    }
Laurent Aimar's avatar
Laurent Aimar committed
354
    vlc_list_release( p_list );
355

Laurent Aimar's avatar
Laurent Aimar committed
356
357
358
    /* 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++ )
359
    {
Laurent Aimar's avatar
Laurent Aimar committed
360
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
361
    }
Laurent Aimar's avatar
Laurent Aimar committed
362
    vlc_list_release( p_list );
363

Laurent Aimar's avatar
Laurent Aimar committed
364
365
366
367
368
369
370
    /* 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
371

Laurent Aimar's avatar
Laurent Aimar committed
372
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
   
Sam Hocevar committed
373
374
375
376
377
378
379
380
381
382
}

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

Laurent Aimar's avatar
Laurent Aimar committed
385
386
387
388
389
    /* 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
390
391
}

392
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
393
 * Run: main thread loop
394
 *****************************************************************************
395
 * Thread in charge of processing the network packets and demultiplexing.
396
397
398
399
 *
 * TODO:
 *  read subtitle support (XXX take care of spu-delay in the right way).
 *  multi-input support (XXX may be done with subs)
400
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
401
static int Run( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
402
{
Laurent Aimar's avatar
Laurent Aimar committed
403
    int64_t i_intf_update = 0;
404

Laurent Aimar's avatar
Laurent Aimar committed
405
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
406
407
    vlc_thread_ready( p_input );

408
    if( Init( p_input, VLC_FALSE ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
409
410
    {
        /* If we failed, wait before we are killed, and exit */
Laurent Aimar's avatar
Laurent Aimar committed
411
        p_input->b_error = VLC_TRUE;
412

Laurent Aimar's avatar
Laurent Aimar committed
413
        Error( p_input );
414
415

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

Sam Hocevar's avatar
   
Sam Hocevar committed
418
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
419
    }
Michel Kaempf's avatar
Michel Kaempf committed
420

Laurent Aimar's avatar
Laurent Aimar committed
421
    /* Main loop */
422
    while( !p_input->b_die && !p_input->b_error && !p_input->input.b_eof )
Sam Hocevar's avatar
   
Sam Hocevar committed
423
    {
Laurent Aimar's avatar
Laurent Aimar committed
424
425
426
427
        vlc_bool_t b_force_update = VLC_FALSE;
        int i_ret;
        int i_type;
        vlc_value_t val;
428

Laurent Aimar's avatar
Laurent Aimar committed
429
430
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
431
        {
Laurent Aimar's avatar
Laurent Aimar committed
432
433
434
435
            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 */
436

Laurent Aimar's avatar
Laurent Aimar committed
437
438
439
440
441
442
            if( i_ret > 0 )
            {
                /* TODO */
                if( p_input->input.b_title_demux &&
                    p_input->input.p_demux->info.i_update )
                {
443
                    i_ret = UpdateFromDemux( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
444
445
446
447
448
449
                    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 )
                {
450
                    i_ret = UpdateFromAccess( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
451
452
453
                    b_force_update = VLC_TRUE;
                }
            }
454
455

            if( i_ret == 0 )    /* EOF */
Laurent Aimar's avatar
Laurent Aimar committed
456
457
            {
                vlc_value_t repeat;
458

Laurent Aimar's avatar
Laurent Aimar committed
459
460
461
462
463
464
465
466
467
                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
468
                {
gbazin's avatar
gbazin committed
469
470
                    msg_Dbg( p_input, "repeating the same input (%d)",
                             repeat.i_int );
Laurent Aimar's avatar
Laurent Aimar committed
471
472
473
474
475
                    if( repeat.i_int > 0 )
                    {
                        repeat.i_int--;
                        var_Set( p_input, "input-repeat", repeat );
                    }
476

477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
                    /* Seek to start title/seekpoint */
                    val.i_int = p_input->input.i_title_start -
                        p_input->input.i_title_offset;
                    if( val.i_int < 0 || val.i_int >= p_input->input.i_title )
                        val.i_int = 0;
                    input_ControlPush( p_input,
                                       INPUT_CONTROL_SET_TITLE, &val );

                    val.i_int = p_input->input.i_seekpoint_start -
                        p_input->input.i_seekpoint_offset;
                    if( val.i_int > 0 /* TODO: check upper boundary */ )
                        input_ControlPush( p_input,
                                           INPUT_CONTROL_SET_SEEKPOINT, &val );

                    /* Seek to start position */
Laurent Aimar's avatar
Laurent Aimar committed
492
493
494
495
496
497
498
499
500
501
502
503
                    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 );
                    }
504
505
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
506
507
508
509
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
510
511
512
513
514

            if( i_ret > 0 && p_input->i_slave > 0 )
            {
                SlaveDemux( p_input );
            }
515
        }
Laurent Aimar's avatar
Laurent Aimar committed
516
        else
517
        {
Laurent Aimar's avatar
Laurent Aimar committed
518
519
520
            /* Small wait */
            msleep( 10*1000 );
        }
521

Laurent Aimar's avatar
Laurent Aimar committed
522
523
524
525
526
527
528
529
530
531
        /* 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 );
532

533
        if( b_force_update || i_intf_update < mdate() )
Laurent Aimar's avatar
Laurent Aimar committed
534
535
536
537
538
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
gbazin's avatar
gbazin committed
539
540
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_POSITION, &f_pos ) )
Laurent Aimar's avatar
Laurent Aimar committed
541
542
543
544
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
gbazin's avatar
gbazin committed
545
546
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_TIME, &i_time ) )
Laurent Aimar's avatar
Laurent Aimar committed
547
548
549
550
551
            {
                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
552
553
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_LENGTH, &i_length ) )
Laurent Aimar's avatar
Laurent Aimar committed
554
555
556
557
558
            {
                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 );
559

Laurent Aimar's avatar
Laurent Aimar committed
560
                if( old_val.i_time != val.i_time )
561
                {
562
                    UpdateItemLength( p_input, i_length, VLC_TRUE );
563
564
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
565
566
567

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

571
    if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
Laurent Aimar's avatar
Laurent Aimar committed
572
    {
573
574
        /* We have finish to demux data but not to play them */
        while( !p_input->b_die )
Sam Hocevar's avatar
   
Sam Hocevar committed
575
        {
576
577
            if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
                break;
578

579
            msg_Dbg( p_input, "waiting decoder fifos to empty" );
580

581
            msleep( INPUT_IDLE_SLEEP );
Sam Hocevar's avatar
   
Sam Hocevar committed
582
        }
583

584
585
        /* We have finished */
        p_input->b_eof = VLC_TRUE;
586
587
    }

588
589
    /* Wait we are asked to die */
    if( !p_input->b_die )
590
    {
591
        Error( p_input );
592
    }
593

594
595
    /* Clean up */
    End( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
596

Sam Hocevar's avatar
   
Sam Hocevar committed
597
    return 0;
598
599
}

600
601

static int Init( input_thread_t * p_input, vlc_bool_t b_quick )
Michel Kaempf's avatar
Michel Kaempf committed
602
{
Laurent Aimar's avatar
Laurent Aimar committed
603
    char *psz;
Laurent Aimar's avatar
   
Laurent Aimar committed
604
    char *psz_subtitle;
Laurent Aimar's avatar
Laurent Aimar committed
605
    vlc_value_t val;
Laurent Aimar's avatar
   
Laurent Aimar committed
606
    double f_fps;
607
    vlc_meta_t *p_meta, *p_meta_tmp;
608
    int i_es_out_mode;
zorglub's avatar
zorglub committed
609
    int i, i_delay;
610

Laurent Aimar's avatar
Laurent Aimar committed
611
    /* Initialize optional stream output. (before access/demuxer) */
612
    if( !b_quick )
613
    {
614
615
        psz = var_GetString( p_input, "sout" );
        if( *psz )
616
        {
617
618
619
            p_input->p_sout = sout_NewInstance( p_input, psz );
            if( p_input->p_sout == NULL )
            {
gbazin's avatar
gbazin committed
620
                msg_Err( p_input, "cannot start stream output instance, " \
621
622
623
624
                                  "aborting" );
                free( psz );
                return VLC_EGENERIC;
            }
625
        }
626
        free( psz );
627
    }
Christophe Massiot's avatar
Christophe Massiot committed
628

Laurent Aimar's avatar
Laurent Aimar committed
629
    /* Create es out */
630
    p_input->p_es_out = input_EsOutNew( p_input );
631
632
    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 );
633

634
    if( InputSourceInit( p_input, &p_input->input,
635
                         p_input->input.p_item->psz_uri, NULL, b_quick ) )
636
    {
637
        goto error;
Laurent Aimar's avatar
Laurent Aimar committed
638
    }
639

640
    /* Create global title (from master) */
641
    if( !b_quick )
642
    {
643
644
645
646
647
648
649
650
651
652
        p_input->i_title = p_input->input.i_title;
        p_input->title   = p_input->input.title;
        p_input->i_title_offset = p_input->input.i_title_offset;
        p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
        if( p_input->i_title > 0 )
        {
            /* Setup variables */
            input_ControlVarNavigation( p_input );
            input_ControlVarTitle( p_input, 0 );
        }
653

654
655
656
        /* 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;
Laurent Aimar's avatar
Laurent Aimar committed
657

658
659
660
        /* Fix pts delay */
        if( p_input->i_pts_delay <= 0 )
            p_input->i_pts_delay = DEFAULT_PTS_DELAY;
661

662
663
664
665
        /* If the desynchronisation requested by the user is < 0, we need to
         * cache more data. */
        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
666

667
668
669
670
671
        /* Update cr_average depending on the caching */
        p_input->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
        p_input->input.i_cr_average /= 10;
        if( p_input->input.i_cr_average <= 0 ) p_input->input.i_cr_average = 1;
    }
672

673
    /* Load master infos */
Laurent Aimar's avatar
Laurent Aimar committed
674
    /* Init length */
gbazin's avatar
gbazin committed
675
676
    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
677
678
    {
        var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
679
        UpdateItemLength( p_input, val.i_time, b_quick );
zorglub's avatar
zorglub committed
680
        p_input->input.p_item->i_duration = val.i_time;
Laurent Aimar's avatar
Laurent Aimar committed
681
    }
682
683

    /* Start title/chapter */
684
    if( !b_quick )
Laurent Aimar's avatar
Laurent Aimar committed
685
    {
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
        val.i_int = p_input->input.i_title_start -
                    p_input->input.i_title_offset;
        if( val.i_int > 0 && val.i_int < p_input->input.i_title )
            input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
        val.i_int = p_input->input.i_seekpoint_start -
                    p_input->input.i_seekpoint_offset;
        if( val.i_int > 0 /* TODO: check upper boundary */ )
            input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );

        /* 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 )
703
        {
704
705
706
707
708
709
710
            if( p_input->i_start >= val.i_time )
            {
                msg_Warn( p_input, "invalid start-time ignored" );
            }
            else
            {
                vlc_value_t s;
Laurent Aimar's avatar
Laurent Aimar committed
711

zorglub's avatar
zorglub committed
712
                msg_Dbg( p_input, "starting at time: %ds",
713
                                  (int)( p_input->i_start / I64C(1000000) ) );
Laurent Aimar's avatar
Laurent Aimar committed
714

715
716
717
                s.i_time = p_input->i_start;
                input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
            }
718
        }
719
        if( p_input->i_stop > 0 && p_input->i_stop <= p_input->i_start )
Laurent Aimar's avatar
   
Laurent Aimar committed
720
        {
721
722
            msg_Warn( p_input, "invalid stop-time ignored" );
            p_input->i_stop = 0;
Laurent Aimar's avatar
   
Laurent Aimar committed
723
724
        }

zorglub's avatar
zorglub committed
725

726
727
728
729
730
731
        /* 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 )
        {
            float f_requested_fps;
zorglub's avatar
zorglub committed
732

733
734
            var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
            var_SetFloat( p_input, "sub-original-fps", f_fps );
zorglub's avatar
zorglub committed
735

736
737
738
739
740
741
742
743
            f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
            if( f_requested_fps != f_fps )
            {
                var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
                                                VLC_VAR_DOINHERIT );
                var_SetFloat( p_input, "sub-fps", f_requested_fps );
            }
        }
Laurent Aimar's avatar
   
Laurent Aimar committed
744

745
746
747
748
749
        i_delay = var_CreateGetInteger( p_input, "sub-delay" );
        if( i_delay != 0 )
        {
            var_SetTime( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
        }
Laurent Aimar's avatar
   
Laurent Aimar committed
750
751


752
753
754
        /* Look for and add subtitle files */
        psz_subtitle = var_GetString( p_input, "sub-file" );
        if( *psz_subtitle )
Laurent Aimar's avatar
   
Laurent Aimar committed
755
        {
756
757
758
759
760
            input_source_t *sub;
            vlc_value_t count;
            vlc_value_t list;

            msg_Dbg( p_input, "forced subtitle: %s", psz_subtitle );
Laurent Aimar's avatar
   
Laurent Aimar committed
761

762
763
764
765
766
767
            var_Change( p_input, "spu-es", VLC_VAR_CHOICESCOUNT, &count, NULL );

            /* */
            sub = InputSourceNew( p_input );
            if( !InputSourceInit( p_input, sub, psz_subtitle, "subtitle",
                                  VLC_FALSE ) )
Laurent Aimar's avatar
   
Laurent Aimar committed
768
            {
769
                TAB_APPEND( p_input->i_slave, p_input->slave, sub );
Laurent Aimar's avatar
   
Laurent Aimar committed
770

771
772
773
                /* Select the ES */
                if( !var_Change( p_input, "spu-es", VLC_VAR_GETLIST, &list,
                                 NULL ) )
Laurent Aimar's avatar
   
Laurent Aimar committed
774
                {
775
776
777
778
779
780
781
782
783
784
785
                    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 )
                    {
                        input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
                                          &list.p_list->p_values[count.i_int] );
                    }
                    var_Change( p_input, "spu-es", VLC_VAR_FREELIST, &list,
                                NULL );
Laurent Aimar's avatar
   
Laurent Aimar committed
786
787
788
                }
            }
        }
789

790
791
        var_Get( p_input, "sub-autodetect-file", &val );
        if( val.b_bool )
Laurent Aimar's avatar
   
Laurent Aimar committed
792
        {
793
794
795
796
797
798
           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;

            for( i = 0; subs[i] != NULL; i++ )
Laurent Aimar's avatar
   
Laurent Aimar committed
799
            {
800
                if( strcmp( psz_subtitle, subs[i] ) )
Laurent Aimar's avatar
   
Laurent Aimar committed
801
                {
802
803
804
805
806
807
                    sub = InputSourceNew( p_input );
                    if( !InputSourceInit( p_input, sub, subs[i], "subtitle",
                                          VLC_FALSE ) )
                    {
                         TAB_APPEND( p_input->i_slave, p_input->slave, sub );
                    }
Laurent Aimar's avatar
   
Laurent Aimar committed
808
                }
809
                free( subs[i] );
Laurent Aimar's avatar
   
Laurent Aimar committed
810
            }
811
812
            free( subs );
            free( psz_autopath );
Laurent Aimar's avatar
   
Laurent Aimar committed
813
        }
814
        free( psz_subtitle );
815

816
817
818
        /* Look for slave */
        psz = var_GetString( p_input, "input-slave" );
        if( *psz )
819
        {
820
821
822
            char *psz_delim;
            input_source_t *slave;
            while( psz && *psz )
823
            {
824
825
826
827
828
829
830
831
832
833
834
835
                while( *psz == ' ' || *psz == '#' )
                {
                    psz++;
                }
                if( ( psz_delim = strchr( psz, '#' ) ) )
                {
                    *psz_delim++ = '\0';
                }
                if( *psz == 0 )
                {
                    break;
                }
836

zorglub's avatar
zorglub committed
837
                msg_Dbg( p_input, "adding slave input '%s'", psz );
838
839
840
841
842
843
                slave = InputSourceNew( p_input );
                if( !InputSourceInit( p_input, slave, psz, NULL, VLC_FALSE ) )
                {
                    TAB_APPEND( p_input->i_slave, p_input->slave, slave );
                }
                psz = psz_delim;
844
845
            }
        }
846
847
848
849
850
851
        if( psz ) free( psz );
    }
    else
    {
        p_input->i_start = 0;
        p_input->i_start = 0;
852
    }
Laurent Aimar's avatar
Laurent Aimar committed
853
854

    /* Set up es_out */
855
    if( !b_quick )
Laurent Aimar's avatar
Laurent Aimar committed
856
    {
857
858
859
860
        es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
        i_es_out_mode = ES_OUT_MODE_AUTO;
        val.p_list = NULL;
        if( p_input->p_sout )
861
        {
862
863
            var_Get( p_input, "sout-all", &val );
            if ( val.b_bool )
864
            {
865
866
                i_es_out_mode = ES_OUT_MODE_ALL;
                val.p_list = NULL;
867
868
            }
            else
869
870
871
872
873
874
875
876
877
878
879
            {
                var_Get( p_input, "programs", &val );
                if ( val.p_list && val.p_list->i_count )
                {
                    i_es_out_mode = ES_OUT_MODE_PARTIAL;
                    /* Note : we should remove the "program" callback. */
                }
                else
                    var_Change( p_input, "programs", VLC_VAR_FREELIST, &val,
                                NULL );
            }
880
        }
881
        es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
882

883
884
        /* Inform the demuxer about waited group (needed only for DVB) */
        if( i_es_out_mode == ES_OUT_MODE_ALL )
Laurent Aimar's avatar
Laurent Aimar committed
885
        {
886
887
888
889
890
891
            demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1, NULL );
        }
        else if( i_es_out_mode == ES_OUT_MODE_PARTIAL )
        {
            demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP, -1,
                            val.p_list );
892
        }
Laurent Aimar's avatar
Laurent Aimar committed
893
894
        else
        {
895
896
897
898
899
900
901
902
903
904
905
906
907
908
            demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
                           (int) var_GetInteger( p_input, "program" ), NULL );
        }

        if( p_input->p_sout )
        {
            if( p_input->p_sout->i_out_pace_nocontrol > 0 )
            {
                p_input->b_out_pace_control = VLC_FALSE;
            }
            else
            {
                p_input->b_out_pace_control = VLC_TRUE;
            }
909
910
911
912
913
914
915
916

            if( p_input->b_can_pace_control && p_input->b_out_pace_control )
            {
                /* We don't want a high input priority here or we'll
                 * end-up sucking up all the CPU time */
                vlc_thread_set_priority( p_input, VLC_THREAD_PRIORITY_LOW );
            }

917
918
            msg_Dbg( p_input, "starting in %s mode",
                     p_input->b_out_pace_control ? "asynch" : "synch" );
Laurent Aimar's avatar
Laurent Aimar committed
919
        }
920
921
    }

922
    /* Get meta data from users */
923
    p_meta_tmp = InputMetaUser( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
924

925
926
927
    /* Get meta data from master input */
    if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
        p_meta = NULL;
928

929
930
    /* Merge them */
    if( p_meta == NULL )
gbazin's avatar
gbazin committed
931
    {
932
        p_meta = p_meta_tmp;
gbazin's avatar
gbazin committed
933
    }
934
    else if( p_meta_tmp )
935
    {
936
937
938
939
        vlc_meta_Merge( p_meta, p_meta_tmp );
        vlc_meta_Delete( p_meta_tmp );
    }

940
941
    /* Access_file does not give any meta, and there are no slave */
    if( !b_quick )
942
    {
943
944
945
946
        if( !p_input->input.p_access ||
            access2_Control( p_input->input.p_access, ACCESS_GET_META,
                             &p_meta_tmp))
            p_meta_tmp = NULL;
gbazin's avatar
gbazin committed
947

948
        if( p_meta == NULL )
949
        {
950
951
952
953
954
955
            p_meta = p_meta_tmp;
        }
        else if( p_meta_tmp )
        {
            vlc_meta_Merge( p_meta, p_meta_tmp );
            vlc_meta_Delete( p_meta_tmp );
956
957
        }

958
959
        /* Get meta data from slave input */
        for( i = 0; i < p_input->i_slave; i++ )
960
        {
961
962
963
964
            vlc_meta_t *p_meta_slave;

            if( !demux2_Control( p_input->slave[i]->p_demux,
                                 DEMUX_GET_META, &p_meta_slave ) )
965
            {
966
967
968
969
970
971
972
973
974
                if( p_meta == NULL )
                {
                    p_meta = p_meta_slave;
                }
                else if( p_meta_slave )
                {
                    vlc_meta_Merge( p_meta, p_meta_slave );
                    vlc_meta_Delete( p_meta_slave );
                }
975
            }
976
977
978
979

            if( p_input->slave[i]->p_access &&
                !access2_Control( p_input->slave[i]->p_access,
                                  ACCESS_GET_META, &p_meta_slave ) )
980
            {
981
982
983
984
985
986
987
988
989
                if( p_meta == NULL )
                {
                    p_meta = p_meta_slave;
                }
                else if( p_meta_slave )
                {
                    vlc_meta_Merge( p_meta, p_meta_slave );
                    vlc_meta_Delete( p_meta_slave );
                }
990
991
992
            }
        }
    }
993
994

    p_input->p_meta = p_meta;
995
    UpdateMeta( p_input, b_quick );
996

997
998
999
1000
1001
1002
    if( !b_quick )
    {
        msg_Dbg( p_input, "`%s' sucessfully opened",
                 p_input->input.p_item->psz_uri );

    }
1003

zorglub's avatar
zorglub committed
1004
1005
1006
1007
1008
    /* Trigger intf update for this item */
    /* Playlist has a callback on this variable and will forward
     * it to intf */
    var_SetInteger( p_input, "item-change", p_input->input.p_item->i_id );

1009
1010
    /* initialization is complete */
    p_input->i_state = PLAYING_S;
1011

1012
1013
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
gbazin committed
1014

1015
    return VLC_SUCCESS;
1016

1017