input.c 105 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>
Laurent Aimar's avatar
Laurent Aimar committed
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>
Sam Hocevar's avatar
   
Sam Hocevar committed
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

Laurent Aimar's avatar
Laurent Aimar committed
39
#include "input_internal.h"
40
#include "mrl_helpers.h"
41
#include "event.h"
42
#include "es_out.h"
43
#include "es_out_timeshift.h"
44
#include "demux.h"
45
#include "item.h"
46
#include "resource.h"
47

zorglub's avatar
zorglub committed
48
#include <vlc_sout.h>
49
#include <vlc_dialog.h>
zorglub's avatar
zorglub committed
50
51
#include <vlc_url.h>
#include <vlc_charset.h>
52
#include <vlc_fs.h>
53
#include <vlc_strings.h>
54
#include <vlc_modules.h>
55
#include <vlc_stream.h>
56
#include <vlc_stream_extractor.h>
57

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

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

70
static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline, bool b_postpone_seek );
71
static void       ControlRelease( int i_type, vlc_value_t val );
72
static bool       ControlIsSeekRequest( int i_type );
73
static bool       Control( input_thread_t *, int, vlc_value_t );
74
static void       ControlPause( input_thread_t *, mtime_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
83
84
85
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
86
87
static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );

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

93
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
94
static void InputUpdateMeta( input_thread_t *p_input, demux_t *p_demux );
95
96
97
static void InputGetExtraFiles( input_thread_t *p_input,
                                int *pi_list, char ***pppsz_list,
                                const char *psz_access, const char *psz_path );
98

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

103
104
105
106
#define SLAVE_ADD_NOFLAG    0
#define SLAVE_ADD_FORCED    (1<<0)
#define SLAVE_ADD_CANFAIL   (1<<1)
#define SLAVE_ADD_SET_TIME  (1<<2)
107

108
109
static int input_SlaveSourceAdd( input_thread_t *, enum slave_type,
                                 const char *, unsigned );
110
static char *input_SubtitleFile2Uri( input_thread_t *, const char * );
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_Read
134
/**
135
 * Initialize an input thread and run it until it stops by itself.
136
137
138
139
140
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \return an error code, VLC_SUCCESS on success
 */
141
int input_Read( vlc_object_t *p_parent, input_item_t *p_item )
142
{
143
    input_thread_t *p_input = Create( p_parent, p_item, NULL, false, NULL );
144
145
146
    if( !p_input )
        return VLC_EGENERIC;

147
148
    if( !Init( p_input ) )
    {
149
        MainLoop( p_input, false );
150
151
152
153
        End( p_input );
    }

    vlc_object_release( p_input );
154
155
156
    return VLC_SUCCESS;
}

157
158
159
160
161
162
input_thread_t *input_CreatePreparser( vlc_object_t *parent,
                                       input_item_t *item )
{
    return Create( parent, item, NULL, true, NULL );
}

163
164
165
166
167
168
169
170
171
/**
 * 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 )
{
172
    input_thread_private_t *priv = input_priv(p_input);
173
174
    void *(*func)(void *) = Run;

175
    if( priv->b_preparsing )
176
177
        func = Preparse;

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

    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 );
211
    vlc_interrupt_kill( &sys->interrupt );
212
213
}

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

227
228
229
230
231
232
/**
 * 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;
233
    input_thread_private_t *priv = input_priv(p_input);
234
#ifndef NDEBUG
235
    char * psz_name = input_item_GetName( priv->p_item );
236
237
238
239
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

240
241
    if( priv->p_es_out_display )
        es_out_Delete( priv->p_es_out_display );
242

243
244
245
246
    if( priv->p_resource )
        input_resource_Release( priv->p_resource );
    if( priv->p_resource_private )
        input_resource_Release( priv->p_resource_private );
247

248
    vlc_gc_decref( priv->p_item );
249

250
    vlc_mutex_destroy( &priv->counters.counters_lock );
251

252
    for( int i = 0; i < priv->i_control; i++ )
253
    {
254
        input_control_t *p_ctrl = &priv->control[i];
255
256
257
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }

258
259
    vlc_cond_destroy( &priv->wait_control );
    vlc_mutex_destroy( &priv->lock_control );
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 )
{
270
271
    assert( p_input != NULL );
    return input_priv(p_input)->p_item;
272
273
}

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

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

291
292
    input_thread_t *p_input = &priv->input;

293
    char * psz_name = input_item_GetName( p_item );
294
295
    msg_Dbg( p_input, "Creating an input for %s'%s'",
             b_preparsing ? "preparsing " : "", psz_name);
296
297
    free( psz_name );

298
    /* Parse input options */
