input.c 97.5 KB
Newer Older
1 2
/*****************************************************************************
 * input.c: input thread
3
 *****************************************************************************
4
 * Copyright (C) 1998-2007 the VideoLAN team
5
 * $Id$
6
 *
7
 * Authors: Christophe Massiot <massiot@via.ecp.fr>
8
 *          Laurent Aimar <fenrir@via.ecp.fr>
9 10 11 12 13
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (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
17 18
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
19
 *
20 21
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
Antoine Cellerier's avatar
Antoine Cellerier committed
22
 * 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/vlc.h>
33

34
#include <ctype.h>
Christophe Mutricy's avatar
Christophe Mutricy committed
35
#include <limits.h>
36
#include <assert.h>
37

38
#include "input_internal.h"
39

Clément Stenac's avatar
Clément Stenac committed
40 41
#include <vlc_sout.h>
#include "../stream_output/stream_output.h"
42

Clément Stenac's avatar
Clément Stenac committed
43 44 45
#include <vlc_interface.h>
#include <vlc_url.h>
#include <vlc_charset.h>
46
#include <vlc_playlist.h>
47

48 49 50 51
#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif

52
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
53
 * Local prototypes
54
 *****************************************************************************/
55 56
static void Destructor( input_thread_t * p_input );

57
static  int Run  ( input_thread_t *p_input );
58
static  int RunAndDestroy  ( input_thread_t *p_input );
59

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

static inline int ControlPopNoLock( input_thread_t *, int *, vlc_value_t * );
static void       ControlReduce( input_thread_t * );
69
static bool Control( input_thread_t *, int, vlc_value_t );
70

71 72
static int  UpdateFromAccess( input_thread_t * );
static int  UpdateFromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
73

74
static void UpdateItemLength( input_thread_t *, int64_t i_length );
75

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

static input_source_t *InputSourceNew( input_thread_t *);
79
static int  InputSourceInit( input_thread_t *, input_source_t *,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
80
                             const char *, const char *psz_forced_demux );
81
static void InputSourceClean( input_source_t * );
82 83
/* TODO */
//static void InputGetAttachments( input_thread_t *, input_source_t * );
84 85
static void SlaveDemux( input_thread_t *p_input );
static void SlaveSeek( input_thread_t *p_input );
86

87 88
static void InputMetaUser( input_thread_t *p_input, vlc_meta_t *p_meta );
static void InputUpdateMeta( input_thread_t *p_input, vlc_meta_t *p_meta );
89

90
static sout_instance_t *SoutFind( vlc_object_t *p_parent, input_item_t *p_item, bool * );
91 92
static void SoutKeep( sout_instance_t * );

93
static void DemuxMeta( input_thread_t *p_input, vlc_meta_t *p_meta, demux_t *p_demux );
94
static void AccessMeta( input_thread_t * p_input, vlc_meta_t *p_meta );
95 96 97
static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                              int i_new, input_attachment_t **pp_new );

98
/*****************************************************************************
99 100
 * This function creates a new input, and returns a pointer
 * to its description. On error, it returns NULL.
101 102 103 104 105 106 107 108 109 110
 *
 * Variables for _public_ use:
 * * Get and Set:
 *  - state
 *  - rate,rate-slower, rate-faster
 *  - position, position-offset
 *  - time, time-offset
 *  - title,title-next,title-prev
 *  - chapter,chapter-next, chapter-prev
 *  - program, audio-es, video-es, spu-es
111
 *  - audio-delay, spu-delay
112 113 114 115
 *  - bookmark
 * * Get only:
 *  - length
 *  - bookmarks
116 117
 *  - seekable (if you can seek, it doesn't say if 'bar display' has be shown
 *    or not, for that check position != 0.0)
118
 *  - can-pause
119 120
 * * For intf callback upon changes
 *  - intf-change
121
 *  - rate-change for when playback rate changes
122 123
 * TODO explain when Callback is called
 * TODO complete this list (?)
124
 *****************************************************************************/
125
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
126
                               const char *psz_header, bool b_quick,
