input.c 73.8 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
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

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

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

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
70
static int  InputSourceInit( input_thread_t *, input_source_t *,
                             char *, char *psz_forced_demux );
71
72
73
74
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 );
75

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

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

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

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

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

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

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

gbazin's avatar
   
gbazin committed
160
    /* Parse input options */
161
162
    vlc_mutex_lock( &p_item->lock );
    for( i = 0; i < p_item->i_options; i++ )
gbazin's avatar
   
gbazin committed
163
    {
164
//        msg_Dbg( p_input, "option: %s", p_item->ppsz_options[i] );
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
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
    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 ) )
                {
207
                    seekpoint.i_byte_offset = atoll(psz_start + 6);
gbazin's avatar
gbazin committed
208
209
210
                }
                else if( !strncmp( psz_start, "time=", 5 ) )
                {
211
                    seekpoint.i_time_offset = atoll(psz_start + 5) * 1000000;
gbazin's avatar
gbazin committed
212
213
214
215
216
217
218
219
220
221
222
223
                }
                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
224
    /* Now we can attach our new input */
225
    vlc_object_attach( p_input, p_parent );
Sam Hocevar's avatar
   
Sam Hocevar committed
226

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

237
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
238
239
}

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

Laurent Aimar's avatar
Laurent Aimar committed
250
251
    /* Set die for input */
    p_input->b_die = VLC_TRUE;
252

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

Laurent Aimar's avatar
Laurent Aimar committed
256
257
258
    /* 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++ )
259
    {
Laurent Aimar's avatar
Laurent Aimar committed
260
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
261
    }
Laurent Aimar's avatar
Laurent Aimar committed
262
    vlc_list_release( p_list );
263

Laurent Aimar's avatar
Laurent Aimar committed
264
265
266
    /* 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++ )
267
    {
Laurent Aimar's avatar
Laurent Aimar committed
268
        p_list->p_values[i].p_object->b_die = VLC_TRUE;
269
    }
Laurent Aimar's avatar
Laurent Aimar committed
270
    vlc_list_release( p_list );
271

Laurent Aimar's avatar
Laurent Aimar committed
272
273
274
275
276
277
278
    /* 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
279

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

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

Laurent Aimar's avatar
Laurent Aimar committed
293
294
295
296
297
    /* 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
298
299
}

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

Laurent Aimar's avatar
Laurent Aimar committed
313
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
314
315
    vlc_thread_ready( p_input );

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

Laurent Aimar's avatar
Laurent Aimar committed
321
        Error( p_input );
322
323

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

Sam Hocevar's avatar
   
Sam Hocevar committed
326
        return 0;
Sam Hocevar's avatar
   
Sam Hocevar committed
327
    }
Michel Kaempf's avatar
Michel Kaempf committed
328

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

Laurent Aimar's avatar
Laurent Aimar committed
337
338
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
339
        {
Laurent Aimar's avatar
Laurent Aimar committed
340
341
342
343
            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 */
344

