input.c 98 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 <math.h>
37
#include <sys/stat.h>
38

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

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

55
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
56
 * Local prototypes
57
 *****************************************************************************/
58 59
static  void *Run( void * );
static  void *Preparse( void * );
60

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

67
static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline, bool b_postpone_seek );
68
static void       ControlRelease( int i_type, vlc_value_t val );
69
static bool       ControlIsSeekRequest( int i_type );
70
static bool       Control( input_thread_t *, int, vlc_value_t );
71
static void       ControlPause( input_thread_t *, mtime_t );
72

73 74
static int  UpdateTitleSeekpointFromDemux( input_thread_t * );
static void UpdateGenericFromDemux( input_thread_t * );
75
static void UpdateTitleListfromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
76

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

79 80 81 82
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
83 84
static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );

85 86
/* TODO */
//static void InputGetAttachments( input_thread_t *, input_source_t * );
87
static void SlaveDemux( input_thread_t *p_input );
88
static void SlaveSeek( input_thread_t *p_input );
89

90
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
91
static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux );
92 93 94
static void InputGetExtraFiles( input_thread_t *p_input,
                                int *pi_list, char ***pppsz_list,
                                const char *psz_access, const char *psz_path );
95

96 97 98
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 );
99

100 101 102 103
#define SLAVE_ADD_NOFLAG    0
#define SLAVE_ADD_FORCED    (1<<0)
#define SLAVE_ADD_CANFAIL   (1<<1)
#define SLAVE_ADD_SET_TIME  (1<<2)
104

105 106
static int input_SlaveSourceAdd( input_thread_t *, enum slave_type,
                                 const char *, unsigned );
107
static char *input_SubtitleFile2Uri( input_thread_t *, const char * );
108 109
static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */

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

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

144 145
    if( !Init( p_input ) )
    {
146
        MainLoop( p_input, false );
147 148 149 150
        End( p_input );
    }

    vlc_object_release( p_input );
151 152 153
    return VLC_SUCCESS;
}

154 155 156 157 158 159
input_thread_t *input_CreatePreparser( vlc_object_t *parent,
                                       input_item_t *item )
{
    return Create( parent, item, NULL, true, NULL );
}

160 161 162 163 164 165 166 167 168
/**
 * 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 )
{
169 170 171 172 173
    void *(*func)(void *) = Run;

    if( p_input->b_preparsing )
        func = Preparse;

174
    assert( !p_input->p->is_running );
175
    /* Create thread and wait for its readiness. */
176 177
    p_input->p->is_running = !vlc_clone( &p_input->p->thread, func, p_input,
                                         VLC_THREAD_PRIORITY_INPUT );
178
    if( !p_input->p->is_running )
179 180 181 182 183 184 185 186 187 188 189 190 191
    {
        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
 */
192
void input_Stop( input_thread_t *p_input )
193
{
194 195 196 197 198 199 200 201 202 203 204 205 206
    input_thread_private_t *sys = p_input->p;

    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 );
207
    vlc_interrupt_kill( &sys->interrupt );
208 209
}

Laurent Aimar's avatar
Laurent Aimar committed
210 211 212 213 214
/**
 * Close an input
 *
 * It does not call input_Stop itself.
 */
215
void input_Close( input_thread_t *p_input )
Laurent Aimar's avatar
Laurent Aimar committed
216
{
217 218
    if( p_input->p->is_running )
        vlc_join( p_input->p->thread, NULL );
219
    vlc_interrupt_deinit( &p_input->p->interrupt );
220
    vlc_object_release( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
221 222
}

223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257
/**
 * 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;
#ifndef NDEBUG
    char * psz_name = input_item_GetName( p_input->p->p_item );
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

    if( p_input->p->p_es_out_display )
        es_out_Delete( p_input->p->p_es_out_display );

    if( p_input->p->p_resource )
        input_resource_Release( p_input->p->p_resource );
    if( p_input->p->p_resource_private )
        input_resource_Release( p_input->p->p_resource_private );

    vlc_gc_decref( p_input->p->p_item );

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

    for( int i = 0; i < p_input->p->i_control; i++ )
    {
        input_control_t *p_ctrl = &p_input->p->control[i];
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }

    vlc_cond_destroy( &p_input->p->wait_control );
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
}

258 259 260 261 262 263 264 265 266 267 268 269
/**
 * 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;
}

270
/*****************************************************************************
271 272
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
273
 *
Laurent Aimar's avatar
Laurent Aimar committed
274
 * XXX Do not forget to update vlc_input.h if you add new variables.
275
 *****************************************************************************/
276
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
277
                               const char *psz_header, bool b_preparsing,
278
                               input_resource_t *p_resource )
