input.c 83.7 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
//        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
166
        ParseOption( p_input, p_item->ppsz_options[i] );
gbazin's avatar
   
gbazin committed
167
    }
168
    vlc_mutex_unlock( &p_item->lock );
gbazin's avatar
   
gbazin committed
169

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

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

Laurent Aimar's avatar
Laurent Aimar committed
177
    /* TODO */
gbazin's avatar
gbazin committed
178
179
180
181
182
183
184
185
    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, '{' ) ) )
        {
186
            seekpoint_t *p_seekpoint = vlc_seekpoint_New();
gbazin's avatar
gbazin committed
187
188
189
190
191
192
193
194
195
196
197
198
199
200
            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 ) )
                {
201
                    p_seekpoint->psz_name = psz_start + 5;
gbazin's avatar
gbazin committed
202
203
204
                }
                else if( !strncmp( psz_start, "bytes=", 6 ) )
                {
205
                    p_seekpoint->i_byte_offset = atoll(psz_start + 6);
gbazin's avatar
gbazin committed
206
207
208
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
209
                    p_seekpoint->i_time_offset = atoll(psz_start + 5) * 1000000;
gbazin's avatar
gbazin committed
210
211
212
213
                }
                psz_start = psz_end + 1;
            }
            msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
214
215
216
217
                     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
218
219
220
221
222
            *psz_parser = backup;
        }
        free( val.psz_string );
    }

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

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

236
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
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
304
/*****************************************************************************
 * 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 );
305
    input_ControlVarInit( p_input );
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
332

    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;
}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
                    /* 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
493
494
495
496
497
498
499
500
501
502
503
504
                    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 );
                    }
505
506
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
507
508
509
510
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
511
512
513
514
515

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

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

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

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

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

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

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

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

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

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

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

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

601
602

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

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

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

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

641
    /* Create global title (from master) */
642
    if( !b_quick )
643
    {
644
645
646
647
648
649
650
651
652
653
        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 );
        }
654

655
656
657
        /* 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
658

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

663
664
665
666
        /* 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
667

668
669
670
671
672
        /* 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;
    }
673

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

    /* Start title/chapter */
685
    if( !b_quick )
Laurent Aimar's avatar
Laurent Aimar committed
686
    {
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
        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 )
704
        {
705
706
707
708
709
710
711
            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
712

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

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

zorglub's avatar
zorglub committed
726

727
728
729
730
731
732
        /* 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
733

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

737
738
739
740
741
742
743
744
            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
745

746
747
748
749
750
        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
751
752


753
754
755
        /* Look for and add subtitle files */
        psz_subtitle = var_GetString( p_input, "sub-file" );
        if( *psz_subtitle )
Laurent Aimar's avatar
   
Laurent Aimar committed
756
        {
757
758
759
760
761
            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
762

763
764
765
766
767
768
            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
769
            {
770
                TAB_APPEND( p_input->i_slave, p_input->slave, sub );
Laurent Aimar's avatar
   
Laurent Aimar committed
771

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

791
792
        var_Get( p_input, "sub-autodetect-file", &val );
        if( val.b_bool )
Laurent Aimar's avatar
   
Laurent Aimar committed
793
        {
794
795
796
797
798
799
           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
800
            {
801
                if( strcmp( psz_subtitle, subs[i] ) )
Laurent Aimar's avatar
   
Laurent Aimar committed
802
                {
803
804
805
806
807
808
                    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
809
                }
810
                free( subs[i] );
Laurent Aimar's avatar
   
Laurent Aimar committed
811
            }
812
813
            free( subs );
            free( psz_autopath );
Laurent Aimar's avatar
   
Laurent Aimar committed
814
        }
815
        free( psz_subtitle );
816

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

838
839
840
841
842
843
844
                msg_Dbg( p_input, "adding slave '%s'", psz );
                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;
845
846
            }
        }
847
848
849
850
851
852
        if( psz ) free( psz );
    }
    else
    {
        p_input->i_start = 0;
        p_input->i_start = 0;
853
    }