Laurent Aimar's avatar
Laurent Aimar committed
345
346
347
348
349
350
            if( i_ret > 0 )
            {
                /* TODO */
                if( p_input->input.b_title_demux &&
                    p_input->input.p_demux->info.i_update )
                {
351
                    i_ret = UpdateFromDemux( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
352
353
354
355
356
357
                    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 )
                {
358
                    i_ret = UpdateFromAccess( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
359
360
361
                    b_force_update = VLC_TRUE;
                }
            }
362
363

            if( i_ret == 0 )    /* EOF */
Laurent Aimar's avatar
Laurent Aimar committed
364
365
            {
                vlc_value_t repeat;
366

Laurent Aimar's avatar
Laurent Aimar committed
367
368
369
370
371
372
373
374
375
                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
376
                {
gbazin's avatar
gbazin committed
377
378
                    msg_Dbg( p_input, "repeating the same input (%d)",
                             repeat.i_int );
Laurent Aimar's avatar
Laurent Aimar committed
379
380
381
382
383
                    if( repeat.i_int > 0 )
                    {
                        repeat.i_int--;
                        var_Set( p_input, "input-repeat", repeat );
                    }
384

385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
                    /* 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
400
401
402
403
404
405
406
407
408
409
410
411
                    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 );
                    }
412
413
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
414
415
416
417
            else if( i_ret < 0 )
            {
                p_input->b_error = VLC_TRUE;
            }
418
419
420
421
422

            if( i_ret > 0 && p_input->i_slave > 0 )
            {
                SlaveDemux( p_input );
            }
423
        }
Laurent Aimar's avatar
Laurent Aimar committed
424
        else
425
        {
Laurent Aimar's avatar
Laurent Aimar committed
426
427
428
            /* Small wait */
            msleep( 10*1000 );
        }
429

Laurent Aimar's avatar
Laurent Aimar committed
430
431
432
433
434
435
436
437
438
439
        /* 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 );
440

441
        if( b_force_update || i_intf_update < mdate() )
Laurent Aimar's avatar
Laurent Aimar committed
442
443
444
445
446
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
gbazin's avatar
gbazin committed
447
448
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_POSITION, &f_pos ) )
Laurent Aimar's avatar
Laurent Aimar committed
449
450
451
452
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
gbazin's avatar
gbazin committed
453
454
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_TIME, &i_time ) )
Laurent Aimar's avatar
Laurent Aimar committed
455
456
457
458
459
            {
                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
460
461
            if( !demux2_Control( p_input->input.p_demux,
                                 DEMUX_GET_LENGTH, &i_length ) )
Laurent Aimar's avatar
Laurent Aimar committed
462
463
464
465
466
            {
                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 );
467

Laurent Aimar's avatar
Laurent Aimar committed
468
                if( old_val.i_time != val.i_time )
469
                {
470
                    UpdateItemLength( p_input, i_length );
471
472
                }
            }
Laurent Aimar's avatar
Laurent Aimar committed
473
474
475

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

479
    if( !p_input->b_eof && !p_input->b_error && p_input->input.b_eof )
Laurent Aimar's avatar
Laurent Aimar committed
480
    {
481
482
        /* We have finish to demux data but not to play them */
        while( !p_input->b_die )
Sam Hocevar's avatar
   
Sam Hocevar committed
483
        {
484
485
            if( input_EsOutDecodersEmpty( p_input->p_es_out ) )
                break;
486

487
            msg_Dbg( p_input, "waiting decoder fifos to empty" );
488

489
            msleep( INPUT_IDLE_SLEEP );
Sam Hocevar's avatar
   
Sam Hocevar committed
490
        }
491

492
493
        /* We have finished */
        p_input->b_eof = VLC_TRUE;
494
495
    }

496
497
    /* Wait we are asked to die */
    if( !p_input->b_die )
498
    {
499
        Error( p_input );
500
    }
501

502
503
    /* Clean up */
    End( p_input );
Sam Hocevar's avatar
   
Sam Hocevar committed
504

Sam Hocevar's avatar
   
Sam Hocevar committed
505
    return 0;
506
507
}

508
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
509
 * Init: init the input Thread
510
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
511
static int Init( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
512
{
Laurent Aimar's avatar
Laurent Aimar committed
513
    char *psz;
Laurent Aimar's avatar
   
Laurent Aimar committed
514
    char *psz_subtitle;
Laurent Aimar's avatar
Laurent Aimar committed
515
    vlc_value_t val;
Laurent Aimar's avatar
   
Laurent Aimar committed
516
    double f_fps;
517
    vlc_meta_t *p_meta, *p_meta_tmp;
518
    int i_es_out_mode;
zorglub's avatar
zorglub committed
519
    int i, i_delay;
520

Laurent Aimar's avatar
Laurent Aimar committed
521
522
523
    /* Initialize optional stream output. (before access/demuxer) */
    psz = var_GetString( p_input, "sout" );
    if( *psz )
524
    {
Laurent Aimar's avatar
Laurent Aimar committed
525
526
        p_input->p_sout = sout_NewInstance( p_input, psz );
        if( p_input->p_sout == NULL )
527
528
        {
            msg_Err( p_input, "cannot start stream output instance, aborting" );
Laurent Aimar's avatar
Laurent Aimar committed
529
            free( psz );
530
531
            return VLC_EGENERIC;
        }
532
    }
Laurent Aimar's avatar
Laurent Aimar committed
533
    free( psz );
Christophe Massiot's avatar
Christophe Massiot committed
534

Laurent Aimar's avatar
Laurent Aimar committed
535
    /* Create es out */
536
    p_input->p_es_out = input_EsOutNew( p_input );
537
538
    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 );
539

540
    if( InputSourceInit( p_input, &p_input->input,
Laurent Aimar's avatar
   
Laurent Aimar committed
541
                         p_input->input.p_item->psz_uri, NULL ) )
542
    {
543
        goto error;
Laurent Aimar's avatar
Laurent Aimar committed
544
    }
545

546
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
547
    p_input->i_title = p_input->input.i_title;
548
    p_input->title   = p_input->input.title;
549
550
    p_input->i_title_offset = p_input->input.i_title_offset;
    p_input->i_seekpoint_offset = p_input->input.i_seekpoint_offset;
Laurent Aimar's avatar
Laurent Aimar committed
551
    if( p_input->i_title > 0 )
552
    {
Laurent Aimar's avatar
Laurent Aimar committed
553
554
555
        /* Setup variables */
        input_ControlVarNavigation( p_input );
        input_ControlVarTitle( p_input, 0 );
556
    }
557

Laurent Aimar's avatar
Laurent Aimar committed
558
559
560
561
562
563
564
    /* 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;
565

gbazin's avatar
   
gbazin committed
566
567
    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
gbazin's avatar
   
gbazin committed
568
    var_Get( p_input, "audio-desync", &val );
569
    if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);
gbazin's avatar
   
gbazin committed
570

571
572
573
574
575
    /* 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;

576
    /* Load master infos */
Laurent Aimar's avatar
Laurent Aimar committed
577
    /* Init length */
gbazin's avatar
gbazin committed
578
579
    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
580
581
    {
        var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
582
583

        UpdateItemLength( p_input, val.i_time );
zorglub's avatar
zorglub committed
584
        p_input->input.p_item->i_duration = val.i_time;
Laurent Aimar's avatar
Laurent Aimar committed
585
    }
586
587
588
589
590
591
592
593
594
595
596

    /* Start title/chapter */
    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 );

Laurent Aimar's avatar
Laurent Aimar committed
597
598
599
600
601
602
603
604
605
606
    /* 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 )
607
        {
Laurent Aimar's avatar
Laurent Aimar committed
608
            msg_Warn( p_input, "invalid start-time ignored" );
609
        }
Laurent Aimar's avatar
Laurent Aimar committed
610
        else
611
        {
Laurent Aimar's avatar
Laurent Aimar committed
612
613
614
615
616
617
618
            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 );
619
        }
Laurent Aimar's avatar
Laurent Aimar committed
620
621
622
623
624
    }
    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;
625
626
    }

Sam Hocevar's avatar
   
Sam Hocevar committed
627

Laurent Aimar's avatar
   
Laurent Aimar committed
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;
zorglub's avatar
zorglub committed
634
635
636
637
        float f_requested_fps;

        var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
        var_SetFloat( p_input, "sub-original-fps", f_fps );
Laurent Aimar's avatar
   
Laurent Aimar committed
638

zorglub's avatar
zorglub committed
639
640
        f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
        if( f_requested_fps != f_fps )
Laurent Aimar's avatar
   
Laurent Aimar committed
641
642
        {
            var_Create( p_input, "sub-fps", VLC_VAR_FLOAT| VLC_VAR_DOINHERIT );
zorglub's avatar
zorglub committed
643
            var_SetFloat( p_input, "sub-fps", f_requested_fps );
Laurent Aimar's avatar
   
Laurent Aimar committed
644
645
646
        }
    }

zorglub's avatar
zorglub committed
647
648
649
650
651
652
653
654
    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
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
    /* 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
681
682
                    input_ControlPush( p_input, INPUT_CONTROL_SET_ES,
                                       &list.p_list->p_values[count.i_int] );
Laurent Aimar's avatar
   
Laurent Aimar committed
683
684
685
686
687
688
689
690
691
692
693
694
695
                }
                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;
696

Laurent Aimar's avatar
   
Laurent Aimar committed
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
        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 );
713
714
715
716
717

    /* Look for slave */
    psz = var_GetString( p_input, "input-slave" );
    if( *psz )
    {
zorglub's avatar
zorglub committed
718
719
720
        char *psz_delim;
        input_source_t *slave;
        while( psz && *psz )
721
        {
zorglub's avatar
zorglub committed
722
723
724
725
726
            while( *psz == ' ' || *psz == '#' )
            {
                psz++;
            }
            if( ( psz_delim = strchr( psz, '#' ) ) )
727
728
729
            {
                *psz_delim++ = '\0';
            }
zorglub's avatar
zorglub committed
730
            if( *psz == 0 )
731
            {
zorglub's avatar
zorglub committed
732
                break;
733
734
735
736
737
738
739
740
            }

            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 );
            }
zorglub's avatar
zorglub committed
741
            psz = psz_delim;
742
743
        }
    }
