input.c 112 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
4
 * Copyright (C) 1998-2007 VLC authors and VideoLAN
5
 * $Id$
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
10 11 12
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as published by
 * the Free Software Foundation; either version 2.1 of the License, or
13
 * (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
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 * GNU Lesser General Public License for more details.
19
 *
Jean-Baptiste Kempf's avatar
Jean-Baptiste Kempf committed
20 21 22
 * You should have received a copy of the GNU Lesser General Public License
 * along with this program; if not, write to the Free Software 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 <limits.h>
35
#include <assert.h>
36
#include <sys/stat.h>
37

38
#include "input_internal.h"
39
#include "event.h"
40
#include "es_out.h"
41
#include "es_out_timeshift.h"
42
#include "demux.h"
43
#include "item.h"
44
#include "resource.h"
45
#include "stream.h"
46

47
#include <vlc_aout.h>
48
#include <vlc_sout.h>
49
#include <vlc_dialog.h>
50 51
#include <vlc_url.h>
#include <vlc_charset.h>
52
#include <vlc_fs.h>
53
#include <vlc_strings.h>
54
#include <vlc_modules.h>
55
#include <vlc_stream.h>
56
#include <vlc_stream_extractor.h>
57
#include <vlc_renderer_discovery.h>
58

59
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
60
 * Local prototypes
61
 *****************************************************************************/
62 63
static  void *Run( void * );
static  void *Preparse( void * );
64

65
static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
66 67
                                  const char *, bool, input_resource_t *,
                                  vlc_renderer_item_t * );
68
static  int             Init    ( input_thread_t *p_input );
69
static void             End     ( input_thread_t *p_input );
70
static void             MainLoop( input_thread_t *p_input, bool b_interactive );
71

72
static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline, bool b_postpone_seek );
73
static void       ControlRelease( int i_type, vlc_value_t val );
74
static bool       ControlIsSeekRequest( int i_type );
75
static bool       Control( input_thread_t *, int, vlc_value_t );
76
static void       ControlPause( input_thread_t *, mtime_t );
77

78 79
static int  UpdateTitleSeekpointFromDemux( input_thread_t * );
static void UpdateGenericFromDemux( input_thread_t * );
80
static void UpdateTitleListfromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
81

82
static void MRLSections( const char *, int *, int *, int *, int *);
83

84 85 86 87
static input_source_t *InputSourceNew( input_thread_t *, const char *,
                                       const char *psz_forced_demux,
                                       bool b_in_can_fail );
static void InputSourceDestroy( input_source_t * );
Laurent Aimar's avatar
Laurent Aimar committed
88 89
static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );

90 91
/* TODO */
//static void InputGetAttachments( input_thread_t *, input_source_t * );
92
static void SlaveDemux( input_thread_t *p_input );
93
static void SlaveSeek( input_thread_t *p_input );
94

95
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
96
static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux );
97 98
static void InputGetExtraFiles( input_thread_t *p_input,
                                int *pi_list, char ***pppsz_list,
99
                                const char **psz_access, const char *psz_path );
100

101 102 103
static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                              const demux_t ***ppp_attachment_demux,
                              int i_new, input_attachment_t **pp_new, const demux_t *p_demux );
104

105 106 107 108
#define SLAVE_ADD_NOFLAG    0
#define SLAVE_ADD_FORCED    (1<<0)
#define SLAVE_ADD_CANFAIL   (1<<1)
#define SLAVE_ADD_SET_TIME  (1<<2)
109

110 111
static int input_SlaveSourceAdd( input_thread_t *, enum slave_type,
                                 const char *, unsigned );
112
static char *input_SubtitleFile2Uri( input_thread_t *, const char * );
113 114
static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */

115
#undef input_Create
116 117 118 119 120 121 122 123 124 125 126 127
/**
 * Create a new input_thread_t.
 *
 * You need to call input_Start on it when you are done
 * adding callback on the variables/events you want to monitor.
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \param psz_log an optional prefix for this input logs
 * \param p_resource an optional input ressource
 * \return a pointer to the spawned input thread
 */
128 129
input_thread_t *input_Create( vlc_object_t *p_parent,
                              input_item_t *p_item,
130 131
                              const char *psz_log, input_resource_t *p_resource,
                              vlc_renderer_item_t *p_renderer )
132
{
133
    return Create( p_parent, p_item, psz_log, false, p_resource, p_renderer );
134 135
}

136
#undef input_Read
137
/**
138
 * Initialize an input thread and run it until it stops by itself.
139 140 141 142 143
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \return an error code, VLC_SUCCESS on success
 */