Michel Kaempf's avatar
Michel Kaempf committed
279
{
280
    input_thread_t *p_input = NULL;                 /* thread descriptor */
281

282
    /* Allocate descriptor */
283
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ), "input" );
284
    if( p_input == NULL )
285
        return NULL;
286 287 288 289 290 291

    /* 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 );
292

293
    msg_Dbg( p_input, "Creating an input for %s'%s'", b_preparsing ? "preparsing " : "", psz_name);
294

295 296
    free( psz_name );

297 298
    p_input->p = calloc( 1, sizeof( input_thread_private_t ) );
    if( !p_input->p )
299 300
    {
        vlc_object_release( p_input );
301
        return NULL;
302
    }
303

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

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

310
    /* Init Common fields */
311
    p_input->p->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
312
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
313
    p_input->p->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
314 315
    p_input->p->i_stop  = 0;
    p_input->p->i_title = 0;
316
    p_input->p->title = NULL;
Clément Stenac's avatar
Clément Stenac committed
317
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
318
    p_input->p->i_state = INIT_S;
319 320
    p_input->p->is_running = false;
    p_input->p->is_stopped = false;
321
    p_input->p->b_recording = false;
322
    p_input->p->i_rate = INPUT_RATE_DEFAULT;
323 324
    memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) );
    TAB_INIT( p_input->p->i_bookmark, p_input->p->pp_bookmark );
325
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
326
    p_input->p->attachment_demux = NULL;
327
    p_input->p->p_sout   = NULL;
328
    p_input->p->b_out_pace_control = false;
329

Pierre's avatar
Pierre committed
330
    vlc_gc_incref( p_item ); /* Released in Destructor() */
331 332 333
    p_input->p->p_item = p_item;

    /* Init Input fields */
334
    p_input->p->master = NULL;
335
    vlc_mutex_lock( &p_item->lock );
336 337

    if( !p_item->p_stats )
338
        p_item->p_stats = stats_NewInputStats( p_input );
339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358

    /* 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;
    }

359 360
    /* */
    if( p_input->b_preparsing )
361
        p_input->obj.flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
362 363 364

    /* Make sure the interaction option is honored */
    if( !var_InheritBool( p_input, "interact" ) )
365
        p_input->obj.flags |= OBJECT_FLAGS_NOINTERACT;
366 367 368
    else if( p_item->b_preparse_interact )
    {
        /* If true, this item was asked explicitly to interact with the user
369
         * (via libvlc_MetadataRequest). Sub items created from this input won't
370
         * have this flag and won't interact with the user */
371
        p_input->obj.flags &= ~OBJECT_FLAGS_NOINTERACT;
372 373
    }

374
    vlc_mutex_unlock( &p_item->lock );
375

376
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
377 378
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
379

380
    /* */
381
    if( p_resource )
382 383
    {
        p_input->p->p_resource_private = NULL;
384
        p_input->p->p_resource = input_resource_Hold( p_resource );
385
    }
386
    else
387 388
    {
        p_input->p->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) );
389
        p_input->p->p_resource = input_resource_Hold( p_input->p->p_resource_private );
390
    }
391
    input_resource_SetInput( p_input->p->p_resource, p_input );
392

393
    /* Init control buffer */
394
    vlc_mutex_init( &p_input->p->lock_control );
395
    vlc_cond_init( &p_input->p->wait_control );
Clément Stenac's avatar
Clément Stenac committed
396
    p_input->p->i_control = 0;
397
    vlc_interrupt_init(&p_input->p->interrupt);
398

399 400
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
401

402
    /* Create Objects variables for public Get and Set */
403
    input_ControlVarInit( p_input );
404

405
    /* */
