input.c 99.7 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
Jean-Baptiste Kempf's avatar
LGPL  
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
LGPL  
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
LGPL  
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
LGPL  
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

Christophe Mutricy's avatar
Christophe Mutricy committed
34
#include <limits.h>
35
#include <assert.h>
36
#include <errno.h>
37
#include <math.h>
38
#include <sys/stat.h>
39

40
#include "input_internal.h"
41
#include "event.h"
42
#include "es_out.h"
43
#include "es_out_timeshift.h"
44
#include "access.h"
45
#include "demux.h"
46
#include "stream.h"
47
#include "item.h"
48
#include "resource.h"
49

Clément Stenac's avatar
Clément Stenac committed
50
#include <vlc_sout.h>
51
#include <vlc_dialog.h>
Clément Stenac's avatar
Clément Stenac committed
52 53
#include <vlc_url.h>
#include <vlc_charset.h>
54
#include <vlc_fs.h>
55
#include <vlc_strings.h>
56
#include <vlc_modules.h>
57

58
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
59
 * Local prototypes
60
 *****************************************************************************/
61 62
static void Destructor( input_thread_t * p_input );

63
static  void *Run            ( void * );
64

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
65
static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
66
                                  const char *, bool, input_resource_t * );
67
static  int             Init    ( input_thread_t *p_input );
68
static void             End     ( input_thread_t *p_input );
69
static void             MainLoop( input_thread_t *p_input, bool b_interactive );
70

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

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

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

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

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

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

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

103 104 105
enum {
    SUB_NOFLAG = 0x00,
    SUB_FORCED = 0x01,
106
    SUB_CANFAIL = 0x02,
107
};
108

109 110
static void input_SubtitleAdd( input_thread_t *, const char *, unsigned );
static void input_SubtitleFileAdd( input_thread_t *, char *, unsigned );
111 112
static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */

113
#undef input_Create
114 115 116 117 118 119 120 121 122 123 124 125
/**
 * 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
 */
126 127 128
input_thread_t *input_Create( vlc_object_t *p_parent,
                              input_item_t *p_item,
                              const char *psz_log, input_resource_t *p_resource )
129 130 131 132
{
    return Create( p_parent, p_item, psz_log, false, p_resource );
}

133
#undef input_CreateAndStart
134 135 136 137 138 139 140
/**
 * Create a new input_thread_t and start it.
 *
 * Provided for convenience.
 *
 * \see input_Create
 */
141 142
input_thread_t *input_CreateAndStart( vlc_object_t *p_parent,
                                      input_item_t *p_item, const char *psz_log )
143
{
144
    input_thread_t *p_input = input_Create( p_parent, p_item, psz_log, NULL );
145 146 147 148 149 150 151 152 153

    if( input_Start( p_input ) )
    {
        vlc_object_release( p_input );
        return NULL;
    }
    return p_input;
}

154
#undef input_Read
155
/**
156
 * Initialize an input thread and run it until it stops by itself.
157 158 159 160 161
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \return an error code, VLC_SUCCESS on success
 */
162
int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
163
{
164
    input_thread_t *p_input = Create( p_parent, p_item, NULL, false, NULL );
165 166 167
    if( !p_input )
        return VLC_EGENERIC;

168 169
    if( !Init( p_input ) )
    {
170
        MainLoop( p_input, false );
171 172 173 174
        End( p_input );
    }

    vlc_object_release( p_input );
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194
    return VLC_SUCCESS;
}

/**
 * Initialize an input and initialize it to preparse the item
 * This function is blocking. It will only accept parsing regular 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 )
{
    input_thread_t *p_input;

    /* Allocate descriptor */
    p_input = Create( p_parent, p_item, NULL, true, NULL );
    if( !p_input )
        return VLC_EGENERIC;

195 196 197 198 199
    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;

200 201
        if ( input_item_ShouldPreparseSubItems( p_item )
          && demux_Control( p_input->p->input.p_demux,
202 203 204 205 206
                            DEMUX_IS_PLAYLIST,
                            &b_is_playlist ) )
            b_is_playlist = false;
        if( b_is_playlist )
            MainLoop( p_input, false );
207
        End( p_input );
208
    }
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224

    vlc_object_release( p_input );

    return VLC_SUCCESS;
}

/**
 * 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 )
{
    /* Create thread and wait for its readiness. */
225 226 227
    p_input->p->is_running = !vlc_clone( &p_input->p->thread,
                                         Run, p_input, VLC_THREAD_PRIORITY_INPUT );
    if( !p_input->p->is_running )
228 229 230 231 232 233 234 235 236 237 238 239 240
    {
        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
 */
241
void input_Stop( input_thread_t *p_input )
242 243 244 245
{
    /* 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 */
246
    ObjectKillChildrens( VLC_OBJECT(p_input) );
247 248 249
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
}

250 251 252 253 254 255 256 257 258 259 260
void input_Join( input_thread_t *p_input )
{
    if( p_input->p->is_running )
        vlc_join( p_input->p->thread, NULL );
}

void input_Release( input_thread_t *p_input )
{
    vlc_object_release( p_input );
}

Laurent Aimar's avatar
Laurent Aimar committed
261 262 263 264 265
/**
 * Close an input
 *
 * It does not call input_Stop itself.
 */
266
void input_Close( input_thread_t *p_input )
Laurent Aimar's avatar
Laurent Aimar committed
267
{
268 269
    input_Join( p_input );
    input_Release( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
270 271
}

272 273 274 275 276 277 278 279 280 281 282 283
/**
 * 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 )
{
    assert( p_input && p_input->p );
    return p_input->p->p_item;
}

284
/*****************************************************************************
285 286
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
287
 *
Laurent Aimar's avatar
Laurent Aimar committed
288
 * XXX Do not forget to update vlc_input.h if you add new variables.
289
 *****************************************************************************/
290
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
291
                               const char *psz_header, bool b_quick,
292
                               input_resource_t *p_resource )
Michel Kaempf's avatar
Michel Kaempf committed
293
{
294
    input_thread_t *p_input = NULL;                 /* thread descriptor */
295
    int i;
296

297
    /* Allocate descriptor */
298
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ), "input" );
299
    if( p_input == NULL )
300
        return NULL;
301 302 303 304 305 306

    /* 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 );
307 308 309

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

310 311
    free( psz_name );

312 313
    p_input->p = calloc( 1, sizeof( input_thread_private_t ) );
    if( !p_input->p )
314 315
    {
        vlc_object_release( p_input );
316
        return NULL;
317
    }
318

319 320 321 322 323 324 325 326
    /* Parse input options */
    vlc_mutex_lock( &p_item->lock );
    assert( (int)p_item->optflagc == p_item->i_options );
    for( i = 0; i < p_item->i_options; i++ )
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
    vlc_mutex_unlock( &p_item->lock );

327
    p_input->b_preparsing = b_quick;
328
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
329

330
    /* Init Common fields */
331
    p_input->b_eof = false;
332
    p_input->p->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
333
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
334
    p_input->p->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
335
    p_input->p->i_stop  = 0;
336
    p_input->p->i_run   = 0;
Clément Stenac's avatar
Clément Stenac committed
337
    p_input->p->i_title = 0;
338
    p_input->p->title = NULL;
Clément Stenac's avatar
Clément Stenac committed
339
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
340
    p_input->p->i_state = INIT_S;
341
    p_input->p->i_rate = INPUT_RATE_DEFAULT;
342
    p_input->p->b_recording = false;
343 344
    memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) );
    TAB_INIT( p_input->p->i_bookmark, p_input->p->pp_bookmark );
345
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
346
    p_input->p->attachment_demux = NULL;
347
    p_input->p->p_sout   = NULL;
348
    p_input->p->b_out_pace_control = false;
349

Pierre's avatar
Pierre committed
350
    vlc_gc_incref( p_item ); /* Released in Destructor() */
351 352 353
    p_input->p->p_item = p_item;

    /* Init Input fields */
Clément Stenac's avatar
Clément Stenac committed
354
    p_input->p->input.p_demux  = NULL;
355
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
356 357 358
    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;
359 360 361 362
    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
363

364
    vlc_mutex_lock( &p_item->lock );
365 366

    if( !p_item->p_stats )
367
        p_item->p_stats = stats_NewInputStats( p_input );
368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387

    /* setup the preparse depth of the item
     * if we are preparsing, use the i_preparse_depth of the parent item */
    if( !p_input->b_preparsing )
    {
        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;
    }

388
    vlc_mutex_unlock( &p_item->lock );
389

390
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
391 392
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
393

394
    /* */
395
    if( p_resource )
396 397
    {
        p_input->p->p_resource_private = NULL;
398
        p_input->p->p_resource = input_resource_Hold( p_resource );
399
    }
400
    else
401 402
    {
        p_input->p->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) );
403
        p_input->p->p_resource = input_resource_Hold( p_input->p->p_resource_private );
404
    }
405
    input_resource_SetInput( p_input->p->p_resource, p_input );
406

407
    /* Init control buffer */
408
    vlc_mutex_init( &p_input->p->lock_control );
409
    vlc_cond_init( &p_input->p->wait_control );
Clément Stenac's avatar
Clément Stenac committed
410
    p_input->p->i_control = 0;
411
    p_input->p->is_running = false;
412

413 414
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
415

416
    /* Create Objects variables for public Get and Set */
417
    input_ControlVarInit( p_input );
418

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

                 p_seekpoint = vlc_seekpoint_New();
441 442 443 444 445
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
446
                         p_seekpoint->psz_name = strdup(psz_start + 5);
447 448 449 450 451 452 453
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
454
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
Ilkka Ollakka's avatar
Ilkka Ollakka committed
455
                                                        CLOCK_FREQ;
456 457
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
458
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
459
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
460 461 462 463 464
                                  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
465
            }
466
            free( psz_bookmarks );
Gildas Bazin's avatar
Gildas Bazin committed
467 468 469
        }
    }

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

475 476 477 478
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

479 480 481 482
    /* Make sure the interaction option is honored */
    if( !var_InheritBool( p_input, "interact" ) )
        p_input->i_flags |= OBJECT_FLAGS_NOINTERACT;

483
    /* */
484
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
485
    vlc_mutex_init( &p_input->p->counters.counters_lock );
486

487 488 489
    p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
    p_input->p->p_es_out = NULL;

490 491 492
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

493 494 495
    return p_input;
}

496 497 498 499
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
500
{
501
#ifndef NDEBUG
502
    char * psz_name = input_item_GetName( p_input->p->p_item );
503 504 505 506
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

507 508 509
    if( p_input->p->p_es_out_display )
        es_out_Delete( p_input->p->p_es_out_display );

510 511
    if( p_input->p->p_resource )
        input_resource_Release( p_input->p->p_resource );
512
    if( p_input->p->p_resource_private )
513
        input_resource_Release( p_input->p->p_resource_private );
514

515
    vlc_gc_decref( p_input->p->p_item );
Pierre's avatar
Pierre committed
516

517 518
    vlc_mutex_destroy( &p_input->p->counters.counters_lock );

519
    for( int i = 0; i < p_input->p->i_control; i++ )
Laurent Aimar's avatar
Laurent Aimar committed
520 521 522 523
    {
        input_control_t *p_ctrl = &p_input->p->control[i];
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }
524

525
    vlc_cond_destroy( &p_input->p->wait_control );
526 527
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
528
}
529

530
/*****************************************************************************
531
 * Run: main thread loop
532 533
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
534
 *****************************************************************************/
535
static void *Run( void *obj )
Michel Kaempf's avatar
Michel Kaempf committed
536
{
537
    input_thread_t *p_input = (input_thread_t *)obj;
538
    const int canc = vlc_savecancel();
539

540 541 542
    if( !Init( p_input ) )
    {
        MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
543

544 545 546
        /* Clean up */
        End( p_input );
    }
547

548
    input_SendEventDead( p_input );
549

550
    vlc_restorecancel( canc );
551
    return NULL;
552 553 554 555 556
}

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

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
562
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t i_start_mdate )
563
{
564
    int i_ret;
565

566
    *pb_changed = false;
567

Laurent Aimar's avatar
Laurent Aimar committed
568
    if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) ||
569
        ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
570 571
        i_ret = 0; /* EOF */
    else
Laurent Aimar's avatar
Laurent Aimar committed
572
        i_ret = demux_Demux( p_input->p->input.p_demux );
573 574

    if( i_ret > 0 )
575
    {
576
        if( p_input->p->input.p_demux->info.i_update )
577
        {
578 579 580 581 582
            if( p_input->p->input.p_demux->info.i_update & INPUT_UPDATE_TITLE_LIST )
            {
                UpdateTitleListfromDemux( p_input );
                p_input->p->input.p_demux->info.i_update &= ~INPUT_UPDATE_TITLE_LIST;
            }
583 584 585 586 587 588
            if( p_input->p->input.b_title_demux )
            {
                i_ret = UpdateTitleSeekpointFromDemux( p_input );
                *pb_changed = true;
            }
            UpdateGenericFromDemux( p_input );
589 590
        }
    }
591

592 593
    if( i_ret == 0 )    /* EOF */
    {
594 595
        msg_Dbg( p_input, "EOF reached" );
        p_input->p->input.b_eof = true;
596
        es_out_Eos(p_input->p->p_es_out);
597 598 599 600 601 602 603
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
604
        SlaveDemux( p_input );
605 606
}

607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643
static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate )
{
    int i_repeat = var_GetInteger( p_input, "input-repeat" );
    if( i_repeat == 0 )
        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 */
    val.i_int = p_input->p->input.i_title_start -
        p_input->p->input.i_title_offset;
    if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title )
        val.i_int = 0;
    input_ControlPush( p_input,
                       INPUT_CONTROL_SET_TITLE, &val );

    val.i_int = p_input->p->input.i_seekpoint_start -
        p_input->p->input.i_seekpoint_offset;
    if( val.i_int > 0 /* TODO: check upper boundary */ )
        input_ControlPush( p_input,
                           INPUT_CONTROL_SET_SEEKPOINT, &val );

    /* Seek to start position */
    if( p_input->p->i_start > 0 )
    {
        val.i_time = p_input->p->i_start;
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val );
    }
    else
    {
644
        val.f_float = 0.f;
645 646 647 648 649 650 651 652
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

    /* */
    *pi_start_mdate = mdate();
    return VLC_SUCCESS;
}

653
/**
654
 * Update timing infos and statistics.
655
 */
656
static void MainLoopStatistics( input_thread_t *p_input )
657
{
658 659 660
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
661 662

    /* update input status variables */
663
    if( demux_Control( p_input->p->input.p_demux,
664 665
                       DEMUX_GET_POSITION, &f_position ) )
        f_position = 0.0;
666

667
    if( demux_Control( p_input->p->input.p_demux,
668 669
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
Laurent Aimar's avatar
Laurent Aimar committed
670
    p_input->p->i_time = i_time;
671 672

    if( demux_Control( p_input->p->input.p_demux,
673 674
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
675

676
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
677 678 679 680

    /* update current bookmark */
    vlc_mutex_lock( &p_input->p->p_item->lock );
    p_input->p->bookmark.i_time_offset = i_time;
681
    p_input->p->bookmark.i_byte_offset = -1;
682
    vlc_mutex_unlock( &p_input->p->p_item->lock );
683

684
    stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
685
    input_SendEventStatistics( p_input );
686 687 688 689 690 691
}

/**
 * MainLoop
 * The main input loop.
 */
692
static void MainLoop( input_thread_t *p_input, bool b_interactive )
693 694
{
    mtime_t i_start_mdate = mdate();
695
    mtime_t i_intf_update = 0;
696
    mtime_t i_last_seek_mdate = 0;
697 698
    bool b_pause_after_eof = b_interactive &&
                             var_CreateGetBool( p_input, "play-and-pause" );
699

700
    while( vlc_object_alive( p_input ) && !p_input->b_error )
701
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
702
        mtime_t i_wakeup = -1;
703
        bool b_paused = p_input->p->i_state == PAUSE_S;
Laurent Aimar's avatar
Laurent Aimar committed
704
        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
705 706
         * is paused -> this may cause problem with some of them
         * The same problem can be seen when seeking while paused */
707 708
        if( b_paused )
            b_paused = !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof;
709 710

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

716
                MainLoopDemux( p_input, &b_force_update, i_start_mdate );
717
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
718 719 720

                if( b_force_update )
                    i_intf_update = 0;
721
            }
722
            else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
723 724 725 726
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
727 728 729
            /* Pause after eof only if the input is pausable.
             * This way we won't trigger timeshifting for nothing */
            else if( b_pause_after_eof && p_input->p->b_can_pause )
730
            {
731 732
                vlc_value_t val = { .i_int = PAUSE_S };

733 734 735 736 737
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

                b_paused = true;
            }
738 739
            else
            {
740 741
                if( MainLoopTryRepeat( p_input, &i_start_mdate ) )
                    break;
742
                b_pause_after_eof = var_GetBool( p_input, "play-and-pause" );
743
            }
744 745 746 747 748 749 750 751

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

754 755 756
        /* Handle control */
        for( ;; )
        {
757
            mtime_t i_deadline = i_wakeup;
758 759 760 761 762 763

            /* Postpone seeking until ES buffering is complete or at most
             * 125 ms. */
            bool b_postpone = es_out_GetBuffering( p_input->p->p_es_out )
                            && !p_input->p->input.b_eof;
            if( b_postpone )
764
            {
765 766 767 768
                mtime_t now = mdate();

                /* Recheck ES buffer level every 20 ms when seeking */
                if( now < i_last_seek_mdate + INT64_C(125000)
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
769
                 && (i_deadline < 0 || i_deadline > now + INT64_C(20000)) )
770 771 772 773
                    i_deadline = now + INT64_C(20000);
                else
                    b_postpone = false;
            }
774

775 776
            int i_type;
            vlc_value_t val;
777

778 779 780 781 782 783
            if( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) )
            {
                if( b_postpone )
                    continue;
                break; /* Wake-up time reached */
            }
784

785
#ifndef NDEBUG
786
            msg_Dbg( p_input, "control type=%d", i_type );
787
#endif
788 789 790 791 792
            if( Control( p_input, i_type, val ) )
            {
                if( ControlIsSeekRequest( i_type ) )
                    i_last_seek_mdate = mdate();
                i_intf_update = 0;
793
            }
794

795
            /* Update the wakeup time */
796
            if( i_wakeup != 0 )
797
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
798
        }
799
    }
800

801
    if( !p_input->b_error )
802
        input_ChangeState( p_input, END_S );
803 804
}

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

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

834
#ifdef ENABLE_SOUT
835 836
static int InitSout( input_thread_t * p_input )
{
837 838
    if( p_input->b_preparsing )
        return VLC_SUCCESS;
839 840

    /* Find a usable sout and attach it to p_input */
841
    char *psz = var_GetNonEmptyString( p_input, "sout" );
842
    if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
843
    {
844
        p_input->p->p_sout  = input_resource_RequestSout( p_input->p->p_resource, NULL, psz );
845
        if( !p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
846
        {
847 848 849 850 851
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot start stream output instance, " \
                              "aborting" );
            free( psz );
            return VLC_EGENERIC;
852
        }
853
        if( libvlc_stats( p_input ) )
854
        {
855 856 857
            INIT_COUNTER( sout_sent_packets, COUNTER );
            INIT_COUNTER( sout_sent_bytes, COUNTER );
            INIT_COUNTER( sout_send_bitrate, DERIVATIVE );
858
        }
859
    }
860
    else
861
    {
862
        input_resource_RequestSout( p_input->p->p_resource, NULL, NULL );
863
    }
864
    free( psz );
865

866 867
    return VLC_SUCCESS;
}
868
#endif
869

870 871
static void InitTitle( input_thread_t * p_input )
{
Laurent Aimar's avatar
Laurent Aimar committed
872
    input_source_t *p_master = &p_input->p->input;
873

Laurent Aimar's avatar
Laurent Aimar committed
874 875
    if( p_input->b_preparsing )
        return;
876

877
    vlc_mutex_lock( &p_input->p->p_item->lock );
878
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
879 880 881 882
    p_input->p->i_title = p_master->i_title;
    p_input->p->title   = p_master->title;
    p_input->p->i_title_offset = p_master->i_title_offset;
    p_input->p->i_seekpoint_offset = p_master->i_seekpoint_offset;
883 884 885 886
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
887
        input_SendEventTitle( p_input, 0 );
888 889 890
    }

    /* Global flag */
891
    p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
Laurent Aimar's avatar
Laurent Aimar committed
892 893
    p_input->p->b_can_pause        = p_master->b_can_pause;
    p_input->p->b_can_rate_control = p_master->b_can_rate_control;
894
    vlc_mutex_unlock( &p_input->p->p_item->lock );
895
}
896

897 898 899
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
900

901 902 903 904 905
    /* Start title/chapter */
    val.i_int = p_input->p->input.i_title_start -
                p_input->p->input.i_title_offset;
    if( val.i_int > 0 && val.i_int < p_input->p->input.i_title )
        input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
Laurent Aimar's avatar
Laurent Aimar committed
906

907 908 909 910 911
    val.i_int = p_input->p->input.i_seekpoint_start -
                p_input->p->input.i_seekpoint_offset;
    if( val.i_int > 0 /* TODO: check upper boundary */ )
        input_ControlPush( p_input, INPUT_CONTROL_SET_SEEKPOINT, &val );

Laurent Aimar's avatar
Laurent Aimar committed
912
    /* Start/stop/run time */
913
    p_input->p->i_start = llroundf(1000000.f
914
                                     * var_GetFloat( p_input, "start-time" ));
915
    p_input->p->i_stop  = llroundf(1000000.f
916
                                     * var_GetFloat( p_input, "stop-time" ));
917
    p_input->p->i_run   = llroundf(1000000.f
918
                                     * var_GetFloat( p_input, "run-time" ));
919
    if( p_input->p->i_run < 0 )
920
    {
921 922
        msg_Warn( p_input, "invalid run-time ignored" );
        p_input->p->i_run = 0;
Rafaël Carré's avatar
Rafaël Carré committed
923
    }
924

925
    if( p_input->p->i_start > 0 )
926
    {
927
        vlc_value_t s;
928

929
        msg_Dbg( p_input, "starting at time: %ds",
Ilkka Ollakka's avatar
Ilkka Ollakka committed
930
                 (int)( p_input->p->i_start / CLOCK_FREQ ) );
931

932 933
        s.i_time = p_input->p->i_start;
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
934 935 936 937 938 939
    }
    if( p_input->p->i_stop > 0 && p_input->p->i_stop <= p_input->p->i_start )
    {
        msg_Warn( p_input, "invalid stop-time ignored" );
        p_input->p->i_stop = 0;
    }
940
    p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
Laurent Aimar's avatar
Laurent Aimar committed
941
}
942

Laurent Aimar's avatar
Laurent Aimar committed
943 944
static void LoadSubtitles( input_thread_t *p_input )
{