input.c 109 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>
Laurent Aimar's avatar
Laurent Aimar committed
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_common.h>
Sam Hocevar's avatar
 
Sam Hocevar committed
33

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

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

Clément Stenac's avatar
Clément Stenac committed
49 50
#include <vlc_sout.h>
#include "../stream_output/stream_output.h"
Sam Hocevar's avatar
 
Sam Hocevar committed
51

52
#include <vlc_dialog.h>
Clément Stenac's avatar
Clément Stenac committed
53 54
#include <vlc_url.h>
#include <vlc_charset.h>
55
#include <vlc_strings.h>
56

57 58 59 60
#ifdef HAVE_SYS_STAT_H
#   include <sys/stat.h>
#endif

61
/*****************************************************************************
Michel Kaempf's avatar
Michel Kaempf committed
62
 * Local prototypes
63
 *****************************************************************************/
64 65
static void Destructor( input_thread_t * p_input );

66 67
static  void *Run            ( vlc_object_t *p_this );
static  void *RunAndDestroy  ( vlc_object_t *p_this );
Laurent Aimar's avatar
Laurent Aimar committed
68

Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
69
static input_thread_t * Create  ( vlc_object_t *, input_item_t *,
70
                                  const char *, bool, input_resource_t * );
71
static  int             Init    ( input_thread_t *p_input );
72 73
static void             End     ( input_thread_t *p_input );
static void             MainLoop( input_thread_t *p_input );
Laurent Aimar's avatar
Laurent Aimar committed
74

Laurent Aimar's avatar
Laurent Aimar committed
75 76
static void ObjectKillChildrens( input_thread_t *, vlc_object_t * );

77
static inline int ControlPop( input_thread_t *, int *, vlc_value_t *, mtime_t i_deadline );
Laurent Aimar's avatar
Laurent Aimar committed
78
static void       ControlReduce( input_thread_t * );
79 80
static void       ControlRelease( int i_type, vlc_value_t val );
static bool       Control( input_thread_t *, int, vlc_value_t );
81

82 83 84 85 86
static int  UpdateTitleSeekpointFromAccess( input_thread_t * );
static void UpdateGenericFromAccess( input_thread_t * );

static int  UpdateTitleSeekpointFromDemux( input_thread_t * );
static void UpdateGenericFromDemux( input_thread_t * );
Michel Kaempf's avatar
Michel Kaempf committed
87

88
static void MRLSections( input_thread_t *, char *, int *, int *, int *, int *);
89 90

static input_source_t *InputSourceNew( input_thread_t *);
Laurent Aimar's avatar
 
Laurent Aimar committed
91
static int  InputSourceInit( input_thread_t *, input_source_t *,
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
92
                             const char *, const char *psz_forced_demux );
93
static void InputSourceClean( input_source_t * );
Laurent Aimar's avatar
Laurent Aimar committed
94 95
static void InputSourceMeta( input_thread_t *, input_source_t *, vlc_meta_t * );

96 97
/* TODO */
//static void InputGetAttachments( input_thread_t *, input_source_t * );
98
static void SlaveDemux( input_thread_t *p_input, bool *pb_demux_polled );
99
static void SlaveSeek( input_thread_t *p_input );
100

101 102
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 );
103 104 105
static void InputGetExtraFiles( input_thread_t *p_input,
                                int *pi_list, char ***pppsz_list,
                                const char *psz_access, const char *psz_path );
106

107 108 109
static void AppendAttachment( int *pi_attachment, input_attachment_t ***ppp_attachment,
                              int i_new, input_attachment_t **pp_new );

110 111
static void SubtitleAdd( input_thread_t *p_input, char *psz_subtitle, bool b_forced );

112 113
static void input_ChangeState( input_thread_t *p_input, int i_state ); /* TODO fix name */

114
/* Do not let a pts_delay from access/demux go beyong 60s */
115
#define INPUT_PTS_DELAY_MAX INT64_C(60000000)
116

117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 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 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
/**
 * 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
 */

input_thread_t *__input_Create( vlc_object_t *p_parent,
                                input_item_t *p_item,
                                const char *psz_log, input_resource_t *p_resource )
{

    return Create( p_parent, p_item, psz_log, false, p_resource );
}

