input.c 101 KB
Newer Older
1
2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
4
 * Copyright (C) 1998-2007 the VideoLAN team
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
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
dionoea's avatar
dionoea committed
22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
23
 *****************************************************************************/
Michel Kaempf's avatar
Michel Kaempf committed
24

25
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
26
 * Preamble
27
 *****************************************************************************/
28
29
30
31
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif

32
#include <vlc_common.h>
Sam Hocevar's avatar
   
Sam Hocevar committed
33

34
#include <ctype.h>
Christophe Mutricy's avatar
Christophe Mutricy committed
35
#include <limits.h>
36
#include <assert.h>
37

Laurent Aimar's avatar
Laurent Aimar committed
38
#include "input_internal.h"
39

zorglub's avatar
zorglub committed
40
41
#include <vlc_sout.h>
#include "../stream_output/stream_output.h"
Sam Hocevar's avatar
   
Sam Hocevar committed
42

zorglub's avatar
zorglub committed
43
44
45
#include <vlc_interface.h>
#include <vlc_url.h>
#include <vlc_charset.h>
46
#include <vlc_strings.h>
47

48
49
50
51
#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif

52
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
53
 * Local prototypes
54
 *****************************************************************************/
55
56
static void Destructor( input_thread_t * p_input );

ivoire's avatar
ivoire committed
57
58
static  void* Run            ( vlc_object_t *p_this );
static  void* RunAndDestroy  ( vlc_object_t *p_this );
Laurent Aimar's avatar
Laurent Aimar committed
59

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
60
static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
61
                                  const char *, bool, sout_instance_t * );
62
static  int             Init    ( input_thread_t *p_input );
63
static void             WaitDie   ( input_thread_t *p_input );
64
65
static void             End     ( input_thread_t *p_input );
static void             MainLoop( input_thread_t *p_input );
Laurent Aimar's avatar
Laurent Aimar committed
66

67
static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
Laurent Aimar's avatar
Laurent Aimar committed
68
static void       ControlReduce( input_thread_t * );
69
static bool Control( input_thread_t *, int, vlc_value_t );
70

71
72
static int  UpdateFromAccess( input_thread_t * );
static int  UpdateFromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
73

74
static void UpdateItemLength( input_thread_t *, int64_t i_length );
75

76
static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
77
78

static input_source_t *InputSourceNew( input_thread_t *);
Laurent Aimar's avatar
   
Laurent Aimar committed
79
static int  InputSourceInit( input_thread_t *, input_source_t *,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
80
                             const char *, const char *psz_forced_demux );
81
static void InputSourceClean( input_source_t * );
82
83
/* TODO */
//static void InputGetAttachments( input_thread_t *, input_source_t * );
84
85
static void SlaveDemux( input_thread_t *p_input );
static void SlaveSeek( input_thread_t *p_input );
86

87
88
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta );
89
90
static char *InputGetExtraFiles( input_thread_t *p_input,
                                 const char *psz_access, const char *psz_path );
91

92
static void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_demux );
93
static void AccessMeta( input_thread_t * p_input, vlc_meta_t *p_meta );
94
95
96
static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                              int i_new, input_attachment_t **pp_new );

97
98
static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_forced );

99
/*****************************************************************************
100
101
 * 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
102
103
104
105
106
107
108
109
110
111
 *
 * 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
112
 *  - audio-delay, spu-delay
Laurent Aimar's avatar
Laurent Aimar committed
113
114
115
116
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
117
118
 *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown
 *    or not, for that check position != 0.0)
119
 *  - can-pause
120
 *  - can-record (if a stream can be recorded while playing)
121
 *  - teletext-es to get the index of spu track that is teletext --1 if no teletext)
122
 * * For intf callback upon changes:
Laurent Aimar's avatar
Laurent Aimar committed
123
 *  - intf-change
124
 *  - intf-change-vout for when a vout is created or destroyed
125
 *  - rate-change for when playback rate changes
126
 *  - stats-change for when statistics are updated
Laurent Aimar's avatar
Laurent Aimar committed
127
128
 * TODO explain when Callback is called
 * TODO complete this list (?)
129
 *****************************************************************************/
