input.c 108 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
        bool b_pause_after_each = var_CreateGetBool( p_input, "play-and-pause" );
635
        msg_Dbg( p_input, "EOF reached" );
636 637 638 639 640 641 642
        if ( b_pause_after_each )
        {
            msg_Dbg( p_input, "pausing at EOF (pause after each)");
            vlc_value_t pause_state;
            pause_state.i_int = PAUSE_S;
            Control( p_input, INPUT_CONTROL_SET_STATE, pause_state );
        }
643
        p_input->p->input.b_eof = true;
644 645 646 647 648 649 650 651
    }
    else if( i_ret < 0 )
    {
        input_ChangeState( p_input, ERROR_S );
    }

    if( i_ret > 0 && p_input->p->i_slave > 0 )
    {
652 653 654 655
        bool b_demux_polled;
        SlaveDemux( p_input, &b_demux_polled );

        *pb_demux_polled |= b_demux_polled;
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 697 698 699 700 701 702 703 704
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;
}

705 706 707 708 709 710
/**
 * MainLoopInterface
 * It update the variables used by the interfaces
 */
static void MainLoopInterface( input_thread_t *p_input )
{
711 712 713
    double f_position = 0.0;
    mtime_t i_time = 0;
    mtime_t i_length = 0;
714 715

    /* update input status variables */
716
    if( demux_Control( p_input->p->input.p_demux,
717 718
                       DEMUX_GET_POSITION, &f_position ) )
        f_position = 0.0;
719

720
    if( demux_Control( p_input->p->input.p_demux,
721 722
                       DEMUX_GET_TIME, &i_time ) )
        i_time = 0;
Laurent Aimar's avatar
Laurent Aimar committed
723
    p_input->p->i_time = i_time;
724 725

    if( demux_Control( p_input->p->input.p_demux,
726 727
                       DEMUX_GET_LENGTH, &i_length ) )
        i_length = 0;
728

729
    es_out_SetTimes( p_input->p->p_es_out, f_position, i_time, i_length );
730 731 732 733 734 735 736

    /* 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 );
737 738 739 740 741 742 743 744
}

/**
 * MainLoopStatistic
 * It updates the globals statics
 */
static void MainLoopStatistic( input_thread_t *p_input )
{
745
    stats_ComputeInputStats( p_input, p_input->p->p_item->p_stats );
746
    input_SendEventStatistics( p_input );
747 748 749 750 751 752 753 754 755
}

/**
 * MainLoop
 * The main input loop.
 */
static void MainLoop( input_thread_t *p_input )
{
    mtime_t i_start_mdate = mdate();
756 757
    mtime_t i_intf_update = 0;
    mtime_t i_statistic_update = 0;
758 759 760 761

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

762
    while( vlc_object_alive( p_input ) && !p_input->b_error )
763 764 765 766
    {
        bool b_force_update;
        int i_type;
        vlc_value_t val;
767
        mtime_t i_current;
768
        mtime_t i_deadline;
769
        mtime_t i_wakeup;
770
        bool b_paused;
771
        bool b_demux_polled;
772

773 774
        /* Demux data */
        b_force_update = false;
775
        i_wakeup = 0;
Laurent Aimar's avatar
Laurent Aimar committed
776
        /* FIXME if p_input->p->i_state == PAUSE_S the access/access_demux
777 778
         * 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
779
        b_paused = p_input->p->i_state == PAUSE_S &&
780
                   !es_out_GetBuffering( p_input->p->p_es_out );
781

782
        b_demux_polled = true;
783
        if( !b_paused )
784
        {
785 786
            if( !p_input->p->input.b_eof )
            {
787
                MainLoopDemux( p_input, &b_force_update, &b_demux_polled, i_start_mdate );
788

789 790
                i_wakeup = es_out_GetWakeup( p_input->p->p_es_out );
            }
791
            else if( !es_out_GetEmpty( p_input->p->p_es_out ) )
792 793 794 795 796 797
            {
                msg_Dbg( p_input, "waiting decoder fifos to empty" );
                i_wakeup = mdate() + INPUT_IDLE_SLEEP;
            }
            else
            {
798 799
                if( MainLoopTryRepeat( p_input, &i_start_mdate ) )
                    break;
800
            }
801
        }
802 803

        /* */
804 805
        do {
            i_deadline = i_wakeup;
806
            if( b_paused || !b_demux_polled )
807 808 809 810
                i_deadline = __MIN( i_intf_update, i_statistic_update );

            /* Handle control */
            ControlReduce( p_input );
811
            while( !ControlPop( p_input, &i_type, &val, i_deadline ) )
812
            {
813

814
                msg_Dbg( p_input, "control type=%d", i_type );
815

816 817 818
                if( Control( p_input, i_type, val ) )
                    b_force_update = true;
            }
819

820 821 822 823 824 825 826 827 828 829 830 831 832
            /* 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);
            }
833

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

840
    if( !p_input->b_error )
841
        input_ChangeState( p_input, END_S );
842 843
}

844
static void InitStatistics( input_thread_t * p_input )
Michel Kaempf's avatar
Michel Kaempf committed
845
{
846
    if( p_input->b_preparsing ) return;
847

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

877
#ifdef ENABLE_SOUT
878 879
static int InitSout( input_thread_t * p_input )
{
880 881
    if( p_input->b_preparsing )
        return VLC_SUCCESS;
882 883

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

912 913
    return VLC_SUCCESS;
}
914
#endif
915

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

Laurent Aimar's avatar
Laurent Aimar committed
920 921
    if( p_input->b_preparsing )
        return;
922

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

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

941 942 943
static void StartTitle( input_thread_t * p_input )
{
    vlc_value_t val;
944

945 946 947 948 949
    /* 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
950