input.c 98 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>
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
Antoine Cellerier's avatar
Antoine Cellerier 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

38
#include "input_internal.h"
39

Clément Stenac's avatar
Clément Stenac committed
40 41
#include <vlc_sout.h>
#include "../stream_output/stream_output.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
42

Clément Stenac's avatar
Clément Stenac 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 );

57 58
static  void* Run            ( vlc_object_t *p_this );
static  void* RunAndDestroy  ( vlc_object_t *p_this );
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 );
66 67 68

static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
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 void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_demux );
91
static void AccessMeta( input_thread_t * p_input, vlc_meta_t *p_meta );
92 93 94
static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                              int i_new, input_attachment_t **pp_new );

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

133
    /* Allocate descriptor */
134 135
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
                                 VLC_OBJECT_INPUT, input_name );
136
    if( p_input == NULL )
137
        return NULL;
138 139 140 141 142 143

    /* 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 );
144 145 146

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

147 148 149 150 151 152 153
    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 );

Clément Stenac's avatar
Clément Stenac committed
154
    MALLOC_NULL( p_input->p, input_thread_private_t );
Rafaël Carré's avatar
Rafaël Carré committed
155
    memset( p_input->p, 0, sizeof( input_thread_private_t ) );
156 157 158

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

168
    p_input->b_preparsing = b_quick;
169
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
170

171
    /* Init events */
172 173 174
    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 );
175
    vlc_event_manager_register_event_type( p_em, vlc_InputSelectedStreamChanged );
176

177
    /* Init Common fields */
178 179
    p_input->b_eof = false;
    p_input->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
180
    p_input->p->i_start = 0;
181
    p_input->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
182
    p_input->p->i_stop  = 0;
183
    p_input->p->i_run  = 0;
Clément Stenac's avatar
Clément Stenac committed
184 185 186
    p_input->p->i_title = 0;
    p_input->p->title   = NULL;
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
187
    p_input->i_state = INIT_S;
Clément Stenac's avatar
Clément Stenac committed
188
    p_input->p->i_rate  = INPUT_RATE_DEFAULT;
189
    p_input->p->b_recording = false;
190 191
    TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
Clément Stenac's avatar
Clément Stenac committed
192 193
    p_input->p->p_es_out = NULL;
    p_input->p->p_sout  = NULL;
194
    p_input->p->b_out_pace_control = false;
195 196 197
    p_input->i_pts_delay = 0;

    /* Init Input fields */
Pierre's avatar
Pierre committed
198
    vlc_gc_incref( p_item ); /* Released in Destructor() */
Clément Stenac's avatar
Clément Stenac committed
199 200 201 202
    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;
203
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
204 205 206
    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;
207 208 209 210
    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;
Clément Stenac's avatar
Clément Stenac committed
211 212
    p_input->p->input.i_cr_average = 0;

213
    vlc_mutex_lock( &p_item->lock );
214 215

    if( !p_item->p_stats )
216 217
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
218

219
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
220 221
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
222

223
    /* Init control buffer */
224
    vlc_mutex_init( &p_input->p->lock_control );
Clément Stenac's avatar
Clément Stenac committed
225
    p_input->p->i_control = 0;
226

Gildas Bazin's avatar
 
Gildas Bazin committed
227
    /* Parse input options */
228
    vlc_mutex_lock( &p_item->lock );
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
229
    assert( (int)p_item->optflagc == p_item->i_options );
230
    for( i = 0; i < p_item->i_options; i++ )
231 232
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
233
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
234

235 236
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
237

238
    /* Create Objects variables for public Get and Set */
239
    input_ControlVarInit( p_input );
240

241 242
    /* */
    p_input->p->pts_adjust.b_auto_adjust = var_GetBool( p_input, "auto-adjust-pts-delay" );
Clément Stenac's avatar
Clément Stenac committed
243
    p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
Gildas Bazin's avatar
Gildas Bazin committed
244