130
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
131
                               const char *psz_header, bool b_quick,
132
                               sout_instance_t *p_sout )
Michel Kaempf's avatar
Michel Kaempf committed
133
{
134
    static const char input_name[] = "input";
135
    input_thread_t *p_input = NULL;                 /* thread descriptor */
136
137
    vlc_value_t val;
    int i;
138

139
    /* Allocate descriptor */
140
141
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
                                 VLC_OBJECT_INPUT, input_name );
142
    if( p_input == NULL )
143
        return NULL;
144
145
146
147
148
149

    /* Construct a nice name for the input timer */
    char psz_timer_name[255];
    char * psz_name = input_item_GetName( p_item );
    snprintf( psz_timer_name, sizeof(psz_timer_name),
              "input launching for '%s'", psz_name );
150
151
152

    msg_Dbg( p_input, "Creating an input for '%s'", psz_name);

153
154
155
156
157
158
159
    free( psz_name );

    /* Start a timer to mesure how long it takes
     * to launch an input */
    stats_TimerStart( p_input, psz_timer_name,
        STATS_TIMER_INPUT_LAUNCHING );

zorglub's avatar
zorglub committed
160
    MALLOC_NULL( p_input->p, input_thread_private_t );
Rafaël Carré's avatar
Rafaël Carré committed
161
    memset( p_input->p, 0, sizeof( input_thread_private_t ) );
162
163
164

    /* One "randomly" selected input thread is responsible for computing
     * the global stats. Check if there is already someone doing this */
165
    if( p_input->p_libvlc->p_stats && !b_quick )
166
    {
167
        libvlc_priv_t *p_private = libvlc_priv( p_input->p_libvlc );
168
        vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
169
170
        if( p_private->p_stats_computer == NULL )
            p_private->p_stats_computer = p_input;
171
        vlc_mutex_unlock( &p_input->p_libvlc->p_stats->lock );
172
173
    }

174
    p_input->b_preparsing = b_quick;
175
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
176

177
    /* Init events */
178
179
180
    vlc_event_manager_t * p_em = &p_input->p->event_manager;
    vlc_event_manager_init_with_vlc_object( p_em, p_input );
    vlc_event_manager_register_event_type( p_em, vlc_InputStateChanged );
181
    vlc_event_manager_register_event_type( p_em, vlc_InputSelectedStreamChanged );
182

Laurent Aimar's avatar
Laurent Aimar committed
183
    /* Init Common fields */
184
185
    p_input->b_eof = false;
    p_input->b_can_pace_control = true;
zorglub's avatar
zorglub committed
186
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
187
    p_input->i_time  = 0;
zorglub's avatar
zorglub committed
188
    p_input->p->i_stop  = 0;
189
    p_input->p->i_run  = 0;
zorglub's avatar
zorglub committed
190
191
192
    p_input->p->i_title = 0;
    p_input->p->title   = NULL;
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
193
    p_input->i_state = INIT_S;
zorglub's avatar
zorglub committed
194
    p_input->p->i_rate  = INPUT_RATE_DEFAULT;
195
    p_input->p->b_recording = false;
196
197
    TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
zorglub's avatar
zorglub committed
198
199
    p_input->p->p_es_out = NULL;
    p_input->p->p_sout  = NULL;
200
    p_input->p->b_out_pace_control = false;
Laurent Aimar's avatar
Laurent Aimar committed
201
202
203
    p_input->i_pts_delay = 0;

    /* Init Input fields */
Pierre's avatar
Pierre committed
204
    vlc_gc_incref( p_item ); /* Released in Destructor() */
zorglub's avatar
zorglub committed
205
206
207
208
    p_input->p->input.p_item = p_item;
    p_input->p->input.p_access = NULL;
    p_input->p->input.p_stream = NULL;
    p_input->p->input.p_demux  = NULL;
209
    p_input->p->input.b_title_demux = false;
zorglub's avatar
zorglub committed
210
211
212
    p_input->p->input.i_title  = 0;
    p_input->p->input.title    = NULL;
    p_input->p->input.i_title_offset = p_input->p->input.i_seekpoint_offset = 0;