406
    if( !p_input->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
407
    {
408 409
        char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
        if( psz_bookmarks )
Gildas Bazin's avatar
Gildas Bazin committed
410
        {
411 412
            /* FIXME: have a common cfg parsing routine used by sout and others */
            char *psz_parser, *psz_start, *psz_end;
413
            psz_parser = psz_bookmarks;
414
            while( (psz_start = strchr( psz_parser, '{' ) ) )
Gildas Bazin's avatar
Gildas Bazin committed
415
            {
416
                 seekpoint_t *p_seekpoint;
417 418 419 420 421 422 423 424
                 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 = ',';
425 426

                 p_seekpoint = vlc_seekpoint_New();
427 428 429 430
                 
                 if( unlikely( p_seekpoint == NULL ) )
                     break;
                    
431 432 433 434 435
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
436 437
                         free( p_seekpoint->psz_name );

438
                         p_seekpoint->psz_name = strdup(psz_start + 5);
439 440 441
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
442
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
Ilkka Ollakka's avatar
Ilkka Ollakka committed
443
                                                        CLOCK_FREQ;
444 445
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
446
                }
447 448
                msg_Dbg( p_input, "adding bookmark: %s, time=%"PRId64,
                                  p_seekpoint->psz_name,
449 450 451 452
                                  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
453
            }
454
            free( psz_bookmarks );
Gildas Bazin's avatar
Gildas Bazin committed
455 456 457
        }
    }

458
    /* Remove 'Now playing' info as it is probably outdated */
459
    input_item_SetNowPlaying( p_item, NULL );
460
    input_item_SetESNowPlaying( p_item, NULL );
461
    input_SendEventMeta( p_input );
462

463
    /* */
464
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
465
    vlc_mutex_init( &p_input->p->counters.counters_lock );
466

467 468 469
    p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
    p_input->p->p_es_out = NULL;

470
    /* Set the destructor when we are sure we are initialized */
471
    vlc_object_set_destructor( p_input, input_Destructor );
472

473 474 475
    return p_input;
}

476
/*****************************************************************************
477
 * Run: main thread loop
478 479
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
480
 *****************************************************************************/
481
static void *Run( void *obj )
Michel Kaempf's avatar
Michel Kaempf committed
482
{
483
    input_thread_t *p_input = (input_thread_t *)obj;
484

485 486
    vlc_interrupt_set(&p_input->p->interrupt);

487 488
    if( !Init( p_input ) )
    {
489 490 491 492 493 494 495
        if( p_input->p->b_can_pace_control && p_input->p->b_out_pace_control )
        {
            /* We don't want a high input priority here or we'll
             * end-up sucking up all the CPU time */
            vlc_set_priority( p_input->p->thread, VLC_THREAD_PRIORITY_LOW );
        }

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

498 499 500
        /* Clean up */
        End( p_input );
    }
501

502
    input_SendEventDead( p_input );
503
    return NULL;
504 505
}

506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530
static void *Preparse( void *obj )
{
    input_thread_t *p_input = (input_thread_t *)obj;

    vlc_interrupt_set(&p_input->p->interrupt);

    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;

        if ( input_item_ShouldPreparseSubItems( p_input->p->p_item )
          && demux_Control( p_input->p->master->p_demux,
                            DEMUX_IS_PLAYLIST,
                            &b_is_playlist ) )
            b_is_playlist = false;
        if( b_is_playlist )
            MainLoop( p_input, false );
        End( p_input );
    }

    input_SendEventDead( p_input );
    return NULL;
}

531 532 533 534 535 536 537 538 539 540 541
bool input_Stopped( input_thread_t *input )
{
    input_thread_private_t *sys = input->p;
    bool ret;

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

542 543 544
/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
545 546 547 548 549

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
550
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed )
551
{
552
    int i_ret;
Steve Lhomme's avatar
Steve Lhomme committed
553
    demux_t *p_demux = p_input->p->master->p_demux;
554

555
    *pb_changed = false;
556

557
    if( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop )
558
        i_ret = VLC_DEMUXER_EOF;
559
    else
Steve Lhomme's avatar
Steve Lhomme committed
560
        i_ret = demux_Demux( p_demux );
561

562 563 564
    i_ret = i_ret > 0 ? VLC_DEMUXER_SUCCESS : ( i_ret < 0 ? VLC_DEMUXER_EGENERIC : VLC_DEMUXER_EOF);

    if( i_ret == VLC_DEMUXER_SUCCESS )
565
    {
566 567 568 569
        if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_TITLE_LIST ) )
            UpdateTitleListfromDemux( p_input );

        if( p_input->p->master->b_title_demux )
570
        {
571 572
            i_ret = UpdateTitleSeekpointFromDemux( p_input );
            *pb_changed = true;
573
        }
574 575

        UpdateGenericFromDemux( p_input );
576
    }
577

578
    if( i_ret == VLC_DEMUXER_EOF )
579
    {
580
        msg_Dbg( p_input, "EOF reached" );
581
        p_input->p->master->b_eof = true;
582
        es_out_Eos(p_input->p->p_es_out);
583
    }
584
    else if( i_ret == VLC_DEMUXER_EGENERIC )
585 586 587
    {
        input_ChangeState( p_input, ERROR_S );
    }
588
    else if( p_input->p->i_slave > 0 )
589
        SlaveDemux( p_input );
590 591
}