245
    if( !p_input->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
246
    {
247 248
        var_Get( p_input, "bookmarks", &val );
        if( val.psz_string )
Gildas Bazin's avatar
Gildas Bazin committed
249
        {
250 251 252 253
            /* 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, '{' ) ) )
Gildas Bazin's avatar
Gildas Bazin committed
254
            {
255 256 257 258 259 260 261 262 263 264 265 266 267 268
                 seekpoint_t *p_seekpoint = vlc_seekpoint_New();
                 char backup;
                 psz_start++;
                 psz_end = strchr( psz_start, '}' );
                 if( !psz_end ) break;
                 psz_parser = psz_end + 1;
                 backup = *psz_parser;
                 *psz_parser = 0;
                 *psz_end = ',';
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
269
                         p_seekpoint->psz_name = strdup(psz_start + 5);
270 271 272 273 274 275 276
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
277 278
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
                                                        1000000;
279 280
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
281
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
282
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
283 284 285 286 287
                                  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;
Gildas Bazin's avatar
Gildas Bazin committed
288
            }
289
            free( val.psz_string );
Gildas Bazin's avatar
Gildas Bazin committed
290 291 292
        }
    }

293
    /* Remove 'Now playing' info as it is probably outdated */
294
    input_item_SetNowPlaying( p_item, NULL );
295

296 297 298 299
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

300 301 302 303
    /* */
    if( p_sout )
        p_input->p->p_sout = p_sout;

304
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
305
    vlc_mutex_init( &p_input->p->counters.counters_lock );
306

307 308 309
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

310 311 312
    /* Attach only once we are ready */
    vlc_object_attach( p_input, p_parent );

313 314 315
    return p_input;
}

316 317 318 319
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
320
{
321 322 323 324 325 326
#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

327 328
    vlc_event_manager_fini( &p_input->p->event_manager );

329 330
    stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
    stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
331
#ifdef ENABLE_SOUT
332 333
    if( p_input->p->p_sout )
        sout_DeleteInstance( p_input->p->p_sout );
334
#endif
Pierre's avatar
Pierre committed
335 336
    vlc_gc_decref( p_input->p->input.p_item );

337 338
    vlc_mutex_destroy( &p_input->p->counters.counters_lock );

339 340
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
341
}
342

343
/**
344 345
 * Initialize an input thread and run it. You will need to monitor the
 * thread to clean up after it is done
346 347 348 349 350 351 352
 *
 * \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 )
353
{
354
    return __input_CreateThreadExtended( p_parent, p_item, NULL, NULL );
355 356
}

357 358 359 360
/* */
input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
                                              input_item_t *p_item,
                                              const char *psz_log, sout_instance_t *p_sout )
361
{
362
    input_thread_t *p_input;
363

364
    p_input = Create( p_parent, p_item, psz_log, false, p_sout );
365 366 367
    if( !p_input )
        return NULL;

Sam Hocevar's avatar
Sam Hocevar committed
368
    /* Create thread and wait for its readiness. */
369
    if( vlc_thread_create( p_input, "input", Run,
370
                           VLC_THREAD_PRIORITY_INPUT, true ) )
Michel Kaempf's avatar
Michel Kaempf committed
371
    {
372
        input_ChangeState( p_input, ERROR_S );
373
        msg_Err( p_input, "cannot create input thread" );
374 375
        vlc_object_detach( p_input );
        vlc_object_release( p_input );
376
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
377
    }
378

379
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
380 381
}

382
/**
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
383
 * Initialize an input thread and run it. This thread will clean after itself,
384 385 386 387 388
 * 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 ?
Clément Stenac's avatar
Clément Stenac committed
389
 * \return the input object id if non blocking, an error code else
390
 */
391
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
392
                   bool b_block )
393
{
394
    input_thread_t *p_input;
395

396
    p_input = Create( p_parent, p_item, NULL, false, NULL );
397
    if( !p_input )
398 399
        return VLC_EGENERIC;

400
    if( b_block )
401
    {
402
        RunAndDestroy( VLC_OBJECT(p_input) );
Clément Stenac's avatar
Clément Stenac committed
403
        return VLC_SUCCESS;
404
    }
405
    else
406
    {
407
        if( vlc_thread_create( p_input, "input", RunAndDestroy,
408
                               VLC_THREAD_PRIORITY_INPUT, true ) )
409
        {
410
            input_ChangeState( p_input, ERROR_S );
411
            msg_Err( p_input, "cannot create input thread" );
412
            vlc_object_release( p_input );
Clément Stenac's avatar
Clément Stenac committed
413
            return VLC_EGENERIC;
414
        }
415
    }
416
    return p_input->i_object_id;
417
}
418