144
int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
145
{
146
    input_thread_t *p_input = Create( p_parent, p_item, NULL, false, NULL, NULL );
147 148 149
    if( !p_input )
        return VLC_EGENERIC;

150 151
    if( !Init( p_input ) )
    {
152
        MainLoop( p_input, false );
153 154 155 156
        End( p_input );
    }

    vlc_object_release( p_input );
157 158 159
    return VLC_SUCCESS;
}

160 161 162
input_thread_t *input_CreatePreparser( vlc_object_t *parent,
                                       input_item_t *item )
{
163
    return Create( parent, item, NULL, true, NULL, NULL );
164 165
}

166 167 168 169 170 171 172 173 174
/**
 * Start a input_thread_t created by input_Create.
 *
 * You must not start an already running input_thread_t.
 *
 * \param the input thread to start
 */
int input_Start( input_thread_t *p_input )
{
175
    input_thread_private_t *priv = input_priv(p_input);
176 177
    void *(*func)(void *) = Run;

178
    if( priv->b_preparsing )
179 180
        func = Preparse;

181
    assert( !priv->is_running );
182
    /* Create thread and wait for its readiness. */
183 184 185
    priv->is_running = !vlc_clone( &priv->thread, func, priv,
                                   VLC_THREAD_PRIORITY_INPUT );
    if( !priv->is_running )
186 187 188 189 190 191 192 193 194 195 196 197 198
    {
        input_ChangeState( p_input, ERROR_S );
        msg_Err( p_input, "cannot create input thread" );
        return VLC_EGENERIC;
    }
    return VLC_SUCCESS;
}

/**
 * Request a running input thread to stop and die
 *
 * \param p_input the input thread to stop
 */
199
void input_Stop( input_thread_t *p_input )
200
{
201
    input_thread_private_t *sys = input_priv(p_input);
202 203 204 205 206 207 208 209 210 211 212 213

    vlc_mutex_lock( &sys->lock_control );
    /* Discard all pending controls */
    for( int i = 0; i < sys->i_control; i++ )
    {
        input_control_t *ctrl = &sys->control[i];
        ControlRelease( ctrl->i_type, ctrl->val );
    }
    sys->i_control = 0;
    sys->is_stopped = true;
    vlc_cond_signal( &sys->wait_control );
    vlc_mutex_unlock( &sys->lock_control );
214
    vlc_interrupt_kill( &sys->interrupt );
215 216
}

217 218 219 220 221
/**
 * Close an input
 *
 * It does not call input_Stop itself.
 */
222
void input_Close( input_thread_t *p_input )
223
{
224 225 226
    if( input_priv(p_input)->is_running )
        vlc_join( input_priv(p_input)->thread, NULL );
    vlc_interrupt_deinit( &input_priv(p_input)->interrupt );
227
    vlc_object_release( p_input );
228 229
}

230 231 232 233 234 235
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void input_Destructor( vlc_object_t *obj )
{
    input_thread_t *p_input = (input_thread_t *)obj;
236
    input_thread_private_t *priv = input_priv(p_input);
237
#ifndef NDEBUG
238
    char * psz_name = input_item_GetName( priv->p_item );
239 240 241 242
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

243 244
    if( priv->p_renderer )
        vlc_renderer_item_release( priv->p_renderer );
245 246
    if( priv->p_es_out_display )
        es_out_Delete( priv->p_es_out_display );
247

248 249 250 251
    if( priv->p_resource )
        input_resource_Release( priv->p_resource );
    if( priv->p_resource_private )
        input_resource_Release( priv->p_resource_private );
252

253
    input_item_Release( priv->p_item );
254

255
    vlc_mutex_destroy( &priv->counters.counters_lock );
256

257
    for( int i = 0; i < priv->i_control; i++ )
258
    {
259
        input_control_t *p_ctrl = &priv->control[i];
260 261 262
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }

263 264
    vlc_cond_destroy( &priv->wait_control );
    vlc_mutex_destroy( &priv->lock_control );
265 266
}

267 268 269 270 271 272 273 274
/**
 * Get the item from an input thread
 * FIXME it does not increase ref count of the item.
 * if it is used after p_input is destroyed nothing prevent it from
 * being freed.
 */
input_item_t *input_GetItem( input_thread_t *p_input )
{
275 276
    assert( p_input != NULL );
    return input_priv(p_input)->p_item;
277 278
}

279
/*****************************************************************************
280 281
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
282
 *
Laurent Aimar's avatar
Laurent Aimar committed
283
 * XXX Do not forget to update vlc_input.h if you add new variables.
284
 *****************************************************************************/
285
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
286
                               const char *psz_header, bool b_preparsing,
287 288
                               input_resource_t *p_resource,
                               vlc_renderer_item_t *p_renderer )