213
214
215
216
    p_input->p->input.b_can_pace_control = true;
    p_input->p->input.b_can_rate_control = true;
    p_input->p->input.b_rescale_ts = true;
    p_input->p->input.b_eof = false;
zorglub's avatar
zorglub committed
217
218
    p_input->p->input.i_cr_average = 0;

219
    vlc_mutex_lock( &p_item->lock );
220
221

    if( !p_item->p_stats )
222
223
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
zorglub's avatar
zorglub committed
224

225
    /* No slave */
zorglub's avatar
zorglub committed
226
227
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
228

Laurent Aimar's avatar
Laurent Aimar committed
229
    /* Init control buffer */
230
    vlc_mutex_init( &p_input->p->lock_control );
231
    vlc_cond_init( &p_input->p->wait_control );
zorglub's avatar
zorglub committed
232
    p_input->p->i_control = 0;
233

gbazin's avatar
   
gbazin committed
234
    /* Parse input options */
235
    vlc_mutex_lock( &p_item->lock );
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
236
    assert( (int)p_item->optflagc == p_item->i_options );
237
    for( i = 0; i < p_item->i_options; i++ )
238
239
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
240
    vlc_mutex_unlock( &p_item->lock );
gbazin's avatar
   
gbazin committed
241

Laurent Aimar's avatar
Laurent Aimar committed
242
243
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
244

Laurent Aimar's avatar
Laurent Aimar committed
245
    /* Create Objects variables for public Get and Set */
246
    input_ControlVarInit( p_input );
247

248
    /* */
zorglub's avatar
zorglub committed
249
    p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
gbazin's avatar
gbazin committed
250

251
    if( !p_input->b_preparsing )
gbazin's avatar
gbazin committed
252
    {
253
254
        var_Get( p_input, "bookmarks", &val );
        if( val.psz_string )
gbazin's avatar
gbazin committed
255
        {
256
257
258
259
            /* 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, '{' ) ) )
gbazin's avatar
gbazin committed
260
            {
hartman's avatar
hartman committed
261
                 seekpoint_t *p_seekpoint;
262
263
264
265
266
267
268
269
                 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 = ',';
hartman's avatar
hartman committed
270
271

                 p_seekpoint = vlc_seekpoint_New();
272
273
274
275
276
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
277
                         p_seekpoint->psz_name = strdup(psz_start + 5);
278
279
280
281
282
283
284
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
zorglub's avatar
zorglub committed
285
286
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
                                                        1000000;
287
288
                     }
                     psz_start = psz_end + 1;
gbazin's avatar
gbazin committed
289
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
290
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
291
292
293
294
295
                                  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 );
                *psz_parser = backup;
gbazin's avatar
gbazin committed
296
            }
297
            free( val.psz_string );
gbazin's avatar
gbazin committed
298
299
300
        }
    }

301
    /* Remove 'Now playing' info as it is probably outdated */
302
    input_item_SetNowPlaying( p_item, NULL );
303

304
305
306
307
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

308
309
310
311
    /* */
    if( p_sout )
        p_input->p->p_sout = p_sout;

312
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
313
    vlc_mutex_init( &p_input->p->counters.counters_lock );
314

315
316
317
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

318
319
320
    /* Attach only once we are ready */
    vlc_object_attach( p_input, p_parent );

321
322
323
    return p_input;
}

324
325
326
327
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
328
{
329
330
331
332
333
334
#ifndef NDEBUG
    char * psz_name = input_item_GetName( p_input->p->input.p_item );
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

335
336
    vlc_event_manager_fini( &p_input->p->event_manager );

337
338
    stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
    stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
339
#ifdef ENABLE_SOUT
340
341
    if( p_input->p->p_sout )
        sout_DeleteInstance( p_input->p->p_sout );
342
#endif
Pierre's avatar
Pierre committed
343
344
    vlc_gc_decref( p_input->p->input.p_item );

345
346
    vlc_mutex_destroy( &p_input->p->counters.counters_lock );

347
    vlc_cond_destroy( &p_input->p->wait_control );
348
349
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
350
}
351

352
/**
353
354
 * Initialize an input thread and run it. You will need to monitor the
 * thread to clean up after it is done
355
356
357
358
359
360
361
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \return a pointer to the spawned input thread
 */
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
362
{
363
    return __input_CreateThreadExtended( p_parent, p_item, NULL, NULL );
364
365
}

366
367
368
369
/* */
input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
                                              input_item_t *p_item,
                                              const char *psz_log, sout_instance_t *p_sout )