299
    input_item_ApplyOptions( VLC_OBJECT(p_input), p_item );
300

301
    p_input->obj.header = psz_header ? strdup( psz_header ) : NULL;
302

Laurent Aimar's avatar
Laurent Aimar committed
303
    /* Init Common fields */
304
    priv->b_preparsing = b_preparsing;
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
    priv->b_can_pace_control = true;
    priv->i_start = 0;
    priv->i_time  = 0;
    priv->i_stop  = 0;
    priv->i_title = 0;
    priv->title = NULL;
    priv->i_title_offset = input_priv(p_input)->i_seekpoint_offset = 0;
    priv->i_state = INIT_S;
    priv->is_running = false;
    priv->is_stopped = false;
    priv->b_recording = false;
    priv->i_rate = INPUT_RATE_DEFAULT;
    memset( &priv->bookmark, 0, sizeof(priv->bookmark) );
    TAB_INIT( priv->i_bookmark, priv->pp_bookmark );
    TAB_INIT( priv->i_attachment, priv->attachment );
    priv->attachment_demux = NULL;
    priv->p_sout   = NULL;
    priv->b_out_pace_control = false;
Laurent Aimar's avatar
Laurent Aimar committed
323

324
325
326
327
328
329
    vlc_viewpoint_t *p_viewpoint = var_InheritAddress( p_input, "viewpoint" );
    if (likely(p_viewpoint != NULL))
        priv->viewpoint = *p_viewpoint;
    else
        vlc_viewpoint_init( &priv->viewpoint );

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

    /* Init Input fields */
334
    priv->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

    /* setup the preparse depth of the item
     * if we are preparsing, use the i_preparse_depth of the parent item */
342
    if( !priv->b_preparsing )
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
    {
        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;
    }
358
    else
359
        p_input->obj.flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;
360
361
362

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

372
    vlc_mutex_unlock( &p_item->lock );
zorglub's avatar
zorglub committed
373

374
    /* No slave */
375
376
    priv->i_slave = 0;
    priv->slave   = NULL;
377

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

Laurent Aimar's avatar
Laurent Aimar committed
391
    /* Init control buffer */
392
393
394
395
    vlc_mutex_init( &priv->lock_control );
    vlc_cond_init( &priv->wait_control );
    priv->i_control = 0;
    vlc_interrupt_init(&priv->interrupt);
396

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

Laurent Aimar's avatar
Laurent Aimar committed
400
    /* Create Objects variables for public Get and Set */
401
    input_ControlVarInit( p_input );
402

403
    /* */
404
    if( !priv->b_preparsing )
gbazin's avatar
gbazin committed
405
    {
Laurent Aimar's avatar
Laurent Aimar committed
406
407
        char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
        if( psz_bookmarks )
gbazin's avatar
gbazin committed
408
        {
409
410
            /* FIXME: have a common cfg parsing routine used by sout and others */
            char *psz_parser, *psz_start, *psz_end;
Laurent Aimar's avatar
Laurent Aimar committed
411
            psz_parser = psz_bookmarks;
412
            while( (psz_start = strchr( psz_parser, '{' ) ) )
gbazin's avatar
gbazin committed
413
            {
hartman's avatar
hartman committed
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 = ',';
hartman's avatar
hartman committed
423
424

                 p_seekpoint = vlc_seekpoint_New();
425

426
427
                 if( unlikely( p_seekpoint == NULL ) )
                     break;
428

429
430
431
432
433
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
434
435
                         free( p_seekpoint->psz_name );

436
                         p_seekpoint->psz_name = strdup(psz_start + 5);
437
438
439
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
zorglub's avatar
zorglub committed
440
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
Ilkka Ollakka's avatar
Ilkka Ollakka committed
441
                                                        CLOCK_FREQ;
442
443
                     }
                     psz_start = psz_end + 1;
gbazin's avatar
gbazin committed
444
                }
445
446
                msg_Dbg( p_input, "adding bookmark: %s, time=%"PRId64,
                                  p_seekpoint->psz_name,
447
448
449
450
                                  p_seekpoint->i_time_offset );
                input_Control( p_input, INPUT_ADD_BOOKMARK, p_seekpoint );
                vlc_seekpoint_Delete( p_seekpoint );
                *psz_parser = backup;
gbazin's avatar
gbazin committed
451
            }