Michel Kaempf's avatar
Michel Kaempf committed
289
{
290
    /* Allocate descriptor */
291 292 293 294
    input_thread_private_t *priv;

    priv = vlc_custom_create( p_parent, sizeof( *priv ), "input" );
    if( unlikely(priv == NULL) )
295
        return NULL;
296

297 298
    input_thread_t *p_input = &priv->input;

299
    char * psz_name = input_item_GetName( p_item );
300 301
    msg_Dbg( p_input, "Creating an input for %s'%s'",
             b_preparsing ? "preparsing " : "", psz_name);
302 303
    free( psz_name );

304
    /* Parse input options */
305
    input_item_ApplyOptions( VLC_OBJECT(p_input), p_item );
306

307
    p_input->obj.header = psz_header ? strdup( psz_header ) : NULL;
308

309
    /* Init Common fields */
310
    priv->b_preparsing = b_preparsing;
311 312 313 314
    priv->b_can_pace_control = true;
    priv->i_start = 0;
    priv->i_time  = 0;
    priv->i_stop  = 0;
315 316
    priv->i_title = 0;
    priv->title = NULL;
317 318 319 320 321 322 323 324 325 326 327 328
    priv->i_title_offset = input_priv(p_input)->i_seekpoint_offset = 0;
    priv->i_state = INIT_S;
    priv->is_running = false;
    priv->is_stopped = false;
    priv->b_recording = false;
    priv->i_rate = INPUT_RATE_DEFAULT;
    memset( &priv->bookmark, 0, sizeof(priv->bookmark) );
    TAB_INIT( priv->i_bookmark, priv->pp_bookmark );
    TAB_INIT( priv->i_attachment, priv->attachment );
    priv->attachment_demux = NULL;
    priv->p_sout   = NULL;
    priv->b_out_pace_control = false;
329 330 331
    /* The renderer is passed after its refcount was incremented.
     * The input thread is now responsible for releasing it */
    priv->p_renderer = p_renderer;
332

333 334
    priv->viewpoint_changed = false;
    /* Fetch the viewpoint from the mediaplayer or the playlist if any */
335
    vlc_viewpoint_t *p_viewpoint = var_InheritAddress( p_input, "viewpoint" );
336
    if (p_viewpoint != NULL)
337 338 339 340
        priv->viewpoint = *p_viewpoint;
    else
        vlc_viewpoint_init( &priv->viewpoint );

341
    input_item_Hold( p_item ); /* Released in Destructor() */
342
    priv->p_item = p_item;
343 344

    /* Init Input fields */
345
    priv->master = NULL;
346
    vlc_mutex_lock( &p_item->lock );
347 348

    if( !p_item->p_stats )
349
        p_item->p_stats = stats_NewInputStats( p_input );
350 351 352

    /* setup the preparse depth of the item
     * if we are preparsing, use the i_preparse_depth of the parent item */
353
    if( !priv->b_preparsing )
354 355 356 357 358 359 360 361 362 363 364 365 366 367 368
    {
        char *psz_rec = var_InheritString( p_parent, "recursive" );

        if( psz_rec != NULL )
        {
            if ( !strcasecmp( psz_rec, "none" ) )
                p_item->i_preparse_depth = 0;
            else if ( !strcasecmp( psz_rec, "collapse" ) )
                p_item->i_preparse_depth = 1;
            else
                p_item->i_preparse_depth = -1; /* default is expand */
            free (psz_rec);
        } else
            p_item->i_preparse_depth = -1;
    }
369
    else
370
        p_input->obj.flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
371 372 373

    /* Make sure the interaction option is honored */
    if( !var_InheritBool( p_input, "interact" ) )
374
        p_input->obj.flags |= OBJECT_FLAGS_NOINTERACT;
375 376 377
    else if( p_item->b_preparse_interact )
    {
        /* If true, this item was asked explicitly to interact with the user
378
         * (via libvlc_MetadataRequest). Sub items created from this input won't
379
         * have this flag and won't interact with the user */
380
        p_input->obj.flags &= ~OBJECT_FLAGS_NOINTERACT;
381 382
    }

383
    vlc_mutex_unlock( &p_item->lock );
384

385
    /* No slave */
386 387
    priv->i_slave = 0;
    priv->slave   = NULL;
388

389
    /* */
390
    if( p_resource )
391
    {
392 393
        priv->p_resource_private = NULL;
        priv->p_resource = input_resource_Hold( p_resource );
394
    }
395
    else
396
    {
397 398
        priv->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) );
        priv->p_resource = input_resource_Hold( priv->p_resource_private );
399
    }
400
    input_resource_SetInput( priv->p_resource, p_input );