127
                               sout_instance_t *p_sout )
Michel Kaempf's avatar
Michel Kaempf committed
128
{
129
    static const char input_name[] = "input";
130
    input_thread_t *p_input = NULL;                 /* thread descriptor */
131 132
    vlc_value_t val;
    int i;
133

134
    /* Allocate descriptor */
135 136
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
                                 VLC_OBJECT_INPUT, input_name );
137
    if( p_input == NULL )
Michel Kaempf's avatar
Michel Kaempf committed
138
    {
139
        msg_Err( p_parent, "out of memory" );
140
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
141
    }
Clément Stenac's avatar
Clément Stenac committed
142
    MALLOC_NULL( p_input->p, input_thread_private_t );
143 144 145

    /* One "randomly" selected input thread is responsible for computing
     * the global stats. Check if there is already someone doing this */
146
    if( p_input->p_libvlc->p_stats && !b_quick )
147
    {
148 149
        vlc_mutex_lock( &p_input->p_libvlc->p_stats->lock );
        if( p_input->p_libvlc->p_stats_computer == NULL )
150
        {
151
            p_input->p_libvlc->p_stats_computer = p_input;
152
        }
153
        vlc_mutex_unlock( &p_input->p_libvlc->p_stats->lock );
154 155
    }

156
    p_input->b_preparsing = b_quick;
157
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
158

159
    /* Init Common fields */
160 161
    p_input->b_eof = false;
    p_input->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
162
    p_input->p->i_start = 0;
163
    p_input->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
164
    p_input->p->i_stop  = 0;
165
    p_input->p->i_run  = 0;
Clément Stenac's avatar
Clément Stenac committed
166 167 168
    p_input->p->i_title = 0;
    p_input->p->title   = NULL;
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
169
    p_input->i_state = INIT_S;
Clément Stenac's avatar
Clément Stenac committed
170
    p_input->p->i_rate  = INPUT_RATE_DEFAULT;
171 172
    TAB_INIT( p_input->p->i_bookmark, p_input->p->bookmark );
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
Clément Stenac's avatar
Clément Stenac committed
173 174
    p_input->p->p_es_out = NULL;
    p_input->p->p_sout  = NULL;
175 176 177
    p_input->p->b_owns_its_sout = true;
    p_input->p->b_sout_keep  = false;
    p_input->p->b_out_pace_control = false;
178 179 180
    p_input->i_pts_delay = 0;

    /* Init Input fields */
Pierre's avatar
Pierre committed
181
    vlc_gc_incref( p_item ); /* Released in Destructor() */
Clément Stenac's avatar
Clément Stenac committed
182 183 184 185
    p_input->p->input.p_item = p_item;
    p_input->p->input.p_access = NULL;
    p_input->p->input.p_stream = NULL;
    p_input->p->input.p_demux  = NULL;
186
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
187 188 189
    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;
190 191 192 193
    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
194 195
    p_input->p->input.i_cr_average = 0;

196
    vlc_mutex_lock( &p_item->lock );
197 198

    if( !p_item->p_stats )
199 200
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
201

202
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
203 204
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
205

206
    /* Init control buffer */
Clément Stenac's avatar
Clément Stenac committed
207 208
    vlc_mutex_init( p_input, &p_input->p->lock_control );
    p_input->p->i_control = 0;
209

210
    /* Parse input options */
211
    vlc_mutex_lock( &p_item->lock );
212
    assert( p_item->optflagc == p_item->i_options );
213
    for( i = 0; i < p_item->i_options; i++ )
214 215
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
216
    vlc_mutex_unlock( &p_item->lock );
217

218 219
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
220

221
    /* Create Objects variables for public Get and Set */
222
    input_ControlVarInit( p_input );
223

Clément Stenac's avatar
Clément Stenac committed
224
    p_input->p->input.i_cr_average = var_GetInteger( p_input, "cr-average" );
Gildas Bazin's avatar
Gildas Bazin committed
225

