input.c 99 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
static void       ControlPause( input_thread_t *, mtime_t );
76

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

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

static input_source_t *InputSourceNew( input_thread_t *);
84
static int  InputSourceInit( input_thread_t *, input_source_t *,
85 86
                             const char *, const char *psz_forced_demux,
                             bool b_in_can_fail );
87
static void InputSourceClean( 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 99
static void InputGetExtraFiles( input_thread_t *p_input,
                                int *pi_list, char ***pppsz_list,
                                const char *psz_access, const char *psz_path );
100

101 102
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 );
103

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

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

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

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

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

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

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

    vlc_object_release( p_input );
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195
    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;

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

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

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

Laurent Aimar's avatar
Laurent Aimar committed
251 252 253 254 255
/**
 * Close an input
 *
 * It does not call input_Stop itself.
 */
256
void input_Close( input_thread_t *p_input )
Laurent Aimar's avatar
Laurent Aimar committed
257
{
258 259 260
    if( p_input->p->is_running )
        vlc_join( p_input->p->thread, NULL );
    vlc_object_release( p_input );
Laurent Aimar's avatar
Laurent Aimar committed
261 262
}

263 264 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 )
{
    assert( p_input && p_input->p );
    return p_input->p->p_item;
}

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

287
    /* Allocate descriptor */
288
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ), "input" );
289
    if( p_input == NULL )
290
        return NULL;
291 292 293 294 295 296

    /* 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 );
297 298 299

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

300 301
    free( psz_name );

302 303
    p_input->p = calloc( 1, sizeof( input_thread_private_t ) );
    if( !p_input->p )
304 305
    {
        vlc_object_release( p_input );
306
        return NULL;
307
    }
308

309
    /* Parse input options */
310
    input_item_ApplyOptions( VLC_OBJECT(p_input), p_item );
311

312
    p_input->b_preparsing = b_quick;
313
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
314

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

Pierre's avatar
Pierre committed
334
    vlc_gc_incref( p_item ); /* Released in Destructor() */
335 336 337
    p_input->p->p_item = p_item;

    /* Init Input fields */
Clément Stenac's avatar
Clément Stenac committed
338
    p_input->p->input.p_demux  = NULL;
339
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
340 341 342
    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;
343 344 345 346
    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
347

348
    vlc_mutex_lock( &p_item->lock );
349 350

    if( !p_item->p_stats )
351
        p_item->p_stats = stats_NewInputStats( p_input );
352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371

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

372
    vlc_mutex_unlock( &p_item->lock );
373

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

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

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

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

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

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

                 p_seekpoint = vlc_seekpoint_New();
425 426 427 428 429
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
430
                         p_seekpoint->psz_name = strdup(psz_start + 5);
431 432 433 434 435 436 437
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
438
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
Ilkka Ollakka's avatar
Ilkka Ollakka committed
439
                                                        CLOCK_FREQ;
440 441
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
442
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
443
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
444 445 446 447 448
                                  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
449
            }
450
            free( psz_bookmarks );
Gildas Bazin's avatar
Gildas Bazin committed
451 452 453
        }
    }

454
    /* Remove 'Now playing' info as it is probably outdated */
455
    input_item_SetNowPlaying( p_item, NULL );
456
    input_item_SetESNowPlaying( p_item, NULL );
457
    input_SendEventMeta( p_input );
458

459 460 461 462
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

463 464 465 466
    /* Make sure the interaction option is honored */
    if( !var_InheritBool( p_input, "interact" ) )
        p_input->i_flags |= OBJECT_FLAGS_NOINTERACT;

467
    /* */
468
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
469
    vlc_mutex_init( &p_input->p->counters.counters_lock );
470

471 472 473
    p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
    p_input->p->p_es_out = NULL;

474 475 476
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

477 478 479
    return p_input;
}

480 481 482 483
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
484
{
485
#ifndef NDEBUG
486
    char * psz_name = input_item_GetName( p_input->p->p_item );
487 488 489 490
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

491 492 493
    if( p_input->p->p_es_out_display )
        es_out_Delete( p_input->p->p_es_out_display );

494 495
    if( p_input->p->p_resource )
        input_resource_Release( p_input->p->p_resource );
496
    if( p_input->p->p_resource_private )
497
        input_resource_Release( p_input->p->p_resource_private );
498

499
    vlc_gc_decref( p_input->p->p_item );
Pierre's avatar
Pierre committed
500

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

503
    for( int i = 0; i < p_input->p->i_control; i++ )
Laurent Aimar's avatar
Laurent Aimar committed
504 505 506 507
    {
        input_control_t *p_ctrl = &p_input->p->control[i];
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }
508

509
    vlc_cond_destroy( &p_input->p->wait_control );
510 511
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
512
}
513

514
/*****************************************************************************
515
 * Run: main thread loop
516 517
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
518
 *****************************************************************************/