401

402
    /* Init control buffer */
403 404 405 406
    vlc_mutex_init( &priv->lock_control );
    vlc_cond_init( &priv->wait_control );
    priv->i_control = 0;
    vlc_interrupt_init(&priv->interrupt);
407

408 409
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
410

411
    /* Create Objects variables for public Get and Set */
412
    input_ControlVarInit( p_input );
413

414
    /* */
415
    if( !priv->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
416
    {
417 418
        char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
        if( psz_bookmarks )
Gildas Bazin's avatar
Gildas Bazin committed
419
        {
420 421
            /* FIXME: have a common cfg parsing routine used by sout and others */
            char *psz_parser, *psz_start, *psz_end;
422
            psz_parser = psz_bookmarks;
423
            while( (psz_start = strchr( psz_parser, '{' ) ) )
Gildas Bazin's avatar
Gildas Bazin committed
424
            {
425
                 seekpoint_t *p_seekpoint;
426 427 428 429 430 431 432 433
                 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 = ',';
434 435

                 p_seekpoint = vlc_seekpoint_New();
436

437 438
                 if( unlikely( p_seekpoint == NULL ) )
                     break;
439

440 441 442 443 444
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
445 446
                         free( p_seekpoint->psz_name );

447
                         p_seekpoint->psz_name = strdup(psz_start + 5);
448 449 450
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
451
                         p_seekpoint->i_time_offset = atof(psz_start + 5) *
Ilkka Ollakka's avatar
Ilkka Ollakka committed
452
                                                        CLOCK_FREQ;
453 454
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
455
                }
456 457
                msg_Dbg( p_input, "adding bookmark: %s, time=%"PRId64,
                                  p_seekpoint->psz_name,
458 459 460 461
                                  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
462
            }
463
            free( psz_bookmarks );
Gildas Bazin's avatar
Gildas Bazin committed
464 465 466
        }
    }

467
    /* Remove 'Now playing' info as it is probably outdated */
468
    input_item_SetNowPlaying( p_item, NULL );
469
    input_item_SetESNowPlaying( p_item, NULL );
470
    input_SendEventMeta( p_input );
471

472
    /* */
473 474
    memset( &priv->counters, 0, sizeof( priv->counters ) );
    vlc_mutex_init( &priv->counters.counters_lock );
475

476 477
    priv->p_es_out_display = input_EsOutNew( p_input, priv->i_rate );
    priv->p_es_out = NULL;
478

479
    /* Set the destructor when we are sure we are initialized */
480
    vlc_object_set_destructor( p_input, input_Destructor );
481

482 483 484
    return p_input;
}

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( void *data )
Michel Kaempf's avatar
Michel Kaempf committed
491
{
492 493
    input_thread_private_t *priv = data;
    input_thread_t *p_input = &priv->input;
494

495
    vlc_interrupt_set(&priv->interrupt);
496

497 498
    if( !Init( p_input ) )
    {
499
        if( priv->b_can_pace_control && priv->b_out_pace_control )
500 501 502
        {
            /* We don't want a high input priority here or we'll
             * end-up sucking up all the CPU time */
503
            vlc_set_priority( priv->thread, VLC_THREAD_PRIORITY_LOW );
504 505
        }

506
        MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
507

508 509 510
        /* Clean up */
        End( p_input );
    }
511

512
    input_SendEventDead( p_input );
513
    return NULL;
514 515
}

516
static void *Preparse( void *data )
517
{
518 519
    input_thread_private_t *priv = data;
    input_thread_t *p_input = &priv->input;
520

521
    vlc_interrupt_set(&priv->interrupt);
522 523 524 525 526 527

    if( !Init( p_input ) )
    {   /* if the demux is a playlist, call Mainloop that will call
         * demux_Demux in order to fetch sub items */
        bool b_is_playlist = false;

528 529
        if ( input_item_ShouldPreparseSubItems( priv->p_item )
          && demux_Control( priv->master->p_demux, DEMUX_IS_PLAYLIST,
530 531 532 533 534 535 536 537 538 539 540
                            &b_is_playlist ) )
            b_is_playlist = false;
        if( b_is_playlist )
            MainLoop( p_input, false );
        End( p_input );
    }

    input_SendEventDead( p_input );
    return NULL;
}