744
    if( psz ) free( psz );
Laurent Aimar's avatar
Laurent Aimar committed
745
746
747

    /* Set up es_out */
    es_out_Control( p_input->p_es_out, ES_OUT_SET_ACTIVE, VLC_TRUE );
748
749
    i_es_out_mode = ES_OUT_MODE_AUTO;
    val.p_list = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
750
751
752
    if( p_input->p_sout )
    {
        var_Get( p_input, "sout-all", &val );
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
        if ( val.b_bool )
        {
            i_es_out_mode = ES_OUT_MODE_ALL;
            val.p_list = NULL;
        }
        else
        {
            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 );
        }
Laurent Aimar's avatar
Laurent Aimar committed
769
    }
770
    es_out_Control( p_input->p_es_out, ES_OUT_SET_MODE, i_es_out_mode );
Laurent Aimar's avatar
Laurent Aimar committed
771

772
    /* Inform the demuxer about waited group (needed only for DVB) */
773
774
775
776
777
778
779
780
781
    if( i_es_out_mode == ES_OUT_MODE_ALL )
    {
        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 );
    }
782
    else
783
    {
784
        demux2_Control( p_input->input.p_demux, DEMUX_SET_GROUP,
785
786
                       (int) var_GetInteger( p_input, "program" ), NULL );
    }