519
static void *Run( void *obj )
Michel Kaempf's avatar
Michel Kaempf committed
520
{
521
    input_thread_t *p_input = (input_thread_t *)obj;
522
    const int canc = vlc_savecancel();
523

524 525 526
    if( !Init( p_input ) )
    {
        MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
527

528 529 530
        /* Clean up */
        End( p_input );
    }
531

532
    input_SendEventDead( p_input );
533

534
    vlc_restorecancel( canc );
535
    return NULL;
536 537 538 539 540
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
541 542 543 544 545

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
546
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, mtime_t i_start_mdate )
547
{
548
    int i_ret;
549

550
    *pb_changed = false;
551

Laurent Aimar's avatar
Laurent Aimar committed
552
    if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) ||
553
        ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
554 555
        i_ret = 0; /* EOF */
    else
Laurent Aimar's avatar
Laurent Aimar committed
556
        i_ret = demux_Demux( p_input->p->input.p_demux );
557 558

    if( i_ret > 0 )
559
    {
560
        if( p_input->p->input.p_demux->info.i_update )
561
        {
562 563 564 565 566
            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;
            }
567 568 569 570 571 572
            if( p_input->p->input.b_title_demux )
            {
                i_ret = UpdateTitleSeekpointFromDemux( p_input );
                *pb_changed = true;
            }
            UpdateGenericFromDemux( p_input );
573 574
        }
    }
575

576 577
    if( i_ret == 0 )    /* EOF */
    {
578 579
        msg_Dbg( p_input, "EOF reached" );
        p_input->p->input.b_eof = true;
580
        es_out_Eos(p_input->p->p_es_out);
581 582 583 584 585 586 587
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
588
        SlaveDemux( p_input );
589 590
}

591 592 593
static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate )
{
    int i_repeat = var_GetInteger( p_input, "input-repeat" );
594
    if( i_repeat <= 0 )
595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622
        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 )
    {
623
        val.i_int = p_input->p->i_start;
624 625 626 627
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &val );
    }
    else
    {
628
        val.f_float = 0.f;
629 630 631 632 633 634 635 636
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

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

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

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

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

    if( demux_Control( p_input->p->input.p_demux,
657 658
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
659

660
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
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;
665
    p_input->p->bookmark.i_byte_offset = -1;
666
    vlc_mutex_unlock( &p_input->p->p_item->lock );
667

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

/**
 * MainLoop
 * The main input loop.
 */
676
static void MainLoop( input_thread_t *p_input, bool b_interactive )
677 678
{
    mtime_t i_start_mdate = mdate();
679
    mtime_t i_intf_update = 0;
680
    mtime_t i_last_seek_mdate = 0;
681 682 683 684

    if( b_interactive && var_InheritBool( p_input, "start-paused" ) )
        ControlPause( p_input, i_start_mdate );

685
    bool b_pause_after_eof = b_interactive &&
686
                             var_InheritBool( p_input, "play-and-pause" );
687

688
    while( vlc_object_alive( 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 696
        if( b_paused )
            b_paused = !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof;
697 698

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

704
                MainLoopDemux( p_input, &b_force_update, i_start_mdate );
705
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
706 707 708

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

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

                b_paused = true;
            }
726 727
            else
            {
728 729
                if( MainLoopTryRepeat( p_input, &i_start_mdate ) )
                    break;
730
            }
731 732 733 734 735 736 737 738

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

741 742 743
        /* Handle control */
        for( ;; )
        {
744
            mtime_t i_deadline = i_wakeup;
745 746 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 )
                            && !p_input->p->input.b_eof;
            if( b_postpone )
751
            {
752 753 754 755
                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
756
                 && (i_deadline < 0 || i_deadline > now + INT64_C(20000)) )
757 758 759 760
                    i_deadline = now + INT64_C(20000);
                else
                    b_postpone = false;
            }
761

762 763
            int i_type;
            vlc_value_t val;
764

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

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

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

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

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

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

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

850 851
    return VLC_SUCCESS;
}
852
#endif
853

854 855
static void InitTitle( input_thread_t * p_input )
{
Laurent Aimar's avatar
Laurent Aimar committed
856
    input_source_t *p_master = &p_input->p->input;
857

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

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

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

881 882 883
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
884

885 886 887 888 889
    /* 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
890

891 892 893 894 895
    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
896
    /* Start/stop/run time */
897
    p_input->p->i_start = llroundf(1000000.f
898
                                     * var_GetFloat( p_input, "start-time" ));
899
    p_input->p->i_stop  = llroundf(1000000.f
900
                                     * var_GetFloat( p_input, "stop-time" ));
901
    p_input->p->i_run   = llroundf(1000000.f
902
                                     * var_GetFloat( p_input, "run-time" ));
903
    if( p_input->p->i_run < 0 )
904
    {
905 906
        msg_Warn( p_input, "invalid run-time ignored" );
        p_input->p->i_run = 0;
Rafaël Carré's avatar
Rafaël Carré committed
907
    }
908

909
    if( p_input->p->i_start > 0 )
910
    {
911
        vlc_value_t s;
912

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

916
        s.i_int = p_input->p->i_start;
917
        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME, &s );
918 919 920 921 922 923
    }
    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;
    }
924
    p_input->p->b_fast_seek = var_GetBool( p_input, "input-fast-seek" );
Laurent Aimar's avatar
Laurent Aimar committed
925
}
926

Laurent Aimar's avatar
Laurent Aimar committed
927 928
static void LoadSubtitles( input_thread_t *p_input )