input.c 97.8 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>
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"
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 *);
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 *priv = libvlc_priv (p_input->p_libvlc);
162
        vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
163 164
        if( priv->p_stats_computer == NULL )
            priv->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

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 );
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
    input_thread_private_t *priv = p_input->p;
322

323 324 325 326 327 328
#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

329 330
    vlc_event_manager_fini( &p_input->p->event_manager );

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

339 340
    vlc_mutex_destroy( &p_input->p->counters.counters_lock );

341 342
    vlc_mutex_destroy( &priv->lock_control );
    free( priv );
343
}
344

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

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

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

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

381
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
382 383
}

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

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

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

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

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

438 439
    if( !Init( p_input ) )
        End( p_input );
440

441 442
    vlc_object_detach( p_input );
    vlc_object_release( p_input );
443 444 445 446

    return VLC_SUCCESS;
}

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

    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;

462
    vlc_object_kill( p_obj );
463

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

476
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
477 478
}

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

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

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

500
    if( Init( p_input ) )
501 502
    {
        /* If we failed, wait before we are killed, and exit */
503
        p_input->b_error = true;
504

505
        WaitDie( p_input );
506 507

        /* Tell we're dead */
508
        p_input->b_dead = true;
509

510
        return NULL;
511
    }
Michel Kaempf's avatar
Michel Kaempf committed
512

513 514
    MainLoop( p_input );

Clément Stenac's avatar
Clément Stenac committed
515
    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
516 517 518 519
    {
        /* 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
520
            if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
521 522 523 524 525 526 527 528
                break;

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

            msleep( INPUT_IDLE_SLEEP );
        }

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

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

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

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

555 556
    /* Signal that the thread is launched */
    vlc_thread_ready( p_input );
557
    canc = vlc_savecancel ();
558

559
    if( Init( p_input ) )
560
        goto exit;
561 562 563

    MainLoop( p_input );

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

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

            msleep( INPUT_IDLE_SLEEP );
        }
576

577
        /* We have finished */
578
        p_input->b_eof = true;
579 580 581 582 583
    }

    /* Clean up */
    End( p_input );

584
exit:
585
    /* Release memory */
586
    vlc_object_release( p_input );
587
    vlc_restorecancel (canc);
588 589 590 591 592 593 594 595
    return 0;
}

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

600 601 602
    /* Stop the timer */
    stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING );

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

610
        /* Do the read */
611
        if( p_input->i_state != PAUSE_S )
612
        {
613 614 615
            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 */
616
            else
617
                i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);
618

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

            if( i_ret == 0 )    /* EOF */
638 639
            {
                vlc_value_t repeat;
640

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

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

Clément Stenac's avatar
Clément Stenac committed
667 668
                    val.i_int = p_input->p->input.i_seekpoint_start -
                        p_input->p->input.i_seekpoint_offset;
669 670 671 672 673
                    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
674
                    if( p_input->p->i_start > 0 )
675
                    {
Clément Stenac's avatar
Clément Stenac committed
676
                        val.i_time = p_input->p->i_start;
677 678 679 680 681 682 683 684 685
                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                           &val );
                    }
                    else
                    {
                        val.f_float = 0.0;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                           &val );
                    }
686 687 688

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

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

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

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

745
                if( old_val.i_time != val.i_time )
746
                {
747
                    UpdateItemLength( p_input, i_length );
748 749
                }
            }
750

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

768
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
769
{
770
    if( p_input->b_preparsing ) return;
771

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

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

817 818
                sout_DeleteInstance( p_input->p->p_sout );
                p_input->p->p_sout = NULL;
819
            }
820
        }
821

822 823 824 825 826 827 828 829 830 831 832 833 834
        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
835
            {
836 837 838 839 840
                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
841
            }
842
        }
843
        if( libvlc_stats (p_input) )
844
        {
845 846 847 848 849 850
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
            INIT_COUNTER (sout_sent_bytes, INTEGER, COUNTER );
            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;
851
        }
852
    }
853
    else if( p_input->p->p_sout )
854
    {
855 856 857 858
        msg_Dbg( p_input, "destroying useless sout" );

        sout_DeleteInstance( p_input->p->p_sout );
        p_input->p->p_sout = NULL;
859
    }
860
    free( psz );
861

862 863
    return VLC_SUCCESS;
}
864
#endif
865

866 867 868
static void InitTitle( input_thread_t * p_input )
{
    vlc_value_t val;
869

870
    if( p_input->b_preparsing ) return;
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 900 901 902
    /* 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;
}
903

904 905 906 907 908 909 910
static void StartTitle( input_thread_t * p_input )
{
    double f_fps;
    vlc_value_t val;
    int i, i_delay;
    char *psz;
    char *psz_subtitle;