419 420 421 422 423 424 425 426 427 428
/**
 * 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 )
{
429
    input_thread_t *p_input;
430

431
    /* Allocate descriptor */
432
    p_input = Create( p_parent, p_item, NULL, true, NULL );
433 434 435
    if( !p_input )
        return VLC_EGENERIC;

436 437
    if( !Init( p_input ) )
        End( p_input );
438

439 440
    vlc_object_detach( p_input );
    vlc_object_release( p_input );
441 442 443 444

    return VLC_SUCCESS;
}

445 446 447 448 449
/**
 * Request a running input thread to stop and die
 *
 * \param the input thread to stop
 */
450
static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
Michel Kaempf's avatar
Michel Kaempf committed
451
{
452 453
    vlc_list_t *p_list;
    int i;
454 455 456 457 458 459

    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;

460
    vlc_object_kill( p_obj );
461

462
    p_list = vlc_list_children( p_obj );
463
    for( i = 0; i < p_list->i_count; i++ )
464
        ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
465
    vlc_list_release( p_list );
466 467 468 469 470 471
}
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 */
472
    ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );
Michel Kaempf's avatar
Michel Kaempf committed
473

474
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
Sam Hocevar's avatar
 
Sam Hocevar committed
475 476
}

477 478
sout_instance_t * input_DetachSout( input_thread_t *p_input )
{
479 480 481 482
    sout_instance_t *p_sout = p_input->p->p_sout;
    vlc_object_detach( p_sout );
    p_input->p->p_sout = NULL;
    return p_sout;
483 484
}

485
/*****************************************************************************
486
 * Run: main thread loop
487 488
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
489
 *****************************************************************************/