Laurent Aimar's avatar
Laurent Aimar committed
452
            free( psz_bookmarks );
gbazin's avatar
gbazin committed
453
454
455
        }
    }

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

461
    /* */
462
463
    memset( &priv->counters, 0, sizeof( priv->counters ) );
    vlc_mutex_init( &priv->counters.counters_lock );
464

465
466
    priv->p_es_out_display = input_EsOutNew( p_input, priv->i_rate );
    priv->p_es_out = NULL;
467

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

471
472
473
    return p_input;
}

474
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
475
 * Run: main thread loop
476
477
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
478
 *****************************************************************************/
479
static void *Run( void *data )
Michel Kaempf's avatar
Michel Kaempf committed
480
{
481
482
    input_thread_private_t *priv = data;
    input_thread_t *p_input = &priv->input;
483

484
    vlc_interrupt_set(&priv->interrupt);
485

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

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

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

501
    input_SendEventDead( p_input );
ivoire's avatar
ivoire committed
502
    return NULL;
503
504
}

505
static void *Preparse( void *data )
506
{
507
508
    input_thread_private_t *priv = data;
    input_thread_t *p_input = &priv->input;
509

510
    vlc_interrupt_set(&priv->interrupt);
511
512
513
514
515
516

    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;

517
518
        if ( input_item_ShouldPreparseSubItems( priv->p_item )
          && demux_Control( priv->master->p_demux, DEMUX_IS_PLAYLIST,
519
520
521
522
523
524
525
526
527
528
529
                            &b_is_playlist ) )
            b_is_playlist = false;
        if( b_is_playlist )
            MainLoop( p_input, false );
        End( p_input );
    }

    input_SendEventDead( p_input );
    return NULL;
}