Laurent Aimar's avatar
Laurent Aimar committed
854
855

    /* Set up es_out */
856
    if( !b_quick )
Laurent Aimar's avatar
Laurent Aimar committed
857
    {
858
859
860
861
        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 )
862
        {
863
864
            var_Get( p_input, "sout-all", &val );
            if ( val.b_bool )
865
            {
866
867
                i_es_out_mode = ES_OUT_MODE_ALL;
                val.p_list = NULL;
868
869
            }
            else
870
871
872
873
874
875
876
877
878
879
880
            {
                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 );
            }
881
        }
882
        es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
883

884
885
        /* 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
886
        {
887
888
889
890
891
892
            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 );
893
        }
Laurent Aimar's avatar
Laurent Aimar committed
894
895
        else
        {
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
            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;
            }
            msg_Dbg( p_input, "starting in %s mode",
                     p_input->b_out_pace_control ? "asynch" : "synch" );
Laurent Aimar's avatar
Laurent Aimar committed
912
        }
913
914
    }

915
    /* Get meta data from users */
916
    p_meta_tmp = InputMetaUser( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
917

918
919
920
    /* Get meta data from master input */
    if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
        p_meta = NULL;
921

922
923
    /* Merge them */
    if( p_meta == NULL )
gbazin's avatar
gbazin committed
924
    {
925
        p_meta = p_meta_tmp;
gbazin's avatar
gbazin committed
926
    }
927
    else if( p_meta_tmp )
928
    {
929
930
931
932
        vlc_meta_Merge( p_meta, p_meta_tmp );
        vlc_meta_Delete( p_meta_tmp );
    }

933
934
    /* Access_file does not give any meta, and there are no slave */
    if( !b_quick )
935
    {
936
937
938
939
        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
940

941
        if( p_meta == NULL )
942
        {
943
944
945
946
947
948
            p_meta = p_meta_tmp;
        }
        else if( p_meta_tmp )
        {
            vlc_meta_Merge( p_meta, p_meta_tmp );
            vlc_meta_Delete( p_meta_tmp );
949
950
        }

951
952
        /* Get meta data from slave input */
        for( i = 0; i < p_input->i_slave; i++ )
953
        {
954
955
956
957
            vlc_meta_t *p_meta_slave;

            if( !demux2_Control( p_input->slave[i]->p_demux,
                                 DEMUX_GET_META, &p_meta_slave ) )
958
            {
959
960
961
962
963
964
965
966
967
                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 );
                }
968
            }
969
970
971
972

            if( p_input->slave[i]->p_access &&
                !access2_Control( p_input->slave[i]->p_access,
                                  ACCESS_GET_META, &p_meta_slave ) )
973
            {
974
975
976
977
978
979
980
981
982
                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 );
                }
983
984
985
            }
        }
    }
986
987

    p_input->p_meta = p_meta;
988
    UpdateMeta( p_input, b_quick );
989

990
991
992
993
994
995
    if( !b_quick )
    {
        msg_Dbg( p_input, "`%s' sucessfully opened",
                 p_input->input.p_item->psz_uri );

    }
996

zorglub's avatar
zorglub committed
997
998
999
1000
1001
    /* 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 );

1002
1003
    /* initialization is complete */
    p_input->i_state = PLAYING_S;
1004

1005
1006
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
gbazin committed
1007

1008
    return VLC_SUCCESS;
1009

1010
1011
1012
error:
    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );
Laurent Aimar's avatar
Laurent Aimar committed
1013

1014
1015
    if( p_input->p_sout )
        sout_DeleteInstance( p_input->p_sout );
1016

1017
1018
1019
1020
1021
1022
    /* 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;
1023

1024
    return VLC_EGENERIC;
Michel Kaempf's avatar
Michel Kaempf committed
1025
1026
}

1027
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
1028
 * Error: RunThread() error loop
1029
 *****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
1030
 * This function is called when an error occurred during thread main's loop.
1031
 *****************************************************************************/