226
    if( !p_input->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
227
    {
228 229
        var_Get( p_input, "bookmarks", &val );
        if( val.psz_string )
Gildas Bazin's avatar
Gildas Bazin committed
230
        {
231 232 233 234
            /* FIXME: have a common cfg parsing routine used by sout and others */
            char *psz_parser, *psz_start, *psz_end;
            psz_parser = val.psz_string;
            while( (psz_start = strchr( psz_parser, '{' ) ) )
Gildas Bazin's avatar
Gildas Bazin committed
235
            {
236 237 238 239 240 241 242 243 244 245 246 247 248 249
                 seekpoint_t *p_seekpoint = vlc_seekpoint_New();
                 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 = ',';
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
250
                         p_seekpoint->psz_name = strdup(psz_start + 5);
251 252 253 254 255 256 257
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
258 259
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
                                                        1000000;
260 261
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
262
                }
263 264 265 266 267 268
                msg_Dbg( p_input, "adding bookmark: %s, bytes="I64Fd", time="I64Fd,
                                  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
269
            }
270
            free( val.psz_string );
Gildas Bazin's avatar
Gildas Bazin committed
271 272 273
        }
    }

274
    /* Remove 'Now playing' info as it is probably outdated */
275 276 277 278
    input_Control( p_input, INPUT_DEL_INFO,
        _(VLC_META_INFO_CAT),
        _(VLC_META_NOW_PLAYING) );
    input_item_SetNowPlaying( p_item, NULL );
279

280 281 282 283
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

284 285
    /* */
    if( p_sout )
286
    {
287
        p_input->p->p_sout = p_sout;
288
        p_input->p->b_owns_its_sout = false;
289
    }
290

291 292 293
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
    vlc_mutex_init( p_input, &p_input->p->counters.counters_lock );

294 295 296
    /* Attach only once we are ready */
    vlc_object_attach( p_input, p_parent );

297 298 299
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

300 301 302
    return p_input;
}

303 304 305 306
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
307
{
308
    input_thread_private_t *priv = p_input->p;
309

310
    if( priv->b_owns_its_sout && priv->p_sout )
311
    {
312
        if( priv->b_sout_keep )
313
            SoutKeep( priv->p_sout );
314
        else
315
            sout_DeleteInstance( priv->p_sout );
316 317
    }

Pierre's avatar
Pierre committed
318 319
    vlc_gc_decref( p_input->p->input.p_item );

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

322 323
    vlc_mutex_destroy( &priv->lock_control );
    free( priv );
324
}
325

326
/**
327 328
 * Initialize an input thread and run it. You will need to monitor the
 * thread to clean up after it is done
329 330 331 332 333 334 335
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \return a pointer to the spawned input thread
 */
input_thread_t *__input_CreateThread( vlc_object_t *p_parent,
                                      input_item_t *p_item )
336
{
337
    bool b_sout_keep;
338 339 340 341 342 343 344 345
    sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
    input_thread_t *p_input =  __input_CreateThreadExtended( p_parent, p_item, NULL, p_sout );

    if( !p_input && p_sout )
        SoutKeep( p_sout );

    p_input->p->b_sout_keep = b_sout_keep;
    return p_input;
346 347
}

348 349 350 351
/* */
input_thread_t *__input_CreateThreadExtended( vlc_object_t *p_parent,
                                              input_item_t *p_item,
                                              const char *psz_log, sout_instance_t *p_sout )
352
{
353
    input_thread_t *p_input;
354

355
    p_input = Create( p_parent, p_item, psz_log, false, p_sout );
356 357 358
    if( !p_input )
        return NULL;

Sam Hocevar's avatar
Sam Hocevar committed
359
    /* Create thread and wait for its readiness. */
360
    if( vlc_thread_create( p_input, "input", Run,
361
                           VLC_THREAD_PRIORITY_INPUT, true ) )
Michel Kaempf's avatar
Michel Kaempf committed
362
    {
363
        input_ChangeState( p_input, ERROR_S );
364
        msg_Err( p_input, "cannot create input thread" );
365 366
        vlc_object_detach( p_input );
        vlc_object_release( p_input );
367
        return NULL;
Michel Kaempf's avatar
Michel Kaempf committed
368
    }
369

370
    return p_input;
Michel Kaempf's avatar
Michel Kaempf committed
371 372
}

