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

Laurent Aimar's avatar
Laurent Aimar committed
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

zorglub's avatar
zorglub committed
50
#include <vlc_sout.h>
51
#include <vlc_dialog.h>
zorglub's avatar
zorglub 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 * );
Laurent Aimar's avatar
Laurent Aimar committed
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 );
Laurent Aimar's avatar
Laurent Aimar committed
70

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    vlc_object_release( p_input );
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
    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;

    if( !Init( p_input ) )
        End( p_input );

    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. */
213
214
215
    p_input->p->is_running = !vlc_clone( &p_input->p->thread,
                                         Run, p_input, VLC_THREAD_PRIORITY_INPUT );
    if( !p_input->p->is_running )
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
    {
        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
 *
 * b_abort must be true when a user stop is requested and not because you have
 * detected an error or an eof. It will be used to properly send the
 * INPUT_EVENT_ABORT event.
 *
 * \param p_input the input thread to stop
 * \param b_abort true if the input has been aborted by a user request
 */
void input_Stop( input_thread_t *p_input, bool b_abort )
{
    /* 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 */
239
    ObjectKillChildrens( VLC_OBJECT(p_input) );
240
241
242
243
244
245
246
247

    vlc_mutex_lock( &p_input->p->lock_control );
    p_input->p->b_abort |= b_abort;
    vlc_mutex_unlock( &p_input->p->lock_control );

    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
}

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

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

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

270
271
272
273
274
275
276
277
278
279
280
281
/**
 * 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;
}

282
/*****************************************************************************
283
284
 * 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
285
 *
Laurent Aimar's avatar
Laurent Aimar committed
286
 * XXX Do not forget to update vlc_input.h if you add new variables.
287
 *****************************************************************************/
288
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
289
                               const char *psz_header, bool b_quick,
290
                               input_resource_t *p_resource )