490
static void* Run( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
491
{
492
    input_thread_t *p_input = (input_thread_t *)p_this;
493
    const int canc = vlc_savecancel();
494

495
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
496 497
    vlc_thread_ready( p_input );

498
    if( Init( p_input ) )
Sam Hocevar's avatar
 
Sam Hocevar committed
499 500
    {
        /* If we failed, wait before we are killed, and exit */
501
        p_input->b_error = true;
502

503
        WaitDie( p_input );
504 505

        /* Tell we're dead */
506
        p_input->b_dead = true;
507

508
        return NULL;
Sam Hocevar's avatar
 
Sam Hocevar committed
509
    }
Michel Kaempf's avatar
Michel Kaempf committed
510

511 512
    MainLoop( p_input );

Clément Stenac's avatar
Clément Stenac committed
513
    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
514 515 516 517
    {
        /* We have finish to demux data but not to play them */
        while( !p_input->b_die )
        {
Clément Stenac's avatar
Clément Stenac committed
518
            if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
519 520 521 522 523 524 525 526
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }

        /* We have finished */
527
        p_input->b_eof = true;
528
        input_ChangeState( p_input, END_S );
529 530
    }

531
    /* Wait until we are asked to die */
532 533
    if( !p_input->b_die )
    {
534
        WaitDie( p_input );
535 536 537 538
    }

    /* Clean up */
    End( p_input );
539
    vlc_restorecancel( canc );
540
    return NULL;
541 542 543
}

/*****************************************************************************
544
 * RunAndDestroy: main thread loop
545 546 547
 * This is the "just forget me" thread that spawns the input processing chain,
 * reads the stream, cleans up and releases memory
 *****************************************************************************/
548
static void* RunAndDestroy( vlc_object_t *p_this )
549
{
550
    input_thread_t *p_input = (input_thread_t *)p_this;
551
    const int canc = vlc_savecancel();
552

553 554 555
    /* Signal that the thread is launched */
    vlc_thread_ready( p_input );

556
    if( Init( p_input ) )
557
        goto exit;
558 559 560

    MainLoop( p_input );

Clément Stenac's avatar
Clément Stenac committed
561
    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
562
    {
563
        /* We have finished demuxing data but not playing it */
564 565
        while( !p_input->b_die )
        {
Clément Stenac's avatar
Clément Stenac committed
566
            if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
567 568 569 570 571 572
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }
573

574
        /* We have finished */
575
        p_input->b_eof = true;
576 577 578 579 580
    }

    /* Clean up */
    End( p_input );

581
exit:
582
    /* Release memory */
583
    vlc_object_release( p_input );
584 585
    vlc_restorecancel( canc );
    return NULL;
586 587 588 589 590 591 592
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
static void MainLoop( input_thread_t *p_input )
{
593
    int64_t i_start_mdate = mdate();
594
    int64_t i_intf_update = 0;
595
    int i_updates = 0;
596

597 598 599
    /* Stop the timer */
    stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING );

Clément Stenac's avatar
Clément Stenac committed
600
    while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
Sam Hocevar's avatar
 
Sam Hocevar committed
601
    {
602
        bool b_force_update = false;
603 604 605
        int i_ret;
        int i_type;
        vlc_value_t val;
606

607
        /* Do the read */
608
        if( p_input->i_state != PAUSE_S )
609
        {
610 611 612
            if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) ||
                ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
                i_ret = 0; /* EOF */
613
            else
614
                i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);
615

616 617 618
            if( i_ret > 0 )
            {
                /* TODO */
Clément Stenac's avatar
Clément Stenac committed
619 620
                if( p_input->p->input.b_title_demux &&
                    p_input->p->input.p_demux->info.i_update )
621
                {
622
                    i_ret = UpdateFromDemux( p_input );
623
                    b_force_update = true;
624
                }
Clément Stenac's avatar
Clément Stenac committed
625 626 627
                else if( !p_input->p->input.b_title_demux &&
                          p_input->p->input.p_access &&
                          p_input->p->input.p_access->info.i_update )
628
                {
629
                    i_ret = UpdateFromAccess( p_input );
630
                    b_force_update = true;
631 632
                }
            }
633 634

            if( i_ret == 0 )    /* EOF */
635 636
            {
                vlc_value_t repeat;
637

638 639 640 641 642 643
                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" );
644
                    p_input->p->input.b_eof = true;
645 646
                }
                else
647
                {
Gildas Bazin's avatar
Gildas Bazin committed
648 649
                    msg_Dbg( p_input, "repeating the same input (%d)",
                             repeat.i_int );
650 651 652 653 654
                    if( repeat.i_int > 0 )
                    {
                        repeat.i_int--;
                        var_Set( p_input, "input-repeat", repeat );
                    }
655

656
                    /* Seek to start title/seekpoint */
Clément Stenac's avatar
Clément Stenac committed
657 658 659
                    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 )
660 661 662 663
                        val.i_int = 0;
                    input_ControlPush( p_input,
                                       INPUT_CONTROL_SET_TITLE, &val );

Clément Stenac's avatar
Clément Stenac committed
664 665
                    val.i_int = p_input->p->input.i_seekpoint_start -
                        p_input->p->input.i_seekpoint_offset;
666 667 668 669 670
                    if( val.i_int > 0 /* TODO: check upper boundary */ )
                        input_ControlPush( p_input,
                                           INPUT_CONTROL_SET_SEEKPOINT, &val );

                    /* Seek to start position */
Clément Stenac's avatar
Clément Stenac committed
671
                    if( p_input->p->i_start > 0 )
672
                    {
Clément Stenac's avatar
Clément Stenac committed
673
                        val.i_time = p_input->p->i_start;
674 675 676 677 678 679 680 681 682
                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                           &val );
                    }
                    else
                    {
                        val.f_float = 0.0;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                           &val );
                    }
683 684 685

                    /* */
                    i_start_mdate = mdate();
686 687
                }
            }
688 689
            else if( i_ret < 0 )
            {
690
                p_input->b_error = true;
691
            }
692