373 374 375 376 377 378 379
/**
 * Initialize an input thread and run it. This thread will clean after himself,
 * you can forget about it. It can work either in blocking or non-blocking mode
 *
 * \param p_parent a vlc_object
 * \param p_item an input item
 * \param b_block should we block until read is finished ?
Clément Stenac's avatar
Clément Stenac committed
380
 * \return the input object id if non blocking, an error code else
381
 */
382
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
383
                   bool b_block )
384
{
385
    bool b_sout_keep;
386 387
    sout_instance_t *p_sout = SoutFind( p_parent, p_item, &b_sout_keep );
    input_thread_t *p_input;
388

389
    p_input = Create( p_parent, p_item, NULL, false, p_sout );
390 391 392
    if( !p_input && p_sout )
    {
        SoutKeep( p_sout );
393
        return VLC_EGENERIC;
394 395
    }
    p_input->p->b_sout_keep = b_sout_keep;
396

397
    if( b_block )
398
    {
399
        RunAndDestroy( p_input );
Clément Stenac's avatar
Clément Stenac committed
400
        return VLC_SUCCESS;
401
    }
402
    else
403
    {
404
        if( vlc_thread_create( p_input, "input", RunAndDestroy,
405
                               VLC_THREAD_PRIORITY_INPUT, true ) )
406
        {
407
            input_ChangeState( p_input, ERROR_S );
408
            msg_Err( p_input, "cannot create input thread" );
409
            vlc_object_release( p_input );
Clément Stenac's avatar
Clément Stenac committed
410
            return VLC_EGENERIC;
411
        }
412
    }
413
    return p_input->i_object_id;
414
}
415

416 417 418 419 420 421 422 423 424 425
/**
 * Initialize an input and initialize it to preparse the item
 * This function is blocking. It will only accept to parse 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 )
{
426
    input_thread_t *p_input;
427

428
    /* Allocate descriptor */
429
    p_input = Create( p_parent, p_item, NULL, true, NULL );
430 431 432
    if( !p_input )
        return VLC_EGENERIC;

433 434
    if( !Init( p_input ) )
        End( p_input );
435

436 437
    vlc_object_detach( p_input );
    vlc_object_release( p_input );
438 439 440 441

    return VLC_SUCCESS;
}

442 443 444 445 446
/**
 * Request a running input thread to stop and die
 *
 * \param the input thread to stop
 */