370
{
371
    input_thread_t *p_input;
372

373
    p_input = Create( p_parent, p_item, psz_log, false, p_sout );
374
375
376
    if( !p_input )
        return NULL;

Sam Hocevar's avatar
Sam Hocevar committed
377
    /* Create thread and wait for its readiness. */
Laurent Aimar's avatar
Laurent Aimar committed
378
    if( vlc_thread_create( p_input, "input", Run,
379
                           VLC_THREAD_PRIORITY_INPUT, false ) )
Michel Kaempf's avatar
Michel Kaempf committed
380
    {
381
        input_ChangeState( p_input, ERROR_S );
382
        msg_Err( p_input, "cannot create input thread" );
383
384
        vlc_object_detach( p_input );
        vlc_object_release( p_input );
385
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
386
    }
387

388
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
389
390
}

391
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
392
 * Initialize an input thread and run it. This thread will clean after itself,
393
394
395
396
397
 * you can forget about it. It can work either in blocking or non-blocking mode
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \param b_block should we block until read is finished ?
398
 * \return an error code, VLC_SUCCESS on success
399
 */
400
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
401
                   bool b_block )
402
{
403
    input_thread_t *p_input;
404

405
    p_input = Create( p_parent, p_item, NULL, false, NULL );
406
    if( !p_input )
407
408
        return VLC_EGENERIC;

409
    if( b_block )
410
    {
ivoire's avatar
ivoire committed
411
        RunAndDestroy( VLC_OBJECT(p_input) );
zorglub's avatar
zorglub committed
412
        return VLC_SUCCESS;
413
    }
414
    else
415
    {
416
        if( vlc_thread_create( p_input, "input", RunAndDestroy,
417
                               VLC_THREAD_PRIORITY_INPUT, false ) )
418
        {
419
            input_ChangeState( p_input, ERROR_S );
420
            msg_Err( p_input, "cannot create input thread" );
421
            vlc_object_release( p_input );
zorglub's avatar
zorglub committed
422
            return VLC_EGENERIC;
423
        }
424
    }
425
    return VLC_SUCCESS;
426
}
427

428
429
430
431
432
433
434
435
436
437
/**
 * Initialize an input and initialize it to preparse the item
 * This function is blocking. It will only accept to parse files
 *
 * \param p_parent a vlc_object_t
 * \param p_item an input item
 * \return VLC_SUCCESS or an error
 */
int __input_Preparse( vlc_object_t *p_parent, input_item_t *p_item )
{
438
    input_thread_t *p_input;
439

440
    /* Allocate descriptor */
441
    p_input = Create( p_parent, p_item, NULL, true, NULL );
442
443
444
    if( !p_input )
        return VLC_EGENERIC;

445
446
    if( !Init( p_input ) )
        End( p_input );
447

448
449
    vlc_object_detach( p_input );
    vlc_object_release( p_input );
450
451
452
453

    return VLC_SUCCESS;
}

454
455
456
457
458
/**
 * Request a running input thread to stop and die
 *
 * \param the input thread to stop
 */
459
static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
Michel Kaempf's avatar
Michel Kaempf committed
460
{
Laurent Aimar's avatar
Laurent Aimar committed
461
462
    vlc_list_t *p_list;
    int i;
463
464
465
466
467
468

    if( p_obj->i_object_type == VLC_OBJECT_VOUT ||
        p_obj->i_object_type == VLC_OBJECT_AOUT ||
        p_obj == VLC_OBJECT(p_input->p->p_sout) )
        return;

469
    vlc_object_kill( p_obj );
470

471
    p_list = vlc_list_children( p_obj );
Laurent Aimar's avatar
Laurent Aimar committed
472
    for( i = 0; i < p_list->i_count; i++ )
473
        ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
Laurent Aimar's avatar
Laurent Aimar committed
474
    vlc_list_release( p_list );
475
476
477
478
479
480
}
void input_StopThread( input_thread_t *p_input )
{
    /* Set die for input and ALL of this childrens (even (grand-)grand-childrens)
     * It is needed here even if it is done in INPUT_CONTROL_SET_DIE handler to
     * unlock the control loop */
481
    ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
Michel Kaempf's avatar
Michel Kaempf committed
482

Laurent Aimar's avatar
Laurent Aimar committed
483
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
   
Sam Hocevar committed
484
485
}

486
487
sout_instance_t * input_DetachSout( input_thread_t *p_input )
{
488
489
490
491
    sout_instance_t *p_sout = p_input->p->p_sout;
    vlc_object_detach( p_sout );
    p_input->p->p_sout = NULL;
    return p_sout;
492
493
}

494
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
495
 * Run: main thread loop
496
497
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
498
 *****************************************************************************/
ivoire's avatar
ivoire committed
499
static void* Run( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
500
{
ivoire's avatar
ivoire committed
501
    input_thread_t *p_input = (input_thread_t *)p_this;
502
    const int canc = vlc_savecancel();
503

504
    if( Init( p_input ) )
Sam Hocevar's avatar
   
Sam Hocevar committed
505
506
    {
        /* If we failed, wait before we are killed, and exit */
507
        WaitDie( p_input );
508
        goto exit;
Sam Hocevar's avatar
   
Sam Hocevar committed
509
    }
Michel Kaempf's avatar
Michel Kaempf committed
510

511
512
    MainLoop( p_input );

513
    /* Wait until we are asked to die */
514
    if( !p_input->b_die )
515
        WaitDie( p_input );
516
517
518

    /* Clean up */
    End( p_input );
519
520
521

exit:
    p_input->b_dead = true;
522
    vlc_restorecancel( canc );
ivoire's avatar
ivoire committed
523
    return NULL;
524
525
526
}

/*****************************************************************************
527
 * RunAndDestroy: main thread loop
528
529
530
 * This is the "just forget me" thread that spawns the input processing chain,
 * reads the stream, cleans up and releases memory
 *****************************************************************************/
ivoire's avatar
ivoire committed
531
static void* RunAndDestroy( vlc_object_t *p_this )
532
{
ivoire's avatar
ivoire committed
533
    input_thread_t *p_input = (input_thread_t *)p_this;
534
    const int canc = vlc_savecancel();
535

536
    if( Init( p_input ) )
537
        goto exit;
538
539
540
541
542
543

    MainLoop( p_input );

    /* Clean up */
    End( p_input );

544
exit:
545
    /* Release memory */
546
    vlc_object_release( p_input );
547
548
    vlc_restorecancel( canc );
    return NULL;
549
550
551
552
553
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
554
555
556
557
558
559

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t *pi_start_mdate )
560
{
561
    int i_ret;
562

563
    *pb_changed = false;
564

565
566
567
568
569
570
571
    if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) ||
        ( p_input->p->i_run > 0 && *pi_start_mdate+p_input->p->i_run < mdate() ) )
        i_ret = 0; /* EOF */
    else
        i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);

    if( i_ret > 0 )
Sam Hocevar's avatar
   
Sam Hocevar committed
572
    {
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
        /* TODO */
        if( p_input->p->input.b_title_demux &&
            p_input->p->input.p_demux->info.i_update )
        {
            i_ret = UpdateFromDemux( p_input );
            *pb_changed = true;
        }
        else if( !p_input->p->input.b_title_demux &&
                  p_input->p->input.p_access &&
                  p_input->p->input.p_access->info.i_update )
        {
            i_ret = UpdateFromAccess( p_input );
            *pb_changed = true;
        }
    }
588

589
590
591
592
593
594
    if( i_ret == 0 )    /* EOF */
    {
        vlc_value_t repeat;

        var_Get( p_input, "input-repeat", &repeat );
        if( repeat.i_int == 0 )
595
        {
596
597
598
599
600
601
602
603
            /* 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->p->input.b_eof = true;
        }
        else
        {
            vlc_value_t val;
604

605
606
607
            msg_Dbg( p_input, "repeating the same input (%d)",
                     repeat.i_int );
            if( repeat.i_int > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
608
            {
609
610
                repeat.i_int--;
                var_Set( p_input, "input-repeat", repeat );
Laurent Aimar's avatar
Laurent Aimar committed
611
            }
612

613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
            /* Seek to start title/seekpoint */
            val.i_int = p_input->p->input.i_title_start -
                p_input->p->input.i_title_offset;
            if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title )
                val.i_int = 0;
            input_ControlPush( p_input,
                               INPUT_CONTROL_SET_TITLE, &val );

            val.i_int = p_input->p->input.i_seekpoint_start -
                p_input->p->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 */
            if( p_input->p->i_start > 0 )
Laurent Aimar's avatar
Laurent Aimar committed
629
            {
630
631
632
                val.i_time = p_input->p->i_start;
                input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                   &val );
633
            }
634
            else
Laurent Aimar's avatar
Laurent Aimar committed
635
            {
636
637
638
                val.f_float = 0.0;
                input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                   &val );
Laurent Aimar's avatar
Laurent Aimar committed
639
            }
640

641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
            /* */
            *pi_start_mdate = mdate();
        }
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
    {
        SlaveDemux( p_input );
    }
}

/**
 * MainLoopInterface
 * It update the variables used by the interfaces
 */
static void MainLoopInterface( input_thread_t *p_input )
{
    vlc_value_t val;
    double f_pos;
    int64_t i_time, i_length;

    /* update input status variables */
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_POSITION, &f_pos ) )
    {
        val.f_float = (float)f_pos;
        var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
    }
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_TIME, &i_time ) )
    {
        p_input->i_time = i_time;
        val.i_time = i_time;
        var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
    }
    if( !demux_Control( p_input->p->input.p_demux,
                         DEMUX_GET_LENGTH, &i_length ) )
    {
        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 );

        if( old_val.i_time != val.i_time )
        {
            UpdateItemLength( p_input, i_length );
        }
    }

    var_SetBool( p_input, "intf-change", true );
}

/**
 * MainLoopStatistic
 * It updates the globals statics
 */
static void MainLoopStatistic( input_thread_t *p_input )
{
    stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
    /* Are we the thread responsible for computing global stats ? */
    if( libvlc_priv( p_input->p_libvlc )->p_stats_computer == p_input )
    {
        stats_ComputeGlobalStats( p_input->p_libvlc,
                                  p_input->p_libvlc->p_stats );
    }
710
    var_SetBool( p_input, "stats-change", true );
711
712
713
714
715
716
717
718
719
}

/**
 * MainLoop
 * The main input loop.
 */
static void MainLoop( input_thread_t *p_input )
{
    mtime_t i_start_mdate = mdate();
720
721
    mtime_t i_intf_update = 0;
    mtime_t i_statistic_update = 0;
722
723
724
725
726
727
728
729
730

    /* Start the timer */
    stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING );

    while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
    {
        bool b_force_update;
        int i_type;
        vlc_value_t val;
731
        mtime_t i_current;
732
        mtime_t i_deadline;
733
        mtime_t i_wakeup;
734
        bool b_paused;
735

736
737
        /* Demux data */
        b_force_update = false;
738
        i_wakeup = 0;
739
740
741
742
        b_paused = p_input->i_state == PAUSE_S &&
                   !input_EsOutIsBuffering( p_input->p->p_es_out );

        if( !b_paused )
743
        {
744
            MainLoopDemux( p_input, &b_force_update, &i_start_mdate );
745
746
            i_wakeup = input_EsOutGetWakeup( p_input->p->p_es_out );
        }
747
748

        /* */
749
750
        do {
            i_deadline = i_wakeup;
751
            if( b_paused )
752
753
754
755
756
757
758
759
760
761
762
763
                i_deadline = __MIN( i_intf_update, i_statistic_update );

            /* Handle control */
            vlc_mutex_lock( &p_input->p->lock_control );
            ControlReduce( p_input );
            while( !ControlPopNoLock( p_input, &i_type, &val, i_deadline ) )
            {
                msg_Dbg( p_input, "control type=%d", i_type );
                if( Control( p_input, i_type, val ) )
                    b_force_update = true;
            }
            vlc_mutex_unlock( &p_input->p->lock_control );
764

765
766
767
768
769
770
771
772
773
774
775
776
777
            /* Update interface and statistics */
            i_current = mdate();
            if( i_intf_update < i_current || b_force_update )
            {
                MainLoopInterface( p_input );
                i_intf_update = i_current + INT64_C(250000);
                b_force_update = false;
            }
            if( i_statistic_update < i_current )
            {
                MainLoopStatistic( p_input );
                i_statistic_update = i_current + INT64_C(1000000);
            }
778
779
780
781
782
783
784
785

            /* Check if i_wakeup is still valid */
            if( i_wakeup != 0 )
            {
                mtime_t i_new_wakeup = input_EsOutGetWakeup( p_input->p->p_es_out );
                if( !i_new_wakeup )
                    i_wakeup = 0;
            }
786
        } while( i_current < i_wakeup );
Laurent Aimar's avatar
Laurent Aimar committed
787
    }