787

Laurent Aimar's avatar
Laurent Aimar committed
788
789
790
791
792
    if( p_input->p_sout )
    {
        if( p_input->p_sout->i_out_pace_nocontrol > 0 )
        {
            p_input->b_out_pace_control = VLC_FALSE;
793
        }
Laurent Aimar's avatar
Laurent Aimar committed
794
795
796
797
798
799
        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" );
800
801
    }

802
    /* Get meta data from users */
803
    p_meta_tmp = InputMetaUser( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
804

805
806
807
    /* Get meta data from master input */
    if( demux2_Control( p_input->input.p_demux, DEMUX_GET_META, &p_meta ) )
        p_meta = NULL;
808

809
810
    /* Merge them */
    if( p_meta == NULL )
gbazin's avatar
gbazin committed
811
    {
812
        p_meta = p_meta_tmp;
gbazin's avatar
gbazin committed
813
    }
814
    else if( p_meta_tmp )
815
    {
816
817
818
819
        vlc_meta_Merge( p_meta, p_meta_tmp );
        vlc_meta_Delete( p_meta_tmp );
    }

820
821
    if( !p_input->input.p_access ||
        access2_Control( p_input->input.p_access, ACCESS_GET_META, &p_meta_tmp))
822
823
824
825
826
827
828
829
830
831
        p_meta_tmp = NULL;

    if( p_meta == NULL )
    {
        p_meta = p_meta_tmp;
    }
    else if( p_meta_tmp )
    {
        vlc_meta_Merge( p_meta, p_meta_tmp );
        vlc_meta_Delete( p_meta_tmp );
832
    }
833

834
835
836
837
    /* 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
838

839
840
        if( !demux2_Control( p_input->slave[i]->p_demux,
                             DEMUX_GET_META, &p_meta_slave ) )
841
        {
842
            if( p_meta == NULL )
843
            {
844
                p_meta = p_meta_slave;
845
            }
846
847
848
849
850
851
852
            else if( p_meta_slave )
            {
                vlc_meta_Merge( p_meta, p_meta_slave );
                vlc_meta_Delete( p_meta_slave );
            }
        }

853
854
        if( p_input->slave[i]->p_access && 
            !access2_Control( p_input->slave[i]->p_access,
855
                              ACCESS_GET_META, &p_meta_slave ) )
856
        {
857
            if( p_meta == NULL )
858
            {
859
860
861
862
863
864
                p_meta = p_meta_slave;
            }
            else if( p_meta_slave )
            {
                vlc_meta_Merge( p_meta, p_meta_slave );
                vlc_meta_Delete( p_meta_slave );
865
866
867
868
            }
        }

    }
869
870
871

    p_input->p_meta = p_meta;
    UpdateMeta( p_input );
872

873
874
    msg_Dbg( p_input, "`%s' sucessfully opened",
             p_input->input.p_item->psz_uri );
875

zorglub's avatar
zorglub committed
876
877
878
879
880
    /* 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 );

881
882
    /* initialization is complete */
    p_input->i_state = PLAYING_S;
883

884
885
    val.i_int = PLAYING_S;
    var_Change( p_input, "state", VLC_VAR_SETVALUE, &val, NULL );
gbazin's avatar
gbazin committed
886

887
    return VLC_SUCCESS;
888

889
890
891
error:
    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );
Laurent Aimar's avatar
Laurent Aimar committed
892

893
894
    if( p_input->p_sout )
        sout_DeleteInstance( p_input->p_sout );
895

896
897
898
899
900
901
    /* 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;
902

903
    return VLC_EGENERIC;
Michel Kaempf's avatar
Michel Kaempf committed
904
905
}

906
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
907
 * Error: RunThread() error loop
908
 *****************************************************************************
Sam Hocevar's avatar
Sam Hocevar committed
909
 * This function is called when an error occurred during thread main's loop.
910
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
911
static void Error( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
912
{
913
    while( !p_input->b_die )
Michel Kaempf's avatar
Michel Kaempf committed
914
    {
915
916
        /* Sleep a while */
        msleep( INPUT_IDLE_SLEEP );
Michel Kaempf's avatar
Michel Kaempf committed
917
918
919
    }
}

920
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
921
 * End: end the input thread
922
 *****************************************************************************/
Laurent Aimar's avatar
Laurent Aimar committed
923
static void End( input_thread_t * p_input )
924
{
Laurent Aimar's avatar
Laurent Aimar committed
925
    vlc_value_t val;
926
    int i;
927

928
    msg_Dbg( p_input, "closing input" );
929

Laurent Aimar's avatar
Laurent Aimar committed
930
931
932
933
934
935
936
937
    /* 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 );
938

939
940
    /* Clean up master */
    InputSourceClean( p_input, &p_input->input );
Laurent Aimar's avatar
Laurent Aimar committed
941

942
943
944
945
946
947
948
    /* 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
949

950
    /* Unload all modules */
Laurent Aimar's avatar
Laurent Aimar committed
951
952
    if( p_input->p_es_out )
        input_EsOutDelete( p_input->p_es_out );
gbazin's avatar
   
gbazin committed
953

954
    /* Close optional stream output instance */
Laurent Aimar's avatar
Laurent Aimar committed
955
    if( p_input->p_sout )
956
    {
957
958
        vlc_object_t *p_pl =
            vlc_object_find( p_input, VLC_OBJECT_PLAYLIST, FIND_ANYWHERE );
959
960
961
962
963
964
        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
965
966
            vlc_object_detach( p_input->p_sout );
            vlc_object_attach( p_input->p_sout, p_pl );
967
968
969
970
        }
        else
        {
            msg_Warn( p_input, "destroying sout" );
Laurent Aimar's avatar
Laurent Aimar committed
971
            sout_DeleteInstance( p_input->p_sout );
972
973
974
        }
        if( p_pl )
            vlc_object_release( p_pl );
975
976
    }

977
978
979
980
    /* Delete meta */
    if( p_input->p_meta )
        vlc_meta_Delete( p_input->p_meta );