Sam Hocevar's avatar
Sam Hocevar committed
447
void input_StopThread( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
448
{
449 450
    vlc_list_t *p_list;
    int i;
451

452
    /* Set die for input */
453 454
    vlc_object_kill( p_input );
    /* FIXME: seems to be duplicated in ControlPush(INPUT_CONTROL_SET_DIE) */
455

456
    /* We cannot touch p_input fields directly (we come from another thread),
457
     * so use the vlc_object_find way, it's perfectly safe */
458

459 460 461
    /* Set die for all access */
    p_list = vlc_list_find( p_input, VLC_OBJECT_ACCESS, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
462
    {
463
        vlc_object_kill( p_list->p_values[i].p_object );
464
    }
465
    vlc_list_release( p_list );
466

467 468 469
    /* Set die for all stream */
    p_list = vlc_list_find( p_input, VLC_OBJECT_STREAM, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
470
    {
471
        vlc_object_kill( p_list->p_values[i].p_object );
472
    }
473
    vlc_list_release( p_list );
474

475 476 477 478
    /* Set die for all demux */
    p_list = vlc_list_find( p_input, VLC_OBJECT_DEMUX, FIND_CHILD );
    for( i = 0; i < p_list->i_count; i++ )
    {
479
        vlc_object_kill( p_list->p_values[i].p_object );
480 481
    }
    vlc_list_release( p_list );
Michel Kaempf's avatar
Michel Kaempf committed
482

483
    input_ControlPush( p_input, INPUT_CONTROL_SET_DIE, NULL );
484 485
}

486 487
sout_instance_t * input_DetachSout( input_thread_t *p_input )
{
488
    p_input->p->b_owns_its_sout = false;
489 490 491
    return p_input->p->p_sout;
}

492
/*****************************************************************************
493
 * Run: main thread loop
494 495
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
496
 *****************************************************************************/
497
static int Run( input_thread_t *p_input )
Michel Kaempf's avatar
Michel Kaempf committed
498
{
499
    /* Signal that the thread is launched */
Sam Hocevar's avatar
Sam Hocevar committed
500 501
    vlc_thread_ready( p_input );

502
    if( Init( p_input ) )
503 504
    {
        /* If we failed, wait before we are killed, and exit */
505
        p_input->b_error = true;
506 507 508 509 510 511 512 513 514

        /* FIXME: we don't want to depend on the playlist */
        playlist_t * p_playlist = vlc_object_find( p_input,
            VLC_OBJECT_PLAYLIST, FIND_PARENT );
        if( p_playlist )
        {
            playlist_Signal( p_playlist );
            vlc_object_release( p_playlist );
        }
515

516
        Error( p_input );
517 518

        /* Tell we're dead */
519
        p_input->b_dead = true;
520

521
        return 0;
522
    }
Michel Kaempf's avatar
Michel Kaempf committed
523

524 525
    MainLoop( p_input );

Clément Stenac's avatar
Clément Stenac committed
526
    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
527 528 529 530
    {
        /* We have finish to demux data but not to play them */
        while( !p_input->b_die )
        {
Clément Stenac's avatar
Clément Stenac committed
531
            if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
532 533 534 535 536 537 538 539
                break;

            msg_Dbg( p_input, "waiting decoder fifos to empty" );

            msleep( INPUT_IDLE_SLEEP );
        }

        /* We have finished */
540
        p_input->b_eof = true;
541
        playlist_Signal( pl_Get( p_input ) );
542 543
    }

544
    /* Wait until we are asked to die */
545 546 547 548 549 550 551 552 553 554 555 556
    if( !p_input->b_die )
    {
        Error( p_input );
    }

    /* Clean up */
    End( p_input );

    return 0;
}

/*****************************************************************************
557
 * RunAndDestroy: main thread loop
558 559 560
 * This is the "just forget me" thread that spawns the input processing chain,
 * reads the stream, cleans up and releases memory
 *****************************************************************************/
561
static int RunAndDestroy( input_thread_t *p_input )
562 563 564 565
{
    /* Signal that the thread is launched */
    vlc_thread_ready( p_input );

566
    if( Init( p_input ) )
567
        goto exit;
568 569 570

    MainLoop( p_input );

Clément Stenac's avatar
Clément Stenac committed
571
    if( !p_input->b_eof && !p_input->b_error && p_input->p->input.b_eof )
572
    {
573
        /* We have finished demuxing data but not playing it */
574 575
        while( !p_input->b_die )
        {
Clément Stenac's avatar
Clément Stenac committed
576
            if( input_EsOutDecodersEmpty( p_input->p->p_es_out ) )
577 578 579 580 581 582
                break;

            msg_Dbg( p_input, "waiting decoder fifos to empty" );

            msleep( INPUT_IDLE_SLEEP );
        }
583

584
        /* We have finished */
585
        p_input->b_eof = true;
586 587 588 589 590
    }

    /* Clean up */
    End( p_input );

591
exit:
592
    /* Release memory */
593
    vlc_object_release( p_input );
594 595 596 597 598 599 600 601
    return 0;
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
static void MainLoop( input_thread_t *p_input )
{
602
    int64_t i_start_mdate = mdate();
603
    int64_t i_intf_update = 0;
604
    int i_updates = 0;
605

Clément Stenac's avatar
Clément Stenac committed
606
    while( !p_input->b_die && !p_input->b_error && !p_input->p->input.b_eof )
607
    {
608
        bool b_force_update = false;
609 610 611
        int i_ret;
        int i_type;
        vlc_value_t val;
612

613 614
        /* Do the read */
        if( p_input->i_state != PAUSE_S  )
615
        {
616 617 618
            if( ( p_input->p->i_stop > 0 && p_input->i_time >= p_input->p->i_stop ) ||
                ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
                i_ret = 0; /* EOF */
619
            else
620
                i_ret = p_input->p->input.p_demux->pf_demux(p_input->p->input.p_demux);
621

622 623 624
            if( i_ret > 0 )
            {
                /* TODO */
Clément Stenac's avatar
Clément Stenac committed
625 626
                if( p_input->p->input.b_title_demux &&
                    p_input->p->input.p_demux->info.i_update )
627
                {
628
                    i_ret = UpdateFromDemux( p_input );
629
                    b_force_update = true;
630
                }
Clément Stenac's avatar
Clément Stenac committed
631 632 633
                else if( !p_input->p->input.b_title_demux &&
                          p_input->p->input.p_access &&
                          p_input->p->input.p_access->info.i_update )
634
                {
635
                    i_ret = UpdateFromAccess( p_input );
636
                    b_force_update = true;
637 638
                }
            }
639 640

            if( i_ret == 0 )    /* EOF */
641 642
            {
                vlc_value_t repeat;
643

644 645 646 647 648
                var_Get( p_input, "input-repeat", &repeat );
                if( repeat.i_int == 0 )
                {
                    /* End of file - we do not set b_die because only the
                     * playlist is allowed to do so. */
649
                    input_ChangeState( p_input, END_S );
650
                    msg_Dbg( p_input, "EOF reached" );
651
                    p_input->p->input.b_eof = true;
652 653
                }
                else
654
                {
Gildas Bazin's avatar
Gildas Bazin committed
655 656
                    msg_Dbg( p_input, "repeating the same input (%d)",
                             repeat.i_int );
657 658 659 660 661
                    if( repeat.i_int > 0 )
                    {
                        repeat.i_int--;
                        var_Set( p_input, "input-repeat", repeat );
                    }
662

663
                    /* Seek to start title/seekpoint */
Clément Stenac's avatar
Clément Stenac committed
664 665 666
                    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 )
667 668 669 670
                        val.i_int = 0;
                    input_ControlPush( p_input,
                                       INPUT_CONTROL_SET_TITLE, &val );

Clément Stenac's avatar
Clément Stenac committed
671 672
                    val.i_int = p_input->p->input.i_seekpoint_start -
                        p_input->p->input.i_seekpoint_offset;
673 674 675 676 677
                    if( val.i_int > 0 /* TODO: check upper boundary */ )
                        input_ControlPush( p_input,
                                           INPUT_CONTROL_SET_SEEKPOINT, &val );

                    /* Seek to start position */
Clément Stenac's avatar
Clément Stenac committed
678
                    if( p_input->p->i_start > 0 )
679
                    {
Clément Stenac's avatar
Clément Stenac committed
680
                        val.i_time = p_input->p->i_start;
681 682 683 684 685 686 687 688 689
                        input_ControlPush( p_input, INPUT_CONTROL_SET_TIME,
                                           &val );
                    }
                    else
                    {
                        val.f_float = 0.0;
                        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION,
                                           &val );
                    }
690 691 692

                    /* */
                    i_start_mdate = mdate();
693 694
                }
            }
695 696
            else if( i_ret < 0 )
            {
697
                p_input->b_error = true;
698
            }
699

Clément Stenac's avatar
Clément Stenac committed
700
            if( i_ret > 0 && p_input->p->i_slave > 0 )
701 702 703
            {
                SlaveDemux( p_input );
            }
704
        }
705
        else
706
        {
707 708 709
            /* Small wait */
            msleep( 10*1000 );
        }
710

711
        /* Handle control */
Clément Stenac's avatar
Clément Stenac committed
712
        vlc_mutex_lock( &p_input->p->lock_control );
713 714 715 716 717
        ControlReduce( p_input );
        while( !ControlPopNoLock( p_input, &i_type, &val ) )
        {
            msg_Dbg( p_input, "control type=%d", i_type );
            if( Control( p_input, i_type, val ) )
718
                b_force_update = true;
719
        }
Clément Stenac's avatar
Clément Stenac committed
720
        vlc_mutex_unlock( &p_input->p->lock_control );
721

722
        if( b_force_update || i_intf_update < mdate() )
723 724 725 726 727
        {
            vlc_value_t val;
            double f_pos;
            int64_t i_time, i_length;
            /* update input status variables */
728
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
729
                                 DEMUX_GET_POSITION, &f_pos ) )
730 731 732 733
            {
                val.f_float = (float)f_pos;
                var_Change( p_input, "position", VLC_VAR_SETVALUE, &val, NULL );
            }
734
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
735
                                 DEMUX_GET_TIME, &i_time ) )
736 737 738 739 740
            {
                p_input->i_time = i_time;
                val.i_time = i_time;
                var_Change( p_input, "time", VLC_VAR_SETVALUE, &val, NULL );
            }
741
            if( !demux_Control( p_input->p->input.p_demux,
Gildas Bazin's avatar
Gildas Bazin committed
742
                                 DEMUX_GET_LENGTH, &i_length ) )
743 744 745 746 747
            {
                vlc_value_t old_val;
                var_Get( p_input, "length", &old_val );
                val.i_time = i_length;
                var_Change( p_input, "length", VLC_VAR_SETVALUE, &val, NULL );
748

749
                if( old_val.i_time != val.i_time )
750
                {
751
                    UpdateItemLength( p_input, i_length );
752 753
                }
            }
754

755
            var_SetBool( p_input, "intf-change", true );
756
            i_intf_update = mdate() + I64C(150000);
757
        }
758 759 760
        /* 150ms * 8 = ~ 1 second */
        if( ++i_updates % 8 == 0 )
        {
Clément Stenac's avatar
Clément Stenac committed
761
            stats_ComputeInputStats( p_input, p_input->p->input.p_item->p_stats );
762
            /* Are we the thread responsible for computing global stats ? */
763
            if( p_input->p_libvlc->p_stats_computer == p_input )
764
            {
765 766
                stats_ComputeGlobalStats( p_input->p_libvlc,
                                     p_input->p_libvlc->p_stats );
767 768
            }
        }
769
    }