Michel Kaempf's avatar
Michel Kaempf committed
291
{
292
    input_thread_t *p_input = NULL;                 /* thread descriptor */
293
    int i;
294

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

    /* 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 );
305
306
307

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

308
309
    free( psz_name );

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

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

325
    p_input->b_preparsing = b_quick;
326
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
327

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

Pierre's avatar
Pierre committed
347
    vlc_gc_incref( p_item ); /* Released in Destructor() */
348
349
350
    p_input->p->p_item = p_item;

    /* Init Input fields */
zorglub's avatar
zorglub committed
351
    p_input->p->input.p_demux  = NULL;
352
    p_input->p->input.b_title_demux = false;
zorglub's avatar
zorglub committed
353
354
355
    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;
356
357
358
359
    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;
zorglub's avatar
zorglub committed
360

361
    vlc_mutex_lock( &p_item->lock );
362
363

    if( !p_item->p_stats )
364
365
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
zorglub's avatar
zorglub committed
366

367
    /* No slave */
zorglub's avatar
zorglub committed
368
369
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
370

371
    /* */
372
    if( p_resource )
373
374
    {
        p_input->p->p_resource_private = NULL;
375
        p_input->p->p_resource = input_resource_Hold( p_resource );
376
    }
377
    else
378
379
    {
        p_input->p->p_resource_private = input_resource_New( VLC_OBJECT( p_input ) );
380
        p_input->p->p_resource = input_resource_Hold( p_input->p->p_resource_private );
381
    }
382
    input_resource_SetInput( p_input->p->p_resource, p_input );
383

Laurent Aimar's avatar
Laurent Aimar committed
384
    /* Init control buffer */
385
    vlc_mutex_init( &p_input->p->lock_control );
386
    vlc_cond_init( &p_input->p->wait_control );
zorglub's avatar
zorglub committed
387
    p_input->p->i_control = 0;
388
    p_input->p->b_abort = false;
389
    p_input->p->is_running = false;
390

Laurent Aimar's avatar
Laurent Aimar committed
391
392
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
393

Laurent Aimar's avatar
Laurent Aimar committed
394
    /* Create Objects variables for public Get and Set */
395
    input_ControlVarInit( p_input );
396

397
    /* */
398
    if( !p_input->b_preparsing )
gbazin's avatar
gbazin committed
399
    {
Laurent Aimar's avatar
Laurent Aimar committed
400
401
        char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
        if( psz_bookmarks )
gbazin's avatar
gbazin committed
402
        {
403
404
            /* 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
405
            psz_parser = psz_bookmarks;
406
            while( (psz_start = strchr( psz_parser, '{' ) ) )
gbazin's avatar
gbazin committed
407
            {
hartman's avatar
hartman committed
408
                 seekpoint_t *p_seekpoint;
409
410
411
412
413
414
415
416
                 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
417
418

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

448
    /* Remove 'Now playing' info as it is probably outdated */
449
    input_item_SetNowPlaying( p_item, NULL );
450
    input_SendEventMeta( p_input );
451

452
453
454
455
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

456
457
458
459
    /* Make sure the interaction option is honored */
    if( !var_InheritBool( p_input, "interact" ) )
        p_input->i_flags |= OBJECT_FLAGS_NOINTERACT;

460
    /* */
461
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
462
    vlc_mutex_init( &p_input->p->counters.counters_lock );
463

464
465
466
    p_input->p->p_es_out_display = input_EsOutNew( p_input, p_input->p->i_rate );
    p_input->p->p_es_out = NULL;

467
468
469
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

470
471
472
    return p_input;
}

473
474
475
476
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
477
{
478
#ifndef NDEBUG
479
    char * psz_name = input_item_GetName( p_input->p->p_item );
480
481
482
483
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

484
485
486
    if( p_input->p->p_es_out_display )
        es_out_Delete( p_input->p->p_es_out_display );

487
488
    if( p_input->p->p_resource )
        input_resource_Release( p_input->p->p_resource );
489
    if( p_input->p->p_resource_private )
490
        input_resource_Release( p_input->p->p_resource_private );
491

492
    vlc_gc_decref( p_input->p->p_item );
Pierre's avatar
Pierre committed
493

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

496
    for( int i = 0; i < p_input->p->i_control; i++ )
Laurent Aimar's avatar
Laurent Aimar committed
497
498
499
500
    {
        input_control_t *p_ctrl = &p_input->p->control[i];
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }
501

502
    vlc_cond_destroy( &p_input->p->wait_control );
503
504
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
505
}
506

507
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
508
 * Run: main thread loop
509
510
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
511
 *****************************************************************************/
512
static void *Run( void *obj )
Michel Kaempf's avatar
Michel Kaempf committed
513
{
514
    input_thread_t *p_input = (input_thread_t *)obj;
515
    const int canc = vlc_savecancel();
516

517
    if( Init( p_input ) )
518
        goto exit;
Michel Kaempf's avatar
Michel Kaempf committed
519

520
    MainLoop( p_input, true ); /* FIXME it can be wrong (like with VLM) */
521
522
523

    /* Clean up */
    End( p_input );
524
525

exit:
526
    /* Tell we're dead */
527
528
529
530
531
    vlc_mutex_lock( &p_input->p->lock_control );
    const bool b_abort = p_input->p->b_abort;
    vlc_mutex_unlock( &p_input->p->lock_control );

    if( b_abort )
532
        input_SendEventAbort( p_input );
533
    input_SendEventDead( p_input );
534

535
    vlc_restorecancel( canc );
ivoire's avatar
ivoire committed
536
    return NULL;
537
538
539
540
541
}

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

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

551
    *pb_changed = false;
552
    *pb_demux_polled = p_input->p->input.p_demux->pf_demux != NULL;
553

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

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

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

    if( i_ret > 0 && p_input->p->i_slave > 0 )
    {
591
592
593
594
        bool b_demux_polled;
        SlaveDemux( p_input, &b_demux_polled );

        *pb_demux_polled |= b_demux_polled;
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
623
624
625
626
627
628
629
630
631
632
633
634
static int MainLoopTryRepeat( input_thread_t *p_input, mtime_t *pi_start_mdate )
{
    int i_repeat = var_GetInteger( p_input, "input-repeat" );
    if( i_repeat == 0 )
        return VLC_EGENERIC;

    vlc_value_t val;

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

    /* Seek to start title/seekpoint */
    val.i_int = p_input->p->input.i_title_start -
        p_input->p->input.i_title_offset;
    if( val.i_int < 0 || val.i_int >= p_input->p->input.i_title )
        val.i_int = 0;
    input_ControlPush( p_input,
                       INPUT_CONTROL_SET_TITLE, &val );

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

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

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

644
645
646
647
648
649
/**
 * MainLoopInterface
 * It update the variables used by the interfaces
 */
static void MainLoopInterface( input_thread_t *p_input )
{
650
651
652
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
653
654

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

659
    if( demux_Control( p_input->p->input.p_demux,
660
661
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
Laurent Aimar's avatar
Laurent Aimar committed
662
    p_input->p->i_time = i_time;
663
664

    if( demux_Control( p_input->p->input.p_demux,
665
666
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
667

668
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
669
670
671
672

    /* update current bookmark */
    vlc_mutex_lock( &p_input->p->p_item->lock );
    p_input->p->bookmark.i_time_offset = i_time;
673
    p_input->p->bookmark.i_byte_offset = -1;
674
    vlc_mutex_unlock( &p_input->p->p_item->lock );
675
676
677
678
679
680
681
682
}

/**
 * MainLoopStatistic
 * It updates the globals statics
 */
static void MainLoopStatistic( input_thread_t *p_input )
{
683
    stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
684
    input_SendEventStatistics( p_input );
685
686
687
688
689
690
}

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

700
    while( vlc_object_alive( p_input ) && !p_input->b_error )
701
702
703
    {
        bool b_force_update;
        vlc_value_t val;
704
        mtime_t i_wakeup, i_current;
705
        bool b_paused;
706
        bool b_demux_polled;
707

708
709
        /* Demux data */
        b_force_update = false;
710
        i_wakeup = 0;
Laurent Aimar's avatar
Laurent Aimar committed
711
        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
712
713
         * is paused -> this may cause problem with some of them
         * The same problem can be seen when seeking while paused */
Laurent Aimar's avatar
Laurent Aimar committed
714
        b_paused = p_input->p->i_state == PAUSE_S &&
715
                   ( !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof );
716

717
        b_demux_polled = true;
718
        if( !b_paused )
719
        {
720
721
            if( !p_input->p->input.b_eof )
            {
722
                MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate );
723

724
725
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
            }
726
            else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
727
728
729
730
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
731
732
733
            /* 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 )
734
735
736
737
738
739
740
            {
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                val.i_int = PAUSE_S;
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

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

        /* */
750
        do {
751
            mtime_t i_deadline = i_wakeup;
752
            if( b_paused || !b_demux_polled )
753
754
755
                i_deadline = __MIN( i_intf_update, i_statistic_update );

            /* Handle control */
756
            for( ;; )
757
            {
758
759
760
761
762
763
764
765
766
767
                mtime_t i_limit = i_deadline;

                /* We will postpone the execution of a seek until we have
                 * finished the ES bufferisation (postpone is limited to
                 * 125ms) */
                bool b_buffering = es_out_GetBuffering( p_input->p->p_es_out ) &&
                                   !p_input->p->input.b_eof;
                if( b_buffering )
                {
                    /* When postpone is in order, check the ES level every 20ms */
768
769
770
                    mtime_t now = mdate();
                    if( i_last_seek_mdate + INT64_C(125000) >= now )
                        i_limit = __MIN( i_deadline, now + INT64_C(20000) );
771
772
773
774
775
776
777
778
779
                }

                int i_type;
                if( ControlPop( p_input, &i_type, &val, i_limit, b_buffering ) )
                {
                    if( b_buffering && i_limit < i_deadline )
                        continue;
                    break;
                }
780

781
#ifndef NDEBUG
782
                msg_Dbg( p_input, "control type=%d", i_type );
783
#endif
784

785
                if( Control( p_input, i_type, val ) )
786
787
788
                {
                    if( ControlIsSeekRequest( i_type ) )
                        i_last_seek_mdate = mdate();
789
                    b_force_update = true;
790
                }
791
            }
792

793
794
795
796
797
798
799
800
801
802
803
            /* Update interface and statistics */
            i_current = mdate();
            if( i_intf_update < i_current || b_force_update )
            {
                MainLoopInterface( p_input );
                i_intf_update = i_current + INT64_C(250000);
                b_force_update = false;
            }
            if( i_statistic_update < i_current )
            {
                MainLoopStatistic( p_input );
Ilkka Ollakka's avatar
Ilkka Ollakka committed
804
                i_statistic_update = i_current + CLOCK_FREQ;
805
            }
806

807
            /* Update the wakeup time */
808
            if( i_wakeup != 0 )
809
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
810
        } while( i_current < i_wakeup );
Laurent Aimar's avatar
Laurent Aimar committed
811
    }
812

813
    if( !p_input->b_error )
814
        input_ChangeState( p_input, END_S );
815
816
}

817
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
818
{
819
    if( p_input->b_preparsing ) return;
820

821
    /* Prepare statistics */
822
823
#define INIT_COUNTER( c, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( STATS_##compute);
824
    if( libvlc_stats( p_input ) )
825
    {
826
827
828
829
830
831
832
833
834
835
836
837
838
839
        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 );
840
841
842
        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;
843
    }
844
}
845

846
#ifdef ENABLE_SOUT
847
848
static int InitSout( input_thread_t * p_input )
{
849
850
    if( p_input->b_preparsing )
        return VLC_SUCCESS;
851
852

    /* Find a usable sout and attach it to p_input */
853
    char *psz = var_GetNonEmptyString( p_input, "sout" );
854
    if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
855
    {
856
        p_input->p->p_sout  = input_resource_RequestSout( p_input->p->p_resource, NULL, psz );
857
        if( !p_input->p->p_sout )
zorglub's avatar
zorglub committed
858
        {
859
860
861
862
863
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot start stream output instance, " \
                              "aborting" );
            free( psz );
            return VLC_EGENERIC;
864
        }
865
        if( libvlc_stats( p_input ) )
866
        {
867
868
869
            INIT_COUNTER( sout_sent_packets, COUNTER );
            INIT_COUNTER( sout_sent_bytes, COUNTER );
            INIT_COUNTER( sout_send_bitrate, DERIVATIVE );
870
        }
871
    }
872
    else
873
    {
874
        input_resource_RequestSout( p_input->p->p_resource, NULL, NULL );
Laurent Aimar's avatar
Laurent Aimar committed
875
    }
876
    free( psz );
877

878
879
    return VLC_SUCCESS;
}
880
#endif
881

882
883
static void InitTitle( input_thread_t * p_input )
{
Laurent Aimar's avatar
Laurent Aimar committed
884
    input_source_t *p_master = &p_input->p->input;
Laurent Aimar's avatar
Laurent Aimar committed
885

Laurent Aimar's avatar
Laurent Aimar committed
886
887
    if( p_input->b_preparsing )
        return;
888

889
    vlc_mutex_lock( &p_input->p->p_item->lock );
890
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
891
892
893
894
    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;
895
896
897
898
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
899
        input_SendEventTitle( p_input, 0 );
900
901
902
    }

    /* Global flag */
903
    p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
Laurent Aimar's avatar
Laurent Aimar committed
904
905
    p_input->p->b_can_pause        = p_master->b_can_pause;
    p_input->p->b_can_rate_control = p_master->b_can_rate_control;
906
    vlc_mutex_unlock( &p_input->p->p_item->lock );
907
}
gbazin's avatar
   
gbazin committed
908

909
910
911
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
912

913
914
915
916
917
    /* 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
918

919
920
921
922
923
    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
924
    /* Start/stop/run time */
925
    p_input->p->i_start = llroundf(1000000.f
926
                                     * var_GetFloat( p_input, "start-time" ));
927
    p_input->p->i_stop  = llroundf(1000000.f
928
                                     * var_GetFloat( p_input, "stop-time" ));
929
    p_input->p->i_run   = llroundf(1000000.f
930
                                     * var_GetFloat( p_input, "run-time" ));
931
    if( p_input->p->i_run < 0 )
932
    {
933
934
        msg_Warn( p_input, "invalid run-time ignored" );
        p_input->p->i_run = 0;