541 542
bool input_Stopped( input_thread_t *input )
{
543
    input_thread_private_t *sys = input_priv(input);
544 545 546 547 548 549 550 551
    bool ret;

    vlc_mutex_lock( &sys->lock_control );
    ret = sys->is_stopped;
    vlc_mutex_unlock( &sys->lock_control );
    return ret;
}

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

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
560
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed )
561
{
562
    int i_ret;
563
    demux_t *p_demux = input_priv(p_input)->master->p_demux;
564

565
    *pb_changed = false;
566

567
    if( input_priv(p_input)->i_stop > 0 && input_priv(p_input)->i_time >= input_priv(p_input)->i_stop )
568
        i_ret = VLC_DEMUXER_EOF;
569
    else
570
        i_ret = demux_Demux( p_demux );
571

572 573 574
    i_ret = i_ret > 0 ? VLC_DEMUXER_SUCCESS : ( i_ret < 0 ? VLC_DEMUXER_EGENERIC : VLC_DEMUXER_EOF);

    if( i_ret == VLC_DEMUXER_SUCCESS )
575
    {
576 577 578
        if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_TITLE_LIST ) )
            UpdateTitleListfromDemux( p_input );

579
        if( input_priv(p_input)->master->b_title_demux )
580
        {
581 582
            i_ret = UpdateTitleSeekpointFromDemux( p_input );
            *pb_changed = true;
583
        }
584 585

        UpdateGenericFromDemux( p_input );
586
    }
587

588
    if( i_ret == VLC_DEMUXER_EOF )
589
    {
590
        msg_Dbg( p_input, "EOF reached" );
591 592
        input_priv(p_input)->master->b_eof = true;
        es_out_Eos(input_priv(p_input)->p_es_out);
593
    }
594
    else if( i_ret == VLC_DEMUXER_EGENERIC )
595 596 597
    {
        input_ChangeState( p_input, ERROR_S );
    }
598
    else if( input_priv(p_input)->i_slave > 0 )
599
        SlaveDemux( p_input );
600 601
}

602
static int MainLoopTryRepeat( input_thread_t *p_input )
603 604
{
    int i_repeat = var_GetInteger( p_input, "input-repeat" );
605
    if( i_repeat <= 0 )
606 607 608 609 610 611 612 613 614 615 616 617
        return VLC_EGENERIC;

    vlc_value_t val;

    msg_Dbg( p_input, "repeating the same input (%d)", i_repeat );
    if( i_repeat > 0 )
    {
        i_repeat--;
        var_SetInteger( p_input, "input-repeat", i_repeat );
    }

    /* Seek to start title/seekpoint */
618 619 620
    val.i_int = input_priv(p_input)->master->i_title_start -
        input_priv(p_input)->master->i_title_offset;
    if( val.i_int < 0 || val.i_int >= input_priv(p_input)->master->i_title )
621 622 623 624
        val.i_int = 0;
    input_ControlPush( p_input,
                       INPUT_CONTROL_SET_TITLE, &val );

625 626
    val.i_int = input_priv(p_input)->master->i_seekpoint_start -
        input_priv(p_input)->master->i_seekpoint_offset;
627 628 629 630 631
    if( val.i_int > 0 /* TODO: check upper boundary */ )
        input_ControlPush( p_input,
                           INPUT_CONTROL_SET_SEEKPOINT, &val );

    /* Seek to start position */
632
    if( input_priv(p_input)->i_start > 0 )
633
    {
634
        val.i_int = input_priv(p_input)->i_start;
635 636 637 638
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val );
    }
    else
    {
639
        val.f_float = 0.f;
640 641 642 643 644 645
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

    return VLC_SUCCESS;
}

646
/**
647
 * Update timing infos and statistics.
648
 */
649
static void MainLoopStatistics( input_thread_t *p_input )
650
{
651 652 653
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
654 655

    /* update input status variables */
656
    if( demux_Control( input_priv(p_input)->master->p_demux,
657 658
                       DEMUX_GET_POSITION, &f_position ) )
        f_position = 0.0;
659

660
    if( demux_Control( input_priv(p_input)->master->p_demux,
661 662
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
663
    input_priv(p_input)->i_time = i_time;
664

665
    if( demux_Control( input_priv(p_input)->master->p_demux,
666 667
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
668

669
    es_out_SetTimes( input_priv(p_input)->p_es_out, f_position, i_time, i_length );
670 671

    /* update current bookmark */
672 673 674
    vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
    input_priv(p_input)->bookmark.i_time_offset = i_time;
    vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
675

676
    stats_ComputeInputStats( p_input, input_priv(p_input)->p_item->p_stats );
677
    input_SendEventStatistics( p_input );
678 679 680 681 682 683
}

/**
 * MainLoop
 * The main input loop.
 */
684
static void MainLoop( input_thread_t *p_input, bool b_interactive )
685
{
686
    mtime_t i_intf_update = 0;
687
    mtime_t i_last_seek_mdate = 0;
688 689

    if( b_interactive && var_InheritBool( p_input, "start-paused" ) )
690
        ControlPause( p_input, mdate() );
691

692
    bool b_pause_after_eof = b_interactive &&
693 694
                           var_InheritBool( p_input, "play-and-pause" );
    bool b_paused_at_eof = false;
695

696
    demux_t *p_demux = input_priv(p_input)->master->p_demux;
697 698
    const bool b_can_demux = p_demux->pf_demux != NULL;

699
    while( !input_Stopped( p_input ) && input_priv(p_input)->i_state != ERROR_S )
700
    {
701
        mtime_t i_wakeup = -1;
702 703
        bool b_paused = input_priv(p_input)->i_state == PAUSE_S;
        /* FIXME if input_priv(p_input)->i_state == PAUSE_S the access/access_demux
704 705
         * is paused -> this may cause problem with some of them
         * The same problem can be seen when seeking while paused */
706
        if( b_paused )
707 708
            b_paused = !es_out_GetBuffering( input_priv(p_input)->p_es_out )
                    || input_priv(p_input)->master->b_eof;
709 710

        if( !b_paused )
711
        {
712
            if( !input_priv(p_input)->master->b_eof )
713
            {
714
                bool b_force_update = false;
715

716
                MainLoopDemux( p_input, &b_force_update );
717

718
                if( b_can_demux )
719
                    i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out );
720 721
                if( b_force_update )
                    i_intf_update = 0;
722 723

                b_paused_at_eof = false;
724
            }
725
            else if( !es_out_GetEmpty( input_priv(p_input)->p_es_out ) )
726 727 728 729
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
730 731
            /* Pause after eof only if the input is pausable.
             * This way we won't trigger timeshifting for nothing */
732
            else if( b_pause_after_eof && input_priv(p_input)->b_can_pause )
733
            {
734 735 736
                if( b_paused_at_eof )
                    break;

737 738
                vlc_value_t val = { .i_int = PAUSE_S };

739 740 741 742
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

                b_paused = true;
743
                b_paused_at_eof = true;
744
            }
745 746
            else
            {
747
                if( MainLoopTryRepeat( p_input ) )
748
                    break;
749
            }
750 751 752 753 754 755 756 757

            /* Update interface and statistics */
            mtime_t now = mdate();
            if( now >= i_intf_update )
            {
                MainLoopStatistics( p_input );
                i_intf_update = now + INT64_C(250000);
            }
758
        }
759

760 761 762
        /* Handle control */
        for( ;; )
        {
763
            mtime_t i_deadline = i_wakeup;
764 765 766

            /* Postpone seeking until ES buffering is complete or at most
             * 125 ms. */
767 768
            bool b_postpone = es_out_GetBuffering( input_priv(p_input)->p_es_out )
                            && !input_priv(p_input)->master->b_eof;
769
            if( b_postpone )
770
            {
771 772 773 774
                mtime_t now = mdate();

                /* Recheck ES buffer level every 20 ms when seeking */
                if( now < i_last_seek_mdate + INT64_C(125000)
775
                 && (i_deadline < 0 || i_deadline > now + INT64_C(20000)) )
776 777 778 779
                    i_deadline = now + INT64_C(20000);
                else
                    b_postpone = false;
            }
780

781 782
            int i_type;
            vlc_value_t val;
783

784 785 786 787 788 789
            if( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) )
            {
                if( b_postpone )
                    continue;
                break; /* Wake-up time reached */
            }
790

791
#ifndef NDEBUG
792
            msg_Dbg( p_input, "control type=%d", i_type );
793
#endif
794 795 796 797 798
            if( Control( p_input, i_type, val ) )
            {
                if( ControlIsSeekRequest( i_type ) )
                    i_last_seek_mdate = mdate();
                i_intf_update = 0;
799
            }
800

801
            /* Update the wakeup time */
802
            if( i_wakeup != 0 )
803
                i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out );
804
        }
805
    }
806 807
}

808
static void InitStatistics( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
809
{
810 811
    input_thread_private_t *priv = input_priv(p_input);

812
    if( priv->b_preparsing ) return;
813

814
    /* Prepare statistics */
815 816
#define INIT_COUNTER( c, compute ) free( priv->counters.p_##c ); \
    priv->counters.p_##c = \
817
 stats_CounterCreate( STATS_##compute);
818
    if( libvlc_stats( p_input ) )
819
    {
820 821 822 823 824 825 826 827 828 829 830 831 832 833
        INIT_COUNTER( read_bytes, COUNTER );
        INIT_COUNTER( read_packets, COUNTER );
        INIT_COUNTER( demux_read, COUNTER );
        INIT_COUNTER( input_bitrate, DERIVATIVE );
        INIT_COUNTER( demux_bitrate, DERIVATIVE );
        INIT_COUNTER( demux_corrupted, COUNTER );
        INIT_COUNTER( demux_discontinuity, COUNTER );
        INIT_COUNTER( played_abuffers, COUNTER );
        INIT_COUNTER( lost_abuffers, COUNTER );
        INIT_COUNTER( displayed_pictures, COUNTER );
        INIT_COUNTER( lost_pictures, COUNTER );
        INIT_COUNTER( decoded_audio, COUNTER );
        INIT_COUNTER( decoded_video, COUNTER );
        INIT_COUNTER( decoded_sub, COUNTER );
834 835 836
        priv->counters.p_sout_send_bitrate = NULL;
        priv->counters.p_sout_sent_packets = NULL;
        priv->counters.p_sout_sent_bytes = NULL;
837
    }
838
}
839

840
#ifdef ENABLE_SOUT
841 842
static int InitSout( input_thread_t * p_input )
{
843 844
    input_thread_private_t *priv = input_priv(p_input);

845
    if( priv->b_preparsing )
846
        return VLC_SUCCESS;
847 848

    /* Find a usable sout and attach it to p_input */
849 850 851 852 853 854 855 856 857
    char *psz = NULL;
    if( priv->p_renderer )
    {
        const char *psz_renderer_sout = vlc_renderer_item_sout( priv->p_renderer );
        if( asprintf( &psz, "#%s", psz_renderer_sout ) < 0 )
            return VLC_ENOMEM;
    }
    if( !psz )
        psz = var_GetNonEmptyString( p_input, "sout" );
858
    if( psz && strncasecmp( priv->p_item->psz_uri, "vlc:", 4 ) )
859
    {
860 861
        priv->p_sout  = input_resource_RequestSout( priv->p_resource, NULL, psz );
        if( priv->p_sout == NULL )
862
        {
863 864 865 866 867
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot start stream output instance, " \
                              "aborting" );
            free( psz );
            return VLC_EGENERIC;
868
        }
869
        if( libvlc_stats( p_input ) )
870
        {
871 872 873
            INIT_COUNTER( sout_sent_packets, COUNTER );
            INIT_COUNTER( sout_sent_bytes, COUNTER );
            INIT_COUNTER( sout_send_bitrate, DERIVATIVE );
874
        }
875
    }
876
    else
877
    {
878
        input_resource_RequestSout( priv->p_resource, NULL, NULL );
879
    }
880
    free( psz );
881

882 883
    return VLC_SUCCESS;
}
884
#endif
885

886 887
static void InitTitle( input_thread_t * p_input )
{
888 889
    input_thread_private_t *priv = input_priv(p_input);
    input_source_t *p_master = priv->master;
890

891
    if( priv->b_preparsing )
Laurent Aimar's avatar
Laurent Aimar committed
892
        return;
893

894
    vlc_mutex_lock( &priv->p_item->lock );
895
    /* Create global title (from master) */
896 897
    priv->i_title = p_master->i_title;
    priv->title   = p_master->title;
898 899
    priv->i_title_offset = p_master->i_title_offset;
    priv->i_seekpoint_offset = p_master->i_seekpoint_offset;
900
    if( priv->i_title > 0 )
901 902 903
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
904
        input_SendEventTitle( p_input, 0 );
905 906 907
    }

    /* Global flag */
908 909 910 911
    priv->b_can_pace_control = p_master->b_can_pace_control;
    priv->b_can_pause        = p_master->b_can_pause;
    priv->b_can_rate_control = p_master->b_can_rate_control;
    vlc_mutex_unlock( &priv->p_item->lock );
912
}
913

914 915
static void StartTitle( input_thread_t * p_input )
{
916
    input_thread_private_t *priv = input_priv(p_input);
917
    vlc_value_t val;
918

919
    /* Start title/chapter */
920 921
    val.i_int = priv->master->i_title_start - priv->master->i_title_offset;
    if( val.i_int > 0 && val.i_int < priv->master->i_title )
922
        input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
Laurent Aimar's avatar
Laurent Aimar committed
923

924 925
    val.i_int = priv->master->i_seekpoint_start -
                priv->master->i_seekpoint_offset;
926 927 928
    if( val.i_int > 0 /* TODO: check upper boundary */ )
        input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );

Laurent Aimar's avatar
Laurent Aimar committed
929
    /* Start/stop/run time */
930
    priv->i_start = llroundf(1000000.f
931
                                     * var_GetFloat( p_input, "start-time" ));
932
    priv->i_stop  = llroundf(1000000.f
933
                                     * var_GetFloat( p_input, "stop-time" ));
934
    if( priv->i_stop <= 0 )
935
    {
936
        priv->i_stop = llroundf(1000000.f
937
                                     * var_GetFloat( p_input, "run-time" ));
938
        if( priv->i_stop < 0 )
939 940
        {
            msg_Warn( p_input, "invalid run-time ignored" );
941
            priv->i_stop = 0;
942 943
        }
        else
944
            priv->i_stop += priv->i_start;
Rafaël Carré's avatar
Rafaël Carré committed
945
    }
946

947
    if( priv->i_start > 0 )
948
    {
949
        vlc_value_t s;
950

951 952
        msg_Dbg( p_input, "starting at time: %"PRId64"s",
                 priv->i_start / CLOCK_FREQ );
953

954
        s.i_int = priv->i_start;
955
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
956
    }
957
    if( priv->i_stop > 0 && priv->i_stop <= priv->i_start )
958 959
    {
        msg_Warn( p_input, "invalid stop-time ignored" );
960
        priv->i_stop = 0;
961
    }
962
    priv->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
Laurent Aimar's avatar
Laurent Aimar committed
963
}
964

965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984
static int SlaveCompare(const void *a, const void *b)
{
    const input_item_slave_t *p_slave0 = *((const input_item_slave_t **) a);
    const input_item_slave_t *p_slave1 = *((const input_item_slave_t **) b);

    if( p_slave0 == NULL || p_slave1 == NULL )
    {
        /* Put NULL (or rejected) subs at the end */
        return p_slave0 == NULL ? 1 : p_slave1 == NULL ? -1 : 0;
    }

    if( p_slave0->i_priority > p_slave1->i_priority )
        return -1;

    if( p_slave0->i_priority < p_slave1->i_priority )
        return 1;

    return 0;
}

985 986 987 988 989 990 991 992 993 994 995 996
static bool SlaveExists( input_item_slave_t **pp_slaves, int i_slaves,
                         const char *psz_uri)
{
    for( int i = 0; i < i_slaves; i++ )
    {
        if( pp_slaves[i] != NULL
         && !strcmp( pp_slaves[i]->psz_uri, psz_uri ) )
            return true;
    }
    return false;
}

997
static void SetSubtitlesOptions( input_thread_t *p_input )
Laurent Aimar's avatar
Laurent Aimar committed
998
{
999
    /* Get fps and set it if not already set */
1000
    const float f_fps = input_priv(p_input)->master->f_fps;
1001
    if( f_fps > 1.f )
1002 1003 1004
    {
        var_Create( p_input, "sub-original-fps", VLC_VAR_FLOAT );
        var_SetFloat( p_input, "sub-original-fps", f_fps );
1005

1006
        float f_requested_fps = var_CreateGetFloat( p_input, "sub-fps" );
1007
        if( f_requested_fps != f_fps )
1008
        {
1009 1010 1011
            var_Create( p_input, "sub-fps", VLC_VAR_FLOAT|
                                            VLC_VAR_DOINHERIT );
            var_SetFloat( p_input, "sub-fps", f_requested_fps );
1012
        }
1013
    }
1014

Laurent Aimar's avatar
Laurent Aimar committed
1015
    const int i_delay = var_CreateGetInteger( p_input, "sub-delay" );
1016
    if( i_delay != 0 )
1017
        var_SetInteger( p_input, "spu-delay", (mtime_t)i_delay * 100000 );
1018
}
1019

1020 1021
static void GetVarSlaves( input_thread_t *p_input,
                          input_item_slave_t ***ppp_slaves, int *p_slaves )
1022 1023 1024 1025 1026
{
    char *psz = var_GetNonEmptyString( p_input, "input-slave" );
    if( !psz )
        return;

1027 1028 1029
    input_item_slave_t **pp_slaves = *ppp_slaves;
    int i_slaves = *p_slaves;

1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048
    char *psz_org = psz;
    while( psz && *psz )
    {
        while( *psz == ' ' || *psz == '#' )
            psz++;

        char *psz_delim = strchr( psz, '#' );
        if( psz_delim )
            *psz_delim++ = '\0';

        if( *psz == 0 )
            break;

        char *uri = strstr(psz, "://")
                                   ? strdup( psz ) : vlc_path2uri( psz, NULL );
        psz = psz_delim;
        if( uri == NULL )
            continue;

1049 1050
        input_item_slave_t *p_slave =
            input_item_slave_New( uri, SLAVE_TYPE_AUDIO, SLAVE_PRIORITY_USER );
1051
        free( uri );
1052 1053 1054

        if( unlikely( p_slave == NULL ) )
            break;
1055
        TAB_APPEND(i_slaves, pp_slaves, p_slave);
1056 1057
    }
    free( psz_org );