770 771
}

772
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
773
{
774
    if( p_input->b_preparsing ) return;
775

776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
    if( p_input->p_libvlc->b_stats )
    {
        INIT_COUNTER( read_bytes, INTEGER, COUNTER );
        INIT_COUNTER( read_packets, INTEGER, COUNTER );
        INIT_COUNTER( demux_read, INTEGER, COUNTER );
        INIT_COUNTER( input_bitrate, FLOAT, DERIVATIVE );
        INIT_COUNTER( demux_bitrate, FLOAT, DERIVATIVE );
        INIT_COUNTER( played_abuffers, INTEGER, COUNTER );
        INIT_COUNTER( lost_abuffers, INTEGER, COUNTER );
        INIT_COUNTER( displayed_pictures, INTEGER, COUNTER );
        INIT_COUNTER( lost_pictures, INTEGER, COUNTER );
        INIT_COUNTER( decoded_audio, INTEGER, COUNTER );
        INIT_COUNTER( decoded_video, INTEGER, COUNTER );
        INIT_COUNTER( decoded_sub, INTEGER, COUNTER );
        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;
        if( p_input->p->counters.p_demux_bitrate )
            p_input->p->counters.p_demux_bitrate->update_interval = 1000000;
        if( p_input->p->counters.p_input_bitrate )
            p_input->p->counters.p_input_bitrate->update_interval = 1000000;
800
    }
801
}
802