/**
 * Create a new input_thread_t and start it.
 *
 * Provided for convenience.
 *
 * \see input_Create
 */
input_thread_t *__input_CreateAndStart( vlc_object_t *p_parent,
                                        input_item_t *p_item, const char *psz_log )
{
    input_thread_t *p_input = __input_Create( p_parent, p_item, psz_log, NULL );

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

/**
 * Initialize an input thread and run it. This thread will clean after itself,
 * 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 ?
 * \return an error code, VLC_SUCCESS on success
 */
int __input_Read( vlc_object_t *p_parent, input_item_t *p_item,
                   bool b_block )
{
    input_thread_t *p_input;

    p_input = Create( p_parent, p_item, NULL, false, NULL );
    if( !p_input )
        return VLC_EGENERIC;

    if( b_block )
    {
        RunAndDestroy( VLC_OBJECT(p_input) );
        return VLC_SUCCESS;
    }
    else
    {
        if( vlc_thread_create( p_input, "input", RunAndDestroy,
                               VLC_THREAD_PRIORITY_INPUT ) )
        {
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot create input thread" );
            vlc_object_release( p_input );
            return VLC_EGENERIC;
        }
    }
    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. */
    if( vlc_thread_create( p_input, "input", Run,
                           VLC_THREAD_PRIORITY_INPUT ) )
    {
        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 */
    ObjectKillChildrens( p_input, VLC_OBJECT(p_input) );

    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 );
}

input_resource_t *input_DetachResource( input_thread_t *p_input )
{
    assert( p_input->b_dead );

    input_resource_SetInput( p_input->p->p_resource, NULL );

    input_resource_t *p_resource = input_resource_Detach( p_input->p->p_resource );
    p_input->p->p_sout = NULL;

    return p_resource;
}

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

/*****************************************************************************
 * ObjectKillChildrens
 *****************************************************************************/
static void ObjectKillChildrens( input_thread_t *p_input, vlc_object_t *p_obj )
{
    vlc_list_t *p_list;
    int i;

    /* FIXME ObjectKillChildrens seems a very bad idea in fact */
    i = vlc_internals( p_obj )->i_object_type;
    if( i == VLC_OBJECT_VOUT ||i == VLC_OBJECT_AOUT ||
        p_obj == VLC_OBJECT(p_input->p->p_sout) ||
300
        i == VLC_OBJECT_DECODER )
301 302 303 304 305 306 307 308 309 310
        return;

    vlc_object_kill( p_obj );

    p_list = vlc_list_children( p_obj );
    for( i = 0; i < p_list->i_count; i++ )
        ObjectKillChildrens( p_input, p_list->p_values[i].p_object );
    vlc_list_release( p_list );
}

311
/*****************************************************************************
312 313
 * 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
314
 *
Laurent Aimar's avatar
Laurent Aimar committed
315
 * XXX Do not forget to update vlc_input.h if you add new variables.
316
 *****************************************************************************/
317
static input_thread_t *Create( vlc_object_t *p_parent, input_item_t *p_item,
318
                               const char *psz_header, bool b_quick,
319
                               input_resource_t *p_resource )
Michel Kaempf's avatar
Michel Kaempf committed
320
{
321
    static const char input_name[] = "input";
322
    input_thread_t *p_input = NULL;                 /* thread descriptor */
323
    int i;
324

325
    /* Allocate descriptor */
326 327
    p_input = vlc_custom_create( p_parent, sizeof( *p_input ),
                                 VLC_OBJECT_INPUT, input_name );
328
    if( p_input == NULL )
329
        return NULL;
330 331 332 333 334 335

    /* 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 );
336 337 338

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

339 340 341 342 343 344 345
    free( psz_name );

    /* Start a timer to mesure how long it takes
     * to launch an input */
    stats_TimerStart( p_input, psz_timer_name,
        STATS_TIMER_INPUT_LAUNCHING );

346 347 348
    p_input->p = calloc( 1, sizeof( input_thread_private_t ) );
    if( !p_input->p )
        return NULL;
349

350
    p_input->b_preparsing = b_quick;
351
    p_input->psz_header = psz_header ? strdup( psz_header ) : NULL;
352

Laurent Aimar's avatar
Laurent Aimar committed
353
    /* Init Common fields */
354
    p_input->b_eof = false;
355
    p_input->p->b_can_pace_control = true;
Clément Stenac's avatar
Clément Stenac committed
356
    p_input->p->i_start = 0;
Laurent Aimar's avatar
Laurent Aimar committed
357
    p_input->p->i_time  = 0;
Clément Stenac's avatar
Clément Stenac committed
358
    p_input->p->i_stop  = 0;
359
    p_input->p->i_run   = 0;
Clément Stenac's avatar
Clément Stenac committed
360
    p_input->p->i_title = 0;
361
    p_input->p->title = NULL;
Clément Stenac's avatar
Clément Stenac committed
362
    p_input->p->i_title_offset = p_input->p->i_seekpoint_offset = 0;
Laurent Aimar's avatar
Laurent Aimar committed
363
    p_input->p->i_state = INIT_S;
364
    p_input->p->i_rate = INPUT_RATE_DEFAULT;
365
    p_input->p->b_recording = false;
366 367
    memset( &p_input->p->bookmark, 0, sizeof(p_input->p->bookmark) );
    TAB_INIT( p_input->p->i_bookmark, p_input->p->pp_bookmark );
368
    TAB_INIT( p_input->p->i_attachment, p_input->p->attachment );
369 370
    p_input->p->p_es_out_display = NULL;
    p_input->p->p_es_out = NULL;
371
    p_input->p->p_sout   = NULL;
372
    p_input->p->b_out_pace_control = false;
Laurent Aimar's avatar
Laurent Aimar committed
373

Pierre's avatar
Pierre committed
374
    vlc_gc_incref( p_item ); /* Released in Destructor() */
375 376 377
    p_input->p->p_item = p_item;

    /* Init Input fields */
Clément Stenac's avatar
Clément Stenac committed
378 379 380
    p_input->p->input.p_access = NULL;
    p_input->p->input.p_stream = NULL;
    p_input->p->input.p_demux  = NULL;
381
    p_input->p->input.b_title_demux = false;
Clément Stenac's avatar
Clément Stenac committed
382 383 384
    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;
385 386 387 388
    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
389

390
    vlc_mutex_lock( &p_item->lock );
391 392

    if( !p_item->p_stats )
393 394
        p_item->p_stats = stats_NewInputStats( p_input );
    vlc_mutex_unlock( &p_item->lock );
Clément Stenac's avatar
Clément Stenac committed
395

396
    /* No slave */
Clément Stenac's avatar
Clément Stenac committed
397 398
    p_input->p->i_slave = 0;
    p_input->p->slave   = NULL;
399

400
    /* */
401 402
    if( p_resource )
        p_input->p->p_resource = p_resource;
403
    else
404 405
        p_input->p->p_resource = input_resource_New();
    input_resource_SetInput( p_input->p->p_resource, p_input );
406

Laurent Aimar's avatar
Laurent Aimar committed
407
    /* Init control buffer */
408
    vlc_mutex_init( &p_input->p->lock_control );
409
    vlc_cond_init( &p_input->p->wait_control );
Clément Stenac's avatar
Clément Stenac committed
410
    p_input->p->i_control = 0;
411
    p_input->p->b_abort = false;
412

Gildas Bazin's avatar
 
Gildas Bazin committed
413
    /* Parse input options */
414
    vlc_mutex_lock( &p_item->lock );
Pierre d'Herbemont's avatar
Pierre d'Herbemont committed
415
    assert( (int)p_item->optflagc == p_item->i_options );
416
    for( i = 0; i < p_item->i_options; i++ )
417 418
        var_OptionParse( VLC_OBJECT(p_input), p_item->ppsz_options[i],
                         !!(p_item->optflagv[i] & VLC_INPUT_OPTION_TRUSTED) );
419
    vlc_mutex_unlock( &p_item->lock );
Gildas Bazin's avatar
 
Gildas Bazin committed
420

Laurent Aimar's avatar
Laurent Aimar committed
421 422
    /* Create Object Variables for private use only */
    input_ConfigVarInit( p_input );
Michel Kaempf's avatar
Michel Kaempf committed
423

Laurent Aimar's avatar
Laurent Aimar committed
424
    /* Create Objects variables for public Get and Set */
425
    input_ControlVarInit( p_input );
426

427
    /* */
428
    if( !p_input->b_preparsing )
Gildas Bazin's avatar
Gildas Bazin committed
429
    {
Laurent Aimar's avatar
Laurent Aimar committed
430 431
        char *psz_bookmarks = var_GetNonEmptyString( p_input, "bookmarks" );
        if( psz_bookmarks )
Gildas Bazin's avatar
Gildas Bazin committed
432
        {
433 434
            /* 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
435
            psz_parser = psz_bookmarks;
436
            while( (psz_start = strchr( psz_parser, '{' ) ) )
Gildas Bazin's avatar
Gildas Bazin committed
437
            {
438
                 seekpoint_t *p_seekpoint;
439 440 441 442 443 444 445 446
                 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 = ',';
447 448

                 p_seekpoint = vlc_seekpoint_New();
449 450 451 452 453
                 while( (psz_end = strchr( psz_start, ',' ) ) )
                 {
                     *psz_end = 0;
                     if( !strncmp( psz_start, "name=", 5 ) )
                     {
454
                         p_seekpoint->psz_name = strdup(psz_start + 5);
455 456 457 458 459 460 461
                     }
                     else if( !strncmp( psz_start, "bytes=", 6 ) )
                     {
                         p_seekpoint->i_byte_offset = atoll(psz_start + 6);
                     }
                     else if( !strncmp( psz_start, "time=", 5 ) )
                     {
462 463
                         p_seekpoint->i_time_offset = atoll(psz_start + 5) *
                                                        1000000;
464 465
                     }
                     psz_start = psz_end + 1;
Gildas Bazin's avatar
Gildas Bazin committed
466
                }
Rémi Denis-Courmont's avatar
Rémi Denis-Courmont committed
467
                msg_Dbg( p_input, "adding bookmark: %s, bytes=%"PRId64", time=%"PRId64,
468 469 470 471 472
                                  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
473
            }
Laurent Aimar's avatar
Laurent Aimar committed
474
            free( psz_bookmarks );
Gildas Bazin's avatar
Gildas Bazin committed
475 476 477
        }
    }

478
    /* Remove 'Now playing' info as it is probably outdated */
479
    input_item_SetNowPlaying( p_item, NULL );
480
    input_SendEventMeta( p_input );
481

482 483 484 485
    /* */
    if( p_input->b_preparsing )
        p_input->i_flags |= OBJECT_FLAGS_QUIET | OBJECT_FLAGS_NOINTERACT;

486
    /* */
487
    memset( &p_input->p->counters, 0, sizeof( p_input->p->counters ) );
488
    vlc_mutex_init( &p_input->p->counters.counters_lock );
489

490 491 492
    /* Set the destructor when we are sure we are initialized */
    vlc_object_set_destructor( p_input, (vlc_destructor_t)Destructor );

493 494 495
    /* Attach only once we are ready */
    vlc_object_attach( p_input, p_parent );

496 497 498
    return p_input;
}

499 500 501 502
/**
 * Input destructor (called when the object's refcount reaches 0).
 */
static void Destructor( input_thread_t * p_input )
503
{
504
#ifndef NDEBUG
505
    char * psz_name = input_item_GetName( p_input->p->p_item );
506 507 508 509
    msg_Dbg( p_input, "Destroying the input for '%s'", psz_name);
    free( psz_name );
#endif

510 511
    stats_TimerDump( p_input, STATS_TIMER_INPUT_LAUNCHING );
    stats_TimerClean( p_input, STATS_TIMER_INPUT_LAUNCHING );
512

513 514
    if( p_input->p->p_resource )
        input_resource_Delete( p_input->p->p_resource );
515

516
    vlc_gc_decref( p_input->p->p_item );
Pierre's avatar
Pierre committed
517

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

520
    for( int i = 0; i < p_input->p->i_control; i++ )
Laurent Aimar's avatar
Laurent Aimar committed
521 522 523 524
    {
        input_control_t *p_ctrl = &p_input->p->control[i];
        ControlRelease( p_ctrl->i_type, p_ctrl->val );
    }
525

526
    vlc_cond_destroy( &p_input->p->wait_control );
527 528
    vlc_mutex_destroy( &p_input->p->lock_control );
    free( p_input->p );
529
}
530

531
/*****************************************************************************
Laurent Aimar's avatar
Laurent Aimar committed
532
 * Run: main thread loop
533 534
 * This is the "normal" thread that spawns the input processing chain,
 * reads the stream, cleans up and waits
535
 *****************************************************************************/
536
static void *Run( vlc_object_t *p_this )
Michel Kaempf's avatar
Michel Kaempf committed
537
{
538
    input_thread_t *p_input = (input_thread_t *)p_this;
539
    const int canc = vlc_savecancel();
540

541
    if( Init( p_input ) )
542
        goto exit;
Michel Kaempf's avatar
Michel Kaempf committed
543

544 545 546 547
    MainLoop( p_input );

    /* Clean up */
    End( p_input );
548 549

exit:
550
    /* Tell we're dead */
551 552 553 554 555
    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 )
556
        input_SendEventAbort( p_input );
557
    input_SendEventDead( p_input );
558

559
    vlc_restorecancel( canc );
560
    return NULL;
561 562 563
}

/*****************************************************************************
564
 * RunAndDestroy: main thread loop
565 566 567
 * This is the "just forget me" thread that spawns the input processing chain,
 * reads the stream, cleans up and releases memory
 *****************************************************************************/
568
static void *RunAndDestroy( vlc_object_t *p_this )
569
{
570
    input_thread_t *p_input = (input_thread_t *)p_this;
571
    const int canc = vlc_savecancel();
572

573
    if( Init( p_input ) )
574
        goto exit;
575 576 577 578 579 580

    MainLoop( p_input );

    /* Clean up */
    End( p_input );

581
exit:
582
    /* Release memory */
583
    vlc_object_release( p_input );
584 585
    vlc_restorecancel( canc );
    return NULL;
586 587 588 589 590
}

/*****************************************************************************
 * Main loop: Fill buffers from access, and demux
 *****************************************************************************/
591 592 593 594 595

/**
 * MainLoopDemux
 * It asks the demuxer to demux some data
 */
596
static void MainLoopDemux( input_thread_t *p_input, bool *pb_changed, bool *pb_demux_polled, mtime_t i_start_mdate )
597
{
598
    int i_ret;
599

600
    *pb_changed = false;
601
    *pb_demux_polled = p_input->p->input.p_demux->pf_demux != NULL;
602

Laurent Aimar's avatar
Laurent Aimar committed
603
    if( ( p_input->p->i_stop > 0 && p_input->p->i_time >= p_input->p->i_stop ) ||
604
        ( p_input->p->i_run > 0 && i_start_mdate+p_input->p->i_run < mdate() ) )
605 606
        i_ret = 0; /* EOF */
    else
Laurent Aimar's avatar
Laurent Aimar committed
607
        i_ret = demux_Demux( p_input->p->input.p_demux );
608 609

    if( i_ret > 0 )
Sam Hocevar's avatar
 
Sam Hocevar committed
610
    {
611
        if( p_input->p->input.p_demux->info.i_update )
612
        {
613 614 615 616 617 618
            if( p_input->p->input.b_title_demux )
            {
                i_ret = UpdateTitleSeekpointFromDemux( p_input );
                *pb_changed = true;
            }
            UpdateGenericFromDemux( p_input );
619
        }
620 621
        else if( p_input->p->input.p_access &&
                 p_input->p->input.p_access->info.i_update )
622
        {
623 624 625 626 627 628
            if( !p_input->p->input.b_title_demux )
            {
                i_ret = UpdateTitleSeekpointFromAccess( p_input );
                *pb_changed = true;
            }
            UpdateGenericFromAccess( p_input );
629 630
        }
    }
631

632 633
    if( i_ret == 0 )    /* EOF */
    {
634 635
        msg_Dbg( p_input, "EOF reached" );
        p_input->p->input.b_eof = true;
636 637 638 639 640 641 642 643
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
    {
644 645 646 647
        bool b_demux_polled;
        SlaveDemux( p_input, &b_demux_polled );

        *pb_demux_polled |= b_demux_polled;
648 649 650
    }
}

651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696
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
    {
        val.f_float = 0.0;
        input_ControlPush( p_input, INPUT_CONTROL_SET_POSITION, &val );
    }

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

697 698 699 700 701 702
/**
 * MainLoopInterface
 * It update the variables used by the interfaces
 */
static void MainLoopInterface( input_thread_t *p_input )
{
703 704 705
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
706 707

    /* update input status variables */
708
    if( demux_Control( p_input->p->input.p_demux,
709 710
                       DEMUX_GET_POSITION, &f_position ) )
        f_position = 0.0;
711

712
    if( demux_Control( p_input->p->input.p_demux,
713 714
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
Laurent Aimar's avatar
Laurent Aimar committed
715
    p_input->p->i_time = i_time;
716 717

    if( demux_Control( p_input->p->input.p_demux,
718 719
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
720

721
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
722 723 724 725 726 727 728

    /* update current bookmark */
    vlc_mutex_lock( &p_input->p->p_item->lock );
    p_input->p->bookmark.i_time_offset = i_time;
    if( p_input->p->input.p_stream )
        p_input->p->bookmark.i_byte_offset = stream_Tell( p_input->p->input.p_stream );
    vlc_mutex_unlock( &p_input->p->p_item->lock );
729 730 731 732 733 734 735 736
}

/**
 * MainLoopStatistic
 * It updates the globals statics
 */
static void MainLoopStatistic( input_thread_t *p_input )
{
737
    stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
738
    input_SendEventStatistics( p_input );
739 740 741 742 743 744 745 746 747
}

/**
 * MainLoop
 * The main input loop.
 */
static void MainLoop( input_thread_t *p_input )
{
    mtime_t i_start_mdate = mdate();
748 749
    mtime_t i_intf_update = 0;
    mtime_t i_statistic_update = 0;
750
    bool b_pause_after_eof = var_CreateGetBool( p_input, "play-and-pause" );
751 752 753 754

    /* Start the timer */
    stats_TimerStop( p_input, STATS_TIMER_INPUT_LAUNCHING );

755
    while( vlc_object_alive( p_input ) && !p_input->b_error )
756 757 758 759
    {
        bool b_force_update;
        int i_type;
        vlc_value_t val;
760
        mtime_t i_current;
761
        mtime_t i_deadline;
762
        mtime_t i_wakeup;
763
        bool b_paused;
764
        bool b_demux_polled;
765

766 767
        /* Demux data */
        b_force_update = false;
768
        i_wakeup = 0;
Laurent Aimar's avatar
Laurent Aimar committed
769
        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
770 771
         * 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
772
        b_paused = p_input->p->i_state == PAUSE_S &&
773
                   ( !es_out_GetBuffering( p_input->p->p_es_out ) || p_input->p->input.b_eof );
774

775
        b_demux_polled = true;
776
        if( !b_paused )
777
        {
778 779
            if( !p_input->p->input.b_eof )
            {
780
                MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate );
781

782 783
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
            }
784
            else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
785 786 787 788
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
789 790 791 792 793 794 795 796 797
            else if( b_pause_after_eof )
            {
                msg_Dbg( p_input, "pausing at EOF (pause after each)");
                val.i_int = PAUSE_S;
                Control( p_input, INPUT_CONTROL_SET_STATE, val );

                b_pause_after_eof = false;
                b_paused = true;
            }
798 799
            else
            {
800 801
                if( MainLoopTryRepeat( p_input, &i_start_mdate ) )
                    break;
802
                b_pause_after_eof = var_GetBool( p_input, "play-and-pause" );
803
            }
804
        }
805 806

        /* */
807 808
        do {
            i_deadline = i_wakeup;
809
            if( b_paused || !b_demux_polled )
810 811 812 813
                i_deadline = __MIN( i_intf_update, i_statistic_update );

            /* Handle control */
            ControlReduce( p_input );
814
            while( !ControlPop( p_input, &i_type, &val, i_deadline ) )
815
            {
816

817
                msg_Dbg( p_input, "control type=%d", i_type );
818

819 820 821
                if( Control( p_input, i_type, val ) )
                    b_force_update = true;
            }
822

823 824 825 826 827 828 829 830 831 832 833 834 835
            /* 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 );
                i_statistic_update = i_current + INT64_C(1000000);
            }
836

837
            /* Update the wakeup time */
838
            if( i_wakeup != 0 )
839
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
840
        } while( i_current < i_wakeup );
Laurent Aimar's avatar
Laurent Aimar committed
841
    }
842

843
    if( !p_input->b_error )
844
        input_ChangeState( p_input, END_S );
845 846
}

847
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
848
{
849
    if( p_input->b_preparsing ) return;
850

851 852 853
    /* Prepare statistics */
#define INIT_COUNTER( c, type, compute ) p_input->p->counters.p_##c = \
 stats_CounterCreate( p_input, VLC_VAR_##type, STATS_##compute);
854
    if( libvlc_stats( p_input ) )
855 856 857 858 859 860
    {
        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 );
861 862
        INIT_COUNTER( demux_corrupted, INTEGER, COUNTER );
        INIT_COUNTER( demux_discontinuity, INTEGER, COUNTER );
863 864 865 866 867 868 869 870 871 872 873 874 875 876
        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;
877
    }
878
}
879

880
#ifdef ENABLE_SOUT
881 882
static int InitSout( input_thread_t * p_input )
{
883 884
    if( p_input->b_preparsing )
        return VLC_SUCCESS;
885 886

    /* Find a usable sout and attach it to p_input */
887
    char *psz = var_GetNonEmptyString( p_input, "sout" );
888
    if( psz && strncasecmp( p_input->p->p_item->psz_uri, "vlc:", 4 ) )
889
    {
890
        p_input->p->p_sout  = input_resource_RequestSout( p_input->p->p_resource, NULL, psz );
891
        if( !p_input->p->p_sout )
Clément Stenac's avatar
Clément Stenac committed
892
        {
893 894 895 896 897
            input_ChangeState( p_input, ERROR_S );
            msg_Err( p_input, "cannot start stream output instance, " \
                              "aborting" );
            free( psz );
            return VLC_EGENERIC;
898
        }
899
        if( libvlc_stats( p_input ) )
900
        {
901
            INIT_COUNTER( sout_sent_packets, INTEGER, COUNTER );
902
            INIT_COUNTER( sout_sent_bytes, INTEGER, COUNTER );
903 904 905 906
            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;
907
        }
908
    }
909
    else
910
    {
911
        input_resource_RequestSout( p_input->p->p_resource, NULL, NULL );
Laurent Aimar's avatar
Laurent Aimar committed
912
    }
913
    free( psz );
914

915 916
    return VLC_SUCCESS;
}
917
#endif
918

919 920
static void InitTitle( input_thread_t * p_input )
{
Laurent Aimar's avatar
Laurent Aimar committed
921
    input_source_t *p_master = &p_input->p->input;
Laurent Aimar's avatar
Laurent Aimar committed
922

Laurent Aimar's avatar
Laurent Aimar committed
923 924
    if( p_input->b_preparsing )
        return;
925

926
    /* Create global title (from master) */
Laurent Aimar's avatar
Laurent Aimar committed
927 928 929 930
    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;
931 932 933 934
    if( p_input->p->i_title > 0 )
    {
        /* Setup variables */
        input_ControlVarNavigation( p_input );
935
        input_SendEventTitle( p_input, 0 );
936 937 938
    }

    /* Global flag */
939
    p_input->p->b_can_pace_control    = p_master->b_can_pace_control;
Laurent Aimar's avatar
Laurent Aimar committed
940 941
    p_input->p->b_can_pause        = p_master->b_can_pause;
    p_input->p->b_can_rate_control = p_master->b_can_rate_control;
942
}
Gildas Bazin's avatar
 
Gildas Bazin committed
943

944 945 946
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
947

948 949 950 951 952
    /* Start title/chapter */
    val.i_int = p_input->p->input.i_title_start -