530
531
bool input_Stopped( input_thread_t *input )
{
532
    input_thread_private_t *sys = input_priv(input);
533
534
535
536
537
538
539
540
    bool ret;

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

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

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
549
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed )
550
{
551
    int i_ret;
552
    demux_t *p_demux = input_priv(p_input)->master->p_demux;
553

554
    *pb_changed = false;
555

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

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

    if( i_ret == VLC_DEMUXER_SUCCESS )
Sam Hocevar's avatar
   
Sam Hocevar committed
564
    {
565
566
567
        if( demux_TestAndClearFlags( p_demux, INPUT_UPDATE_TITLE_LIST ) )
            UpdateTitleListfromDemux( p_input );

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

        UpdateGenericFromDemux( p_input );
575
    }
576

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

591
static int MainLoopTryRepeat( input_thread_t *p_input )
592
593
{
    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
        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 */
607
608
609
    val.i_int = input_priv(p_input)->master->i_title_start -
        input_priv(p_input)->master->i_title_offset;
    if( val.i_int < 0 || val.i_int >= input_priv(p_input)->master->i_title )
610
611
612
613
        val.i_int = 0;
    input_ControlPush( p_input,
                       INPUT_CONTROL_SET_TITLE, &val );

614
615
    val.i_int = input_priv(p_input)->master->i_seekpoint_start -
        input_priv(p_input)->master->i_seekpoint_offset;
616
617
618
619
620
    if( val.i_int > 0 /* TODO: check upper boundary */ )
        input_ControlPush( p_input,
                           INPUT_CONTROL_SET_SEEKPOINT, &val );

    /* Seek to start position */
621
    if( input_priv(p_input)->i_start > 0 )
622
    {
623
        val.i_int = input_priv(p_input)->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
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

    return VLC_SUCCESS;
}

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

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

649
    if( demux_Control( input_priv(p_input)->master->p_demux,
650
651
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
652
    input_priv(p_input)->i_time = i_time;
653

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

658
    es_out_SetTimes( input_priv(p_input)->p_es_out, f_position, i_time, i_length );
659
660

    /* update current bookmark */
661
662
663
    vlc_mutex_lock( &input_priv(p_input)->p_item->lock );
    input_priv(p_input)->bookmark.i_time_offset = i_time;
    vlc_mutex_unlock( &input_priv(p_input)->p_item->lock );
664

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

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

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

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

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

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

        if( !b_paused )
700
        {
701
            if( !input_priv(p_input)->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( input_priv(p_input)->p_es_out );
709
710
                if( b_force_update )
                    i_intf_update = 0;
711
712

                b_paused_at_eof = false;
713
            }
714
            else if( !es_out_GetEmpty( input_priv(p_input)->p_es_out ) )
715
716
717
718
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
719
720
            /* Pause after eof only if the input is pausable.
             * This way we won't trigger timeshifting for nothing */
721
            else if( b_pause_after_eof && input_priv(p_input)->b_can_pause )
722
            {
723
724
725
                if( b_paused_at_eof )
                    break;

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
726
727
                vlc_value_t val = { .i_int = PAUSE_S };

728
729
730
731
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

                b_paused = true;
732
                b_paused_at_eof = true;
733
            }
734
735
            else
            {
736
                if( MainLoopTryRepeat( p_input ) )
737
                    break;
738
            }
739
740
741
742
743
744
745
746

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

749
750
751
        /* Handle control */
        for( ;; )
        {
752
            mtime_t i_deadline = i_wakeup;
753
754
755

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

770
771
            int i_type;
            vlc_value_t val;
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
772

773
774
775
776
777
778
            if( ControlPop( p_input, &i_type, &val, i_deadline, b_postpone ) )
            {
                if( b_postpone )
                    continue;
                break; /* Wake-up time reached */
            }
779

780
#ifndef NDEBUG
781
            msg_Dbg( p_input, "control type=%d", i_type );
782
#endif
783
784
785
786
787
            if( Control( p_input, i_type, val ) )
            {
                if( ControlIsSeekRequest( i_type ) )
                    i_last_seek_mdate = mdate();
                i_intf_update = 0;
788
            }
789

790
            /* Update the wakeup time */
791
            if( i_wakeup != 0 )
792
                i_wakeup = es_out_GetWakeup( input_priv(p_input)->p_es_out );
793
        }
Laurent Aimar's avatar
Laurent Aimar committed
794
    }
795
796
}

797
static void InitStatistics( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
798
{
799
800
    input_thread_private_t *priv = input_priv(p_input);

801
    if( priv->b_preparsing ) return;
802

803
    /* Prepare statistics */
804
#define INIT_COUNTER( c, compute ) priv->counters.p_##c = \
805
 stats_CounterCreate( STATS_##compute);
806
    if( libvlc_stats( p_input ) )
807
    {
808
809
810
811
812
813
814
815
816
817
818
819
820
821
        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 );
822
823
824
        priv->counters.p_sout_send_bitrate = NULL;
        priv->counters.p_sout_sent_packets = NULL;
        priv->counters.p_sout_sent_bytes = NULL;
825
    }
826
}
827

828
#ifdef ENABLE_SOUT
829
830
static int InitSout( input_thread_t * p_input )
{
831
832
    input_thread_private_t *priv = input_priv(p_input);

833
    if( priv->b_preparsing )
834
        return VLC_SUCCESS;
835
836

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

862
863
    return VLC_SUCCESS;
}
864
#endif
865

866
867
static void InitTitle( input_thread_t * p_input )
{
868
869
    input_thread_private_t *priv = input_priv(p_input);
    input_source_t *p_master = priv->master;
Laurent Aimar's avatar
Laurent Aimar committed
870

871
    if( priv->b_preparsing )
Laurent Aimar's avatar
Laurent Aimar committed
872
        return;
873