592
static int MainLoopTryRepeat( input_thread_t *p_input )
593 594
{
    int i_repeat = var_GetInteger( p_input, "input-repeat" );
595
    if( i_repeat <= 0 )
596 597 598 599 600 601 602 603 604 605 606 607
        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 */
608 609 610
    val.i_int = p_input->p->master->i_title_start -
        p_input->p->master->i_title_offset;
    if( val.i_int < 0 || val.i_int >= p_input->p->master->i_title )
611 612 613 614
        val.i_int = 0;
    input_ControlPush( p_input,
                       INPUT_CONTROL_SET_TITLE, &val );

615 616
    val.i_int = p_input->p->master->i_seekpoint_start -
        p_input->p->master->i_seekpoint_offset;
617 618 619 620 621 622 623
    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 )
    {
624
        val.i_int = p_input->p->i_start;
625 626 627 628
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val );
    }
    else
    {
629
        val.f_float = 0.f;
630 631 632 633 634 635
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

    return VLC_SUCCESS;
}

636
/**
637
 * Update timing infos and statistics.
638
 */
639
static void MainLoopStatistics( input_thread_t *p_input )
640
{
641 642 643
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
644 645

    /* update input status variables */
646
    if( demux_Control( p_input->p->master->p_demux,
647 648
                       DEMUX_GET_POSITION, &f_position ) )
        f_position = 0.0;
649

650
    if( demux_Control( p_input->p->master->p_demux,
651 652
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
Laurent Aimar's avatar
Laurent Aimar committed
653
    p_input->p->i_time = i_time;
654

655
    if( demux_Control( p_input->p->master->p_demux,
656 657
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
658

659
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
660 661 662 663 664

    /* update current bookmark */
    vlc_mutex_lock( &p_input->p->p_item->lock );
    p_input->p->bookmark.i_time_offset = i_time;
    vlc_mutex_unlock( &p_input->p->p_item->lock );
665

666
    stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
667
    input_SendEventStatistics( p_input );
668 669 670 671 672 673
}

/**
 * MainLoop
 * The main input loop.
 */
674
static void MainLoop( input_thread_t *p_input, bool b_interactive )
675
{
676
    mtime_t i_intf_update = 0;
677
    mtime_t i_last_seek_mdate = 0;
678 679

    if( b_interactive && var_InheritBool( p_input, "start-paused" ) )
680
        ControlPause( p_input, mdate() );
681

682
    bool b_pause_after_eof = b_interactive &&
683
                             var_InheritBool( p_input, "play-and-pause" );
684

685 686 687
    demux_t *p_demux = p_input->p->master->p_demux;
    const bool b_can_demux = p_demux->pf_demux != NULL;

688
    while( !input_Stopped( p_input ) && p_input->p->i_state != ERROR_S )
689
    {
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
690
        mtime_t i_wakeup = -1;
691
        bool b_paused = p_input->p->i_state == PAUSE_S;
Laurent Aimar's avatar
Laurent Aimar committed
692
        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
693 694
         * is paused -> this may cause problem with some of them
         * The same problem can be seen when seeking while paused */
695
        if( b_paused )
696 697
            b_paused = !es_out_GetBuffering( p_input->p->p_es_out )
                    || p_input->p->master->b_eof;
698 699

        if( !b_paused )
700
        {
701
            if( !p_input->p->master->b_eof )
702
            {
703
                bool b_force_update = false;
704

705
                MainLoopDemux( p_input, &b_force_update );
706

707
                if( b_can_demux )
708
                    i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
709 710
                if( b_force_update )
                    i_intf_update = 0;
711
            }
712
            else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
713 714 715 716
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
717 718 719
            /* 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 )
720
            {
721 722
                vlc_value_t val = { .i_int = PAUSE_S };

723 724 725 726 727
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

                b_paused = true;
            }
728 729
            else
            {
730
                if( MainLoopTryRepeat( p_input ) )
731
                    break;
732
            }
733 734 735 736 737 738 739 740

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

743 744 745
        /* Handle control */
        for( ;; )
        {
746
            mtime_t i_deadline = i_wakeup;
747 748 749 750

            /* Postpone seeking until ES buffering is complete or at most
             * 125 ms. */
            bool b_postpone = es_out_GetBuffering( p_input->p->p_es_out )
751
                            && !p_input->p->master->b_eof;
752
            if( b_postpone )
753
            {
754 755 756 757
                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
758
                 && (i_deadline < 0 || i_deadline > now + INT64_C(20000)) )
759 760 761 762
                    i_deadline = now + INT64_C(20000);
                else
                    b_postpone = false;
            }
763

764 765
            int i_type;
            vlc_value_t val;
766

767 768 769 770 771 772
            if( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) )
            {
                if( b_postpone )
                    continue;
                break; /* Wake-up time reached */
            }
773

774
#ifndef NDEBUG
775
            msg_Dbg( p_input, "control type=%d", i_type );
776
#endif
777 778 779 780 781
            if( Control( p_input, i_type, val ) )
            {
                if( ControlIsSeekRequest( i_type ) )
                    i_last_seek_mdate = mdate();
                i_intf_update = 0;
782
            }
783

784
            /* Update the wakeup time */
785
            if( i_wakeup != 0 )
786
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
787
        }
788
    }
789 790
}

791
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
792
{
793
    if( p_input->b_preparsing ) return;
794

795
    /* Prepare statistics */
796 797
#define INIT_COUNTER( c, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( STATS_##compute);
798
    if( libvlc_stats( p_input ) )
799
    {
800 801 802 803 804 805 806 807 808 809 810 811 812 813
        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 );
814 815 816
        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;
817
    }
818
}
819

820
#ifdef ENABLE_SOUT
821 822
static int InitSout( input_thread_t * p_input )
{
823 824
    if( p_input->b_preparsing )
        return VLC_SUCCESS;
825 826

    /* Find a usable sout and attach it to p_input */
827
    char *psz = var_GetNonEmptyString( p_input, "sout" );
828
    if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
829
    {
830
        p_input->p->p_sout  = input_resource_RequestSout( p_input->p->p_resource, NULL, psz );
831
        if( !p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
832
        {
833 834 835 836 837
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot start stream output instance, " \
                              "aborting" );
            free( psz );
            return VLC_EGENERIC;
838
        }
839
        if( libvlc_stats( p_input ) )
840
        {
841 842 843
            INIT_COUNTER( sout_sent_packets, COUNTER );
            INIT_COUNTER( sout_sent_bytes, COUNTER );
            INIT_COUNTER( sout_send_bitrate, DERIVATIVE );
844
        }
845
    }
846
    else
847
    {
848
        input_resource_RequestSout( p_input->p->p_resource, NULL, NULL );
849
    }
850
    free( psz );
851

852 853
    return VLC_SUCCESS;
}
854
#endif
855

856 857
static void InitTitle( input_thread_t * p_input )
{
858
    input_source_t *p_master = p_input->p->master;
859

Laurent Aimar's avatar
Laurent Aimar committed
860 861
    if( p_input->b_preparsing )
        return;
862

863
    vlc_mutex_lock( &p_input->p->p_item->lock );
864
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
865 866 867 868
    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;
869 870 871 872
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
873
        input_SendEventTitle( p_input, 0 );
874 875 876
    }

    /* Global flag */
877
    p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
Laurent Aimar's avatar
Laurent Aimar committed
878 879
    p_input->p->b_can_pause        = p_master->b_can_pause;
    p_input->p->b_can_rate_control = p_master->b_can_rate_control;
880
    vlc_mutex_unlock( &p_input->p->p_item->lock );
881
}
882

883 884 885
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
886

887
    /* Start title/chapter */
888 889 890
    val.i_int = p_input->p->master->i_title_start -
                p_input->p->master->i_title_offset;
    if( val.i_int > 0 && val.i_int < p_input->p->master->i_title )
891
        input_ControlPush( p_input, INPUT_CONTROL_SET_TITLE, &val );
Laurent Aimar's avatar
Laurent Aimar committed
892

893 894
    val.i_int = p_input->p->master->i_seekpoint_start -
                p_input->p->master->i_seekpoint_offset;
895 896 897
    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
898
    /* Start/stop/run time */
899
    p_input->p->i_start = llroundf(1000000.f
900
                                     * var_GetFloat( p_input, "start-time" ));
901
    p_input->p->i_stop  = llroundf(1000000.f
902
                                     * var_GetFloat( p_input, "stop-time" ));
903
    if( p_input->p->i_stop <= 0 )
904
    {
905 906 907 908 909 910 911 912 913
        p_input->p->i_stop = llroundf(1000000.f
                                     * var_GetFloat( p_input, "run-time" ));
        if( p_input->p->i_stop < 0 )
        {
            msg_Warn( p_input, "invalid run-time ignored" );
            p_input->p->i_stop = 0;
        }
        else
            p_input->p->i_stop += p_input->p->i_start;
Rafaël Carré's avatar
Rafaël Carré committed
914
    }
915

916
    if( p_input->p->i_start > 0 )
917
    {
918
        vlc_value_t s;
919

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

923
        s.i_int = p_input->p->i_start;
924
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );