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
#include "es_out.h"
40

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

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

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

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

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

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

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

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

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

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

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

88
89
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 );
90
91
static char *InputGetExtraFiles( input_thread_t *p_input,
                                 const char *psz_access, const char *psz_path );
92

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

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

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

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

    /* 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 );
151
152
153

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

154
155
156
157
158
159
160
    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
161
    MALLOC_NULL( p_input->p, input_thread_private_t );
Rafaël Carré's avatar
Rafaël Carré committed
162
    memset( p_input->p, 0, sizeof( input_thread_private_t ) );
163
164
165

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

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

178
    /* Init events */
179
180
181
    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 );
182
    vlc_event_manager_register_event_type( p_em, vlc_InputSelectedStreamChanged );
183

Laurent Aimar's avatar
Laurent Aimar committed
184
    /* Init Common fields */
185
186
    p_input->b_eof = false;
    p_input->b_can_pace_control = true;
zorglub's avatar
zorglub committed
187
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
188
    p_input->i_time  = 0;
zorglub's avatar
zorglub committed
189
    p_input->p->i_stop  = 0;
190
    p_input->p->i_run  = 0;
zorglub's avatar
zorglub committed
191
192
193
    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
194
    p_input->i_state = INIT_S;
zorglub's avatar
zorglub committed
195
    p_input->p->i_rate  = INPUT_RATE_DEFAULT;
196
    p_input->p->b_recording = false;
197
198
    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
199
200
    p_input->p->p_es_out = NULL;
    p_input->p->p_sout  = NULL;
201
    p_input->p->b_out_pace_control = false;
Laurent Aimar's avatar
Laurent Aimar committed
202
203
204
    p_input->i_pts_delay = 0;

    /* Init Input fields */
Pierre's avatar
Pierre committed
205
    vlc_gc_incref( p_item ); /* Released in Destructor() */
zorglub's avatar
zorglub committed
206
207
208
209
    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;
210
    p_input->p->input.b_title_demux = false;
zorglub's avatar
zorglub committed
211
212
213
    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;
214
215
216
217
    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
218
219
    p_input->p->input.i_cr_average = 0;

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

322
323
324
    return p_input;
}

325
326
327
328
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
329
{
330
331
332
333
334
335
#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

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

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

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

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

353
/**
354
355
 * Initialize an input thread and run it. You will need to monitor the
 * thread to clean up after it is done
356
357
358
359
360
361
362
 *
 * \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 )
363
{
364
    return __input_CreateThreadExtended( p_parent, p_item, NULL, NULL );
365
366
}

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

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

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

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

392
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
393
 * Initialize an input thread and run it. This thread will clean after itself,
394
395
396
397
398
 * 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 ?
399
 * \return an error code, VLC_SUCCESS on success
400
 */
401
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
402
                   bool b_block )
403
{
404
    input_thread_t *p_input;
405

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

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

429
430
431
432
433
434
435
436
437
438
/**
 * 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 )
{
439
    input_thread_t *p_input;
440

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

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

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

    return VLC_SUCCESS;
}

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

    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;

470
    vlc_object_kill( p_obj );
471

472
    p_list = vlc_list_children( p_obj );
Laurent Aimar's avatar
Laurent Aimar committed
473
    for( i = 0; i < p_list->i_count; i++ )
474
        ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
Laurent Aimar's avatar
Laurent Aimar committed
475
    vlc_list_release( p_list );
476
477
478
479
480
481
}
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 */
482
    ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
Michel Kaempf's avatar
Michel Kaempf committed
483

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

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

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

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

512
513
    MainLoop( p_input );

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

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

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

/*****************************************************************************
528
 * RunAndDestroy: main thread loop
529
530
531
 * 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
532
static void* RunAndDestroy( vlc_object_t *p_this )
533
{
ivoire's avatar
ivoire committed
534
    input_thread_t *p_input = (input_thread_t *)p_this;
535
    const int canc = vlc_savecancel();
536

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

    MainLoop( p_input );

    /* Clean up */
    End( p_input );

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

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

/**
 * 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 )
561
{
562
    int i_ret;
563

564
    *pb_changed = false;
565

566
567
568
569
570
571
572
    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
573
    {
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
        /* 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;
        }
    }
589

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

        var_Get( p_input, "input-repeat", &repeat );
        if( repeat.i_int == 0 )
596
        {
597
598
599
600
601
602
603
604
            /* 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;
605

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

614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
            /* 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
630
            {
631
632
633
                val.i_time = p_input->p->i_start;
                input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                   &val );
634
            }
635
            else
Laurent Aimar's avatar
Laurent Aimar committed
636
            {
637
638
639
                val.f_float = 0.0;
                input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                   &val );
Laurent Aimar's avatar
Laurent Aimar committed
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
710
            /* */
            *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 );
    }
711
    var_SetBool( p_input, "stats-change", true );
712
713
714
715
716
717
718
719
720
}

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

    /* 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;
732
        mtime_t i_current;
733
        mtime_t i_deadline;
734
        mtime_t i_wakeup;
735
        bool b_paused;
736

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

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

        /* */
750
751
        do {
            i_deadline = i_wakeup;
752
            if( b_paused )
753
754
755
756
757
758
759
760
761
762
763
764
                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 );
765

766
767
768
769
770
771
772
773
774
775
776
777
778
            /* 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);
            }
779
780
781
782
783
784
785
786

            /* 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;
            }
787
        } while( i_current < i_wakeup );
Laurent Aimar's avatar
Laurent Aimar committed
788
    }
789
790
791
792

    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 */
793
        while( vlc_object_alive( p_input ) )
794
        {
795
            if( input_EsOutDecodersIsEmpty( p_input->p->p_es_out ) )
796
797
798
799
800
801
802
803
804
805
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }

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

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

812
813
814
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
815
    if( libvlc_stats( p_input ) )
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
    {
        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;
836
    }
837
}
838

839
#ifdef ENABLE_SOUT
840
841
842
843
844
845
846
847
848
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 ) )
849
    {
850
851
        /* Check the validity of the provided sout */
        if( p_input->p->p_sout )
zorglub's avatar
zorglub committed
852
        {
853
            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
854
            {
855
                msg_Dbg( p_input, "destroying unusable sout" );
856

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

862
863
864
865
866
867
868
869
870
871
872
873
874
        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
875
            {
876
877
878
879
880
                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
881
            }
882
        }
883
        if( libvlc_stats( p_input ) )
884
        {
885
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
886
            INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
887
888
889
890
            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;
891
        }
892
    }
893
    else if( p_input->p->p_sout )
894
    {
895
896
897
898
        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
899
    }
900
    free( psz );
901

902
903
    return VLC_SUCCESS;
}
904
#endif
905

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

910
    if( p_input->b_preparsing ) return;
911

912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
    /* 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 );
936
937
    if( val.i_int < 0 )
        p_input->i_pts_delay -= (val.i_int * 1000);
938
939
940
941
942
943

    /* 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
944

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

954
955
956
    /* Start title/chapter */

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

    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
973
974
975
    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" );
976
    i_length = var_GetTime( p_input, "length" );
977
    if( p_input->p->i_run < 0 )