788
789
790
791

    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
    {
        /* We have finish to demux data but not to play them */
792
        while( vlc_object_alive( p_input ) )
793
        {
794
            if( input_EsOutDecodersIsEmpty( p_input->p->p_es_out ) )
795
796
797
798
799
800
801
802
803
804
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }

        /* We have finished */
        input_ChangeState( p_input, END_S );
    }
805
806
}

807
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
808
{
809
    if( p_input->b_preparsing ) return;
810

811
812
813
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
814
    if( libvlc_stats( p_input ) )
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
    {
        INIT_COUNTER( read_bytes, INTEGER, COUNTER );
        INIT_COUNTER( read_packets, INTEGER, COUNTER );
        INIT_COUNTER( demux_read, INTEGER, COUNTER );
        INIT_COUNTER( input_bitrate, FLOAT, DERIVATIVE );
        INIT_COUNTER( demux_bitrate, FLOAT, DERIVATIVE );
        INIT_COUNTER( played_abuffers, INTEGER, COUNTER );
        INIT_COUNTER( lost_abuffers, INTEGER, COUNTER );
        INIT_COUNTER( displayed_pictures, INTEGER, COUNTER );
        INIT_COUNTER( lost_pictures, INTEGER, COUNTER );
        INIT_COUNTER( decoded_audio, INTEGER, COUNTER );
        INIT_COUNTER( decoded_video, INTEGER, COUNTER );
        INIT_COUNTER( decoded_sub, INTEGER, COUNTER );
        p_input->p->counters.p_sout_send_bitrate = NULL;
        p_input->p->counters.p_sout_sent_packets = NULL;
        p_input->p->counters.p_sout_sent_bytes = NULL;
        if( p_input->p->counters.p_demux_bitrate )
            p_input->p->counters.p_demux_bitrate->update_interval = 1000000;
        if( p_input->p->counters.p_input_bitrate )
            p_input->p->counters.p_input_bitrate->update_interval = 1000000;
835
    }
836
}
837