Clément Stenac's avatar
Clément Stenac committed
693
            if( i_ret > 0 && p_input->p->i_slave > 0 )
694 695 696
            {
                SlaveDemux( p_input );
            }
697
        }
698
        else
699
        {
700 701 702
            /* Small wait */
            msleep( 10*1000 );
        }
703

704
        /* Handle control */
Clément Stenac's avatar
Clément Stenac committed
705
        vlc_mutex_lock( &p_input->p->lock_control );
706 707 708 709 710
        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 ) )
711
                b_force_update = true;
712
        }
Clément Stenac's avatar
Clément Stenac committed
713
        vlc_mutex_unlock( &p_input->p->lock_control );
714

715
        if( b_force_update || i_intf_update < mdate() )
716 717 718 719 720
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
721
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
722
                                 DEMUX_GET_POSITION, &f_pos ) )
723 724 725 726
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
727
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
728
                                 DEMUX_GET_TIME, &i_time ) )
729 730 731 732 733
            {
                p_input->i_time = i_time;
                val.i_time = i_time;
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
734
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
735
                                 DEMUX_GET_LENGTH, &i_length ) )
736 737 738 739 740
            {
                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 );
741

742
                if( old_val.i_time != val.i_time )
743
                {
744
                    UpdateItemLength( p_input, i_length );
745 746
                }
            }
747

748
            var_SetBool( p_input, "intf-change", true );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
749
            i_intf_update = mdate() + INT64_C(150000);
750
        }
751 752 753
        /* 150ms * 8 = ~ 1 second */
        if( ++i_updates % 8 == 0 )
        {
Clément Stenac's avatar
Clément Stenac committed
754
            stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
755
            /* Are we the thread responsible for computing global stats ? */
756
            if( libvlc_priv( p_input->p_libvlc )->p_stats_computer == p_input )
757
            {
758
                stats_ComputeGlobalStats( p_input->p_libvlc,
759
                                          p_input->p_libvlc->p_stats );
760 761
            }
        }
762
    }
763 764
}

765
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
766
{
767
    if( p_input->b_preparsing ) return;
768

769 770 771
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
772
    if( libvlc_stats( p_input ) )
773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
    {
        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;
793
    }
794
}
795

796
#ifdef ENABLE_SOUT
797 798 799 800 801 802 803 804 805
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 ) )
806
    {
807 808
        /* Check the validity of the provided sout */
        if( p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
809
        {
810
            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
811
            {
812
                msg_Dbg( p_input, "destroying unusable sout" );
813

814 815
                sout_DeleteInstance( p_input->p->p_sout );
                p_input->p->p_sout = NULL;
816
            }
817
        }
818

819 820 821 822 823 824 825 826 827 828 829 830 831
        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 )
Clément Stenac's avatar
Clément Stenac committed
832
            {
833 834 835 836 837
                input_ChangeState( p_input, ERROR_S );
                msg_Err( p_input, "cannot start stream output instance, " \
                                  "aborting" );
                free( psz );
                return VLC_EGENERIC;
Clément Stenac's avatar
Clément Stenac committed
838
            }
839
        }
840
        if( libvlc_stats( p_input ) )
841
        {
842
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
843
            INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
844 845 846 847
            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;
848
        }
849
    }
850
    else if( p_input->p->p_sout )
851
    {
852 853 854 855
        msg_Dbg( p_input, "destroying useless sout" );

        sout_DeleteInstance( p_input->p->p_sout );
        p_input->p->p_sout = NULL;
856
    }
857
    free( psz );
858

859 860
    return VLC_SUCCESS;
}
861
#endif
862

863 864 865
static void InitTitle( input_thread_t * p_input )
{
    vlc_value_t val;
866

867
    if( p_input->b_preparsing ) return;
868

869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899
    /* 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 );
    if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);

    /* 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;
}
Gildas Bazin's avatar
 
Gildas Bazin committed
900

901 902 903 904 905 906 907
static void StartTitle( input_thread_t * p_input )
{
    double f_fps;
    vlc_value_t val;
    int i, i_delay;
    char *psz;
    char *psz_subtitle;
908
    int64_t i_length;