803 804 805 806 807 808 809 810 811
static int InitSout( input_thread_t * p_input )
{
    char *psz;

    if( p_input->b_preparsing ) return VLC_SUCCESS;

    /* Find a usable sout and attach it to p_input */
    psz = var_GetNonEmptyString( p_input, "sout" );
    if( psz && strncasecmp( p_input->p->input.p_item->psz_uri, "vlc:", 4 ) )
812
    {
813 814
        /* Check the validity of the provided sout */
        if( p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
815
        {
816
            if( strcmp( p_input->p->p_sout->psz_sout, psz ) )
817
            {
818
                msg_Dbg( p_input, "destroying unusable sout" );
819

820 821
                sout_DeleteInstance( p_input->p->p_sout );
                p_input->p->p_sout = NULL;
822
            }
823
        }
824

825 826 827 828 829 830 831 832 833 834 835 836 837
        if( p_input->p->p_sout )
        {
            /* Reuse it */
            msg_Dbg( p_input, "sout keep: reusing sout" );
            msg_Dbg( p_input, "sout keep: you probably want to use "
                              "gather stream_out" );
            vlc_object_attach( p_input->p->p_sout, p_input );
        }
        else
        {
            /* Create a new one */
            p_input->p->p_sout = sout_NewInstance( p_input, psz );
            if( !p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
838
            {
839 840 841 842 843
                input_ChangeState( p_input, ERROR_S );
                msg_Err( p_input, "cannot start stream output instance, " \
                                  "aborting" );
                free( psz );
                return VLC_EGENERIC;
Clément Stenac's avatar
Clément Stenac committed
844
            }
845
        }
846
        if( p_input->p_libvlc->b_stats )
847
        {
848 849 850 851 852 853
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
            INIT_COUNTER (sout_sent_bytes, INTEGER, COUNTER );
            INIT_COUNTER( sout_send_bitrate, FLOAT, DERIVATIVE );
            if( p_input->p->counters.p_sout_send_bitrate )
                 p_input->p->counters.p_sout_send_bitrate->update_interval =
                         1000000;
854
        }
855
    }
856
    else if( p_input->p->p_sout )
857
    {
858 859 860 861
        msg_Dbg( p_input, "destroying useless sout" );

        sout_DeleteInstance( p_input->p->p_sout );
        p_input->p->p_sout = NULL;
862
    }
863
    free( psz );
864

865 866
    return VLC_SUCCESS;
}
867

868 869 870
static void InitTitle( input_thread_t * p_input )
{
    vlc_value_t val;
871

872
    if( p_input->b_preparsing ) return;
873

874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904
    /* Create global title (from master) */
    p_input->p->i_title = p_input->p->input.i_title;
    p_input->p->title   = p_input->p->input.title;
    p_input->p->i_title_offset = p_input->p->input.i_title_offset;
    p_input->p->i_seekpoint_offset = p_input->p->input.i_seekpoint_offset;
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
        input_ControlVarTitle( p_input, 0 );
    }

    /* Global flag */
    p_input->b_can_pace_control = p_input->p->input.b_can_pace_control;
    p_input->p->b_can_pause        = p_input->p->input.b_can_pause;
    p_input->p->b_can_rate_control = p_input->p->input.b_can_rate_control;

    /* Fix pts delay */
    if( p_input->i_pts_delay < 0 )
        p_input->i_pts_delay = 0;

    /* If the desynchronisation requested by the user is < 0, we need to
     * cache more data. */
    var_Get( p_input, "audio-desync", &val );
    if( val.i_int < 0 ) p_input->i_pts_delay -= (val.i_int * 1000);

    /* Update cr_average depending on the caching */
    p_input->p->input.i_cr_average *= (10 * p_input->i_pts_delay / 200000);
    p_input->p->input.i_cr_average /= 10;
    if( p_input->p->input.i_cr_average < 10 ) p_input->p->input.i_cr_average = 10;
}
905

906 907 908 909 910 911 912
static void StartTitle( input_thread_t * p_input )
{
    double f_fps;
    vlc_value_t val;
    int i, i_delay;
    char *psz;
    char *psz_subtitle;
913

914 915 916
    /* Start title/chapter */

    if( p_input->b_preparsing )
917
    {
918 919
        p_input->p->i_start = 0;
        return;
920
    }
921 922 923 924 925 926 927 928 929 930 931 932 933