838
#ifdef ENABLE_SOUT
839
840
841
842
843
844
845
846
847
static int InitSout( input_thread_t * p_input )
{
    char *psz;

    if( p_input->b_preparsing ) return VLC_SUCCESS;

    /* Find a usable sout and attach it to p_input */
    psz = var_GetNonEmptyString( p_input, "sout" );
    if( psz && strncasecmp( p_input->p->input.p_item->psz_uri, "vlc:", 4 ) )
848
    {
849
850
        /* Check the validity of the provided sout */
        if( p_input->p->p_sout )
zorglub's avatar
zorglub committed
851
        {
852
            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
853
            {
854
                msg_Dbg( p_input, "destroying unusable sout" );
855

856
857
                sout_DeleteInstance( p_input->p->p_sout );
                p_input->p->p_sout = NULL;
858
            }
859
        }
860

861
862
863
864
865
866
867
868
869
870
871
872
873
        if( p_input->p->p_sout )
        {
            /* Reuse it */
            msg_Dbg( p_input, "sout keep: reusing sout" );
            msg_Dbg( p_input, "sout keep: you probably want to use "
                              "gather stream_out" );
            vlc_object_attach( p_input->p->p_sout, p_input );
        }
        else
        {
            /* Create a new one */
            p_input->p->p_sout = sout_NewInstance( p_input, psz );
            if( !p_input->p->p_sout )
zorglub's avatar
zorglub committed
874
            {
875
876
877
878
879
                input_ChangeState( p_input, ERROR_S );
                msg_Err( p_input, "cannot start stream output instance, " \
                                  "aborting" );
                free( psz );
                return VLC_EGENERIC;
zorglub's avatar
zorglub committed
880
            }
881
        }
882
        if( libvlc_stats( p_input ) )
883
        {
884
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
885
            INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
886
887
888
889
            INIT_COUNTER( sout_send_bitrate, FLOAT, DERIVATIVE );
            if( p_input->p->counters.p_sout_send_bitrate )
                 p_input->p->counters.p_sout_send_bitrate->update_interval =
                         1000000;
890
        }
891
    }
892
    else if( p_input->p->p_sout )
893
    {
894
895
896
897
        msg_Dbg( p_input, "destroying useless sout" );

        sout_DeleteInstance( p_input->p->p_sout );
        p_input->p->p_sout = NULL;
Laurent Aimar's avatar
Laurent Aimar committed
898
    }
899
    free( psz );
900

901
902
    return VLC_SUCCESS;
}
903
#endif
904

905
906
907
static void InitTitle( input_thread_t * p_input )
{
    vlc_value_t val;
Laurent Aimar's avatar
Laurent Aimar committed
908

909
    if( p_input->b_preparsing ) return;
910

911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
    /* Create global title (from master) */
    p_input->p->i_title = p_input->p->input.i_title;
    p_input->p->title   = p_input->p->input.title;
    p_input->p->i_title_offset = p_input->p->input.i_title_offset;
    p_input->p->i_seekpoint_offset = p_input->p->input.i_seekpoint_offset;
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
        input_ControlVarTitle( p_input, 0 );
    }

    /* Global flag */
    p_input->b_can_pace_control = p_input->p->input.b_can_pace_control;
    p_input->p->b_can_pause        = p_input->p->input.b_can_pause;
    p_input->p->b_can_rate_control = p_input->p->input.b_can_rate_control;

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

    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
    var_Get( p_input, "audio-desync", &val );
935
936
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
937
938
939
940
941
942

    /* Update cr_average depending on the caching */
    p_input->p->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
    p_input->p->input.i_cr_average /= 10;
    if( p_input->p->input.i_cr_average < 10 ) p_input->p->input.i_cr_average = 10;
}
gbazin's avatar
   
gbazin committed
943

944
945
946
947
static void StartTitle( input_thread_t * p_input )
{
    double f_fps;
    vlc_value_t val;
948
    int i_delay;
949
950
    char *psz;
    char *psz_subtitle;
951
    int64_t i_length;
952

953
954
955
    /* Start title/chapter */

    if( p_input->b_preparsing )
Laurent Aimar's avatar
Laurent Aimar committed
956
    {
957
958
        p_input->p->i_start = 0;
        return;
Laurent Aimar's avatar
Laurent Aimar committed
959
    }
960
961
962
963
964
965
966
967
968
969
970
971

    val.i_int = p_input->p->input.i_title_start -
                p_input->p->input.i_title_offset;
    if( val.i_int > 0 && val.i_int < p_input->p->input.i_title )
        input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
    val.i_int = p_input->p->input.i_seekpoint_start -
                p_input->p->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 */
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
972
973
974
    p_input->p->i_start = INT64_C(1000000) * var_GetInteger( p_input, "start-time" );
    p_input->p->i_stop  = INT64_C(1000000) * var_GetInteger( p_input, "stop-time" );
    p_input->p->i_run   = INT64_C(1000000) * var_GetInteger( p_input, "run-time" );
975
    i_length = var_GetTime( p_input, "length" );
976
    if( p_input->p->i_run < 0 )
977
    {